Bug 1006718. Add some sanity static asserts about DOM object slot counts. r=peterv,jorendorff
authorBoris Zbarsky <bzbarsky@mit.edu>
Wed, 07 May 2014 22:28:57 -0400
changeset 182082 b766e7d111b90d1502b06fa289b21ad449d23cd0
parent 182081 3c695f32262b66ad19bd211aeb8568c12a4cfbdf
child 182083 d002d113feca0dee320a91fba7837c77d0bf297b
push id43203
push userbzbarsky@mozilla.com
push dateThu, 08 May 2014 02:29:25 +0000
treeherdermozilla-inbound@b766e7d111b9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv, jorendorff
bugs1006718
milestone32.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 1006718. Add some sanity static asserts about DOM object slot counts. r=peterv,jorendorff
dom/bindings/Codegen.py
js/public/Class.h
js/src/vm/GlobalObject.h
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -18,17 +18,17 @@ AUTOGENERATED_WARNING_COMMENT = \
 ADDPROPERTY_HOOK_NAME = '_addProperty'
 FINALIZE_HOOK_NAME = '_finalize'
 CONSTRUCT_HOOK_NAME = '_constructor'
 LEGACYCALLER_HOOK_NAME = '_legacycaller'
 HASINSTANCE_HOOK_NAME = '_hasInstance'
 NEWRESOLVE_HOOK_NAME = '_newResolve'
 ENUMERATE_HOOK_NAME = '_enumerate'
 ENUM_ENTRY_VARIABLE_NAME = 'strings'
-INSTANCE_RESERVED_SLOTS = 3
+INSTANCE_RESERVED_SLOTS = 1
 
 
 def memberReservedSlot(member):
     return "(DOM_INSTANCE_RESERVED_SLOTS + %d)" % member.slotIndex
 
 
 def toStringBool(arg):
     return str(not not arg).lower()
@@ -348,16 +348,17 @@ class CGDOMJSClass(CGThing):
         classFlags = "JSCLASS_IS_DOMJSCLASS | "
         classExtensionAndObjectOps = """\
 JS_NULL_CLASS_EXT,
 JS_NULL_OBJECT_OPS
 """
         if self.descriptor.interface.getExtendedAttribute("Global"):
             classFlags += "JSCLASS_DOM_GLOBAL | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS) | JSCLASS_IMPLEMENTS_BARRIERS"
             traceHook = "JS_GlobalObjectTraceHook"
+            reservedSlots = "JSCLASS_GLOBAL_APPLICATION_SLOTS"
             if not self.descriptor.workers:
                 classExtensionAndObjectOps = """\
 {
   nsGlobalWindow::OuterObject, /* outerObject */
   nullptr, /* innerObject */
   nullptr, /* iteratorObject */
   false, /* isWrappedNative */
   nullptr /* weakmapKeyDelegateOp */
@@ -383,16 +384,17 @@ JS_NULL_OBJECT_OPS
   nullptr, /* unwatch */
   nullptr, /* slice */
   nullptr, /* enumerate */
   JS_ObjectToOuterObject /* thisObject */
 }
 """
         else:
             classFlags += "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount
+            reservedSlots = slotCount
         if self.descriptor.interface.getExtendedAttribute("NeedNewResolve"):
             newResolveHook = "(JSResolveOp)" + NEWRESOLVE_HOOK_NAME
             classFlags += " | JSCLASS_NEW_RESOLVE"
             enumerateHook = ENUMERATE_HOOK_NAME
         elif self.descriptor.interface.getExtendedAttribute("Global"):
             newResolveHook = "(JSResolveOp) mozilla::dom::ResolveGlobal"
             classFlags += " | JSCLASS_NEW_RESOLVE"
             enumerateHook = "mozilla::dom::EnumerateGlobal"
@@ -418,27 +420,34 @@ JS_NULL_OBJECT_OPS
                 nullptr,               /* hasInstance */
                 nullptr,               /* construct */
                 ${trace}, /* trace */
                 JS_NULL_CLASS_SPEC,
                 $*{classExtensionAndObjectOps}
               },
               $*{descriptor}
             };
