Bug 1438688, part 4 - Hoist arrays to XPTHeader. r=njn
☠☠ backed out by 70400746eb53 ☠ ☠
authorAndrew McCreight <continuation@gmail.com>
Wed, 28 Feb 2018 15:12:07 -0800
changeset 776471 4c437ba9d9841597038e36a6244f428b8cf01816
parent 776470 2f243bca1af344ee781aaa616147016b26d74693
child 776472 e05ec1e08b46732b5552a48fe48d32108f9cca4c
push id104888
push userbmo:emilio@crisal.io
push dateTue, 03 Apr 2018 07:00:14 +0000
reviewersnjn
bugs1438688
milestone61.0a1
Bug 1438688, part 4 - Hoist arrays to XPTHeader. r=njn To allow XPT information to be shared between processes, it needs to not contain any pointers, because they cause relocations. I've eliminated pointers by hoisting all of the variable length data structures to XPTHeader, into a single array for each type of data. These data structures now use an index into these arrays to find their first element. Strings are similar, but they are mashed into a single giant string, including embedded null terminators. Modifying the accessor methods to support this is easy, because there is only a single global instance of each of these arrays in XPTHeader. MozReview-Commit-ID: 5rgwaEBvDYl
xpcom/reflect/xptinfo/xptiInterfaceInfo.cpp
xpcom/typelib/xpt/xpt_struct.h
--- a/xpcom/reflect/xptinfo/xptiInterfaceInfo.cpp
+++ b/xpcom/reflect/xptinfo/xptiInterfaceInfo.cpp
@@ -296,17 +296,17 @@ xptiInterfaceEntry::GetInterfaceIndexFor
     {
         NS_ERROR("bad param");
         return NS_ERROR_INVALID_ARG;
     }
 
     const XPTTypeDescriptor *td = &param->mType;
 
     while (td->Tag() == TD_ARRAY) {
-        td = td->ArrayElementType(mDescriptor);
+        td = td->ArrayElementType();
     }
 
     if (td->Tag() != TD_INTERFACE_TYPE) {
         NS_ERROR("not an interface");
         return NS_ERROR_INVALID_ARG;
     }
     *interfaceIndex = td->InterfaceIndex();
     return NS_OK;
