Rename the MozMap C++ type to "record" and give it a template parameter for the key type

This commit is contained in:
JustOff 2019-03-13 20:04:13 +02:00 • committed by Roy Tam
commit 6196fdda47
7 changed files with 145 additions and 126 deletions

View file

@ -996,6 +996,8 @@ class CGElseChain(CGThing):
class CGTemplatedType(CGWrapper):
def __init__(self, templateName, child, isConst=False, isReference=False):
if isinstance(child, list):
child = CGList(child, ", ")
const = "const " if isConst else ""
pre = "%s%s<" % (const, templateName)
ref = "&" if isReference else ""
@ -1173,10 +1175,10 @@ class CGHeaders(CGWrapper):
bindingHeaders.add("mozilla/dom/PrimitiveConversions.h")
elif unrolled.isRecord():
if dictionary or jsImplementedDescriptors:
declareIncludes.add("mozilla/dom/MozMap.h")
declareIncludes.add("mozilla/dom/Record.h")
else:
bindingHeaders.add("mozilla/dom/MozMap.h")
# Also add headers for the type the MozMap is
bindingHeaders.add("mozilla/dom/Record.h")
# Also add headers for the type the record is
# parametrized over, if needed.
addHeadersForType((t.inner, dictionary))
@ -1389,7 +1391,7 @@ def UnionTypes(unionTypes, config):
# code.
headers.add(CGHeaders.getDeclarationFilename(f.callback))
elif f.isRecord():
headers.add("mozilla/dom/MozMap.h")
headers.add("mozilla/dom/Record.h")
# And add headers for the type we're parametrized over
addHeadersForType(f.inner)
@ -1449,8 +1451,8 @@ def UnionConversions(unionTypes, config):
elif f.isPrimitive():
headers.add("mozilla/dom/PrimitiveConversions.h")
elif f.isRecord():
headers.add("mozilla/dom/MozMap.h")
# And the internal type of the MozMap
headers.add("mozilla/dom/Record.h")
# And the internal type of the record
addHeadersForType(f.inner)
# We plan to include UnionTypes.h no matter what, so it's
@ -4370,6 +4372,13 @@ def handleDefaultStringValue(defaultValue, method):
}
def recordKeyDeclType(recordType):
assert recordType.keyType.isString()
if recordType.keyType.isByteString():
return CGGeneric("nsCString")
return CGGeneric("nsString")
# If this function is modified, modify CGNativeMember.getArg and
# CGNativeMember.getRetvalInfo accordingly. The latter cares about the decltype
# and holdertype we end up using, because it needs to be able to return the code
@ -4564,7 +4573,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
declArgs = "cx"
else:
assert (isMember in
("Sequence", "Variadic", "Dictionary", "OwningUnion", "MozMap"))
("Sequence", "Variadic", "Dictionary", "OwningUnion", "Record"))
# We'll get traced by the sequence or dictionary or union tracer
declType = CGGeneric("JSObject*")
declArgs = None
@ -4733,36 +4742,38 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if type.isRecord():
assert not isEnforceRange and not isClamp
if failureCode is None:
notMozMap = ('ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s");\n'
notRecord = ('ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s");\n'
"%s" % (firstCap(sourceDescription), exceptionCode))
else:
notMozMap = failureCode
notRecord = failureCode
nullable = type.nullable()
# Be very careful not to change "type": we need it later
if nullable:
valueType = type.inner.inner
recordType = type.inner
else:
valueType = type.inner
recordType = type
valueType = recordType.inner
valueInfo = getJSToNativeConversionInfo(
valueType, descriptorProvider, isMember="MozMap",
valueType, descriptorProvider, isMember="Record",
exceptionCode=exceptionCode, lenientFloatCode=lenientFloatCode,
isCallbackReturnValue=isCallbackReturnValue,
sourceDescription="value in %s" % sourceDescription,
nestingLevel=incrementNestingLevel())
if valueInfo.dealWithOptional:
raise TypeError("Shouldn't have optional things in MozMap")
raise TypeError("Shouldn't have optional things in record")
if valueInfo.holderType is not None:
raise TypeError("Shouldn't need holders for MozMap")
raise TypeError("Shouldn't need holders for record")
typeName = CGTemplatedType("MozMap", valueInfo.declType)
mozMapType = typeName.define()
declType = CGTemplatedType("Record", [recordKeyDeclType(recordType),
valueInfo.declType])
typeName = declType.define()
if nullable:
typeName = CGTemplatedType("Nullable", typeName)
mozMapRef = "${declName}.SetValue()"
declType = CGTemplatedType("Nullable", declType)
recordRef = "${declName}.SetValue()"
else:
mozMapRef = "${declName}"
recordRef = "${declName}"
valueConversion = string.Template(valueInfo.template).substitute({
"val": "temp",
@ -4777,17 +4788,17 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
templateBody = fill(
"""
auto& mozMapEntries = ${mozMapRef}.Entries();
auto& recordEntries = ${recordRef}.Entries();
JS::Rooted<JSObject*> mozMapObj(cx, &$${val}.toObject());
JS::Rooted<JSObject*> recordObj(cx, &$${val}.toObject());
JS::AutoIdVector ids(cx);
// Keep skipping symbols until
// https://github.com/heycam/webidl/issues/294 is sorted out.
if (!js::GetPropertyKeys(cx, mozMapObj,
if (!js::GetPropertyKeys(cx, recordObj,
JSITER_OWNONLY | JSITER_HIDDEN, &ids)) {
$*{exceptionCode}
}
if (!mozMapEntries.SetCapacity(ids.length(), mozilla::fallible)) {
if (!recordEntries.SetCapacity(ids.length(), mozilla::fallible)) {
JS_ReportOutOfMemory(cx);
$*{exceptionCode}
}
@ -4800,7 +4811,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
MOZ_ASSERT(!JSID_IS_SYMBOL(curId), "No symbols, we said!");
JS::Rooted<JS::PropertyDescriptor> desc(cx);
if (!JS_GetOwnPropertyDescriptorById(cx, mozMapObj, curId,
if (!JS_GetOwnPropertyDescriptorById(cx, recordObj, curId,
&desc)) {
$*{exceptionCode}
}
@ -4817,44 +4828,45 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
}
MOZ_ASSERT(!isSymbol, "We said, no symbols!");
if (!JS_GetPropertyById(cx, mozMapObj, curId, &temp)) {
if (!JS_GetPropertyById(cx, recordObj, curId, &temp)) {
$*{exceptionCode}
}
// Safe to do an infallible append here, because we did a
// SetCapacity above to the right capacity.
${mozMapType}::EntryType* entry = mozMapEntries.AppendElement();
${typeName}::EntryType* entry = recordEntries.AppendElement();
entry->mKey = propName;
${valueType}& slot = entry->mValue;
$*{valueConversion}
}
""",
exceptionCode=exceptionCode,
mozMapRef=mozMapRef,
mozMapType=mozMapType,
recordRef=recordRef,
typeName=typeName,
valueType=valueInfo.declType.define(),
valueConversion=valueConversion)
templateBody = wrapObjectTemplate(templateBody, type,
"${declName}.SetNull();\n",
notMozMap)
notRecord)
declType = typeName
declArgs = None
holderType = None
holderArgs = None
# MozMap arguments that might contain traceable things need
# record arguments that might contain traceable things need
# to get traced
if not isMember and isCallbackReturnValue:
# Go ahead and just convert directly into our actual return value
declType = CGWrapper(declType, post="&")
declArgs = "aRetVal"
elif not isMember and typeNeedsRooting(valueType):
holderType = CGTemplatedType("MozMapRooter", valueInfo.declType)
# If our MozMap is nullable, this will set the Nullable to be
holderType = CGTemplatedType("RecordRooter",
[recordKeyDeclType(recordType),
valueInfo.declType])
# If our record is nullable, this will set the Nullable to be
# not-null, but that's ok because we make an explicit SetNull() call
# on it as needed if our JS value is actually null.
holderArgs = "cx, &%s" % mozMapRef
holderArgs = "cx, &%s" % recordRef
return JSToNativeConversionInfo(templateBody, declType=declType,
declArgs=declArgs,
@ -4937,16 +4949,16 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
else:
setDictionary = None
mozMapMemberTypes = filter(lambda t: t.isRecord(), memberTypes)
if len(mozMapMemberTypes) > 0:
assert len(mozMapMemberTypes) == 1
name = getUnionMemberName(mozMapMemberTypes[0])
mozMapObject = CGGeneric(
recordMemberTypes = filter(lambda t: t.isRecord(), memberTypes)
if len(recordMemberTypes) > 0:
assert len(recordMemberTypes) == 1
name = getUnionMemberName(recordMemberTypes[0])
recordObject = CGGeneric(
"done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
(unionArgumentObj, name))
names.append(name)
else:
mozMapObject = None
recordObject = None
objectMemberTypes = filter(lambda t: t.isObject(), memberTypes)
if len(objectMemberTypes) > 0:
@ -4962,10 +4974,10 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
else:
object = None
hasObjectTypes = interfaceObject or sequenceObject or dateObject or callbackObject or object or mozMapObject
hasObjectTypes = interfaceObject or sequenceObject or dateObject or callbackObject or object or recordObject
if hasObjectTypes:
# "object" is not distinguishable from other types
assert not object or not (interfaceObject or sequenceObject or dateObject or callbackObject or mozMapObject)
assert not object or not (interfaceObject or sequenceObject or dateObject or callbackObject or recordObject)
if sequenceObject or dateObject or callbackObject:
# An object can be both an sequence object and a callback or
# dictionary, but we shouldn't have both in the union's members
@ -4985,9 +4997,9 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if dateObject:
templateBody.prepend(CGGeneric("JS::Rooted<JSObject*> argObj(cx, &${val}.toObject());\n"))
if mozMapObject:
if recordObject:
templateBody = CGList([templateBody,
CGIfWrapper(mozMapObject, "!done")])
CGIfWrapper(recordObject, "!done")])
templateBody = CGIfWrapper(templateBody, "${val}.isObject()")
else:
@ -5747,7 +5759,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
assert not isEnforceRange and not isClamp
declArgs = None
if isMember in ("Variadic", "Sequence", "Dictionary", "MozMap"):
if isMember in ("Variadic", "Sequence", "Dictionary", "Record"):
# Rooting is handled by the sequence and dictionary tracers.
declType = "JS::Value"
else:
@ -6280,7 +6292,7 @@ def getMaybeWrapValueFuncForType(type):
sequenceWrapLevel = 0
mozMapWrapLevel = 0
recordWrapLevel = 0
def getWrapTemplateForType(type, descriptorProvider, result, successCode,
@ -6459,13 +6471,13 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
return (code, False)
if type.isRecord():
# Now do non-nullable MozMap. Our success code is just to break to
# Now do non-nullable record. Our success code is just to break to
# where we define the property on the object. Note that we bump the
# mozMapWrapLevel around this call so that nested MozMap conversions
# recordWrapLevel around this call so that nested record conversions
# will use different temp value names.
global mozMapWrapLevel
valueName = "mozMapValue%d" % mozMapWrapLevel
mozMapWrapLevel += 1
global recordWrapLevel
valueName = "recordValue%d" % recordWrapLevel
recordWrapLevel += 1
innerTemplate = wrapForType(
type.inner, descriptorProvider,
{
@ -6478,7 +6490,7 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
'obj': "returnObj",
'typedArraysAreStructs': typedArraysAreStructs
})
mozMapWrapLevel -= 1
recordWrapLevel -= 1
code = fill(
"""
@ -6895,14 +6907,15 @@ def getRetvalDeclarationForType(returnType, descriptorProvider,
returnType = returnType.inner
result, _, _, _, _ = getRetvalDeclarationForType(returnType.inner,
descriptorProvider,
isMember="MozMap")
isMember="Record")
# While we have our inner type, set up our rooter, if needed
if not isMember and typeNeedsRooting(returnType):
rooter = CGGeneric("MozMapRooter<%s> resultRooter(cx, &result);\n" %
result.define())
rooter = CGGeneric("RecordRooter<%s> resultRooter(cx, &result);\n" %
("nsString, " + result.define()))
else:
rooter = None
result = CGTemplatedType("MozMap", result)
result = CGTemplatedType("Record", [recordKeyDeclType(returnType),
result])
if nullable:
result = CGTemplatedType("Nullable", result)
return result, "ref", rooter, None, None
@ -7161,7 +7174,7 @@ class MethodNotNewObjectError(Exception):
# nested sequences we don't use the same variable name to iterate over
# different sequences.
sequenceWrapLevel = 0
mapWrapLevel = 0
recordWrapLevel = 0
def wrapTypeIntoCurrentCompartment(type, value, isMember=True):
@ -7226,20 +7239,20 @@ def wrapTypeIntoCurrentCompartment(type, value, isMember=True):
origType = type
if type.nullable():
type = type.inner
mozMapRef = "%s.Value()" % value
recordRef = "%s.Value()" % value
else:
mozMapRef = value
global mapWrapLevel
entryRef = "mapEntry%d" % mapWrapLevel
mapWrapLevel += 1
recordRef = value
global recordWrapLevel
entryRef = "mapEntry%d" % recordWrapLevel
recordWrapLevel += 1
wrapElement = wrapTypeIntoCurrentCompartment(type.inner,
"%s.mValue" % entryRef)
mapWrapLevel -= 1
recordWrapLevel -= 1
if not wrapElement:
return None
wrapCode = CGWrapper(CGIndenter(wrapElement),
pre=("for (auto& %s : %s.Entries()) {\n" %
(entryRef, mozMapRef)),
(entryRef, recordRef)),
post="}\n")
if origType.nullable():
wrapCode = CGIfWrapper(wrapCode, "!%s.IsNull()" % value)
@ -8131,7 +8144,7 @@ class CGMethodCall(CGThing):
if distinguishingType(s).isSequence())
# Now append all the overloads that take a dictionary or callback
# interface or MozMap. There should be only one of these!
# interface or record. There should be only one of these!
genericObjectSigs = [
s for s in possibleSignatures
if (distinguishingType(s).isDictionary() or
@ -9694,13 +9707,18 @@ def getUnionAccessorSignatureType(type, descriptorProvider):
if type.isSequence():
wrapperType = "Sequence"
else:
wrapperType = "MozMap"
wrapperType = "Record"
# We don't use the returned template here, so it's OK to just pass no
# sourceDescription.
elementInfo = getJSToNativeConversionInfo(type.inner,
descriptorProvider,
isMember=wrapperType)
return CGTemplatedType(wrapperType, elementInfo.declType,
if wrapperType == "Sequence":
innerType = elementInfo.declType
else:
innerType = [recordKeyDeclType(type), elementInfo.declType]
return CGTemplatedType(wrapperType, innerType,
isConst=True, isReference=True)
# Nested unions are unwrapped automatically into our flatMemberTypes.
@ -10064,7 +10082,7 @@ class CGUnionStruct(CGThing):
elif t.isRecord():
traceCases.append(
CGCase("e" + vars["name"],
CGGeneric("TraceMozMap(trc, mValue.m%s.Value());\n" %
CGGeneric("TraceRecord(trc, mValue.m%s.Value());\n" %
vars["name"])))
else:
assert t.isSpiderMonkeyInterface()
@ -13194,7 +13212,7 @@ class CGDictionary(CGThing):
if type.nullable():
trace = CGIfWrapper(trace, "!%s.IsNull()" % memberNullable)
elif type.isRecord():
# If you implement this, add a MozMap<object> to
# If you implement this, add a record<DOMString, object> to
# TestInterfaceJSDictionary and test it in test_bug1036214.html
# to make sure we end up with the correct security properties.
assert False
@ -14111,8 +14129,8 @@ class CGNativeMember(ClassMethod):
returnCode = "aRetVal.SwapElements(${declName});\n"
return "void", "", returnCode
if type.isRecord():
# If we want to handle MozMap-of-MozMap return values, we're
# going to need to fix example codegen to not produce MozMap<void>
# If we want to handle record-of-record return values, we're
# going to need to fix example codegen to not produce record<void>
# for the relevant argument...
assert not isMember
# In this case we convert directly into our outparam to start with
@ -14166,7 +14184,8 @@ class CGNativeMember(ClassMethod):
returnType = returnType.inner
# And now the actual underlying type
elementDecl = self.getReturnType(returnType.inner, True)
type = CGTemplatedType("MozMap", CGGeneric(elementDecl))
type = CGTemplatedType("Record", [recordKeyDeclType(returnType),
CGGeneric(elementDecl)])
if nullable:
type = CGTemplatedType("Nullable", type)
args.append(Argument("%s&" % type.define(), "aRetVal"))
@ -14227,7 +14246,7 @@ class CGNativeMember(ClassMethod):
Nullable as needed.
isMember can be false or one of the strings "Sequence", "Variadic",
"MozMap"
"Record"
"""
if type.isSequence():
nullable = type.nullable()
@ -14243,8 +14262,8 @@ class CGNativeMember(ClassMethod):
if nullable:
type = type.inner
elementType = type.inner
argType = self.getArgType(elementType, False, "MozMap")[0]
decl = CGTemplatedType("MozMap", argType)
argType = self.getArgType(elementType, False, "Record")[0]
decl = CGTemplatedType("Record", [recordKeyDeclType(type), argType])
return decl.define(), True, True
if type.isUnion():