+            static_assert(${instanceReservedSlots} == DOM_INSTANCE_RESERVED_SLOTS,
+                          "Must have the right minimal number of reserved slots.");
+            static_assert(${reservedSlots} >= ${slotCount},
+                          "Must have enough reserved slots.");
             """,
             name=self.descriptor.interface.identifier.name,
             flags=classFlags,
             addProperty=ADDPROPERTY_HOOK_NAME if wantsAddProperty(self.descriptor) else 'JS_PropertyStub',
             enumerate=enumerateHook,
             resolve=newResolveHook,
             finalize=FINALIZE_HOOK_NAME,
             call=callHook,
             trace=traceHook,
             classExtensionAndObjectOps=classExtensionAndObjectOps,
-            descriptor=DOMClass(self.descriptor))
+            descriptor=DOMClass(self.descriptor),
+            instanceReservedSlots=INSTANCE_RESERVED_SLOTS,
+            reservedSlots=reservedSlots,
+            slotCount=slotCount)
 
 
 class CGDOMProxyJSClass(CGThing):
     """
     Generate a DOMJSClass for a given proxy descriptor
     """
     def __init__(self, descriptor):
         CGThing.__init__(self)
@@ -10024,16 +10033,22 @@ class CGDescriptor(CGThing):
 
         if ((descriptor.interface.hasInterfaceObject() or descriptor.interface.getNavigatorProperty()) and
             not descriptor.interface.isExternal() and
             descriptor.isExposedConditionally() and
             # Workers stuff is never conditional
             not descriptor.workers):
             cgThings.append(CGConstructorEnabled(descriptor))
 
+        if (descriptor.interface.hasMembersInSlots() and
+            descriptor.interface.hasChildInterfaces()):
+            raise TypeError("We don't support members in slots on "
+                            "non-leaf interfaces like %s" %
+                            descriptor.interface.identifier.name)
+
         if descriptor.concrete:
             if descriptor.proxy:
                 if descriptor.interface.totalMembersInSlots != 0:
                     raise TypeError("We can't have extra reserved slots for "
                                     "proxy interface %s" %
                                     descriptor.interface.identifier.name)
                 cgThings.append(CGGeneric(fill(
                     """
@@ -10051,20 +10066,16 @@ class CGDescriptor(CGThing):
                 cgThings.append(CGProxyIsProxy(descriptor))
                 cgThings.append(CGProxyUnwrap(descriptor))
                 cgThings.append(CGDOMJSProxyHandlerDefiner(handlerThing))
                 cgThings.append(CGDOMProxyJSClass(descriptor))
             else:
                 cgThings.append(CGDOMJSClass(descriptor))
                 cgThings.append(CGGetJSClassMethod(descriptor))
                 if descriptor.interface.hasMembersInSlots():
-                    if descriptor.interface.hasChildInterfaces():
-                        raise TypeError("We don't support members in slots on "
-                                        "non-leaf interfaces like %s" %
-                                        descriptor.interface.identifier.name)
                     cgThings.append(CGUpdateMemberSlotsMethod(descriptor))
 
             if descriptor.interface.getExtendedAttribute("Global"):
                 assert descriptor.wrapperCache
                 cgThings.append(CGWrapGlobalMethod(descriptor, properties))
             elif descriptor.wrapperCache:
                 cgThings.append(CGWrapWithCacheMethod(descriptor, properties))
                 cgThings.append(CGWrapMethod(descriptor))
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -416,17 +416,21 @@ struct JSClass {
 // member initial value.  The "original ... value" verbiage is there because
 // in ECMA-262, global properties naming class objects are read/write and
 // deleteable, for the most part.
 //
 // Implementing this efficiently requires that global objects have classes
 // with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
 // previously allowed, but is now an ES5 violation and thus unsupported.
 //
-#define JSCLASS_GLOBAL_SLOT_COUNT      (3 + JSProto_LIMIT * 3 + 31)
+// JSCLASS_GLOBAL_APPLICATION_SLOTS is the number of slots reserved at
+// the beginning of every global object's slots for use by the
+// application.
+#define JSCLASS_GLOBAL_APPLICATION_SLOTS 3
+#define JSCLASS_GLOBAL_SLOT_COUNT      (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 3 + 31)
 #define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n)                                    \
     (JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
 #define JSCLASS_GLOBAL_FLAGS                                                  \
     JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0)
 #define JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(clasp)                              \
   (((clasp)->flags & JSCLASS_IS_GLOBAL)                                       \
    && JSCLASS_RESERVED_SLOTS(clasp) >= JSCLASS_GLOBAL_SLOT_COUNT)
 
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -64,17 +64,17 @@ class TypedObjectModuleObject;
  * Array prototype object", or "as if by the expression new Array()" referring
  * to the original Array constructor. The third range stores the (writable and
  * even deletable) Object, Array, &c. properties (although a slot won't be used
  * again if its property is deleted and readded).
  */
 class GlobalObject : public JSObject
 {
     /* Count of slots set aside for application use. */
-    static const unsigned APPLICATION_SLOTS = 3;
+    static const unsigned APPLICATION_SLOTS = JSCLASS_GLOBAL_APPLICATION_SLOTS;
 
     /*
      * Count of slots to store built-in constructors, prototypes, and initial
      * visible properties for the constructors.
      */
     static const unsigned STANDARD_CLASS_SLOTS  = JSProto_LIMIT * 3;
 
     /* Various function values needed by the engine. */