Bug 1784266 - Part 3: Get rid of union conversion structure; r=peterv

TrySetTo* conversion methods are generated in the regular union structure now.

Differential Revision: https://phabricator.services.mozilla.com/D157327
This commit is contained in:
Edgar Chen 2022-09-28 08:56:07 +00:00
parent 82be3e6295
commit 1aa03613fa
5 changed files with 58 additions and 319 deletions

View file

@ -1394,7 +1394,6 @@ class CGHeaders(CGWrapper):
unrolled = unrolled.inner
if unrolled.isUnion():
headerSet.add(self.getUnionDeclarationFilename(config, unrolled))
bindingHeaders.add("mozilla/dom/UnionConversions.h")
for t in unrolled.flatMemberTypes:
addHeadersForType((t, None))
elif unrolled.isPromise():
@ -1743,79 +1742,6 @@ def UnionTypes(unionTypes, config):
)
def UnionConversions(unionTypes, config):
"""
The unionTypes argument should be a list of tuples, each containing two
elements: a union type and a descriptor. This is typically the list
generated by UnionsForFile.
Returns a tuple containing a list of headers and a CGThing to declare all
union argument conversion helper structs.
"""
headers = set()
unionConversions = dict()
for t in unionTypes:
name = str(t)
if name not in unionConversions:
unionConversions[name] = CGUnionConversionStruct(t, config)
def addHeadersForType(f):
if f.isSequence():
# Sequences require JSAPI C++ for-of iteration code to fill
# them.
headers.add("js/ForOfIterator.h")
# Sequences can always throw "not an object" exceptions.
headers.add("mozilla/dom/BindingCallContext.h")
if typeNeedsRooting(f):
headers.add("mozilla/dom/RootedSequence.h")
f = f.unroll()
if idlTypeNeedsCallContext(f):
headers.add("mozilla/dom/BindingCallContext.h")
if f.isPromise():
headers.add("mozilla/dom/Promise.h")
# We need ToJSValue to do the Promise to JS conversion.
headers.add("mozilla/dom/ToJSValue.h")
elif f.isInterface():
if f.isSpiderMonkeyInterface():
headers.add("js/RootingAPI.h")
headers.add("mozilla/dom/TypedArray.h")
elif f.inner.isExternal():
try:
typeDesc = config.getDescriptor(f.inner.identifier.name)
except NoSuchDescriptorError:
return
headers.add(typeDesc.headerFile)
else:
headers.add(CGHeaders.getDeclarationFilename(f.inner))
elif f.isDictionary():
headers.add(CGHeaders.getDeclarationFilename(f.inner))
elif f.isFloat() and not f.isUnrestricted():
# Restricted floats are tested for finiteness
headers.add("mozilla/FloatingPoint.h")
headers.add("mozilla/dom/PrimitiveConversions.h")
elif f.isPrimitive():
headers.add("mozilla/dom/PrimitiveConversions.h")
elif f.isRecord():
headers.add("mozilla/dom/Record.h")
# And the internal type of the record
addHeadersForType(f.inner)
if typeNeedsRooting(f):
headers.add("mozilla/dom/RootedRecord.h")
# We plan to include UnionTypes.h no matter what, so it's
# OK if we throw it into the set here.
headers.add(CGHeaders.getUnionDeclarationFilename(config, t))
for f in t.flatMemberTypes:
addHeadersForType(f)
return (
headers,
CGWrapper(CGList(SortedDictValues(unionConversions), "\n"), post="\n\n"),
)
class Argument:
"""
A class for outputting the type and name of an argument
@ -6297,11 +6223,13 @@ def getJSToNativeConversionInfo(
type = type.inner
isOwningUnion = (isMember and isMember != "Union") or isCallbackReturnValue
unionArgumentObj = "${declName}" if isOwningUnion else "${holderName}"
unionArgumentObj = "${declName}"
if nullable:
if isOptional and not isOwningUnion:
unionArgumentObj += ".Value()"
# If we're owning, we're a Nullable, which hasn't been told it has
# a value. Otherwise we're an already-constructed Maybe.
unionArgumentObj += ".SetValue()" if isOwningUnion else ".ref()"
unionArgumentObj += ".SetValue()"
extraConditionForNull = ""
if type.hasNullableType:
@ -6341,21 +6269,9 @@ def getJSToNativeConversionInfo(
constructDecl = None
if nullable:
if isOptional and not isOwningUnion:
holderArgs = "${declName}.Value().SetValue()"
declType = CGTemplatedType("Optional", declType)
constructDecl = CGGeneric("${declName}.Construct();\n")
declLoc = "${declName}.Value()"
else:
holderArgs = "${declName}.SetValue()"
if holderType is not None:
constructHolder = CGGeneric("${holderName}.emplace(%s);\n" % holderArgs)
else:
constructHolder = None
# Don't need to pass those args when the holder is being constructed
holderArgs = None
else:
holderArgs = "${declName}"
constructHolder = None
if not isMember and isCallbackReturnValue:
declType = CGWrapper(declType, post="&")
@ -6411,8 +6327,6 @@ def getJSToNativeConversionInfo(
templateBody = CGIfElseWrapper("!(${haveValue})", default, templateBody)
templateBody = CGList([constructHolder, templateBody])
if nullable:
assert not type.hasNullableType
if defaultValue:
@ -6467,8 +6381,6 @@ def getJSToNativeConversionInfo(
templateBody.define(),
declType=declType,
declArgs=declArgs,
holderType=holderType,
holderArgs=holderArgs,
dealWithOptional=isOptional and (not nullable or isOwningUnion),
)
@ -12345,12 +12257,13 @@ def getUnionTypeTemplateVars(unionType, type, descriptorProvider, isMember=False
# By the time tryNextCode is invoked, we're guaranteed the union has been
# constructed as some type, since we've been trying to convert into the
# corresponding member.
prefix = "" if ownsMembers else "mUnion."
tryNextCode = (
"$*{destroyHolder}\n"
"%sDestroy%s();\n"
"tryNext = true;\n"
"return true;\n" % (prefix, name)
tryNextCode = fill(
"""
Destroy${name}();
tryNext = true;
return true;
""",
name=name,
)
sourceDescription = "%s branch of %s" % (type.prettyName(), unionType.prettyName())
@ -12364,12 +12277,6 @@ def getUnionTypeTemplateVars(unionType, type, descriptorProvider, isMember=False
sourceDescription=sourceDescription,
)
if conversionInfo.holderType is not None:
assert not ownsMembers
destroyHolder = "%s.reset();\n" % holderName
else:
destroyHolder = ""
ctorNeedsCx = conversionInfo.declArgs == "cx"
ctorArgs = "cx" if ctorNeedsCx else ""
@ -12378,21 +12285,18 @@ def getUnionTypeTemplateVars(unionType, type, descriptorProvider, isMember=False
if type.isObject():
if ownsMembers:
body = dedent(
"""
MOZ_ASSERT(mType == eUninitialized);
mValue.mObject.SetValue(obj);
mType = eObject;
"""
)
setValue = "mValue.mObject.SetValue(obj);"
else:
body = dedent(
"""
MOZ_ASSERT(mUnion.mType == mUnion.eUninitialized);
mUnion.mValue.mObject.SetValue(cx, obj);
mUnion.mType = mUnion.eObject;
"""
)
setValue = "mValue.mObject.SetValue(cx, obj);"
body = fill(
"""
MOZ_ASSERT(mType == eUninitialized);
${setValue}
mType = eObject;
""",
setValue=setValue,
)
# It's a bit sketchy to do the security check after setting the value,
# but it keeps the code cleaner and lets us avoid rooting |obj| over the
@ -12428,21 +12332,12 @@ def getUnionTypeTemplateVars(unionType, type, descriptorProvider, isMember=False
else:
# Important: we need to not have our declName involve
# maybe-GCing operations.
if conversionInfo.holderType is not None:
holderArgs = conversionInfo.holderArgs
if holderArgs is None:
holderArgs = ""
initHolder = "%s.emplace(%s);\n" % (holderName, holderArgs)
else:
initHolder = ""
jsConversion = fill(
initHolder + conversionInfo.template,
conversionInfo.template,
val="value",
maybeMutableVal="value",
declName="memberSlot",
holderName=(holderName if ownsMembers else "%s.ref()" % holderName),
destroyHolder=destroyHolder,
passedToJSImpl="passedToJSImpl",
)
@ -12481,8 +12376,6 @@ def getUnionTypeTemplateVars(unionType, type, descriptorProvider, isMember=False
Argument("bool&", "tryNext"),
Argument("bool", "passedToJSImpl", default="false"),
],
inline=not ownsMembers,
bodyInHeader=not ownsMembers,
body=jsConversion,
)
]
@ -12507,8 +12400,6 @@ def getUnionTypeTemplateVars(unionType, type, descriptorProvider, isMember=False
Argument("bool&", "tryNext"),
Argument("bool", "passedToJSImpl", default="false"),
],
inline=not ownsMembers,
bodyInHeader=not ownsMembers,
body=shimBody,
)
)
@ -12518,9 +12409,6 @@ def getUnionTypeTemplateVars(unionType, type, descriptorProvider, isMember=False
"structType": structType,
"externalType": externalType,
"setters": setters,
"holderType": conversionInfo.holderType.define()
if conversionInfo.holderType
else None,
"ctorArgs": ctorArgs,
"ctorArgList": [Argument("JSContext*", "cx")] if ctorNeedsCx else [],
}
@ -12897,6 +12785,8 @@ class CGUnionStruct(CGThing):
self.descriptorProvider,
isMember="OwningUnion" if self.ownsMembers else "Union",
)
if vars["setters"]:
methods.extend(vars["setters"])
uninit = "Uninit();"
if hasObjectType and not self.ownsMembers:
uninit = (
@ -12937,30 +12827,28 @@ class CGUnionStruct(CGThing):
body=body % uninit,
)
)
if self.ownsMembers:
if vars["setters"]:
methods.extend(vars["setters"])
# Provide a SetStringLiteral() method to support string defaults.
if t.isByteString() or t.isUTF8String():
charType = "const nsCString::char_type"
elif t.isString():
charType = "const nsString::char_type"
else:
charType = None
if charType:
methods.append(
ClassMethod(
"SetStringLiteral",
"void",
# Hack, but it works...
[Argument(charType, "(&aData)[N]")],
inline=True,
bodyInHeader=True,
templateArgs=["int N"],
body="RawSetAs%s().AssignLiteral(aData);\n" % t.name,
)
# Provide a SetStringLiteral() method to support string defaults.
if t.isByteString() or t.isUTF8String():
charType = "const nsCString::char_type"
elif t.isString():
charType = "const nsString::char_type"
else:
charType = None
if charType:
methods.append(
ClassMethod(
"SetStringLiteral",
"void",
# Hack, but it works...
[Argument(charType, "(&aData)[N]")],
inline=True,
bodyInHeader=True,
templateArgs=["int N"],
body="RawSetAs%s().AssignLiteral(aData);\n" % t.name,
)
)
body = fill("return mType == e${name};\n", **vars)
methods.append(
@ -13210,16 +13098,13 @@ class CGUnionStruct(CGThing):
else:
disallowCopyConstruction = True
if self.ownsMembers:
if idlTypeNeedsCycleCollection(self.type):
friend = (
" friend void ImplCycleCollectionUnlink(%s& aUnion);\n"
% CGUnionStruct.unionTypeName(self.type, True)
)
else:
friend = ""
if self.ownsMembers and idlTypeNeedsCycleCollection(self.type):
friend = (
" friend void ImplCycleCollectionUnlink(%s& aUnion);\n"
% CGUnionStruct.unionTypeName(self.type, True)
)
else:
friend = " friend class %sArgument;\n" % str(self.type)
friend = ""
bases = [ClassBase("AllOwningUnionBase")] if self.ownsMembers else []
return CGClass(
@ -13285,123 +13170,6 @@ class CGUnionStruct(CGThing):
return decl.define()
class CGUnionConversionStruct(CGThing):
def __init__(self, type, descriptorProvider):
CGThing.__init__(self)
self.type = type.unroll()
self.descriptorProvider = descriptorProvider
def declare(self):
structName = str(self.type)
members = [
ClassMember(
"mUnion", structName + "&", body="const_cast<%s&>(aUnion)" % structName
)
]
# Argument needs to be a const ref because that's all Maybe<> allows
ctor = ClassConstructor(
[Argument("const %s&" % structName, "aUnion")],
bodyInHeader=True,
visibility="public",
explicit=True,
)
methods = []
def addSpecialType(typename):
methods.append(
ClassMethod(
"Set" + typename,
"bool",
[],
body=fill(
"""
MOZ_ASSERT(mUnion.mType == mUnion.eUninitialized);
mUnion.mType = mUnion.${enumValue};
return true;
""",
enumValue="e" + typename,
),
inline=True,
bodyInHeader=True,
)
)
if self.type.hasNullableType:
addSpecialType("Null")
for t in self.type.flatMemberTypes:
if t.isUndefined():
addSpecialType("Undefined")
continue
vars = getUnionTypeTemplateVars(
self.type, t, self.descriptorProvider, isMember="Union"
)
if vars["setters"]:
methods.extend(vars["setters"])
if vars["name"] != "Object":
body = fill(
"""
MOZ_ASSERT(mUnion.mType == mUnion.eUninitialized);
mUnion.mType = mUnion.e${name};
return mUnion.mValue.m${name}.SetValue(${ctorArgs});
""",
**vars,
)
methods.append(
ClassMethod(
"RawSetAs" + vars["name"],
vars["structType"] + "&",
vars["ctorArgList"],
bodyInHeader=True,
body=body,
visibility="private",
)
)
# Provide a SetStringLiteral() method to support string defaults.
if t.isByteString() or t.isUTF8String():
charType = "const nsCString::char_type"
elif t.isString():
charType = "const nsString::char_type"
else:
charType = None
if charType:
methods.append(
ClassMethod(
"SetStringLiteral",
"void",
# Hack, but it works...
[Argument(charType, "(&aData)[N]")],
inline=True,
bodyInHeader=True,
templateArgs=["int N"],
body="RawSetAs%s().AssignLiteral(aData);\n" % t.name,
)
)
if vars["holderType"] is not None:
holderType = CGTemplatedType(
"Maybe", CGGeneric(vars["holderType"])
).define()
members.append(ClassMember("m%sHolder" % vars["name"], holderType))
return CGClass(
structName + "Argument",
members=members,
constructors=[ctor],
methods=methods,
disallowCopyConstruction=True,
).declare()
def define(self):
return ""
def deps(self):
return set()
class ClassItem:
"""Use with CGClass"""
@ -23546,28 +23314,6 @@ class GlobalGenRoots:
# Done.
return curr
@staticmethod
def UnionConversions(config):
unionTypes = []
for l in six.itervalues(config.unionsPerFilename):
unionTypes.extend(l)
unionTypes.sort(key=lambda u: u.name)
headers, unions = UnionConversions(unionTypes, config)
# Wrap all of that in our namespaces.
curr = CGNamespace.build(["mozilla", "dom"], unions)
curr = CGWrapper(curr, post="\n")
headers.update(["nsDebug.h", "mozilla/dom/UnionTypes.h"])
curr = CGHeaders([], [], [], [], headers, [], "UnionConversions", curr)
# Add include guards.
curr = CGIncludeGuard("UnionConversions", curr)
# Done.
return curr
@staticmethod
def WebIDLPrefs(config):
prefs = set()

View file

@ -160,7 +160,6 @@ class WebIDLCodegenManager(LoggingMixin):
"RegisterWorkerBindings.h",
"RegisterWorkerDebuggerBindings.h",
"RegisterWorkletBindings.h",
"UnionConversions.h",
"UnionTypes.h",
"WebIDLPrefs.h",
"WebIDLSerializable.h",

View file

@ -9,7 +9,6 @@
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/FileSystemWritableFileStreamBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/UnionConversions.h"
#include "mozilla/dom/WritableStreamDefaultController.h"
namespace mozilla::dom {
@ -32,27 +31,25 @@ static void TryGetAsUnion(
ArrayBufferViewOrArrayBufferOrBlobOrUSVStringOrWriteParams& aOutput,
JS::Handle<JS::Value> aChunk, ErrorResult& aRv) {
JS::Rooted<JS::Value> chunk(aCx, aChunk);
ArrayBufferViewOrArrayBufferOrBlobOrUSVStringOrWriteParamsArgument holder(
aOutput);
bool done = false, failed = false, tryNext;
if (chunk.isObject()) {
done =
(failed =
!holder.TrySetToArrayBufferView(aCx, &chunk, tryNext, false)) ||
!aOutput.TrySetToArrayBufferView(aCx, &chunk, tryNext, false)) ||
!tryNext ||
(failed = !holder.TrySetToArrayBuffer(aCx, &chunk, tryNext, false)) ||
(failed = !aOutput.TrySetToArrayBuffer(aCx, &chunk, tryNext, false)) ||
!tryNext ||
(failed = !holder.TrySetToBlob(aCx, &chunk, tryNext, false)) ||
(failed = !aOutput.TrySetToBlob(aCx, &chunk, tryNext, false)) ||
!tryNext;
}
if (!done) {
done =
(failed = !holder.TrySetToWriteParams(aCx, &chunk, tryNext, false)) ||
(failed = !aOutput.TrySetToWriteParams(aCx, &chunk, tryNext, false)) ||
!tryNext;
}
if (!done) {
do {
done = (failed = !holder.TrySetToUSVString(aCx, &chunk, tryNext)) ||
done = (failed = !aOutput.TrySetToUSVString(aCx, &chunk, tryNext)) ||
!tryNext;
break;
} while (false);

View file

@ -27,7 +27,6 @@
#include "mozilla/dom/SerializedStackHolder.h"
#include "mozilla/dom/StreamBlobImpl.h"
#include "mozilla/dom/StructuredCloneHolder.h"
#include "mozilla/dom/UnionConversions.h"
#include "mozilla/dom/URLSearchParams.h"
#include "mozilla/dom/WorkerScope.h"
#include "mozilla/dom/WorkerRef.h"

View file

@ -80,7 +80,6 @@
#include "mozilla/dom/StorageManager.h"
#include "mozilla/dom/TextDecoderBinding.h"
#include "mozilla/dom/TextEncoderBinding.h"
#include "mozilla/dom/UnionConversions.h"
#include "mozilla/dom/URLBinding.h"
#include "mozilla/dom/URLSearchParamsBinding.h"
#include "mozilla/dom/XMLHttpRequest.h"
@ -297,13 +296,12 @@ static bool SandboxCreateRTCIdentityProvider(JSContext* cx,
static bool SetFetchRequestFromValue(JSContext* cx, RequestOrUSVString& request,
const MutableHandleValue& requestOrUrl) {
RequestOrUSVStringArgument requestHolder(request);
bool noMatch = true;
if (requestOrUrl.isObject() &&
!requestHolder.TrySetToRequest(cx, requestOrUrl, noMatch, false)) {
!request.TrySetToRequest(cx, requestOrUrl, noMatch, false)) {
return false;
}
if (noMatch && !requestHolder.TrySetToUSVString(cx, requestOrUrl, noMatch)) {
if (noMatch && !request.TrySetToUSVString(cx, requestOrUrl, noMatch)) {
return false;
}
if (noMatch) {