Bug 1445710. Reduce codesize a bit by removing DOM DefineInterfaceObject methods. r=peterv
authorBoris Zbarsky <bzbarsky@mit.edu>
Wed, 04 Apr 2018 15:32:19 -0400
changeset 465329 7c26bbdac00f8ef5866b673bfc59fb452f8fb549
parent 465328 9daca50568c83cba3d3ee0ad987d6d686e116a74
child 465330 3b3e894a04cd6433887621458455aecd61c26da8
push id9165
push userasasaki@mozilla.com
push dateThu, 26 Apr 2018 21:04:54 +0000
treeherdermozilla-beta@064c3804de2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv
bugs1445710
milestone61.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 1445710. Reduce codesize a bit by removing DOM DefineInterfaceObject methods. r=peterv MozReview-Commit-ID: 6JRYz4FV9vP
dom/bindings/Codegen.py
dom/bindings/WebIDLGlobalNameHash.cpp
dom/bindings/WebIDLGlobalNameHash.h
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -3391,48 +3391,16 @@ class CGGetNamedPropertiesObjectMethod(C
             return namedPropertiesObject.get();
             """,
             getParentProto=getParentProto,
             ifaceName=self.descriptor.name,
             parentProto=parentProto,
             nativeType=self.descriptor.nativeType)
 
 
-class CGDefineDOMInterfaceMethod(CGAbstractMethod):
-    """
-    A method for resolve hooks to try to lazily define the interface object for
-    a given interface.
-    """
-    def __init__(self, descriptor):
-        args = [Argument('JSContext*', 'aCx'),
-                Argument('JS::Handle<JSObject*>', 'aGlobal'),
-                Argument('JS::Handle<jsid>', 'id'),
-                Argument('bool', 'aDefineOnGlobal')]
-        CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'JSObject*', args)
-
-    def definition_body(self):
-        if len(self.descriptor.interface.namedConstructors) > 0:
-            getConstructor = dedent("""
-                JSObject* interfaceObject = GetConstructorObjectHandle(aCx, aDefineOnGlobal);
-                if (!interfaceObject) {
-                  return nullptr;
-                }
-                for (unsigned slot = DOM_INTERFACE_SLOTS_BASE; slot < JSCLASS_RESERVED_SLOTS(&sInterfaceObjectClass.mBase); ++slot) {
-                  JSObject* constructor = &js::GetReservedSlot(interfaceObject, slot).toObject();
-                  if (JS_GetFunctionId(JS_GetObjectFunction(constructor)) == JSID_TO_STRING(id)) {
-                    return constructor;
-                  }
-                }
-                return interfaceObject;
-                """)
-        else:
-            getConstructor = "return GetConstructorObjectHandle(aCx, aDefineOnGlobal);\n"
-        return getConstructor
-
-
 def getConditionList(idlobj, cxName, objName):
     """
     Get the list of conditions for idlobj (to be used in "is this enabled"
     checks).  This will be returned as a CGList with " &&\n" as the separator,
     for readability.
 
     objName is the name of the object that we're working with, because some of
     our test functions want that.
@@ -12769,19 +12737,16 @@ class CGDescriptor(CGThing):
         if descriptor.interface.hasInterfacePrototypeObject():
             cgThings.append(CGPrototypeJSClass(descriptor, properties))
 
         if ((descriptor.interface.hasInterfaceObject() or descriptor.interface.isNavigatorProperty()) and
             not descriptor.interface.isExternal() and
             descriptor.isExposedConditionally()):
             cgThings.append(CGConstructorEnabled(descriptor))
 
-        if descriptor.registersGlobalNamesOnWindow:
-            cgThings.append(CGDefineDOMInterfaceMethod(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:
@@ -13904,17 +13869,17 @@ class CGRegisterGlobalNames(CGAbstractMe
             if not desc.isExposedConditionally():
                 return "nullptr"
             return "%sBinding::ConstructorEnabled" % desc.name
 
         define = ""
         currentOffset = 0
         for (name, desc) in getGlobalNames(self.config):
             length = len(name)
-            define += "WebIDLGlobalNameHash::Register(%i, %i, %sBinding::DefineDOMInterface, %s, constructors::id::%s);\n" % (
+            define += "WebIDLGlobalNameHash::Register(%i, %i, %sBinding::CreateInterfaceObjects, %s, constructors::id::%s);\n" % (
                 currentOffset, length, desc.name, getCheck(desc), desc.name)
             currentOffset += length + 1 # Add trailing null.
         return define
 
 
 def dependencySortObjects(objects, dependencyGetter, nameGetter):
     """
     Sort IDL objects with dependencies on each other such that if A
--- a/dom/bindings/WebIDLGlobalNameHash.cpp
+++ b/dom/bindings/WebIDLGlobalNameHash.cpp
@@ -1,22 +1,27 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 "WebIDLGlobalNameHash.h"
+#include "js/Class.h"
 #include "js/GCAPI.h"
+#include "js/Id.h"
 #include "js/Wrapper.h"
+#include "jsapi.h"
+#include "jsfriendapi.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/HashFunctions.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/dom/DOMJSClass.h"
 #include "mozilla/dom/DOMJSProxyHandler.h"
+#include "mozilla/dom/JSSlots.h"
 #include "mozilla/dom/PrototypeList.h"
 #include "mozilla/dom/RegisterBindings.h"
 #include "nsGlobalWindow.h"
 #include "nsIMemoryReporter.h"
 #include "nsTHashtable.h"
 #include "WrapperFactory.h"
 
 namespace mozilla {
@@ -60,24 +65,24 @@ struct WebIDLNameTableEntry : public PLD
 {
   typedef const WebIDLNameTableKey& KeyType;
   typedef const WebIDLNameTableKey* KeyTypePointer;
 
   explicit WebIDLNameTableEntry(KeyTypePointer aKey)
     : mNameOffset(0),
       mNameLength(0),
       mConstructorId(constructors::id::_ID_Count),
-      mDefine(nullptr),
+      mCreate(nullptr),
       mEnabled(nullptr)
   {}
   WebIDLNameTableEntry(WebIDLNameTableEntry&& aEntry)
     : mNameOffset(aEntry.mNameOffset),
       mNameLength(aEntry.mNameLength),
       mConstructorId(aEntry.mConstructorId),
-      mDefine(aEntry.mDefine),
+      mCreate(aEntry.mCreate),
       mEnabled(aEntry.mEnabled)
   {}
   ~WebIDLNameTableEntry()
   {}
 
   bool KeyEquals(KeyTypePointer aKey) const
   {
     if (mNameLength != aKey->mLength) {
@@ -104,17 +109,17 @@ struct WebIDLNameTableEntry : public PLD
     return aKey->mHash;
   }
 
   enum { ALLOW_MEMMOVE = true };
 
   uint16_t mNameOffset;
   uint16_t mNameLength;
   constructors::id::ID mConstructorId;
-  WebIDLGlobalNameHash::DefineGlobalName mDefine;
+  CreateInterfaceObjectsMethod mCreate;
   // May be null if enabled unconditionally
   WebIDLGlobalNameHash::ConstructorEnabled mEnabled;
 };
 
 static nsTHashtable<WebIDLNameTableEntry>* sWebIDLGlobalNames;
 
 class WebIDLGlobalNamesHashReporter final : public nsIMemoryReporter
 {
@@ -157,38 +162,67 @@ void
 WebIDLGlobalNameHash::Shutdown()
 {
   delete sWebIDLGlobalNames;
 }
 
 /* static */
 void
 WebIDLGlobalNameHash::Register(uint16_t aNameOffset, uint16_t aNameLength,
-                               DefineGlobalName aDefine,
+                               CreateInterfaceObjectsMethod aCreate,
                                ConstructorEnabled aEnabled,
                                constructors::id::ID aConstructorId)
 {
   const char* name = sNames + aNameOffset;
   WebIDLNameTableKey key(name, aNameLength);
   WebIDLNameTableEntry* entry = sWebIDLGlobalNames->PutEntry(key);
   entry->mNameOffset = aNameOffset;
   entry->mNameLength = aNameLength;
-  entry->mDefine = aDefine;
+  entry->mCreate = aCreate;
   entry->mEnabled = aEnabled;
   entry->mConstructorId = aConstructorId;
 }
 
 /* static */
 void
 WebIDLGlobalNameHash::Remove(const char* aName, uint32_t aLength)
 {
   WebIDLNameTableKey key(aName, aLength);
   sWebIDLGlobalNames->RemoveEntry(key);
 }
 
+static JSObject*
+FindNamedConstructorForXray(JSContext* aCx, JS::Handle<jsid> aId,
+                            const WebIDLNameTableEntry* aEntry)
+{
+  JSObject* interfaceObject =
+    GetPerInterfaceObjectHandle(aCx, aEntry->mConstructorId,
+                                aEntry->mCreate,
+                                /* aDefineOnGlobal = */ false);
+  if (!interfaceObject) {
+    return nullptr;
+  }
+
+  // This is a call over Xrays, so we will actually use the return value
+  // (instead of just having it defined on the global now).  Check for named
+  // constructors with this id, in case that's what the caller is asking for.
+  for (unsigned slot = DOM_INTERFACE_SLOTS_BASE;
+       slot < JSCLASS_RESERVED_SLOTS(js::GetObjectClass(interfaceObject));
+       ++slot) {
+    JSObject* constructor = &js::GetReservedSlot(interfaceObject, slot).toObject();
+    if (JS_GetFunctionId(JS_GetObjectFunction(constructor)) == JSID_TO_STRING(aId)) {
+      return constructor;
+    }
+  }
+
+  // None of the named constructors match, so the caller must want the
+  // interface object itself.
+  return interfaceObject;
+}
+
 /* static */
 bool
 WebIDLGlobalNameHash::DefineIfEnabled(JSContext* aCx,
                                       JS::Handle<JSObject*> aObj,
                                       JS::Handle<jsid> aId,
                                       JS::MutableHandle<JS::PropertyDescriptor> aDesc,
                                       bool* aFound)
 {
@@ -267,34 +301,36 @@ WebIDLGlobalNameHash::DefineIfEnabled(JS
   //
   // * We make sure that we do a non-Xray resolve first, so that all the
   //   slots are set up. In the Xray case, this means unwrapping and doing
   //   a non-Xray resolve before doing the Xray resolve.
   //
   // This all could use some grand refactoring, but for now we just limp
   // along.
   if (xpc::WrapperFactory::IsXrayWrapper(aObj)) {
-    JS::Rooted<JSObject*> interfaceObject(aCx);
+    JS::Rooted<JSObject*> constructor(aCx);
     {
       JSAutoCompartment ac(aCx, global);
-      interfaceObject = entry->mDefine(aCx, global, aId, false);
+      constructor = FindNamedConstructorForXray(aCx, aId, entry);
     }
-    if (NS_WARN_IF(!interfaceObject)) {
+    if (NS_WARN_IF(!constructor)) {
       return Throw(aCx, NS_ERROR_FAILURE);
     }
-    if (!JS_WrapObject(aCx, &interfaceObject)) {
+    if (!JS_WrapObject(aCx, &constructor)) {
       return Throw(aCx, NS_ERROR_FAILURE);
     }
 
-    FillPropertyDescriptor(aDesc, aObj, 0, JS::ObjectValue(*interfaceObject));
+    FillPropertyDescriptor(aDesc, aObj, 0, JS::ObjectValue(*constructor));
     return true;
   }
 
   JS::Rooted<JSObject*> interfaceObject(aCx,
-                                        entry->mDefine(aCx, aObj, aId, true));
+    GetPerInterfaceObjectHandle(aCx, entry->mConstructorId,
+                                entry->mCreate,
+                                /* aDefineOnGlobal = */ true));
   if (NS_WARN_IF(!interfaceObject)) {
     return Throw(aCx, NS_ERROR_FAILURE);
   }
 
   // We've already defined the property.  We indicate this to the caller
   // by filling a property descriptor with JS::UndefinedValue() as the
   // value.  We still have to fill in a property descriptor, though, so
   // that the caller knows the property is in fact on this object.  It
--- a/dom/bindings/WebIDLGlobalNameHash.h
+++ b/dom/bindings/WebIDLGlobalNameHash.h
@@ -4,16 +4,17 @@
  * 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/. */
 
 #ifndef mozilla_dom_WebIDLGlobalNameHash_h__
 #define mozilla_dom_WebIDLGlobalNameHash_h__
 
 #include "js/RootingAPI.h"
 #include "nsTArray.h"
+#include "mozilla/dom/BindingDeclarations.h"
 
 namespace mozilla {
 namespace dom {
 
 struct WebIDLNameTableEntry;
 
 namespace constructors {
 namespace id {
@@ -22,31 +23,28 @@ enum ID : uint16_t;
 } // namespace constructors
 
 class WebIDLGlobalNameHash
 {
 public:
   static void Init();
   static void Shutdown();
 
-  typedef JSObject*
-  (*DefineGlobalName)(JSContext* cx, JS::Handle<JSObject*> global,
-                      JS::Handle<jsid> id, bool defineOnGlobal);
-
   // Check whether a constructor should be enabled for the given object.
   // Note that the object should NOT be an Xray, since Xrays will end up
   // defining constructors on the underlying object.
   // This is a typedef for the function type itself, not the function
   // pointer, so it's more obvious that pointers to a ConstructorEnabled
   // can be null.
   typedef bool
   (*ConstructorEnabled)(JSContext* cx, JS::Handle<JSObject*> obj);
 
   static void Register(uint16_t aNameOffset, uint16_t aNameLength,
-                       DefineGlobalName aDefine, ConstructorEnabled aEnabled,
+                       CreateInterfaceObjectsMethod aCreate,
+                       ConstructorEnabled aEnabled,
                        constructors::id::ID aConstructorId);
 
   static void Remove(const char* aName, uint32_t aLength);
 
   // Returns false if something failed. aFound is set to true if the name is in
   // the hash, whether it's enabled or not.
   static bool DefineIfEnabled(JSContext* aCx, JS::Handle<JSObject*> aObj,
                               JS::Handle<jsid> aId,