@@ -436,17 +436,17 @@ xptiInterfaceEntry::GetTypeInArray(const
 
     const XPTTypeDescriptor *td = &param->mType;
 
     for (uint16_t i = 0; i < dimension; i++) {
         if (td->Tag() != TD_ARRAY) {
             NS_ERROR("bad dimension");
             return NS_ERROR_INVALID_ARG;
         }
-        td = td->ArrayElementType(mDescriptor);
+        td = td->ArrayElementType();
     }
 
     *type = td;
     return NS_OK;
 }
 
 nsresult
 xptiInterfaceEntry::GetTypeForParam(uint16_t methodIndex,
@@ -544,17 +544,17 @@ xptiInterfaceEntry::GetInterfaceIsArgNum
     {
         NS_ERROR("bad index");
         return NS_ERROR_INVALID_ARG;
     }
 
     const XPTTypeDescriptor *td = &param->mType;
 
     while (td->Tag() == TD_ARRAY) {
-        td = td->ArrayElementType(mDescriptor);
+        td = td->ArrayElementType();
     }
 
     if (td->Tag() != TD_INTERFACE_IS_TYPE) {
         NS_ERROR("not an iid_is");
         return NS_ERROR_INVALID_ARG;
     }
 
     *argnum = td->ArgNum();
--- a/xpcom/typelib/xpt/xpt_struct.h
+++ b/xpcom/typelib/xpt/xpt_struct.h
@@ -22,30 +22,41 @@ struct XPTConstDescriptor;
 struct XPTMethodDescriptor;
 struct XPTParamDescriptor;
 struct XPTTypeDescriptor;
 struct XPTTypeDescriptorPrefix;
 
 struct XPTHeader {
   static const uint16_t kNumInterfaces;
   static const XPTInterfaceDirectoryEntry kInterfaceDirectory[];
+  static const XPTInterfaceDescriptor kInterfaces[];
+  static const XPTTypeDescriptor kTypes[];
+  static const XPTParamDescriptor kParams[];
+  static const XPTMethodDescriptor kMethods[];
+  static const XPTConstDescriptor kConsts[];
+
+  // All of the strings for this header, including their null
+  // terminators, concatenated into a single string.
+  static const char kStrings[];
 };
 
 /*
  * An array of directory entries is used to quickly locate an interface
  * description using its IID. No interface should appear more than once in the
  * array.
  */
 struct XPTInterfaceDirectoryEntry {
   inline const XPTInterfaceDescriptor* InterfaceDescriptor() const;
   inline const char* Name() const;
 
   nsID mIID;
-  const char* mName;
-  const XPTInterfaceDescriptor* mInterfaceDescriptor;
+  uint32_t mName; // Index into XPTHeader::mStrings.
+  // mInterfaceDescriptor is a 1-based index into XPTHeader::mInterfaces. The
+  // value 0 is used to indicate unresolved interfaces.
+  uint32_t mInterfaceDescriptor;
 };
 
 /*
  * An InterfaceDescriptor describes a single XPCOM interface, including all of
  * its methods.
  */
 struct XPTInterfaceDescriptor {
   static const uint8_t kScriptableMask =                0x80;
@@ -59,24 +70,22 @@ struct XPTInterfaceDescriptor {
   bool IsMainProcessScriptableOnly() const { return !!(mFlags & kMainProcessScriptableOnlyMask); }
 
   inline const XPTMethodDescriptor& Method(size_t aIndex) const;
   inline const XPTConstDescriptor& Const(size_t aIndex) const;
 
   /*
    * This field ordering minimizes the size of this struct.
    */
-  const XPTMethodDescriptor* mMethodDescriptors;
-  const XPTConstDescriptor* mConstDescriptors;
-  const XPTTypeDescriptor* mAdditionalTypes;
+  uint16_t mMethodDescriptors; // Index into XPTHeader::mMethods.
+  uint16_t mConstDescriptors; // Index into XPTHeader::mConsts.
   uint16_t mParentInterface;
   uint16_t mNumMethods;
   uint16_t mNumConstants;
   uint8_t mFlags;
-  uint8_t mNumAdditionalTypes;
 };
 
 /*
  * A TypeDescriptor is a union used to identify the type of a method
  * argument or return value.
  *
  * There are three types of TypeDescriptors:
  *
@@ -142,19 +151,19 @@ struct XPTTypeDescriptor {
   uint8_t ArgNum() const {
     MOZ_ASSERT(Tag() == TD_INTERFACE_IS_TYPE ||
                Tag() == TD_PSTRING_SIZE_IS ||
                Tag() == TD_PWSTRING_SIZE_IS ||
                Tag() == TD_ARRAY);
     return mData1;
   }
 
-  const XPTTypeDescriptor* ArrayElementType(const XPTInterfaceDescriptor* aDescriptor) const {
+  const XPTTypeDescriptor* ArrayElementType() const {
     MOZ_ASSERT(Tag() == TD_ARRAY);
-    return &aDescriptor->mAdditionalTypes[mData2];
+    return &XPTHeader::kTypes[mData2];
   }
 
   // We store the 16-bit iface value as two 8-bit values in order to
   // avoid 16-bit alignment requirements for XPTTypeDescriptor, which
   // reduces its size and also the size of XPTParamDescriptor.
   uint16_t InterfaceIndex() const {
     MOZ_ASSERT(Tag() == TD_INTERFACE_TYPE);
     return (mData1 << 8) | mData2;
@@ -183,20 +192,20 @@ union XPTConstValue {
   int16_t i16;
   uint16_t ui16;
   int32_t i32;
   uint32_t ui32;
 };
 
 struct XPTConstDescriptor {
   const char* Name() const {
-    return mName;
+    return &XPTHeader::kStrings[mName];
   }
 
-  const char* mName;
+  uint32_t mName; // Index into XPTHeader::mStrings.
   XPTTypeDescriptor mType;
   union XPTConstValue mValue;
 };
 
 /*
  * A ParamDescriptor is used to describe either a single argument to a method or
  * a method's result.
  */
@@ -205,41 +214,44 @@ struct XPTParamDescriptor {
   XPTTypeDescriptor mType;
 };
 
 /*
  * A MethodDescriptor is used to describe a single interface method.
  */
 struct XPTMethodDescriptor {
   const char* Name() const {
-    return mName;
+    return &XPTHeader::kStrings[mName];
   }
   const XPTParamDescriptor& Param(uint8_t aIndex) const {
-    return mParams[aIndex];
+    return XPTHeader::kParams[mParams + aIndex];
   }
 
-  const char* mName;
-  const XPTParamDescriptor* mParams;
+  uint32_t mName; // Index into XPTHeader::mStrings.
+  uint32_t mParams; // Index into XPTHeader::mParams.
   uint8_t mFlags;
   uint8_t mNumArgs;
 };
 
 const char*
 XPTInterfaceDirectoryEntry::Name() const {
-  return mName;
+  return &XPTHeader::kStrings[mName];
 }
 
 const XPTInterfaceDescriptor*
 XPTInterfaceDirectoryEntry::InterfaceDescriptor() const {
-  return mInterfaceDescriptor;
+  if (mInterfaceDescriptor == 0) {
+    return nullptr;
+  }
+  return &XPTHeader::kInterfaces[mInterfaceDescriptor - 1];
 }
 
 const XPTMethodDescriptor&
 XPTInterfaceDescriptor::Method(size_t aIndex) const {
-  return mMethodDescriptors[aIndex];
+  return XPTHeader::kMethods[mMethodDescriptors + aIndex];
 }
 
 const XPTConstDescriptor&
 XPTInterfaceDescriptor::Const(size_t aIndex) const {
-  return mConstDescriptors[aIndex];
+  return XPTHeader::kConsts[mConstDescriptors + aIndex];
 }
 
 #endif /* xpt_struct_h */