Fix for bug 798264 (Split property tables). r=bz.
authorPeter Van der Beken <peterv@propagandism.org>
Tue, 09 Oct 2012 20:50:05 +0200
changeset 110215 d178bdc3a5572677547f829702eb30e6cf42e183
parent 110214 b4ecedf655f2f1b7bee66b738fcaf65d3a2725f7
child 110216 e3239845f9d2222b5e385247ba19eefecc5ad2ae
push id16399
push userpvanderbeken@mozilla.com
push dateSun, 14 Oct 2012 12:12:05 +0000
treeherdermozilla-inbound@d178bdc3a557 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs798264
milestone19.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
Fix for bug 798264 (Split property tables). r=bz.
dom/bindings/BindingUtils.cpp
dom/bindings/BindingUtils.h
dom/bindings/Codegen.py
dom/tests/mochitest/chrome/file_bug799299.xul
dom/tests/mochitest/chrome/test_bug799299.xul
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <stdarg.h>
 
 #include "BindingUtils.h"
 
+#include "AccessCheck.h"
 #include "WrapperFactory.h"
 #include "xpcprivate.h"
 #include "XPCQuickStubs.h"
 #include "nsIXPConnect.h"
 
 namespace mozilla {
 namespace dom {
 
@@ -135,18 +136,18 @@ InterfaceObjectToString(JSContext* cx, u
 
   return xpc::NonVoidStringToJsval(cx, str, vp);
 }
 
 static JSObject*
 CreateInterfaceObject(JSContext* cx, JSObject* global, JSObject* receiver,
                       JSClass* constructorClass, JSNative constructorNative,
                       unsigned ctorNargs, JSObject* proto,
-                      Prefable<JSFunctionSpec>* staticMethods,
-                      Prefable<ConstantSpec>* constants,
+                      const NativeProperties* properties,
+                      const NativeProperties* chromeOnlyProperties,
                       const char* name)
 {
   JSObject* constructor;
   if (constructorClass) {
     JSObject* functionProto = JS_GetFunctionPrototype(cx, global);
     if (!functionProto) {
       return NULL;
     }
@@ -159,20 +160,16 @@ CreateInterfaceObject(JSContext* cx, JSO
       return NULL;
     }
     constructor = JS_GetFunctionObject(fun);
   }
   if (!constructor) {
     return NULL;
   }
 
-  if (staticMethods && !DefinePrefable(cx, constructor, staticMethods)) {
-    return NULL;
-  }
-
   if (constructorClass) {
     JSFunction* toString = js::DefineFunctionWithReserved(cx, constructor,
                                                           "toString",
                                                           InterfaceObjectToString,
                                                           0, 0);
     if (!toString) {
       return NULL;
     }
@@ -184,18 +181,38 @@ CreateInterfaceObject(JSContext* cx, JSO
     JSString *str = ::JS_InternString(cx, name);
     if (!str) {
       return NULL;
     }
     js::SetFunctionNativeReserved(toStringObj, TOSTRING_NAME_RESERVED_SLOT,
                                   STRING_TO_JSVAL(str));
   }
 
-  if (constants && !DefinePrefable(cx, constructor, constants)) {
-    return NULL;
+  if (properties) {
+    if (properties->staticMethods &&
+        !DefinePrefable(cx, constructor, properties->staticMethods)) {
+      return nullptr;
+    }
+
+    if (properties->constants &&
+        !DefinePrefable(cx, constructor, properties->constants)) {
+      return nullptr;
+    }
+  }
+
+  if (chromeOnlyProperties) {
+    if (chromeOnlyProperties->staticMethods &&
+        !DefinePrefable(cx, constructor, chromeOnlyProperties->staticMethods)) {
+      return nullptr;
+    }
+
+    if (chromeOnlyProperties->constants &&
+        !DefinePrefable(cx, constructor, chromeOnlyProperties->constants)) {
+      return nullptr;
+    }
   }
 
   if (proto && !JS_LinkConstructorAndPrototype(cx, constructor, proto)) {
     return NULL;
   }
 
   JSBool alreadyDefined;
   if (!JS_AlreadyHasOwnProperty(cx, receiver, name, &alreadyDefined)) {
@@ -210,81 +227,107 @@ CreateInterfaceObject(JSContext* cx, JSO
   }
 
   return constructor;
 }
 
 static JSObject*
 CreateInterfacePrototypeObject(JSContext* cx, JSObject* global,
                                JSObject* parentProto, JSClass* protoClass,
-                               Prefable<JSFunctionSpec>* methods,
-                               Prefable<JSPropertySpec>* properties,
-                               Prefable<ConstantSpec>* constants)
+                               const NativeProperties* properties,
+                               const NativeProperties* chromeOnlyProperties)
 {
   JSObject* ourProto = JS_NewObjectWithUniqueType(cx, protoClass, parentProto,
                                                   global);
   if (!ourProto) {
     return NULL;
   }
 
-  if (methods && !DefinePrefable(cx, ourProto, methods)) {
-    return NULL;
+  if (properties) {
+    if (properties->methods &&
+        !DefinePrefable(cx, ourProto, properties->methods)) {
+      return nullptr;
+    }
+
+    if (properties->attributes &&
+        !DefinePrefable(cx, ourProto, properties->attributes)) {
+      return nullptr;
+    }
+
+    if (properties->constants &&
+        !DefinePrefable(cx, ourProto, properties->constants)) {
+      return nullptr;
+    }
   }
 
-  if (properties && !DefinePrefable(cx, ourProto, properties)) {
-    return NULL;
-  }
+  if (chromeOnlyProperties) {
+    if (chromeOnlyProperties->methods &&
+        !DefinePrefable(cx, ourProto, chromeOnlyProperties->methods)) {
+      return nullptr;
+    }
 
-  if (constants && !DefinePrefable(cx, ourProto, constants)) {
-    return NULL;
+    if (chromeOnlyProperties->attributes &&
+        !DefinePrefable(cx, ourProto, chromeOnlyProperties->attributes)) {
+      return nullptr;
+    }
+
+    if (chromeOnlyProperties->constants &&
+        !DefinePrefable(cx, ourProto, chromeOnlyProperties->constants)) {
+      return nullptr;
+    }
   }
 
   return ourProto;
 }
 
 JSObject*
 CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject *receiver,
                        JSObject* protoProto, JSClass* protoClass,
                        JSClass* constructorClass, JSNative constructor,
                        unsigned ctorNargs, const DOMClass* domClass,
-                       Prefable<JSFunctionSpec>* methods,
-                       Prefable<JSPropertySpec>* properties,
-                       Prefable<ConstantSpec>* constants,
-                       Prefable<JSFunctionSpec>* staticMethods, const char* name)
+                       const NativeProperties* properties,
+                       const NativeProperties* chromeOnlyProperties,
+                       const char* name)
 {
   MOZ_ASSERT(protoClass || constructorClass || constructor,
              "Need at least one class or a constructor!");
-  MOZ_ASSERT(!(methods || properties) || protoClass,
+  MOZ_ASSERT(!((properties &&
+                (properties->methods || properties->attributes)) ||
+               (chromeOnlyProperties &&
+                (chromeOnlyProperties->methods ||
+                 chromeOnlyProperties->attributes))) || protoClass,
              "Methods or properties but no protoClass!");
-  MOZ_ASSERT(!staticMethods || constructorClass || constructor,
+  MOZ_ASSERT(!((properties && properties->staticMethods) ||
+               (chromeOnlyProperties && chromeOnlyProperties->staticMethods)) ||
+             constructorClass || constructor,
              "Static methods but no constructorClass or constructor!");
   MOZ_ASSERT(bool(name) == bool(constructorClass || constructor),
              "Must have name precisely when we have an interface object");
   MOZ_ASSERT(!constructorClass || !constructor);
 
   JSObject* proto;
   if (protoClass) {
     proto = CreateInterfacePrototypeObject(cx, global, protoProto, protoClass,
-                                           methods, properties, constants);
+                                           properties, chromeOnlyProperties);
     if (!proto) {
       return NULL;
     }
 
     js::SetReservedSlot(proto, DOM_PROTO_INSTANCE_CLASS_SLOT,
                         JS::PrivateValue(const_cast<DOMClass*>(domClass)));
   }
   else {
     proto = NULL;
   }
 
   JSObject* interface;
   if (constructorClass || constructor) {
     interface = CreateInterfaceObject(cx, global, receiver, constructorClass,
                                       constructor, ctorNargs, proto,
-                                      staticMethods, constants, name);
+                                      properties, chromeOnlyProperties, name);
     if (!interface) {
       return NULL;
     }
   }
 
   return protoClass ? proto : interface;
 }
 
@@ -415,185 +458,217 @@ QueryInterface(JSContext* cx, unsigned a
 }
 
 JSBool
 ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp)
 {
   return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR);
 }
 
-bool
+static bool
 XrayResolveProperty(JSContext* cx, JSObject* wrapper, jsid id,
                     JSPropertyDescriptor* desc,
-                    // And the things we need to determine the descriptor
-                    Prefable<JSFunctionSpec>* methods,
-                    jsid* methodIds,
-                    JSFunctionSpec* methodSpecs,
-                    size_t methodCount,
-                    Prefable<JSPropertySpec>* attributes,
-                    jsid* attributeIds,
-                    JSPropertySpec* attributeSpecs,
-                    size_t attributeCount,
-                    Prefable<ConstantSpec>* constants,
-                    jsid* constantIds,
-                    ConstantSpec* constantSpecs,
-                    size_t constantCount)
+                    const NativeProperties* nativeProperties)
 {
-  for (size_t prefIdx = 0; prefIdx < methodCount; ++prefIdx) {
-    MOZ_ASSERT(methods[prefIdx].specs);
-    if (methods[prefIdx].enabled) {
-      // Set i to be the index into our full list of ids/specs that we're
-      // looking at now.
-      size_t i = methods[prefIdx].specs - methodSpecs;
-      for ( ; methodIds[i] != JSID_VOID; ++i) {
-        if (id == methodIds[i]) {
-          JSFunction *fun = JS_NewFunctionById(cx, methodSpecs[i].call.op,
-                                               methodSpecs[i].nargs, 0,
-                                               wrapper, id);
-          if (!fun) {
-            return false;
+  if (nativeProperties->methods) {
+    Prefable<JSFunctionSpec>* method;
+    for (method = nativeProperties->methods; method->specs; ++method) {
+      if (method->enabled) {
+        // Set i to be the index into our full list of ids/specs that we're
+        // looking at now.
+        size_t i = method->specs - nativeProperties->methodsSpecs;
+        for ( ; nativeProperties->methodIds[i] != JSID_VOID; ++i) {
+          if (id == nativeProperties->methodIds[i]) {
+            JSFunctionSpec& methodSpec = nativeProperties->methodsSpecs[i];
+            JSFunction *fun = JS_NewFunctionById(cx, methodSpec.call.op,
+                                                 methodSpec.nargs, 0,
+                                                 wrapper, id);
+            if (!fun) {
+              return false;
+            }
+            SET_JITINFO(fun, methodSpec.call.info);
+            JSObject *funobj = JS_GetFunctionObject(fun);
+            desc->value.setObject(*funobj);
+            desc->attrs = methodSpec.flags;
+            desc->obj = wrapper;
+            desc->setter = nullptr;
+            desc->getter = nullptr;
+           return true;
           }
-          SET_JITINFO(fun, methodSpecs[i].call.info);
-          JSObject *funobj = JS_GetFunctionObject(fun);
-          desc->value.setObject(*funobj);
-          desc->attrs = methodSpecs[i].flags;
-          desc->obj = wrapper;
-          desc->setter = nullptr;
-          desc->getter = nullptr;
-          return true;
         }
       }
     }
   }
 
-  for (size_t prefIdx = 0; prefIdx < attributeCount; ++prefIdx) {
-    MOZ_ASSERT(attributes[prefIdx].specs);
-    if (attributes[prefIdx].enabled) {
-      // Set i to be the index into our full list of ids/specs that we're
-      // looking at now.
-      size_t i = attributes[prefIdx].specs - attributeSpecs;
-      for ( ; attributeIds[i] != JSID_VOID; ++i) {
-        if (id == attributeIds[i]) {
-          // Because of centralization, we need to make sure we fault in the
-          // JitInfos as well. At present, until the JSAPI changes, the easiest
-          // way to do this is wrap them up as functions ourselves.
-          desc->attrs = attributeSpecs[i].flags & ~JSPROP_NATIVE_ACCESSORS;
-          // They all have getters, so we can just make it.
-          JSObject *global = JS_GetGlobalForObject(cx, wrapper);
-          JSFunction *fun = JS_NewFunction(cx, (JSNative)attributeSpecs[i].getter.op,
-                                           0, 0, global, NULL);
-          if (!fun)
-            return false;
-          SET_JITINFO(fun, attributeSpecs[i].getter.info);
-          JSObject *funobj = JS_GetFunctionObject(fun);
-          desc->getter = js::CastAsJSPropertyOp(funobj);
-          desc->attrs |= JSPROP_GETTER;
-          if (attributeSpecs[i].setter.op) {
-            // We have a setter! Make it.
-            fun = JS_NewFunction(cx, (JSNative)attributeSpecs[i].setter.op,
-                                 1, 0, global, NULL);
+  if (nativeProperties->attributes) {
+    Prefable<JSPropertySpec>* attr;
+    for (attr = nativeProperties->attributes; attr->specs; ++attr) {
+      if (attr->enabled) {
+        // Set i to be the index into our full list of ids/specs that we're
+        // looking at now.
+        size_t i = attr->specs - nativeProperties->attributeSpecs;
+        for ( ; nativeProperties->attributeIds[i] != JSID_VOID; ++i) {
+          if (id == nativeProperties->attributeIds[i]) {
+            JSPropertySpec& attrSpec = nativeProperties->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
+            // way to do this is wrap them up as functions ourselves.
+            desc->attrs = attrSpec.flags & ~JSPROP_NATIVE_ACCESSORS;
+            // They all have getters, so we can just make it.
+            JSObject *global = JS_GetGlobalForObject(cx, wrapper);
+            JSFunction *fun = JS_NewFunction(cx, (JSNative)attrSpec.getter.op,
+                                             0, 0, global, nullptr);
             if (!fun)
               return false;
-            SET_JITINFO(fun, attributeSpecs[i].setter.info);
-            funobj = JS_GetFunctionObject(fun);
-            desc->setter = js::CastAsJSStrictPropertyOp(funobj);
-            desc->attrs |= JSPROP_SETTER;
-          } else {
-            desc->setter = NULL;
+            SET_JITINFO(fun, attrSpec.getter.info);
+            JSObject *funobj = JS_GetFunctionObject(fun);
+            desc->getter = js::CastAsJSPropertyOp(funobj);
+            desc->attrs |= JSPROP_GETTER;
+            if (attrSpec.setter.op) {
+              // We have a setter! Make it.
+              fun = JS_NewFunction(cx, (JSNative)attrSpec.setter.op, 1, 0,
+                                   global, nullptr);
+              if (!fun)
+                return false;
+              SET_JITINFO(fun, attrSpec.setter.info);
+              funobj = JS_GetFunctionObject(fun);
+              desc->setter = js::CastAsJSStrictPropertyOp(funobj);
+              desc->attrs |= JSPROP_SETTER;
+            } else {
+              desc->setter = nullptr;
+            }
+            desc->obj = wrapper;
+            return true;
           }
-          desc->obj = wrapper;
-          return true;
         }
       }
     }
   }
 
-  for (size_t prefIdx = 0; prefIdx < constantCount; ++prefIdx) {
-    MOZ_ASSERT(constants[prefIdx].specs);
-    if (constants[prefIdx].enabled) {
-      // Set i to be the index into our full list of ids/specs that we're
-      // looking at now.
-      size_t i = constants[prefIdx].specs - constantSpecs;
-      for ( ; constantIds[i] != JSID_VOID; ++i) {
-        if (id == constantIds[i]) {
-          desc->attrs = JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT;
-          desc->obj = wrapper;
-          desc->value = constantSpecs[i].value;
-          return true;
+  if (nativeProperties->constants) {
+    Prefable<ConstantSpec>* constant;
+    for (constant = nativeProperties->constants; constant->specs; ++constant) {
+      if (constant->enabled) {
+        // 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;
+            return true;
+          }
         }
       }
     }
   }
 
   return true;
 }
 
 bool
+XrayResolveProperty(JSContext* cx, JSObject* wrapper, jsid id,
+                    JSPropertyDescriptor* desc,
+                    const NativeProperties* nativeProperties,
+                    const NativeProperties* chromeOnlyNativeProperties)
+{
+  if (nativeProperties &&
+      !XrayResolveProperty(cx, wrapper, id, desc, nativeProperties)) {
+    return false;
+  }
+
+  if (!desc->obj &&
+      chromeOnlyNativeProperties &&
+      xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper)) &&
+      !XrayResolveProperty(cx, wrapper, id, desc, chromeOnlyNativeProperties)) {
+    return false;
+  }
+
+  return true;
+}
+
+bool
 XrayEnumerateProperties(JS::AutoIdVector& props,
-                        Prefable<JSFunctionSpec>* methods,
-                        jsid* methodIds,
-                        JSFunctionSpec* methodSpecs,
-                        size_t methodCount,
-                        Prefable<JSPropertySpec>* attributes,
-                        jsid* attributeIds,
-                        JSPropertySpec* attributeSpecs,
-                        size_t attributeCount,
-                        Prefable<ConstantSpec>* constants,
-                        jsid* constantIds,
-                        ConstantSpec* constantSpecs,
-                        size_t constantCount)
+                        const NativeProperties* nativeProperties)
 {
-  for (size_t prefIdx = 0; prefIdx < methodCount; ++prefIdx) {
-    MOZ_ASSERT(methods[prefIdx].specs);
-    if (methods[prefIdx].enabled) {
-      // Set i to be the index into our full list of ids/specs that we're
-      // looking at now.
-      size_t i = methods[prefIdx].specs - methodSpecs;
-      for ( ; methodIds[i] != JSID_VOID; ++i) {
-        if ((methodSpecs[i].flags & JSPROP_ENUMERATE) &&
-            !props.append(methodIds[i])) {
-          return false;
+  if (nativeProperties->methods) {
+    Prefable<JSFunctionSpec>* method;
+    for (method = nativeProperties->methods; method->specs; ++method) {
+      if (method->enabled) {
+        // Set i to be the index into our full list of ids/specs that we're
+        // looking at now.
+        size_t i = method->specs - nativeProperties->methodsSpecs;
+        for ( ; nativeProperties->methodIds[i] != JSID_VOID; ++i) {
+          if ((nativeProperties->methodsSpecs[i].flags & JSPROP_ENUMERATE) &&
+              !props.append(nativeProperties->methodIds[i])) {
+            return false;
+          }
         }
       }
     }
   }
 
-  for (size_t prefIdx = 0; prefIdx < attributeCount; ++prefIdx) {
-    MOZ_ASSERT(attributes[prefIdx].specs);
-    if (attributes[prefIdx].enabled) {
-      // Set i to be the index into our full list of ids/specs that we're
-      // looking at now.
-      size_t i = attributes[prefIdx].specs - attributeSpecs;
-      for ( ; attributeIds[i] != JSID_VOID; ++i) {
-        if ((attributeSpecs[i].flags & JSPROP_ENUMERATE) &&
-            !props.append(attributeIds[i])) {
-          return false;
+  if (nativeProperties->attributes) {
+    Prefable<JSPropertySpec>* attr;
+    for (attr = nativeProperties->attributes; attr->specs; ++attr) {
+      if (attr->enabled) {
+        // Set i to be the index into our full list of ids/specs that we're
+        // looking at now.
+        size_t i = attr->specs - nativeProperties->attributeSpecs;
+        for ( ; nativeProperties->attributeIds[i] != JSID_VOID; ++i) {
+          if ((nativeProperties->attributeSpecs[i].flags & JSPROP_ENUMERATE) &&
+              !props.append(nativeProperties->attributeIds[i])) {
+            return false;
+          }
         }
       }
     }
   }
 
-  for (size_t prefIdx = 0; prefIdx < constantCount; ++prefIdx) {
-    MOZ_ASSERT(constants[prefIdx].specs);
-    if (constants[prefIdx].enabled) {
-      // Set i to be the index into our full list of ids/specs that we're
-      // looking at now.
-      size_t i = constants[prefIdx].specs - constantSpecs;
-      for ( ; constantIds[i] != JSID_VOID; ++i) {
-        if (!props.append(constantIds[i])) {
-          return false;
+  if (nativeProperties->constants) {
+    Prefable<ConstantSpec>* constant;
+    for (constant = nativeProperties->constants; constant->specs; ++constant) {
+      if (constant->enabled) {
+        // 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;
+          }
         }
       }
     }
   }
 
   return true;
 }
 
 bool
+XrayEnumerateProperties(JSObject* wrapper,
+                        JS::AutoIdVector& props,
+                        const NativeProperties* nativeProperties,
+                        const NativeProperties* chromeOnlyNativeProperties)
+{
+  if (nativeProperties &&
+      !XrayEnumerateProperties(props, nativeProperties)) {
+    return false;
+  }
+
+  if (chromeOnlyNativeProperties &&
+      xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper)) &&
+      !XrayEnumerateProperties(props, chromeOnlyNativeProperties)) {
+    return false;
+  }
+
+  return true;
+}
+
+bool
 GetPropertyOnPrototype(JSContext* cx, JSObject* proxy, jsid id, bool* found,
                        JS::Value* vp)
 {
   JSObject* proto;
   if (!js::GetObjectProto(cx, proxy, &proto)) {
     return false;
   }
   if (!proto) {
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -339,16 +339,32 @@ struct Prefable {
   // A boolean indicating whether this set of specs is enabled
   bool enabled;
   // 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
+{
+  Prefable<JSFunctionSpec>* staticMethods;
+  jsid* staticMethodIds;
+  JSFunctionSpec* staticMethodsSpecs;
+  Prefable<JSFunctionSpec>* methods;
+  jsid* methodIds;
+  JSFunctionSpec* methodsSpecs;
+  Prefable<JSPropertySpec>* attributes;
+  jsid* attributeIds;
+  JSPropertySpec* attributeSpecs;
+  Prefable<ConstantSpec>* constants;
+  jsid* constantIds;
+  ConstantSpec* constantSpecs;
+};
+
 /*
  * Create a DOM interface object (if constructorClass is non-null) and/or a
  * DOM interface prototype object (if protoClass is non-null).
  *
  * global is used as the parent of the interface object and the interface
  *        prototype object
  * receiver is the object on which we need to define the interface object as a
  *          property
@@ -360,43 +376,41 @@ struct Prefable {
  *                  This is null if we should not create an interface object or
  *                  if it should be a function object.
  * constructor is the JSNative to use as a constructor.  If this is non-null, it
  *             should be used as a JSNative to back the interface object, which
  *             should be a Function.  If this is null, then we should create an
  *             object of constructorClass, unless that's also null, in which
  *             case we should not create an interface object at all.
  * ctorNargs is the length of the constructor function; 0 if no constructor
- * instanceClass is the JSClass of instance objects for this class.  This can
- *               be null if this is not a concrete proto.
- * methods and properties are to be defined on the interface prototype object;
- *                        these arguments are allowed to be null if there are no
- *                        methods or properties respectively.
- * constants are to be defined on the interface object and on the interface
- *           prototype object; allowed to be null if there are no constants.
- * staticMethods are to be defined on the interface object; allowed to be null
- *               if there are no static methods.
+ * domClass is the DOMClass of instance objects for this class.  This can be
+ *          null if this is not a concrete proto.
+ * properties contains the methods, attributes and constants to be defined on
+ *            objects in any compartment.
+ * chromeProperties contains the methods, attributes and constants to be defined
+ *                  on objects in chrome compartments. This must be null if the
+ *                  interface doesn't have any ChromeOnly properties or if the
+ *                  object is being created in non-chrome compartment.
  *
  * At least one of protoClass and constructorClass should be non-null.
  * If constructorClass is non-null, the resulting interface object will be
  * defined on the given global with property name |name|, which must also be
  * non-null.
  *
  * returns the interface prototype object if protoClass is non-null, else it
  * returns the interface object.
  */
 JSObject*
 CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject* receiver,
                        JSObject* protoProto, JSClass* protoClass,
                        JSClass* constructorClass, JSNative constructor,
                        unsigned ctorNargs, const DOMClass* domClass,
-                       Prefable<JSFunctionSpec>* methods,
-                       Prefable<JSPropertySpec>* properties,
-                       Prefable<ConstantSpec>* constants,
-                       Prefable<JSFunctionSpec>* staticMethods, const char* name);
+                       const NativeProperties* properties,
+                       const NativeProperties* chromeProperties,
+                       const char* name);
 
 template <class T>
 inline bool
 WrapNewBindingObject(JSContext* cx, JSObject* scope, T* value, JS::Value* vp)
 {
   JSObject* obj = value->GetWrapper();
   if (obj && js::GetObjectCompartment(obj) == js::GetObjectCompartment(scope)) {
     *vp = JS::ObjectValue(*obj);
@@ -1173,44 +1187,24 @@ public:
       storage.addr()->~T();
     }
 };
 
 // Implementation of the bits that XrayWrapper needs
 bool
 XrayResolveProperty(JSContext* cx, JSObject* wrapper, jsid id,
                     JSPropertyDescriptor* desc,
-                    // And the things we need to determine the descriptor
-                    Prefable<JSFunctionSpec>* methods,
-                    jsid* methodIds,
-                    JSFunctionSpec* methodSpecs,
-                    size_t methodCount,
-                    Prefable<JSPropertySpec>* attributes,
-                    jsid* attributeIds,
-                    JSPropertySpec* attributeSpecs,
-                    size_t attributeCount,
-                    Prefable<ConstantSpec>* constants,
-                    jsid* constantIds,
-                    ConstantSpec* constantSpecs,
-                    size_t constantCount);
+                    const NativeProperties* nativeProperties,
+                    const NativeProperties* chromeOnlyNativeProperties);
 
 bool
-XrayEnumerateProperties(JS::AutoIdVector& props,
-                        Prefable<JSFunctionSpec>* methods,
-                        jsid* methodIds,
-                        JSFunctionSpec* methodSpecs,
-                        size_t methodCount,
-                        Prefable<JSPropertySpec>* attributes,
-                        jsid* attributeIds,
-                        JSPropertySpec* attributeSpecs,
-                        size_t attributeCount,
-                        Prefable<ConstantSpec>* constants,
-                        jsid* constantIds,
-                        ConstantSpec* constantSpecs,
-                        size_t constantCount);
+XrayEnumerateProperties(JSObject* wrapper,
+                        JS::AutoIdVector& props,
+                        const NativeProperties* nativeProperties,
+                        const NativeProperties* chromeOnlyNativeProperties);
 
 // Transfer reference in ptr to smartPtr.
 template<class T>
 inline void
 Take(nsRefPtr<T>& smartPtr, T* ptr)
 {
   smartPtr = dont_AddRef(ptr);
 }
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -861,55 +861,52 @@ def isChromeOnly(m):
     return m.getExtendedAttribute("ChromeOnly")
 
 class PropertyDefiner:
     """
     A common superclass for defining things on prototype objects.
 
     Subclasses should implement generateArray to generate the actual arrays of
     things we're defining.  They should also set self.chrome to the list of
-    things exposed to chrome and self.regular to the list of things exposed to
-    web pages.  self.chrome must be a superset of self.regular but also include
-    all the ChromeOnly stuff.
+    things only exposed to chrome and self.regular to the list of things exposed
+    to both chrome and web pages.
     """
     def __init__(self, descriptor, name):
         self.descriptor = descriptor
         self.name = name
         # self.prefCacheData will store an array of (prefname, bool*)
         # pairs for our bool var caches.  generateArray will fill it
         # in as needed.
         self.prefCacheData = []
     def hasChromeOnly(self):
-        return len(self.chrome) > len(self.regular)
+        return len(self.chrome) > 0
     def hasNonChromeOnly(self):
         return len(self.regular) > 0
     def variableName(self, chrome):
-        if chrome and self.hasChromeOnly():
-            return "sChrome" + self.name
-        if self.hasNonChromeOnly():
-            return "s" + self.name
-        return "NULL"
-    def usedForXrays(self, chrome):
-        # We only need Xrays for methods, attributes and constants.  And we only
-        # need them for the non-chrome ones if we have no chromeonly things.
-        # Otherwise (we have chromeonly attributes) we need Xrays for the chrome
-        # methods/attributes/constants.  Finally, in workers there are no Xrays.
-        return ((self.name is "Methods" or self.name is "Attributes" or
-                 self.name is "Constants") and
-                chrome == self.hasChromeOnly() and
-                not self.descriptor.workers)
+        if chrome:
+            if self.hasChromeOnly():
+                return "sChrome" + self.name
+        else:
+            if self.hasNonChromeOnly():
+                return "s" + self.name
+        return "nullptr"
+    def usedForXrays(self):
+        # We only need Xrays for methods, attributes and constants, but in
+        # workers there are no Xrays.
+        return (self.name is "Methods" or self.name is "Attributes" or
+                self.name is "Constants") and not self.descriptor.workers
 
     def __str__(self):
         # We only need to generate id arrays for things that will end
         # up used via ResolveProperty or EnumerateProperties.
         str = self.generateArray(self.regular, self.variableName(False),
-                                 self.usedForXrays(False))
+                                 self.usedForXrays())
         if self.hasChromeOnly():
             str += self.generateArray(self.chrome, self.variableName(True),
-                                      self.usedForXrays(True))
+                                      self.usedForXrays())
         return str
 
     @staticmethod
     def getControllingPref(interfaceMember):
         prefName = interfaceMember.getExtendedAttribute("Pref")
         if prefName is None:
             return None
         # It's a list of strings
@@ -1013,31 +1010,25 @@ class MethodDefiner(PropertyDefiner):
         #       identifier. For now we check if the name starts with __
         methods = [m for m in descriptor.interface.members if
                    m.isMethod() and m.isStatic() == static and
                    not m.isIdentifierLess()]
         self.chrome = [{"name": m.identifier.name,
                         "length": methodLength(m),
                         "flags": "JSPROP_ENUMERATE",
                         "pref": PropertyDefiner.getControllingPref(m) }
-                       for m in methods]
+                       for m in methods if isChromeOnly(m)]
         self.regular = [{"name": m.identifier.name,
                          "length": methodLength(m),
                          "flags": "JSPROP_ENUMERATE",
                          "pref": PropertyDefiner.getControllingPref(m) }
                         for m in methods if not isChromeOnly(m)]
 
         # FIXME Check for an existing iterator on the interface first.
         if any(m.isGetter() and m.isIndexed() for m in methods):
-            self.chrome.append({"name": 'iterator',
-                                "methodInfo": False,
-                                "nativeName": "JS_ArrayIterator",
-                                "length": 0,
-                                "flags": "JSPROP_ENUMERATE",
-                                "pref": None })
             self.regular.append({"name": 'iterator',
                                  "methodInfo": False,
                                  "nativeName": "JS_ArrayIterator",
                                  "length": 0,
                                  "flags": "JSPROP_ENUMERATE",
                                  "pref": None })
 
         if not descriptor.interface.parent and not static and descriptor.nativeOwnership == 'nsisupports':
@@ -1078,18 +1069,19 @@ class MethodDefiner(PropertyDefiner):
             '  JS_FS_END',
             'JSFunctionSpec',
             pref, specData, doIdArrays)
 
 class AttrDefiner(PropertyDefiner):
     def __init__(self, descriptor, name):
         PropertyDefiner.__init__(self, descriptor, name)
         self.name = name
-        self.chrome = [m for m in descriptor.interface.members if m.isAttr()]
-        self.regular = [m for m in self.chrome if not isChromeOnly(m)]
+        attributes = [m for m in descriptor.interface.members if m.isAttr()]
+        self.chrome = [m for m in attributes if isChromeOnly(m)]
+        self.regular = [m for m in attributes if not isChromeOnly(m)]
 
     def generateArray(self, array, name, doIdArrays):
         if len(array) == 0:
             return ""
 
         def flags(attr):
             return "JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_NATIVE_ACCESSORS"
 
@@ -1122,18 +1114,19 @@ class AttrDefiner(PropertyDefiner):
 
 class ConstDefiner(PropertyDefiner):
     """
     A class for definining constants on the interface object
     """
     def __init__(self, descriptor, name):
         PropertyDefiner.__init__(self, descriptor, name)
         self.name = name
-        self.chrome = [m for m in descriptor.interface.members if m.isConst()]
-        self.regular = [m for m in self.chrome if not isChromeOnly(m)]
+        constants = [m for m in descriptor.interface.members if m.isConst()]
+        self.chrome = [m for m in constants if isChromeOnly(m)]
+        self.regular = [m for m in constants if not isChromeOnly(m)]
 
     def generateArray(self, array, name, doIdArrays):
         if len(array) == 0:
             return ""
 
         def specData(const):
             return (const.identifier.name,
                     convertConstIDLValueToJSVal(const.value))
@@ -1156,29 +1149,59 @@ class PropertyArrays():
     def arrayNames():
         return [ "staticMethods", "methods", "attrs", "consts" ]
 
     @staticmethod
     def xrayRelevantArrayNames():
         return [ "methods", "attrs", "consts" ]
 
     def hasChromeOnly(self):
-        return reduce(lambda b, a: b or getattr(self, a).hasChromeOnly(),
-                      self.arrayNames(), False)
-    def variableNames(self, chrome):
-        names = {}
-        for array in self.arrayNames():
-            names[array] = getattr(self, array).variableName(chrome)
-        return names
+        return any(getattr(self, a).hasChromeOnly() for a in self.arrayNames())
+    def hasNonChromeOnly(self):
+        return any(getattr(self, a).hasNonChromeOnly() for a in self.arrayNames())
     def __str__(self):
         define = ""
         for array in self.arrayNames():
             define += str(getattr(self, array))
         return define
 
+class CGNativeProperties(CGList):
+    def __init__(self, descriptor, properties):
+        def generateNativeProperties(name, chrome):
+            def check(p):
+                return p.hasChromeOnly() if chrome else p.hasNonChromeOnly()
+
+            nativeProps = []
+            for array in properties.arrayNames():
+                propertyArray = getattr(properties, array)
+                if check(propertyArray):
+                    if descriptor.workers:
+                        props = "%(name)s, nullptr, %(name)s_specs"
+                    else:
+                        if propertyArray.usedForXrays():
+                            ids = "%(name)s_ids"
+                        else:
+                            ids = "nullptr"
+                        props = "%(name)s, " + ids + ", %(name)s_specs"
+                    props = (props %
+                             { 'name': propertyArray.variableName(chrome) })
+                else:
+                    props = "nullptr, nullptr, nullptr"
+                nativeProps.append(CGGeneric(props))
+            return CGWrapper(CGIndenter(CGList(nativeProps, ",\n")),
+                             pre="static const NativeProperties %s = {\n" % name,
+                             post="\n};")
+        
+        regular = generateNativeProperties("sNativeProperties", False)
+        chrome = generateNativeProperties("sChromeOnlyNativeProperties", True)
+        CGList.__init__(self, [regular, chrome], "\n\n")
+
+    def declare(self):
+        return ""
+
 class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
     """
     Generate the CreateInterfaceObjects method for an interface descriptor.
 
     properties should be a PropertyArrays instance.
     """
     def __init__(self, descriptor, properties):
         args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal'),
@@ -1204,17 +1227,17 @@ class CGCreateInterfaceObjectsMethod(CGA
         # There is no need to init any IDs in workers, because worker bindings
         # don't have Xrays.
         if not self.descriptor.workers:
             for var in self.properties.xrayRelevantArrayNames():
                 props = getattr(self.properties, var)
                 # We only have non-chrome ids to init if we have no chrome ids.
                 if props.hasChromeOnly():
                     idsToInit.append(props.variableName(True))
-                elif props.hasNonChromeOnly():
+                if props.hasNonChromeOnly():
                     idsToInit.append(props.variableName(False))
         if len(idsToInit) > 0:
             initIds = CGList(
                 [CGGeneric("!InitIds(aCx, %s, %s_ids)" % (varname, varname)) for
                  varname in idsToInit], ' ||\n')
             if len(idsToInit) > 1:
                 initIds = CGWrapper(initIds, pre="(", post=")", reindent=True)
             initIds = CGList(
@@ -1265,42 +1288,44 @@ class CGCreateInterfaceObjectsMethod(CGA
         if self.descriptor.concrete:
             if self.descriptor.proxy:
                 domClass = "&Class"
             else:
                 domClass = "&Class.mClass"
         else:
             domClass = "nullptr"
 
+        if self.properties.hasNonChromeOnly():
+            properties = "&sNativeProperties"
+        else:
+            properties = "nullptr"
+        if self.properties.hasChromeOnly():
+            if self.descriptor.workers:
+                accessCheck = "mozilla::dom::workers::GetWorkerPrivateFromContext(aCx)->IsChromeWorker()"
+            else:
+                accessCheck = "xpc::AccessCheck::isChrome(aGlobal)"
+            chromeProperties = accessCheck + " ? &sChromeOnlyNativeProperties : nullptr"
+        else:
+            chromeProperties = "nullptr"
         call = """return dom::CreateInterfaceObjects(aCx, aGlobal, aReceiver, parentProto,
                                    %s, %s, %s, %d,
                                    %s,
-                                   %%(methods)s, %%(attrs)s,
-                                   %%(consts)s, %%(staticMethods)s,
+                                   %s,
+                                   %s,
                                    %s);""" % (
             "&PrototypeClass" if needInterfacePrototypeObject else "NULL",
             "&InterfaceObjectClass" if needInterfaceObjectClass else "NULL",
             constructHook if needConstructor else "NULL",
             constructArgs,
             domClass,
+            properties,
+            chromeProperties,
             '"' + self.descriptor.interface.identifier.name + '"' if needInterfaceObject else "NULL")
-        if self.properties.hasChromeOnly():
-            if self.descriptor.workers:
-                accessCheck = "mozilla::dom::workers::GetWorkerPrivateFromContext(aCx)->IsChromeWorker()"
-            else:
-                accessCheck = "xpc::AccessCheck::isChrome(js::GetObjectCompartment(aGlobal))"
-            chrome = CGIfWrapper(CGGeneric(call % self.properties.variableNames(True)),
-                                 accessCheck)
-            chrome = CGWrapper(chrome, pre="\n\n")
-        else:
-            chrome = None
-
         functionBody = CGList(
-            [CGGeneric(getParentProto), initIds, prefCache, chrome,
-             CGGeneric(call % self.properties.variableNames(False))],
+            [CGGeneric(getParentProto), initIds, prefCache, CGGeneric(call)],
             "\n\n")
         return CGIndenter(functionBody).define()
 
 class CGGetPerInterfaceObject(CGAbstractMethod):
     """
     A method for getting a per-interface object (a prototype object or interface
     constructor object).
     """
@@ -4536,46 +4561,30 @@ class CGEnumerateOwnProperties(CGAbstrac
 """
 
 class CGXrayHelper(CGAbstractMethod):
     def __init__(self, descriptor, name, args, properties):
         CGAbstractMethod.__init__(self, descriptor, name, "bool", args)
         self.properties = properties
 
     def definition_body(self):
-        varNames = self.properties.variableNames(True)
-
-        methods = self.properties.methods
-        if methods.hasNonChromeOnly() or methods.hasChromeOnly():
-            methodArgs = """// %(methods)s has an end-of-list marker at the end that we ignore
-%(methods)s, %(methods)s_ids, %(methods)s_specs, ArrayLength(%(methods)s) - 1""" % varNames
+        prefixArgs = CGGeneric(self.getPrefixArgs())
+        if self.properties.hasNonChromeOnly():
+            regular = "&sNativeProperties"
         else:
-            methodArgs = "NULL, NULL, NULL, 0"
-        methodArgs = CGGeneric(methodArgs)
-
-        attrs = self.properties.attrs
-        if attrs.hasNonChromeOnly() or attrs.hasChromeOnly():
-            attrArgs = """// %(attrs)s has an end-of-list marker at the end that we ignore
-%(attrs)s, %(attrs)s_ids, %(attrs)s_specs, ArrayLength(%(attrs)s) - 1""" % varNames
+            regular = "nullptr"
+        regular = CGGeneric(regular)
+        if self.properties.hasChromeOnly():
+            chrome = "&sChromeOnlyNativeProperties"
         else:
-            attrArgs = "NULL, NULL, NULL, 0"
-        attrArgs = CGGeneric(attrArgs)
-
-        consts = self.properties.consts
-        if consts.hasNonChromeOnly() or consts.hasChromeOnly():
-            constArgs = """// %(consts)s has an end-of-list marker at the end that we ignore
-%(consts)s, %(consts)s_ids, %(consts)s_specs, ArrayLength(%(consts)s) - 1""" % varNames
-        else:
-            constArgs = "NULL, NULL, NULL, 0"
-        constArgs = CGGeneric(constArgs)
-
-        prefixArgs = CGGeneric(self.getPrefixArgs())
+            chrome = "nullptr"
+        chrome = CGGeneric(chrome)
 
         return CGIndenter(
-            CGWrapper(CGList([prefixArgs, methodArgs, attrArgs, constArgs], ",\n"),
+            CGWrapper(CGList([prefixArgs, regular, chrome], ",\n"),
                       pre=("return Xray%s(" % self.name),
                       post=");",
                       reindent=True)).define()
 
 class CGResolveProperty(CGXrayHelper):
     def __init__(self, descriptor, properties):
         args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'wrapper'),
                 Argument('jsid', 'id'), Argument('bool', 'set'),
@@ -4590,17 +4599,17 @@ class CGResolveProperty(CGXrayHelper):
 class CGEnumerateProperties(CGXrayHelper):
     def __init__(self, descriptor, properties):
         args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'wrapper'),
                 Argument('JS::AutoIdVector&', 'props')]
         CGXrayHelper.__init__(self, descriptor, "EnumerateProperties", args,
                               properties)
 
     def getPrefixArgs(self):
-        return "props"
+        return "wrapper, props"
 
 class CGPrototypeTraitsClass(CGClass):
     def __init__(self, descriptor, indent=''):
         templateArgs = [Argument('prototypes::ID', 'PrototypeID')]
         templateSpecialization = ['prototypes::id::' + descriptor.name]
         enums = [ClassEnum('', ['Depth'],
                            [descriptor.interface.inheritanceDepth()])]
         typedefs = [ClassTypedef('NativeType', descriptor.nativeType)]
@@ -5243,16 +5252,17 @@ class CGDescriptor(CGThing):
             cgThings.append(CGClassHasInstanceHook(descriptor))
             cgThings.append(CGInterfaceObjectJSClass(descriptor))
 
         if descriptor.interface.hasInterfacePrototypeObject():
             cgThings.append(CGPrototypeJSClass(descriptor))
 
         properties = PropertyArrays(descriptor)
         cgThings.append(CGGeneric(define=str(properties)))
+        cgThings.append(CGNativeProperties(descriptor, properties))
         cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties))
         if descriptor.interface.hasInterfacePrototypeObject():
             cgThings.append(CGGetProtoObjectMethod(descriptor))
         else:
             cgThings.append(CGGetConstructorObjectMethod(descriptor))
 
         # Set up our Xray callbacks as needed.  Note that we don't need to do
         # it in workers.