Bug 1447849 - Eliminate the anonymous union from XPTTypeDescriptor. r=njn
For
bug 1438688, I need to statically initialize all of the data types
in xpt_struct.h. It turns out that the approach I was using for unions
is C99 and not C++. While for some reason Clang and GCC are okay with
that, MSVC is not.
One of the unions is a gnarly anonymous union in
XPTTypeDescriptor. However, every arm of this union is either 1 or 2
uint8_t, so I think it is reasonable to eliminate the union and
replace it with two fields, mData1 and mData2. I've fixed up the
places that read this data to use accessor methods with nice asserts
about the tag on the variant, so if anything I think that part is
nicer.
The code in xpt_struct.cpp that writes to this data is maybe less
nice, but I'm deleting it in
bug 1438688 so I think that's okay. We
also lose some detail in the comments about the relationship between
what is stored in memory compared to what is stored on disk, but I
think that's okay, too.
MozReview-Commit-ID: DGi19f8HnMi
--- a/xpcom/reflect/xptinfo/xptiInterfaceInfo.cpp
+++ b/xpcom/reflect/xptinfo/xptiInterfaceInfo.cpp
@@ -296,25 +296,24 @@ xptiInterfaceEntry::GetInterfaceIndexFor
{
NS_ERROR("bad param");
return NS_ERROR_INVALID_ARG;
}
const XPTTypeDescriptor *td = ¶m->mType;
while (td->Tag() == TD_ARRAY) {
- td = &mDescriptor->mAdditionalTypes[td->u.mArray.mAdditionalType];
+ td = td->ArrayElementType(mDescriptor);
}
if (td->Tag() != TD_INTERFACE_TYPE) {
NS_ERROR("not an interface");
return NS_ERROR_INVALID_ARG;
}
-
- *interfaceIndex = (td->u.mIface.mIfaceHi8 << 8) | td->u.mIface.mIfaceLo8;
+ *interfaceIndex = td->InterfaceIndex();
return NS_OK;
}
nsresult
xptiInterfaceEntry::GetEntryForParam(uint16_t methodIndex,
const nsXPTParamInfo * param,
xptiInterfaceEntry** entry)
{
@@ -431,25 +430,23 @@ xptiInterfaceEntry::GetIIDForParamNoAllo
nsresult
xptiInterfaceEntry::GetTypeInArray(const nsXPTParamInfo* param,
uint16_t dimension,
const XPTTypeDescriptor** type)
{
NS_ASSERTION(IsFullyResolved(), "bad state");
const XPTTypeDescriptor *td = ¶m->mType;
- const XPTTypeDescriptor *additional_types =
- mDescriptor->mAdditionalTypes;
for (uint16_t i = 0; i < dimension; i++) {
if (td->Tag() != TD_ARRAY) {
NS_ERROR("bad dimension");
return NS_ERROR_INVALID_ARG;
}
- td = &additional_types[td->u.mArray.mAdditionalType];
+ td = td->ArrayElementType(mDescriptor);
}
*type = td;
return NS_OK;
}
nsresult
xptiInterfaceEntry::GetTypeForParam(uint16_t methodIndex,
@@ -513,21 +510,19 @@ xptiInterfaceEntry::GetSizeIsArgNumberFo
return rv;
}
else
td = ¶m->mType;
// verify that this is a type that has size_is
switch (td->Tag()) {
case TD_ARRAY:
- *argnum = td->u.mArray.mArgNum;
- break;
case TD_PSTRING_SIZE_IS:
case TD_PWSTRING_SIZE_IS:
- *argnum = td->u.mPStringIs.mArgNum;
+ *argnum = td->ArgNum();
break;
default:
NS_ERROR("not a size_is");
return NS_ERROR_INVALID_ARG;
}
return NS_OK;
}
@@ -549,25 +544,25 @@ xptiInterfaceEntry::GetInterfaceIsArgNum
{
NS_ERROR("bad index");
return NS_ERROR_INVALID_ARG;
}
const XPTTypeDescriptor *td = ¶m->mType;
while (td->Tag() == TD_ARRAY) {
- td = &mDescriptor->mAdditionalTypes[td->u.mArray.mAdditionalType];
+ td = td->ArrayElementType(mDescriptor);
}
if (td->Tag() != TD_INTERFACE_IS_TYPE) {
NS_ERROR("not an iid_is");
return NS_ERROR_INVALID_ARG;
}
- *argnum = td->u.mInterfaceIs.mArgNum;
+ *argnum = td->ArgNum();
return NS_OK;
}
nsresult
xptiInterfaceEntry::IsIID(const nsIID * iid, bool *_retval)
{
// It is not necessary to Resolve because this info is read from manifest.
*_retval = mIID.Equals(*iid);
--- a/xpcom/typelib/xpt/xpt_struct.cpp
+++ b/xpcom/typelib/xpt/xpt_struct.cpp
@@ -406,44 +406,44 @@ DoTypeDescriptor(XPTArena *arena, NotNul
return false;
}
switch (td->Tag()) {
case TD_INTERFACE_TYPE:
uint16_t iface;
if (!XPT_Do16(cursor, &iface))
return false;
- td->u.mIface.mIfaceHi8 = (iface >> 8) & 0xff;
- td->u.mIface.mIfaceLo8 = iface & 0xff;
+ td->mData1 = (iface >> 8) & 0xff;
+ td->mData2 = iface & 0xff;
break;
case TD_INTERFACE_IS_TYPE:
- if (!XPT_Do8(cursor, &td->u.mInterfaceIs.mArgNum))
+ if (!XPT_Do8(cursor, &td->mData1))
return false;
break;
case TD_ARRAY: {
// argnum2 appears in the on-disk format but it isn't used.
uint8_t argnum2 = 0;
- if (!XPT_Do8(cursor, &td->u.mArray.mArgNum) ||
+ if (!XPT_Do8(cursor, &td->mData1) ||
!XPT_Do8(cursor, &argnum2))
return false;
XPTTypeDescriptor elementTypeDescriptor;
if (!DoTypeDescriptor(arena, cursor, &elementTypeDescriptor, id))
return false;
if (!InterfaceDescriptorAddType(arena, id, &elementTypeDescriptor))
return false;
- td->u.mArray.mAdditionalType = id->mNumAdditionalTypes - 1;
+ td->mData2 = id->mNumAdditionalTypes - 1;
break;
}
case TD_PSTRING_SIZE_IS:
case TD_PWSTRING_SIZE_IS: {
// argnum2 appears in the on-disk format but it isn't used.
uint8_t argnum2 = 0;
- if (!XPT_Do8(cursor, &td->u.mPStringIs.mArgNum) ||
+ if (!XPT_Do8(cursor, &td->mData1) ||
!XPT_Do8(cursor, &argnum2))
return false;
break;
}
default:
/* nothing special */
break;
}
--- a/xpcom/typelib/xpt/xpt_struct.h
+++ b/xpcom/typelib/xpt/xpt_struct.h
@@ -9,16 +9,17 @@
* http://www.mozilla.org/scriptable/typelib_file.html
*/
#ifndef xpt_struct_h
#define xpt_struct_h
#include "nsID.h"
#include <stdint.h>
+#include "mozilla/Assertions.h"
/*
* Originally, I was going to have structures that exactly matched the on-disk
* representation, but that proved difficult: different compilers can pack
* their structs differently, and that makes overlaying them atop a
* read-from-disk byte buffer troublesome. So now I just have some structures
* that are used in memory, and we're going to write a nice XDR library to
* write them to disk and stuff. It is pure joy. -- shaver
@@ -189,49 +190,46 @@ enum XPTTypeDescriptorTags {
TD_JSVAL = 26
};
struct XPTTypeDescriptor {
uint8_t Tag() const {
return mPrefix.TagPart();
}
+ 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 {
+ MOZ_ASSERT(Tag() == TD_ARRAY);
+ return &aDescriptor->mAdditionalTypes[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;
+ }
+
XPTTypeDescriptorPrefix mPrefix;
- // The memory layout here doesn't exactly match (for the appropriate types)
- // the on-disk format. This is to save memory.
- union {
- // Used for TD_INTERFACE_IS_TYPE.
- struct {
- uint8_t mArgNum;
- } mInterfaceIs;
-
- // Used for TD_PSTRING_SIZE_IS, TD_PWSTRING_SIZE_IS.
- struct {
- uint8_t mArgNum;
- //uint8_t mArgNum2; // Present on disk, omitted here.
- } mPStringIs;
-
- // Used for TD_ARRAY.
- struct {
- uint8_t mArgNum;
- //uint8_t mArgNum2; // Present on disk, omitted here.
- uint8_t mAdditionalType; // uint16_t on disk, uint8_t here;
- // in practice it never exceeds 20.
- } mArray;
-
- // Used for TD_INTERFACE_TYPE.
- struct {
- // 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.
- uint8_t mIfaceHi8;
- uint8_t mIfaceLo8;
- } mIface;
- } u;
+ // The data for the different variants is stored in these two data fields.
+ // These should only be accessed via the getter methods above, which will
+ // assert if the tag is invalid. The memory layout here doesn't exactly match
+ // the on-disk format. This is to save memory. Some fields for some cases are
+ // smaller than they are on disk or omitted entirely.
+ uint8_t mData1;
+ uint8_t mData2;
};
/*
* A ConstDescriptor is a variable-size record that records the name and
* value of a scoped interface constant. This is allowed only for a subset
* of types.
*
* The type (and thus the size) of the value record is determined by the