aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/bindings/codegen/CodegenRust.py
diff options
context:
space:
mode:
authoryvt <i@yvt.jp>2021-07-10 17:24:27 +0900
committeryvt <i@yvt.jp>2021-07-10 17:55:42 +0900
commit01a7de50ab1843d85295f9dccad7f4c099e7208c (patch)
treeee53fb6e8889deb7b880ee969e6c662e6128d210 /components/script/dom/bindings/codegen/CodegenRust.py
parentff8d2cdbbfc7a9dc7f38b7dd47cb350fde39388f (diff)
parent94b613fbdaa2b98f2179fc0bbda13c64e6fa0d38 (diff)
downloadservo-01a7de50ab1843d85295f9dccad7f4c099e7208c.tar.gz
servo-01a7de50ab1843d85295f9dccad7f4c099e7208c.zip
Merge remote-tracking branch 'upstream/master' into feat-cow-infra
`tests/wpt/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects.html` was reverted to the upstream version.
Diffstat (limited to 'components/script/dom/bindings/codegen/CodegenRust.py')
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py2948
1 files changed, 1857 insertions, 1091 deletions
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py
index 09dc19ce411..4a102aacb45 100644
--- a/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/components/script/dom/bindings/codegen/CodegenRust.py
@@ -1,6 +1,6 @@
# 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/.
+# file, You can obtain one at https://mozilla.org/MPL/2.0/.
# Common codegen classes.
@@ -17,11 +17,14 @@ import functools
from WebIDL import (
BuiltinTypes,
IDLBuiltinType,
- IDLNullValue,
+ IDLDefaultDictionaryValue,
+ IDLEmptySequenceValue,
+ IDLInterfaceMember,
IDLNullableType,
+ IDLNullValue,
IDLObject,
+ IDLPromiseType,
IDLType,
- IDLInterfaceMember,
IDLUndefinedValue,
IDLWrapperType,
)
@@ -51,32 +54,6 @@ RUST_KEYWORDS = {"abstract", "alignof", "as", "become", "box", "break", "const",
"use", "virtual", "where", "while", "yield"}
-def replaceFileIfChanged(filename, newContents):
- """
- Read a copy of the old file, so that we don't touch it if it hasn't changed.
- Returns True if the file was updated, false otherwise.
- """
- # XXXjdm This doesn't play well with make right now.
- # Force the file to always be updated, or else changing CodegenRust.py
- # will cause many autogenerated bindings to be regenerated perpetually
- # until the result is actually different.
-
- # oldFileContents = ""
- # try:
- # with open(filename, 'rb') as oldFile:
- # oldFileContents = ''.join(oldFile.readlines())
- # except:
- # pass
-
- # if newContents == oldFileContents:
- # return False
-
- with open(filename, 'wb') as f:
- f.write(newContents)
-
- return True
-
-
def toStringBool(arg):
return str(not not arg).lower()
@@ -94,20 +71,19 @@ def stripTrailingWhitespace(text):
def innerContainerType(type):
- assert type.isSequence() or type.isMozMap()
+ assert type.isSequence() or type.isRecord()
return type.inner.inner if type.nullable() else type.inner
def wrapInNativeContainerType(type, inner):
if type.isSequence():
- containerType = "Vec"
- elif type.isMozMap():
- containerType = "MozMap"
+ return CGWrapper(inner, pre="Vec<", post=">")
+ elif type.isRecord():
+ key = type.inner.keyType if type.nullable() else type.keyType
+ return CGRecord(key, inner)
else:
raise TypeError("Unexpected container type %s", type)
- return CGWrapper(inner, pre=containerType + "<", post=">")
-
builtinNames = {
IDLType.Tags.bool: 'bool',
@@ -320,7 +296,7 @@ class CGMethodCall(CGThing):
if requiredArgs > 0:
code = (
"if argc < %d {\n"
- " throw_type_error(cx, \"Not enough arguments to %s.\");\n"
+ " throw_type_error(*cx, \"Not enough arguments to %s.\");\n"
" return false;\n"
"}" % (requiredArgs, methodName))
self.cgRoot.prepend(
@@ -343,12 +319,17 @@ class CGMethodCall(CGThing):
distinguishingIndex = method.distinguishingIndexForArgCount(argCount)
- # We can't handle unions at the distinguishing index.
+ # We can't handle unions of non-object values at the distinguishing index.
for (returnType, args) in possibleSignatures:
- if args[distinguishingIndex].type.isUnion():
- raise TypeError("No support for unions as distinguishing "
- "arguments yet: %s",
- args[distinguishingIndex].location)
+ type = args[distinguishingIndex].type
+ if type.isUnion():
+ if type.nullable():
+ type = type.inner
+ for type in type.flatMemberTypes:
+ if not (type.isObject() or type.isNonCallbackInterface()):
+ raise TypeError("No support for unions with non-object variants "
+ "as distinguishing arguments yet: %s",
+ args[distinguishingIndex].location)
# Convert all our arguments up to the distinguishing index.
# Doesn't matter which of the possible signatures we use, since
@@ -360,10 +341,10 @@ class CGMethodCall(CGThing):
for i in range(0, distinguishingIndex)]
# Select the right overload from our set.
- distinguishingArg = "args.get(%d)" % distinguishingIndex
+ distinguishingArg = "HandleValue::from_raw(args.get(%d))" % distinguishingIndex
def pickFirstSignature(condition, filterLambda):
- sigs = filter(filterLambda, possibleSignatures)
+ sigs = list(filter(filterLambda, possibleSignatures))
assert len(sigs) < 2
if len(sigs) > 0:
call = getPerSignatureCall(sigs[0], distinguishingIndex)
@@ -378,16 +359,17 @@ class CGMethodCall(CGThing):
# First check for null or undefined
pickFirstSignature("%s.get().is_null_or_undefined()" % distinguishingArg,
- lambda s: (s[1][distinguishingIndex].type.nullable() or
- s[1][distinguishingIndex].type.isDictionary()))
+ lambda s: (s[1][distinguishingIndex].type.nullable()
+ or s[1][distinguishingIndex].type.isDictionary()))
# Now check for distinguishingArg being an object that implements a
# non-callback interface. That includes typed arrays and
# arraybuffers.
interfacesSigs = [
s for s in possibleSignatures
- if (s[1][distinguishingIndex].type.isObject() or
- s[1][distinguishingIndex].type.isNonCallbackInterface())]
+ if (s[1][distinguishingIndex].type.isObject()
+ or s[1][distinguishingIndex].type.isUnion()
+ or s[1][distinguishingIndex].type.isNonCallbackInterface())]
# There might be more than one of these; we need to check
# which ones we unwrap to.
@@ -421,7 +403,8 @@ class CGMethodCall(CGThing):
template,
{"val": distinguishingArg},
declType,
- "arg%d" % distinguishingIndex)
+ "arg%d" % distinguishingIndex,
+ needsAutoRoot=type_needs_auto_root(type))
# Indent by 4, since we need to indent further than our "do" statement
caseBody.append(CGIndenter(testCode, 4))
@@ -438,38 +421,27 @@ class CGMethodCall(CGThing):
# XXXbz Now we're supposed to check for distinguishingArg being
# an array or a platform object that supports indexed
# properties... skip that last for now. It's a bit of a pain.
- pickFirstSignature("%s.get().is_object() && is_array_like(cx, %s)" %
+ pickFirstSignature("%s.get().is_object() && is_array_like(*cx, %s)" %
(distinguishingArg, distinguishingArg),
lambda s:
- (s[1][distinguishingIndex].type.isSequence() or
- s[1][distinguishingIndex].type.isObject()))
-
- # Check for Date objects
- # XXXbz Do we need to worry about security wrappers around the Date?
- pickFirstSignature("%s.get().is_object() && "
- "{ rooted!(in(cx) let obj = %s.get().to_object()); "
- "let mut is_date = false; "
- "assert!(JS_ObjectIsDate(cx, obj.handle(), &mut is_date)); "
- "is_date }" %
- (distinguishingArg, distinguishingArg),
- lambda s: (s[1][distinguishingIndex].type.isDate() or
- s[1][distinguishingIndex].type.isObject()))
+ (s[1][distinguishingIndex].type.isSequence()
+ or s[1][distinguishingIndex].type.isObject()))
# Check for vanilla JS objects
# XXXbz Do we need to worry about security wrappers?
- pickFirstSignature("%s.get().is_object() && !is_platform_object(%s.get().to_object())" %
- (distinguishingArg, distinguishingArg),
- lambda s: (s[1][distinguishingIndex].type.isCallback() or
- s[1][distinguishingIndex].type.isCallbackInterface() or
- s[1][distinguishingIndex].type.isDictionary() or
- s[1][distinguishingIndex].type.isObject()))
+ pickFirstSignature("%s.get().is_object()" %
+ distinguishingArg,
+ lambda s: (s[1][distinguishingIndex].type.isCallback()
+ or s[1][distinguishingIndex].type.isCallbackInterface()
+ or s[1][distinguishingIndex].type.isDictionary()
+ or s[1][distinguishingIndex].type.isObject()))
# The remaining cases are mutually exclusive. The
# pickFirstSignature calls are what change caseBody
# Check for strings or enums
if pickFirstSignature(None,
- lambda s: (s[1][distinguishingIndex].type.isString() or
- s[1][distinguishingIndex].type.isEnum())):
+ lambda s: (s[1][distinguishingIndex].type.isString()
+ or s[1][distinguishingIndex].type.isEnum())):
pass
# Check for primitives
elif pickFirstSignature(None,
@@ -482,7 +454,8 @@ class CGMethodCall(CGThing):
else:
# Just throw; we have no idea what we're supposed to
# do with this.
- caseBody.append(CGGeneric("return Throw(cx, NS_ERROR_XPC_BAD_CONVERT_JS);"))
+ caseBody.append(CGGeneric("throw_type_error(*cx, \"Could not convert JavaScript argument\");\n"
+ "return false;"))
argCountCases.append(CGCase(str(argCount),
CGList(caseBody, "\n")))
@@ -494,7 +467,7 @@ class CGMethodCall(CGThing):
overloadCGThings.append(
CGSwitch("argcount",
argCountCases,
- CGGeneric("throw_type_error(cx, \"Not enough arguments to %s.\");\n"
+ CGGeneric("throw_type_error(*cx, \"Not enough arguments to %s.\");\n"
"return false;" % methodName)))
# XXXjdm Avoid unreachable statement warnings
# overloadCGThings.append(
@@ -509,9 +482,9 @@ class CGMethodCall(CGThing):
def dictionaryHasSequenceMember(dictionary):
return (any(typeIsSequenceOrHasSequenceMember(m.type) for m in
- dictionary.members) or
- (dictionary.parent and
- dictionaryHasSequenceMember(dictionary.parent)))
+ dictionary.members)
+ or (dictionary.parent
+ and dictionaryHasSequenceMember(dictionary.parent)))
def typeIsSequenceOrHasSequenceMember(type):
@@ -560,11 +533,9 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
isDefinitelyObject=False,
isMember=False,
isArgument=False,
+ isAutoRooted=False,
invalidEnumValueFatal=True,
defaultValue=None,
- treatNullAs="Default",
- isEnforceRange=False,
- isClamp=False,
exceptionCode=None,
allowTreatNonObjectAsNull=False,
isCallbackReturnValue=False,
@@ -592,12 +563,6 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
If defaultValue is not None, it's the IDL default value for this conversion
- If isEnforceRange is true, we're converting an integer and throwing if the
- value is out of range.
-
- If isClamp is true, we're converting an integer and clamping if the
- value is out of range.
-
If allowTreatNonObjectAsNull is true, then [TreatNonObjectAsNull]
extended attributes on nullable callback functions will be honored.
@@ -620,6 +585,13 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
# We should not have a defaultValue if we know we're an object
assert not isDefinitelyObject or defaultValue is None
+ isEnforceRange = type.hasEnforceRange()
+ isClamp = type.hasClamp()
+ if type.treatNullAsEmpty:
+ treatNullAs = "EmptyString"
+ else:
+ treatNullAs = "Default"
+
# If exceptionCode is not set, we'll just rethrow the exception we got.
# Note that we can't just set failureCode to exceptionCode, because setting
# failureCode will prevent pending exceptions from being set in cases when
@@ -628,7 +600,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
exceptionCode = "return false;\n"
if failureCode is None:
- failOrPropagate = "throw_type_error(cx, &error);\n%s" % exceptionCode
+ failOrPropagate = "throw_type_error(*cx, &error);\n%s" % exceptionCode
else:
failOrPropagate = failureCode
@@ -646,34 +618,39 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
def onFailureNotAnObject(failureCode):
return CGWrapper(
CGGeneric(
- failureCode or
- ('throw_type_error(cx, "%s is not an object.");\n'
- '%s' % (firstCap(sourceDescription), exceptionCode))),
+ failureCode
+ or ('throw_type_error(*cx, "%s is not an object.");\n'
+ '%s' % (firstCap(sourceDescription), exceptionCode))),
post="\n")
def onFailureInvalidEnumValue(failureCode, passedVarName):
return CGGeneric(
- failureCode or
- ('throw_type_error(cx, &format!("\'{}\' is not a valid enum value for enumeration \'%s\'.", %s)); %s'
- % (type.name, passedVarName, exceptionCode)))
+ failureCode
+ or ('throw_type_error(*cx, &format!("\'{}\' is not a valid enum value for enumeration \'%s\'.", %s)); %s'
+ % (type.name, passedVarName, exceptionCode)))
def onFailureNotCallable(failureCode):
return CGGeneric(
- failureCode or
- ('throw_type_error(cx, \"%s is not callable.\");\n'
- '%s' % (firstCap(sourceDescription), exceptionCode)))
+ failureCode
+ or ('throw_type_error(*cx, \"%s is not callable.\");\n'
+ '%s' % (firstCap(sourceDescription), exceptionCode)))
- # A helper function for handling null default values. Checks that the
- # default value, if it exists, is null.
- def handleDefaultNull(nullValue):
+ # A helper function for handling default values.
+ def handleDefault(nullValue):
if defaultValue is None:
return None
- if not isinstance(defaultValue, IDLNullValue):
- raise TypeError("Can't handle non-null default value here")
+ if isinstance(defaultValue, IDLNullValue):
+ assert type.nullable()
+ return nullValue
+ elif isinstance(defaultValue, IDLDefaultDictionaryValue):
+ assert type.isDictionary()
+ return nullValue
+ elif isinstance(defaultValue, IDLEmptySequenceValue):
+ assert type.isSequence()
+ return "Vec::new()"
- assert type.nullable() or type.isDictionary()
- return nullValue
+ raise TypeError("Can't handle non-null, non-empty sequence or non-empty dictionary default value here")
# A helper function for wrapping up the template body for
# possibly-nullable objecty stuff
@@ -683,31 +660,32 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
# Handle the non-object cases by wrapping up the whole
# thing in an if cascade.
templateBody = (
- "if ${val}.get().is_object() {\n" +
- CGIndenter(CGGeneric(templateBody)).define() + "\n")
+ "if ${val}.get().is_object() {\n"
+ + CGIndenter(CGGeneric(templateBody)).define() + "\n")
if type.nullable():
templateBody += (
"} else if ${val}.get().is_null_or_undefined() {\n"
" %s\n") % nullValue
templateBody += (
- "} else {\n" +
- CGIndenter(onFailureNotAnObject(failureCode)).define() +
- "}")
+ "} else {\n"
+ + CGIndenter(onFailureNotAnObject(failureCode)).define()
+ + "}")
return templateBody
assert not (isEnforceRange and isClamp) # These are mutually exclusive
- if type.isSequence() or type.isMozMap():
+ if type.isSequence() or type.isRecord():
innerInfo = getJSToNativeConversionInfo(innerContainerType(type),
descriptorProvider,
- isMember=isMember)
+ isMember="Sequence",
+ isAutoRooted=isAutoRooted)
declType = wrapInNativeContainerType(type, innerInfo.declType)
config = getConversionConfigForType(type, isEnforceRange, isClamp, treatNullAs)
if type.nullable():
declType = CGWrapper(declType, pre="Option<", post=" >")
- templateBody = ("match FromJSValConvertible::from_jsval(cx, ${val}, %s) {\n"
+ templateBody = ("match FromJSValConvertible::from_jsval(*cx, ${val}, %s) {\n"
" Ok(ConversionResult::Success(value)) => value,\n"
" Ok(ConversionResult::Failure(error)) => {\n"
"%s\n"
@@ -715,17 +693,14 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
" _ => { %s },\n"
"}" % (config, indent(failOrPropagate, 8), exceptionCode))
- return handleOptional(templateBody, declType, handleDefaultNull("None"))
+ return handleOptional(templateBody, declType, handleDefault("None"))
if type.isUnion():
declType = CGGeneric(union_native_type(type))
if type.nullable():
declType = CGWrapper(declType, pre="Option<", post=" >")
- if isMember != "Dictionary" and type_needs_tracing(type):
- declType = CGTemplatedType("RootedTraceableBox", declType)
-
- templateBody = ("match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n"
+ templateBody = ("match FromJSValConvertible::from_jsval(*cx, ${val}, ()) {\n"
" Ok(ConversionResult::Success(value)) => value,\n"
" Ok(ConversionResult::Failure(error)) => {\n"
"%s\n"
@@ -738,11 +713,32 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
for memberType in type.unroll().flatMemberTypes
if memberType.isDictionary()
]
- if dictionaries:
+ if (defaultValue
+ and not isinstance(defaultValue, IDLNullValue)
+ and not isinstance(defaultValue, IDLDefaultDictionaryValue)):
+ tag = defaultValue.type.tag()
+ if tag is IDLType.Tags.bool:
+ default = "%s::Boolean(%s)" % (
+ union_native_type(type),
+ "true" if defaultValue.value else "false")
+ elif tag is IDLType.Tags.usvstring:
+ default = '%s::USVString(USVString("%s".to_owned()))' % (
+ union_native_type(type),
+ defaultValue.value)
+ elif defaultValue.type.isEnum():
+ enum = defaultValue.type.inner.identifier.name
+ default = "%s::%s(%s::%s)" % (
+ union_native_type(type),
+ enum,
+ enum,
+ getEnumValueName(defaultValue.value))
+ else:
+ raise("We don't currently support default values that aren't null, boolean or default dictionary")
+ elif dictionaries:
if defaultValue:
- assert isinstance(defaultValue, IDLNullValue)
+ assert isinstance(defaultValue, IDLDefaultDictionaryValue)
dictionary, = dictionaries
- default = "%s::%s(%s::%s::empty(cx))" % (
+ default = "%s::%s(%s::%s::empty())" % (
union_native_type(type),
dictionary.name,
CGDictionary.makeModuleName(dictionary.inner),
@@ -750,10 +746,60 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
else:
default = None
else:
- default = handleDefaultNull("None")
+ default = handleDefault("None")
return handleOptional(templateBody, declType, default)
+ if type.isPromise():
+ assert not type.nullable()
+ # Per spec, what we're supposed to do is take the original
+ # Promise.resolve and call it with the original Promise as this
+ # value to make a Promise out of whatever value we actually have
+ # here. The question is which global we should use. There are
+ # a couple cases to consider:
+ #
+ # 1) Normal call to API with a Promise argument. This is a case the
+ # spec covers, and we should be using the current Realm's
+ # Promise. That means the current realm.
+ # 2) Promise return value from a callback or callback interface.
+ # This is in theory a case the spec covers but in practice it
+ # really doesn't define behavior here because it doesn't define
+ # what Realm we're in after the callback returns, which is when
+ # the argument conversion happens. We will use the current
+ # realm, which is the realm of the callable (which
+ # may itself be a cross-realm wrapper itself), which makes
+ # as much sense as anything else. In practice, such an API would
+ # once again be providing a Promise to signal completion of an
+ # operation, which would then not be exposed to anyone other than
+ # our own implementation code.
+ templateBody = fill(
+ """
+ { // Scope for our JSAutoRealm.
+
+ rooted!(in(*cx) let globalObj = CurrentGlobalOrNull(*cx));
+ let promiseGlobal = GlobalScope::from_object_maybe_wrapped(globalObj.handle().get(), *cx);
+
+ rooted!(in(*cx) let mut valueToResolve = $${val}.get());
+ if !JS_WrapValue(*cx, valueToResolve.handle_mut()) {
+ $*{exceptionCode}
+ }
+ match Promise::new_resolved(&promiseGlobal, cx, valueToResolve.handle()) {
+ Ok(value) => value,
+ Err(error) => {
+ throw_dom_exception(cx, &promiseGlobal, error);
+ $*{exceptionCode}
+ }
+ }
+ }
+ """,
+ exceptionCode=exceptionCode)
+
+ if isArgument:
+ declType = CGGeneric("&Promise")
+ else:
+ declType = CGGeneric("Rc<Promise>")
+ return handleOptional(templateBody, declType, handleDefault("None"))
+
if type.isGeckoInterface():
assert not isEnforceRange and not isClamp
@@ -770,7 +816,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
isDefinitelyObject, type,
failureCode)
- return handleOptional(template, declType, handleDefaultNull("None"))
+ return handleOptional(template, declType, handleDefault("None"))
conversionFunction = "root_from_handlevalue"
descriptorType = descriptor.returnType
@@ -779,99 +825,129 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
descriptorType = descriptor.nativeType
elif isArgument:
descriptorType = descriptor.argumentType
+ elif descriptor.interface.identifier.name == "WindowProxy":
+ conversionFunction = "windowproxy_from_handlevalue"
+
+ if failureCode is None:
+ substitutions = {
+ "sourceDescription": sourceDescription,
+ "interface": descriptor.interface.identifier.name,
+ "exceptionCode": exceptionCode,
+ }
+ unwrapFailureCode = string.Template(
+ 'throw_type_error(*cx, "${sourceDescription} does not '
+ 'implement interface ${interface}.");\n'
+ '${exceptionCode}').substitute(substitutions)
+ else:
+ unwrapFailureCode = failureCode
- templateBody = ""
- isPromise = descriptor.interface.identifier.name == "Promise"
- if isPromise:
- # Per spec, what we're supposed to do is take the original
- # Promise.resolve and call it with the original Promise as this
- # value to make a Promise out of whatever value we actually have
- # here. The question is which global we should use. There are
- # a couple cases to consider:
- #
- # 1) Normal call to API with a Promise argument. This is a case the
- # spec covers, and we should be using the current Realm's
- # Promise. That means the current compartment.
- # 2) Promise return value from a callback or callback interface.
- # This is in theory a case the spec covers but in practice it
- # really doesn't define behavior here because it doesn't define
- # what Realm we're in after the callback returns, which is when
- # the argument conversion happens. We will use the current
- # compartment, which is the compartment of the callable (which
- # may itself be a cross-compartment wrapper itself), which makes
- # as much sense as anything else. In practice, such an API would
- # once again be providing a Promise to signal completion of an
- # operation, which would then not be exposed to anyone other than
- # our own implementation code.
- templateBody = fill(
- """
- { // Scope for our JSAutoCompartment.
+ templateBody = fill(
+ """
+ match ${function}($${val}, *cx) {
+ Ok(val) => val,
+ Err(()) => {
+ $*{failureCode}
+ }
+ }
+ """,
+ failureCode=unwrapFailureCode + "\n",
+ function=conversionFunction)
- rooted!(in(cx) let globalObj = CurrentGlobalOrNull(cx));
- let promiseGlobal = GlobalScope::from_object_maybe_wrapped(globalObj.handle().get());
+ declType = CGGeneric(descriptorType)
+ if type.nullable():
+ templateBody = "Some(%s)" % templateBody
+ declType = CGWrapper(declType, pre="Option<", post=">")
- rooted!(in(cx) let mut valueToResolve = $${val}.get());
- if !JS_WrapValue(cx, valueToResolve.handle_mut()) {
- $*{exceptionCode}
- }
- match Promise::Resolve(&promiseGlobal, cx, valueToResolve.handle()) {
- Ok(value) => value,
- Err(error) => {
- throw_dom_exception(cx, &promiseGlobal, error);
- $*{exceptionCode}
- }
- }
- }
- """,
- exceptionCode=exceptionCode)
+ templateBody = wrapObjectTemplate(templateBody, "None",
+ isDefinitelyObject, type, failureCode)
+
+ return handleOptional(templateBody, declType, handleDefault("None"))
+
+ if is_typed_array(type):
+ if failureCode is None:
+ substitutions = {
+ "sourceDescription": sourceDescription,
+ "exceptionCode": exceptionCode,
+ }
+ unwrapFailureCode = string.Template(
+ 'throw_type_error(*cx, "${sourceDescription} is not a typed array.");\n'
+ '${exceptionCode}').substitute(substitutions)
else:
- if descriptor.interface.isConsequential():
- raise TypeError("Consequential interface %s being used as an "
- "argument" % descriptor.interface.identifier.name)
-
- if failureCode is None:
- substitutions = {
- "sourceDescription": sourceDescription,
- "interface": descriptor.interface.identifier.name,
- "exceptionCode": exceptionCode,
+ unwrapFailureCode = failureCode
+
+ typeName = type.unroll().name # unroll because it may be nullable
+
+ if isMember == "Union":
+ typeName = "Heap" + typeName
+
+ templateBody = fill(
+ """
+ match typedarray::${ty}::from($${val}.get().to_object()) {
+ Ok(val) => val,
+ Err(()) => {
+ $*{failureCode}
}
- unwrapFailureCode = string.Template(
- 'throw_type_error(cx, "${sourceDescription} does not '
- 'implement interface ${interface}.");\n'
- '${exceptionCode}').substitute(substitutions)
- else:
- unwrapFailureCode = failureCode
+ }
+ """,
+ ty=typeName,
+ failureCode=unwrapFailureCode + "\n",
+ )
- templateBody = fill(
- """
- match ${function}($${val}) {
+ if isMember == "Union":
+ templateBody = "RootedTraceableBox::new(%s)" % templateBody
+
+ declType = CGGeneric("typedarray::%s" % typeName)
+ if type.nullable():
+ templateBody = "Some(%s)" % templateBody
+ declType = CGWrapper(declType, pre="Option<", post=">")
+
+ templateBody = wrapObjectTemplate(templateBody, "None",
+ isDefinitelyObject, type, failureCode)
+
+ return handleOptional(templateBody, declType, handleDefault("None"))
+
+ if type.isReadableStream():
+ assert not isEnforceRange and not isClamp
+
+ if failureCode is None:
+ unwrapFailureCode = '''throw_type_error(*cx, "This object is not \
+ an instance of ReadableStream.");\n'''
+ else:
+ unwrapFailureCode = failureCode
+
+ templateBody = fill(
+ """
+ {
+ use crate::realms::{AlreadyInRealm, InRealm};
+ let in_realm_proof = AlreadyInRealm::assert_for_cx(cx);
+ match ReadableStream::from_js(cx, $${val}.get().to_object(), InRealm::Already(&in_realm_proof)) {
Ok(val) => val,
Err(()) => {
- $*{failureCode}
+ $*{failureCode}
}
}
- """,
- failureCode=unwrapFailureCode + "\n",
- function=conversionFunction)
- declType = CGGeneric(descriptorType)
- if type.nullable():
- templateBody = "Some(%s)" % templateBody
- declType = CGWrapper(declType, pre="Option<", post=">")
+ }
+ """,
+ failureCode=unwrapFailureCode + "\n",
+ )
templateBody = wrapObjectTemplate(templateBody, "None",
isDefinitelyObject, type, failureCode)
- return handleOptional(templateBody, declType, handleDefaultNull("None"))
+ declType = CGGeneric("DomRoot<ReadableStream>")
+
+ return handleOptional(templateBody, declType,
+ handleDefault("None"))
- if type.isSpiderMonkeyInterface():
- raise TypeError("Can't handle SpiderMonkey interface arguments yet")
+ elif type.isSpiderMonkeyInterface():
+ raise TypeError("Can't handle SpiderMonkey interface arguments other than typed arrays yet")
if type.isDOMString():
nullBehavior = getConversionConfigForType(type, isEnforceRange, isClamp, treatNullAs)
conversionCode = (
- "match FromJSValConvertible::from_jsval(cx, ${val}, %s) {\n"
+ "match FromJSValConvertible::from_jsval(*cx, ${val}, %s) {\n"
" Ok(ConversionResult::Success(strval)) => strval,\n"
" Ok(ConversionResult::Failure(error)) => {\n"
"%s\n"
@@ -900,7 +976,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
assert not isEnforceRange and not isClamp
conversionCode = (
- "match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n"
+ "match FromJSValConvertible::from_jsval(*cx, ${val}, ()) {\n"
" Ok(ConversionResult::Success(strval)) => strval,\n"
" Ok(ConversionResult::Failure(error)) => {\n"
"%s\n"
@@ -929,7 +1005,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
assert not isEnforceRange and not isClamp
conversionCode = (
- "match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n"
+ "match FromJSValConvertible::from_jsval(*cx, ${val}, ()) {\n"
" Ok(ConversionResult::Success(strval)) => strval,\n"
" Ok(ConversionResult::Failure(error)) => {\n"
"%s\n"
@@ -962,17 +1038,16 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
"yet")
enum = type.inner.identifier.name
if invalidEnumValueFatal:
- handleInvalidEnumValueCode = onFailureInvalidEnumValue(failureCode, 'search').define()
+ handleInvalidEnumValueCode = failureCode or "throw_type_error(*cx, &error); %s" % exceptionCode
else:
handleInvalidEnumValueCode = "return true;"
template = (
- "match find_enum_value(cx, ${val}, %(pairs)s) {\n"
+ "match FromJSValConvertible::from_jsval(*cx, ${val}, ()) {"
" Err(_) => { %(exceptionCode)s },\n"
- " Ok((None, search)) => { %(handleInvalidEnumValueCode)s },\n"
- " Ok((Some(&value), _)) => value,\n"
- "}" % {"pairs": enum + "Values::pairs",
- "exceptionCode": exceptionCode,
+ " Ok(ConversionResult::Success(v)) => v,\n"
+ " Ok(ConversionResult::Failure(error)) => { %(handleInvalidEnumValueCode)s },\n"
+ "}" % {"exceptionCode": exceptionCode,
"handleInvalidEnumValueCode": handleInvalidEnumValueCode})
if defaultValue is not None:
@@ -1034,20 +1109,28 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
assert not isEnforceRange and not isClamp
assert isMember != "Union"
- if isMember == "Dictionary":
- # TODO: Need to properly root dictionaries
- # https://github.com/servo/servo/issues/6381
- declType = CGGeneric("Heap<JSVal>")
+ if isMember in ("Dictionary", "Sequence") or isAutoRooted:
+ templateBody = "${val}.get()"
if defaultValue is None:
default = None
elif isinstance(defaultValue, IDLNullValue):
- default = "Heap::new(NullValue())"
+ default = "NullValue()"
elif isinstance(defaultValue, IDLUndefinedValue):
- default = "Heap::new(UndefinedValue())"
+ default = "UndefinedValue()"
else:
raise TypeError("Can't handle non-null, non-undefined default value here")
- return handleOptional("Heap::new(${val}.get())", declType, default)
+
+ if not isAutoRooted:
+ templateBody = "RootedTraceableBox::from_box(Heap::boxed(%s))" % templateBody
+ if default is not None:
+ default = "RootedTraceableBox::from_box(Heap::boxed(%s))" % default
+ declType = CGGeneric("RootedTraceableBox<Heap<JSVal>>")
+ # AutoRooter can trace properly inner raw GC thing pointers
+ else:
+ declType = CGGeneric("JSVal")
+
+ return handleOptional(templateBody, declType, default)
declType = CGGeneric("HandleValue")
@@ -1065,39 +1148,37 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if type.isObject():
assert not isEnforceRange and not isClamp
- # TODO: Need to root somehow
- # https://github.com/servo/servo/issues/6382
+ templateBody = "${val}.get().to_object()"
default = "ptr::null_mut()"
- templateBody = wrapObjectTemplate("${val}.get().to_object()",
- default,
- isDefinitelyObject, type, failureCode)
- if isMember in ("Dictionary", "Union"):
- declType = CGGeneric("Heap<*mut JSObject>")
- templateBody = "Heap::new(%s)" % templateBody
- default = "Heap::new(%s)" % default
+ if isMember in ("Dictionary", "Union", "Sequence") and not isAutoRooted:
+ templateBody = "RootedTraceableBox::from_box(Heap::boxed(%s))" % templateBody
+ default = "RootedTraceableBox::new(Heap::default())"
+ declType = CGGeneric("RootedTraceableBox<Heap<*mut JSObject>>")
else:
# TODO: Need to root somehow
# https://github.com/servo/servo/issues/6382
declType = CGGeneric("*mut JSObject")
+ templateBody = wrapObjectTemplate(templateBody, default,
+ isDefinitelyObject, type, failureCode)
+
return handleOptional(templateBody, declType,
- handleDefaultNull(default))
+ handleDefault(default))
if type.isDictionary():
# There are no nullable dictionaries
- assert not type.nullable()
+ assert not type.nullable() or (isMember and isMember != "Dictionary")
typeName = "%s::%s" % (CGDictionary.makeModuleName(type.inner),
CGDictionary.makeDictionaryName(type.inner))
declType = CGGeneric(typeName)
- empty = "%s::empty(cx)" % typeName
+ empty = "%s::empty()" % typeName
- if isMember != "Dictionary" and type_needs_tracing(type):
+ if type_needs_tracing(type):
declType = CGTemplatedType("RootedTraceableBox", declType)
- empty = "RootedTraceableBox::new(%s)" % empty
- template = ("match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n"
+ template = ("match FromJSValConvertible::from_jsval(*cx, ${val}, ()) {\n"
" Ok(ConversionResult::Success(dictionary)) => dictionary,\n"
" Ok(ConversionResult::Failure(error)) => {\n"
"%s\n"
@@ -1105,7 +1186,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
" _ => { %s },\n"
"}" % (indent(failOrPropagate, 8), exceptionCode))
- return handleOptional(template, declType, handleDefaultNull(empty))
+ return handleOptional(template, declType, handleDefault(empty))
if type.isVoid():
# This one only happens for return values, and its easy: Just
@@ -1125,7 +1206,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
declType = CGWrapper(declType, pre="Option<", post=">")
template = (
- "match FromJSValConvertible::from_jsval(cx, ${val}, %s) {\n"
+ "match FromJSValConvertible::from_jsval(*cx, ${val}, %s) {\n"
" Ok(ConversionResult::Success(v)) => v,\n"
" Ok(ConversionResult::Failure(error)) => {\n"
"%s\n"
@@ -1156,7 +1237,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
def instantiateJSToNativeConversionTemplate(templateBody, replacements,
- declType, declName):
+ declType, declName,
+ needsAutoRoot=False):
"""
Take the templateBody and declType as returned by
getJSToNativeConversionInfo, a set of replacements as required by the
@@ -1181,6 +1263,8 @@ def instantiateJSToNativeConversionTemplate(templateBody, replacements,
else:
result.append(conversion)
+ if needsAutoRoot:
+ result.append(CGGeneric("auto_root!(in(*cx) let %s = %s);" % (declName, declName)))
# Add an empty CGGeneric to get an extra newline after the argument
# conversion.
result.append(CGGeneric(""))
@@ -1198,12 +1282,12 @@ def convertConstIDLValueToJSVal(value):
if tag == IDLType.Tags.uint32:
return "ConstantVal::UintVal(%s)" % (value.value)
if tag in [IDLType.Tags.int64, IDLType.Tags.uint64]:
- return "ConstantVal::DoubleVal(%s)" % (value.value)
+ return "ConstantVal::DoubleVal(%s as f64)" % (value.value)
if tag == IDLType.Tags.bool:
return "ConstantVal::BoolVal(true)" if value.value else "ConstantVal::BoolVal(false)"
if tag in [IDLType.Tags.unrestricted_float, IDLType.Tags.float,
IDLType.Tags.unrestricted_double, IDLType.Tags.double]:
- return "ConstantVal::DoubleVal(%s)" % (value.value)
+ return "ConstantVal::DoubleVal(%s as f64)" % (value.value)
raise TypeError("Const value of unhandled type: " + value.type)
@@ -1225,7 +1309,7 @@ class CGArgumentConverter(CGThing):
}
replacementVariables = {
- "val": string.Template("${args}.get(${index})").substitute(replacer),
+ "val": string.Template("HandleValue::from_raw(${args}.get(${index}))").substitute(replacer),
}
info = getJSToNativeConversionInfo(
@@ -1233,10 +1317,8 @@ class CGArgumentConverter(CGThing):
descriptorProvider,
invalidEnumValueFatal=invalidEnumValueFatal,
defaultValue=argument.defaultValue,
- treatNullAs=argument.treatNullAs,
- isEnforceRange=argument.enforceRange,
- isClamp=argument.clamp,
isMember="Variadic" if argument.variadic else False,
+ isAutoRooted=type_needs_auto_root(argument.type),
allowTreatNonObjectAsNull=argument.allowTreatNonCallableAsNull())
template = info.template
default = info.default
@@ -1259,12 +1341,16 @@ class CGArgumentConverter(CGThing):
else:
assert not default
+ arg = "arg%d" % index
+
self.converter = instantiateJSToNativeConversionTemplate(
- template, replacementVariables, declType, "arg%d" % index)
+ template, replacementVariables, declType, arg,
+ needsAutoRoot=type_needs_auto_root(argument.type))
+
else:
assert argument.optional
variadicConversion = {
- "val": string.Template("${args}.get(variadicArg)").substitute(replacer),
+ "val": string.Template("HandleValue::from_raw(${args}.get(variadicArg))").substitute(replacer),
}
innerConverter = [instantiateJSToNativeConversionTemplate(
template, variadicConversion, declType, "slot")]
@@ -1272,7 +1358,7 @@ class CGArgumentConverter(CGThing):
arg = "arg%d" % index
if argument.type.isGeckoInterface():
init = "rooted_vec!(let mut %s)" % arg
- innerConverter.append(CGGeneric("%s.push(JS::from_ref(&*slot));" % arg))
+ innerConverter.append(CGGeneric("%s.push(Dom::from_ref(&*slot));" % arg))
else:
init = "let mut %s = vec![]" % arg
innerConverter.append(CGGeneric("%s.push(slot);" % arg))
@@ -1301,7 +1387,7 @@ def wrapForType(jsvalRef, result='result', successCode='return true;', pre=''):
* 'successCode': the code to run once we have done the conversion.
* 'pre': code to run before the conversion if rooting is necessary
"""
- wrap = "%s\n(%s).to_jsval(cx, %s);" % (pre, result, jsvalRef)
+ wrap = "%s\n(%s).to_jsval(*cx, %s);" % (pre, result, jsvalRef)
if successCode:
wrap += "\n%s" % successCode
return wrap
@@ -1323,7 +1409,7 @@ def typeNeedsCx(type, retVal=False):
# Returns a conversion behavior suitable for a type
def getConversionConfigForType(type, isEnforceRange, isClamp, treatNullAs):
- if type.isSequence() or type.isMozMap():
+ if type.isSequence() or type.isRecord():
return getConversionConfigForType(innerContainerType(type), isEnforceRange, isClamp, treatNullAs)
if type.isDOMString():
assert not isEnforceRange and not isClamp
@@ -1381,6 +1467,9 @@ def getRetvalDeclarationForType(returnType, descriptorProvider):
if returnType.nullable():
result = CGWrapper(result, pre="Option<", post=">")
return result
+ if returnType.isPromise():
+ assert not returnType.nullable()
+ return CGGeneric("Rc<Promise>")
if returnType.isGeckoInterface():
descriptor = descriptorProvider.getDescriptor(
returnType.unroll().inner.identifier.name)
@@ -1404,11 +1493,11 @@ def getRetvalDeclarationForType(returnType, descriptorProvider):
if returnType.isAny():
return CGGeneric("JSVal")
if returnType.isObject() or returnType.isSpiderMonkeyInterface():
- result = CGGeneric("NonZero<*mut JSObject>")
+ result = CGGeneric("NonNull<JSObject>")
if returnType.nullable():
result = CGWrapper(result, pre="Option<", post=">")
return result
- if returnType.isSequence() or returnType.isMozMap():
+ if returnType.isSequence() or returnType.isRecord():
result = getRetvalDeclarationForType(innerContainerType(returnType), descriptorProvider)
result = wrapInNativeContainerType(returnType, result)
if returnType.nullable():
@@ -1418,6 +1507,8 @@ def getRetvalDeclarationForType(returnType, descriptorProvider):
nullable = returnType.nullable()
dictName = returnType.inner.name if nullable else returnType.name
result = CGGeneric(dictName)
+ if type_needs_tracing(returnType):
+ result = CGWrapper(result, pre="RootedTraceableBox<", post=">")
if nullable:
result = CGWrapper(result, pre="Option<", post=">")
return result
@@ -1426,7 +1517,7 @@ def getRetvalDeclarationForType(returnType, descriptorProvider):
returnType)
-def MemberCondition(pref, func):
+def MemberCondition(pref, func, exposed, secure):
"""
A string representing the condition for a member to actually be exposed.
Any of the arguments can be None. If not None, they should have the
@@ -1434,14 +1525,21 @@ def MemberCondition(pref, func):
pref: The name of the preference.
func: The name of the function.
+ exposed: One or more names of an exposed global.
+ secure: Requires secure context.
"""
assert pref is None or isinstance(pref, str)
assert func is None or isinstance(func, str)
- assert func is None or pref is None
+ assert exposed is None or isinstance(exposed, set)
+ assert func is None or pref is None or exposed is None or secure is None
+ if secure:
+ return 'Condition::SecureContext()'
if pref:
return 'Condition::Pref("%s")' % pref
if func:
return 'Condition::Func(%s)' % func
+ if exposed:
+ return ["Condition::Exposed(InterfaceObjectMap::Globals::%s)" % camel_to_upper_snake(i) for i in exposed]
return "Condition::Satisfied"
@@ -1484,7 +1582,9 @@ class PropertyDefiner:
PropertyDefiner.getStringAttr(interfaceMember,
"Pref"),
PropertyDefiner.getStringAttr(interfaceMember,
- "Func"))
+ "Func"),
+ interfaceMember.exposureSet,
+ interfaceMember.getExtendedAttribute("SecureContext"))
def generateGuardedArray(self, array, name, specTemplate, specTerminator,
specType, getCondition, getDataTuple):
@@ -1516,22 +1616,30 @@ class PropertyDefiner:
specs = []
prefableSpecs = []
prefableTemplate = ' Guard::new(%s, %s[%d])'
+ origTemplate = specTemplate
+ if isinstance(specTemplate, str):
+ specTemplate = lambda _: origTemplate # noqa
for cond, members in groupby(array, lambda m: getCondition(m, self.descriptor)):
- currentSpecs = [specTemplate % getDataTuple(m) for m in members]
+ currentSpecs = [specTemplate(m) % getDataTuple(m) for m in members]
if specTerminator:
currentSpecs.append(specTerminator)
specs.append("&[\n" + ",\n".join(currentSpecs) + "]\n")
- prefableSpecs.append(
- prefableTemplate % (cond, name + "_specs", len(specs) - 1))
+ if isinstance(cond, list):
+ for i in cond:
+ prefableSpecs.append(
+ prefableTemplate % (i, name + "_specs", len(specs) - 1))
+ else:
+ prefableSpecs.append(
+ prefableTemplate % (cond, name + "_specs", len(specs) - 1))
- specsArray = ("const %s_specs: &'static [&'static[%s]] = &[\n" +
- ",\n".join(specs) + "\n" +
- "];\n") % (name, specType)
+ specsArray = ("const %s_specs: &'static [&'static[%s]] = &[\n"
+ + ",\n".join(specs) + "\n"
+ + "];\n") % (name, specType)
- prefArray = ("const %s: &'static [Guard<&'static [%s]>] = &[\n" +
- ",\n".join(prefableSpecs) + "\n" +
- "];\n") % (name, specType)
+ prefArray = ("const %s: &'static [Guard<&'static [%s]>] = &[\n"
+ + ",\n".join(prefableSpecs) + "\n"
+ + "];\n") % (name, specType)
return specsArray + prefArray
@@ -1559,45 +1667,70 @@ class MethodDefiner(PropertyDefiner):
# Ignore non-static methods for callback interfaces
if not descriptor.interface.isCallback() or static:
methods = [m for m in descriptor.interface.members if
- m.isMethod() and m.isStatic() == static and
- not m.isIdentifierLess() and
- MemberIsUnforgeable(m, descriptor) == unforgeable]
+ m.isMethod() and m.isStatic() == static
+ and not m.isIdentifierLess()
+ and MemberIsUnforgeable(m, descriptor) == unforgeable]
else:
methods = []
self.regular = [{"name": m.identifier.name,
"methodInfo": not m.isStatic(),
"length": methodLength(m),
+ "flags": "JSPROP_ENUMERATE",
"condition": PropertyDefiner.getControllingCondition(m, descriptor)}
for m in methods]
- # FIXME Check for an existing iterator on the interface first.
- if any(m.isGetter() and m.isIndexed() for m in methods):
+ # TODO: Once iterable is implemented, use tiebreak rules instead of
+ # failing. Also, may be more tiebreak rules to implement once spec bug
+ # is resolved.
+ # https://www.w3.org/Bugs/Public/show_bug.cgi?id=28592
+ def hasIterator(methods, regular):
+ return (any("@@iterator" in m.aliases for m in methods)
+ or any("@@iterator" == r["name"] for r in regular))
+
+ # Check whether we need to output an @@iterator due to having an indexed
+ # getter. We only do this while outputting non-static and
+ # non-unforgeable methods, since the @@iterator function will be
+ # neither.
+ if (not static
+ and not unforgeable
+ and descriptor.supportsIndexedProperties()): # noqa
+ if hasIterator(methods, self.regular): # noqa
+ raise TypeError("Cannot have indexed getter/attr on "
+ "interface %s with other members "
+ "that generate @@iterator, such as "
+ "maplike/setlike or aliased functions." %
+ self.descriptor.interface.identifier.name)
self.regular.append({"name": '@@iterator',
"methodInfo": False,
- "selfHostedName": "ArrayValues",
+ "selfHostedName": "$ArrayValues",
"length": 0,
+ "flags": "0", # Not enumerable, per spec.
"condition": "Condition::Satisfied"})
# Generate the keys/values/entries aliases for value iterables.
maplikeOrSetlikeOrIterable = descriptor.interface.maplikeOrSetlikeOrIterable
- if (not static and not unforgeable and
- (maplikeOrSetlikeOrIterable and
- maplikeOrSetlikeOrIterable.isIterable() and
- maplikeOrSetlikeOrIterable.isValueIterator())):
+ if (not static and not unforgeable
+ and maplikeOrSetlikeOrIterable
+ and maplikeOrSetlikeOrIterable.isIterable()
+ and maplikeOrSetlikeOrIterable.isValueIterator()):
+ m = maplikeOrSetlikeOrIterable
+
# Add our keys/values/entries/forEach
self.regular.append({
"name": "keys",
"methodInfo": False,
"selfHostedName": "ArrayKeys",
"length": 0,
+ "flags": "JSPROP_ENUMERATE",
"condition": PropertyDefiner.getControllingCondition(m,
descriptor)
})
self.regular.append({
"name": "values",
"methodInfo": False,
- "selfHostedName": "ArrayValues",
+ "selfHostedName": "$ArrayValues",
"length": 0,
+ "flags": "JSPROP_ENUMERATE",
"condition": PropertyDefiner.getControllingCondition(m,
descriptor)
})
@@ -1606,6 +1739,7 @@ class MethodDefiner(PropertyDefiner):
"methodInfo": False,
"selfHostedName": "ArrayEntries",
"length": 0,
+ "flags": "JSPROP_ENUMERATE",
"condition": PropertyDefiner.getControllingCondition(m,
descriptor)
})
@@ -1614,6 +1748,7 @@ class MethodDefiner(PropertyDefiner):
"methodInfo": False,
"selfHostedName": "ArrayForEach",
"length": 1,
+ "flags": "JSPROP_ENUMERATE",
"condition": PropertyDefiner.getControllingCondition(m,
descriptor)
})
@@ -1626,6 +1761,7 @@ class MethodDefiner(PropertyDefiner):
"name": "toString",
"nativeName": stringifier.identifier.name,
"length": 0,
+ "flags": "JSPROP_ENUMERATE",
"condition": PropertyDefiner.getControllingCondition(stringifier, descriptor)
})
self.unforgeable = unforgeable
@@ -1637,18 +1773,15 @@ class MethodDefiner(PropertyDefiner):
def condition(m, d):
return m["condition"]
- flags = "JSPROP_ENUMERATE"
- if self.unforgeable:
- flags += " | JSPROP_PERMANENT | JSPROP_READONLY"
-
def specData(m):
- # TODO: Use something like JS_FNSPEC
- # https://github.com/servo/servo/issues/6391
+ flags = m["flags"]
+ if self.unforgeable:
+ flags += " | JSPROP_PERMANENT | JSPROP_READONLY"
if "selfHostedName" in m:
selfHostedName = '%s as *const u8 as *const libc::c_char' % str_to_const_array(m["selfHostedName"])
assert not m.get("methodInfo", True)
accessor = "None"
- jitinfo = "0 as *const JSJitInfo"
+ jitinfo = "ptr::null()"
else:
selfHostedName = "0 as *const libc::c_char"
if m.get("methodInfo", True):
@@ -1660,28 +1793,30 @@ class MethodDefiner(PropertyDefiner):
jitinfo = "&%s_methodinfo as *const _ as *const JSJitInfo" % identifier
accessor = "Some(generic_method)"
else:
- jitinfo = "0 as *const JSJitInfo"
+ jitinfo = "ptr::null()"
accessor = 'Some(%s)' % m.get("nativeName", m["name"])
if m["name"].startswith("@@"):
- return ('(SymbolCode::%s as i32 + 1)'
- % m["name"][2:], accessor, jitinfo, m["length"], flags, selfHostedName)
- return (str_to_const_array(m["name"]), accessor, jitinfo, m["length"], flags, selfHostedName)
+ name = 'JSPropertySpec_Name { symbol_: SymbolCode::%s as usize + 1 }' % m["name"][2:]
+ else:
+ name = ('JSPropertySpec_Name { string_: %s as *const u8 as *const libc::c_char }'
+ % str_to_const_array(m["name"]))
+ return (name, accessor, jitinfo, m["length"], flags, selfHostedName)
return self.generateGuardedArray(
array, name,
' JSFunctionSpec {\n'
- ' name: %s as *const u8 as *const libc::c_char,\n'
+ ' name: %s,\n'
' call: JSNativeWrapper { op: %s, info: %s },\n'
' nargs: %s,\n'
' flags: (%s) as u16,\n'
' selfHostedName: %s\n'
' }',
' JSFunctionSpec {\n'
- ' name: 0 as *const libc::c_char,\n'
- ' call: JSNativeWrapper { op: None, info: 0 as *const JSJitInfo },\n'
+ ' name: JSPropertySpec_Name { string_: ptr::null() },\n'
+ ' call: JSNativeWrapper { op: None, info: ptr::null() },\n'
' nargs: 0,\n'
' flags: 0,\n'
- ' selfHostedName: 0 as *const libc::c_char\n'
+ ' selfHostedName: ptr::null()\n'
' }',
'JSFunctionSpec',
condition, specData)
@@ -1694,23 +1829,35 @@ class AttrDefiner(PropertyDefiner):
self.name = name
self.descriptor = descriptor
self.regular = [
- m
+ {
+ "name": m.identifier.name,
+ "attr": m,
+ "flags": "JSPROP_ENUMERATE",
+ "is_accessor": "true",
+ }
for m in descriptor.interface.members if
- m.isAttr() and m.isStatic() == static and
- MemberIsUnforgeable(m, descriptor) == unforgeable
+ m.isAttr() and m.isStatic() == static
+ and MemberIsUnforgeable(m, descriptor) == unforgeable
]
self.static = static
self.unforgeable = unforgeable
+ if not static and not unforgeable and not (
+ descriptor.interface.isNamespace() or descriptor.interface.isCallback()
+ ):
+ self.regular.append({
+ "name": "@@toStringTag",
+ "attr": None,
+ "flags": "JSPROP_READONLY",
+ "is_accessor": "false",
+ })
+
def generateArray(self, array, name):
if len(array) == 0:
return ""
- flags = "JSPROP_ENUMERATE | JSPROP_SHARED"
- if self.unforgeable:
- flags += " | JSPROP_PERMANENT"
-
def getter(attr):
+ attr = attr['attr']
if self.static:
accessor = 'get_' + self.descriptor.internalNameFor(attr.identifier.name)
jitinfo = "0 as *const JSJitInfo"
@@ -1726,6 +1873,7 @@ class AttrDefiner(PropertyDefiner):
"native": accessor})
def setter(attr):
+ attr = attr['attr']
if (attr.readonly and not attr.getExtendedAttribute("PutForwards")
and not attr.getExtendedAttribute("Replaceable")):
return "JSNativeWrapper { op: None, info: 0 as *const JSJitInfo }"
@@ -1744,26 +1892,61 @@ class AttrDefiner(PropertyDefiner):
% {"info": jitinfo,
"native": accessor})
+ def condition(m, d):
+ if m["name"] == "@@toStringTag":
+ return MemberCondition(pref=None, func=None, exposed=None, secure=None)
+ return PropertyDefiner.getControllingCondition(m["attr"], d)
+
def specData(attr):
- return (str_to_const_array(attr.identifier.name), flags, getter(attr),
+ if attr["name"] == "@@toStringTag":
+ return (attr["name"][2:], attr["flags"], attr["is_accessor"],
+ str_to_const_array(self.descriptor.interface.getClassName()))
+
+ flags = attr["flags"]
+ if self.unforgeable:
+ flags += " | JSPROP_PERMANENT"
+ return (str_to_const_array(attr["attr"].identifier.name), flags, attr["is_accessor"], getter(attr),
setter(attr))
+ def template(m):
+ if m["name"] == "@@toStringTag":
+ return """ JSPropertySpec {
+ name: JSPropertySpec_Name { symbol_: SymbolCode::%s as usize + 1 },
+ attributes_: (%s) as u8,
+ isAccessor_: (%s),
+ u: JSPropertySpec_AccessorsOrValue {
+ value: JSPropertySpec_ValueWrapper {
+ type_: JSPropertySpec_ValueWrapper_Type::String,
+ __bindgen_anon_1: JSPropertySpec_ValueWrapper__bindgen_ty_1 {
+ string: %s as *const u8 as *const libc::c_char,
+ }
+ }
+ }
+ }
+"""
+ return """ JSPropertySpec {
+ name: JSPropertySpec_Name { string_: %s as *const u8 as *const libc::c_char },
+ attributes_: (%s) as u8,
+ isAccessor_: (%s),
+ u: JSPropertySpec_AccessorsOrValue {
+ accessors: JSPropertySpec_AccessorsOrValue_Accessors {
+ getter: JSPropertySpec_Accessor {
+ native: %s,
+ },
+ setter: JSPropertySpec_Accessor {
+ native: %s,
+ }
+ }
+ }
+ }
+"""
+
return self.generateGuardedArray(
array, name,
- ' JSPropertySpec {\n'
- ' name: %s as *const u8 as *const libc::c_char,\n'
- ' flags: (%s) as u8,\n'
- ' getter: %s,\n'
- ' setter: %s\n'
- ' }',
- ' JSPropertySpec {\n'
- ' name: 0 as *const libc::c_char,\n'
- ' flags: 0,\n'
- ' getter: JSNativeWrapper { op: None, info: 0 as *const JSJitInfo },\n'
- ' setter: JSNativeWrapper { op: None, info: 0 as *const JSJitInfo }\n'
- ' }',
+ template,
+ ' JSPropertySpec::ZERO',
'JSPropertySpec',
- PropertyDefiner.getControllingCondition, specData)
+ condition, specData)
class ConstDefiner(PropertyDefiner):
@@ -1790,6 +1973,7 @@ class ConstDefiner(PropertyDefiner):
'ConstantSpec',
PropertyDefiner.getControllingCondition, specData)
+
# We'll want to insert the indent at the beginnings of lines, but we
# don't want to indent empty lines. So only indent lines that have a
# non-newline character on them.
@@ -1835,11 +2019,36 @@ class CGWrapper(CGThing):
return self.pre + defn + self.post
+class CGRecord(CGThing):
+ """
+ CGThing that wraps value CGThing in record with key type equal to keyType parameter
+ """
+ def __init__(self, keyType, value):
+ CGThing.__init__(self)
+ assert keyType.isString()
+ self.keyType = keyType
+ self.value = value
+
+ def define(self):
+ if self.keyType.isByteString():
+ keyDef = "ByteString"
+ elif self.keyType.isDOMString():
+ keyDef = "DOMString"
+ elif self.keyType.isUSVString():
+ keyDef = "USVString"
+ else:
+ assert False
+
+ defn = keyDef + ", " + self.value.define()
+ return "Record<" + defn + ">"
+
+
class CGImports(CGWrapper):
"""
Generates the appropriate import/use statements.
"""
- def __init__(self, child, descriptors, callbacks, dictionaries, enums, imports, config, ignored_warnings=None):
+ def __init__(self, child, descriptors, callbacks, dictionaries, enums, typedefs, imports, config,
+ ignored_warnings=None):
"""
Adds a set of imports.
"""
@@ -1866,8 +2075,8 @@ class CGImports(CGWrapper):
def isImportable(type):
if not type.isType():
- assert (type.isInterface() or type.isDictionary() or
- type.isEnum() or type.isNamespace())
+ assert (type.isInterface() or type.isDictionary()
+ or type.isEnum() or type.isNamespace())
return True
return not (type.builtin or type.isSequence() or type.isUnion())
@@ -1912,7 +2121,7 @@ class CGImports(CGWrapper):
members += [constructor]
if d.proxy:
- members += [o for o in d.operations.values() if o]
+ members += [o for o in list(d.operations.values()) if o]
for m in members:
if m.isMethod():
@@ -1928,6 +2137,11 @@ class CGImports(CGWrapper):
for d in dictionaries:
types += componentTypes(d)
+ # Import the type names used in the typedefs that are being defined.
+ for t in typedefs:
+ if not t.innerType.isCallback():
+ types += componentTypes(t.innerType)
+
# Normalize the types we've collected and remove any ones which can't be imported.
types = removeWrapperAndNullableTypes(types)
@@ -1943,11 +2157,14 @@ class CGImports(CGWrapper):
if name != 'GlobalScope':
extras += [descriptor.path]
parentName = descriptor.getParentName()
- if parentName:
+ while parentName:
descriptor = descriptorProvider.getDescriptor(parentName)
extras += [descriptor.path, descriptor.bindingPath]
- elif t.isType() and t.isMozMap():
- extras += ['dom::bindings::mozmap::MozMap']
+ parentName = descriptor.getParentName()
+ elif t.isType() and t.isRecord():
+ extras += ['crate::dom::bindings::record::Record']
+ elif isinstance(t, IDLPromiseType):
+ extras += ['crate::dom::promise::Promise']
else:
if t.isEnum():
extras += [getModuleFromObject(t) + '::' + getIdentifier(t).name + 'Values']
@@ -1997,15 +2214,15 @@ def DOMClassTypeId(desc):
inner = ""
if desc.hasDescendants():
if desc.interface.getExtendedAttribute("Abstract"):
- return "::dom::bindings::codegen::InheritTypes::TopTypeId { abstract_: () }"
+ return "crate::dom::bindings::codegen::InheritTypes::TopTypeId { abstract_: () }"
name = desc.interface.identifier.name
- inner = "(::dom::bindings::codegen::InheritTypes::%sTypeId::%s)" % (name, name)
+ inner = "(crate::dom::bindings::codegen::InheritTypes::%sTypeId::%s)" % (name, name)
elif len(protochain) == 1:
- return "::dom::bindings::codegen::InheritTypes::TopTypeId { alone: () }"
+ return "crate::dom::bindings::codegen::InheritTypes::TopTypeId { alone: () }"
reversed_protochain = list(reversed(protochain))
for (child, parent) in zip(reversed_protochain, reversed_protochain[1:]):
- inner = "(::dom::bindings::codegen::InheritTypes::%sTypeId::%s%s)" % (parent, child, inner)
- return "::dom::bindings::codegen::InheritTypes::TopTypeId { %s: %s }" % (protochain[0].lower(), inner)
+ inner = "(crate::dom::bindings::codegen::InheritTypes::%sTypeId::%s%s)" % (parent, child, inner)
+ return "crate::dom::bindings::codegen::InheritTypes::TopTypeId { %s: %s }" % (protochain[0].lower(), inner)
def DOMClass(descriptor):
@@ -2016,7 +2233,7 @@ def DOMClass(descriptor):
# padding.
protoList.extend(['PrototypeList::ID::Last'] * (descriptor.config.maxProtoChainLength - len(protoList)))
prototypeChainString = ', '.join(protoList)
- heapSizeOf = 'heap_size_of_raw_self_and_children::<%s>' % descriptor.concreteType
+ mallocSizeOf = 'malloc_size_of_including_raw_self::<%s>' % descriptor.concreteType
if descriptor.isGlobal():
globals_ = camel_to_upper_snake(descriptor.name)
else:
@@ -2025,9 +2242,9 @@ def DOMClass(descriptor):
DOMClass {
interface_chain: [ %s ],
type_id: %s,
- heap_size_of: %s as unsafe fn(_) -> _,
- global: InterfaceObjectMap::%s,
-}""" % (prototypeChainString, DOMClassTypeId(descriptor), heapSizeOf, globals_)
+ malloc_size_of: %s as unsafe fn(&mut _, _) -> _,
+ global: InterfaceObjectMap::Globals::%s,
+}""" % (prototypeChainString, DOMClassTypeId(descriptor), mallocSizeOf, globals_)
class CGDOMJSClass(CGThing):
@@ -2039,11 +2256,15 @@ class CGDOMJSClass(CGThing):
self.descriptor = descriptor
def define(self):
+ parentName = self.descriptor.getParentName()
+ if not parentName:
+ parentName = "crate::dom::bindings::reflector::Reflector"
+
args = {
"domClass": DOMClass(self.descriptor),
"enumerateHook": "None",
"finalizeHook": FINALIZE_HOOK_NAME,
- "flags": "0",
+ "flags": "JSCLASS_FOREGROUND_FINALIZE",
"name": str_to_const_array(self.descriptor.interface.identifier.name),
"resolveHook": "None",
"slots": "1",
@@ -2052,7 +2273,7 @@ class CGDOMJSClass(CGThing):
if self.descriptor.isGlobal():
assert not self.descriptor.weakReferenceable
args["enumerateHook"] = "Some(enumerate_global)"
- args["flags"] = "JSCLASS_IS_GLOBAL | JSCLASS_DOM_GLOBAL"
+ args["flags"] = "JSCLASS_IS_GLOBAL | JSCLASS_DOM_GLOBAL | JSCLASS_FOREGROUND_FINALIZE"
args["slots"] = "JSCLASS_GLOBAL_SLOT_COUNT + 1"
args["resolveHook"] = "Some(resolve_global)"
args["traceHook"] = "js::jsapi::JS_GlobalObjectTraceHook"
@@ -2062,9 +2283,8 @@ class CGDOMJSClass(CGThing):
static CLASS_OPS: js::jsapi::JSClassOps = js::jsapi::JSClassOps {
addProperty: None,
delProperty: None,
- getProperty: None,
- setProperty: None,
- enumerate: %(enumerateHook)s,
+ enumerate: None,
+ newEnumerate: %(enumerateHook)s,
resolve: %(resolveHook)s,
mayResolve: None,
finalize: Some(%(finalizeHook)s),
@@ -2081,10 +2301,56 @@ static Class: DOMJSClass = DOMJSClass {
(((%(slots)s) & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT)
/* JSCLASS_HAS_RESERVED_SLOTS(%(slots)s) */,
cOps: &CLASS_OPS,
- reserved: [0 as *mut _; 3],
+ spec: ptr::null(),
+ ext: ptr::null(),
+ oOps: ptr::null(),
},
dom_class: %(domClass)s
-};""" % args
+};
+""" % args
+
+
+class CGAssertInheritance(CGThing):
+ """
+ Generate a type assertion for inheritance
+ """
+ def __init__(self, descriptor):
+ CGThing.__init__(self)
+ self.descriptor = descriptor
+
+ def define(self):
+ parent = self.descriptor.interface.parent
+ parentName = ""
+ if parent:
+ parentName = parent.identifier.name
+ else:
+ parentName = "crate::dom::bindings::reflector::Reflector"
+
+ selfName = self.descriptor.interface.identifier.name
+
+ if selfName == "PaintRenderingContext2D":
+ # PaintRenderingContext2D embeds a CanvasRenderingContext2D
+ # instead of a Reflector as an optimization,
+ # but this is fine since CanvasRenderingContext2D
+ # also has a reflector
+ #
+ # FIXME *RenderingContext2D should use Inline
+ parentName = "crate::dom::canvasrenderingcontext2d::CanvasRenderingContext2D"
+ args = {
+ "parentName": parentName,
+ "selfName": selfName,
+ }
+
+ return """\
+impl %(selfName)s {
+ fn __assert_parent_type(&self) {
+ use crate::dom::bindings::inheritance::HasParent;
+ // If this type assertion fails, make sure the first field of your
+ // DOM struct is of the correct type -- it must be the parent class.
+ let _: &%(parentName)s = self.as_parent();
+ }
+}
+""" % args
def str_to_const_array(s):
@@ -2108,7 +2374,9 @@ static PrototypeClass: JSClass = JSClass {
// JSCLASS_HAS_RESERVED_SLOTS(%(slotCount)s)
(%(slotCount)s & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT,
cOps: 0 as *const _,
- reserved: [0 as *mut os::raw::c_void; 3]
+ spec: ptr::null(),
+ ext: ptr::null(),
+ oOps: ptr::null(),
};
""" % {'name': name, 'slotCount': slotCount}
@@ -2145,7 +2413,14 @@ static NAMESPACE_OBJECT_CLASS: NamespaceObjectClass = unsafe {
return """\
static INTERFACE_OBJECT_CLASS: NonCallbackInterfaceObjectClass =
NonCallbackInterfaceObjectClass::new(
- &%(constructorBehavior)s,
+ {
+ // Intermediate `const` because as of nightly-2018-10-05,
+ // rustc is conservative in promotion to `'static` of the return values of `const fn`s:
+ // https://github.com/rust-lang/rust/issues/54846
+ // https://github.com/rust-lang/rust/pull/53851
+ const BEHAVIOR: InterfaceConstructorBehavior = %(constructorBehavior)s;
+ &BEHAVIOR
+ },
%(representation)s,
PrototypeList::ID::%(id)s,
%(depth)s);
@@ -2209,20 +2484,19 @@ def getAllTypes(descriptors, dictionaries, callbacks, typedefs):
"""
Generate all the types we're dealing with. For each type, a tuple
containing type, descriptor, dictionary is yielded. The
- descriptor and dictionary can be None if the type does not come
- from a descriptor or dictionary; they will never both be non-None.
+ descriptor can be None if the type does not come from a descriptor.
"""
for d in descriptors:
for t in getTypesFromDescriptor(d):
- yield (t, d, None)
+ yield (t, d)
for dictionary in dictionaries:
for t in getTypesFromDictionary(dictionary):
- yield (t, None, dictionary)
+ yield (t, None)
for callback in callbacks:
for t in getTypesFromCallback(callback):
- yield (t, None, None)
+ yield (t, None)
for typedef in typedefs:
- yield (typedef.innerType, None, None)
+ yield (typedef.innerType, None)
def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config):
@@ -2231,40 +2505,53 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config):
"""
imports = [
- 'dom',
- 'dom::bindings::codegen::PrototypeList',
- 'dom::bindings::conversions::ConversionResult',
- 'dom::bindings::conversions::FromJSValConvertible',
- 'dom::bindings::conversions::ToJSValConvertible',
- 'dom::bindings::conversions::ConversionBehavior',
- 'dom::bindings::conversions::StringificationBehavior',
- 'dom::bindings::conversions::root_from_handlevalue',
- 'dom::bindings::error::throw_not_in_union',
- 'dom::bindings::js::Root',
- 'dom::bindings::mozmap::MozMap',
- 'dom::bindings::str::ByteString',
- 'dom::bindings::str::DOMString',
- 'dom::bindings::str::USVString',
- 'dom::types::*',
+ 'crate::dom',
+ 'crate::dom::bindings::codegen::PrototypeList',
+ 'crate::dom::bindings::conversions::ConversionResult',
+ 'crate::dom::bindings::conversions::FromJSValConvertible',
+ 'crate::dom::bindings::conversions::ToJSValConvertible',
+ 'crate::dom::bindings::conversions::ConversionBehavior',
+ 'crate::dom::bindings::conversions::StringificationBehavior',
+ 'crate::dom::bindings::conversions::root_from_handlevalue',
+ 'crate::dom::bindings::conversions::windowproxy_from_handlevalue',
+ 'std::ptr::NonNull',
+ 'std::rc::Rc',
+ 'crate::dom::bindings::record::Record',
+ 'crate::dom::bindings::num::Finite',
+ 'crate::dom::bindings::root::DomRoot',
+ 'crate::dom::bindings::str::ByteString',
+ 'crate::dom::bindings::str::DOMString',
+ 'crate::dom::bindings::str::USVString',
+ 'crate::dom::bindings::trace::RootedTraceableBox',
+ 'crate::dom::types::*',
+ 'crate::dom::windowproxy::WindowProxy',
+ 'crate::script_runtime::JSContext as SafeJSContext',
'js::error::throw_type_error',
- 'js::jsapi::HandleValue',
+ 'js::rust::HandleValue',
'js::jsapi::Heap',
+ 'js::jsapi::IsCallable',
'js::jsapi::JSContext',
'js::jsapi::JSObject',
- 'js::jsapi::MutableHandleValue',
+ 'js::rust::MutableHandleValue',
'js::jsval::JSVal',
+ 'js::typedarray'
]
# Now find all the things we'll need as arguments and return values because
# we need to wrap or unwrap them.
unionStructs = dict()
- for (t, descriptor, dictionary) in getAllTypes(descriptors, dictionaries, callbacks, typedefs):
- if dictionary:
- imports.append("%s::%s" % (CGDictionary.makeModuleName(dictionary),
- CGDictionary.makeDictionaryName(dictionary)))
+ for (t, descriptor) in getAllTypes(descriptors, dictionaries, callbacks, typedefs):
t = t.unroll()
if not t.isUnion():
continue
+ for memberType in t.flatMemberTypes:
+ if memberType.isDictionary() or memberType.isEnum() or memberType.isCallback():
+ memberModule = getModuleFromObject(memberType)
+ memberName = (memberType.callback.identifier.name
+ if memberType.isCallback() else memberType.inner.identifier.name)
+ imports.append("%s::%s" % (memberModule, memberName))
+ if memberType.isEnum():
+ imports.append("%s::%sValues" % (memberModule, memberName))
name = str(t)
if name not in unionStructs:
provider = descriptor or config.getDescriptorProvider()
@@ -2274,13 +2561,14 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config):
])
# Sort unionStructs by key, retrieve value
- unionStructs = (i[1] for i in sorted(unionStructs.items(), key=operator.itemgetter(0)))
+ unionStructs = (i[1] for i in sorted(list(unionStructs.items()), key=operator.itemgetter(0)))
return CGImports(CGList(unionStructs, "\n\n"),
descriptors=[],
callbacks=[],
dictionaries=[],
enums=[],
+ typedefs=[],
imports=imports,
config=config,
ignored_warnings=[])
@@ -2391,9 +2679,19 @@ class CGAbstractMethod(CGThing):
body = self.definition_body()
if self.catchPanic:
- body = CGWrapper(CGIndenter(body),
- pre="return wrap_panic(panic::AssertUnwindSafe(|| {\n",
- post=("""\n}), %s);""" % ("()" if self.returnType == "void" else "false")))
+ if self.returnType == "void":
+ pre = "wrap_panic(&mut || {\n"
+ post = "\n})"
+ else:
+ pre = (
+ "let mut result = false;\n"
+ "wrap_panic(&mut || result = (|| {\n"
+ )
+ post = (
+ "\n})());\n"
+ "return result"
+ )
+ body = CGWrapper(CGIndenter(body), pre=pre, post=post)
return CGWrapper(CGIndenter(body),
pre=self.definition_prologue(),
@@ -2420,23 +2718,22 @@ class CGConstructorEnabled(CGAbstractMethod):
def __init__(self, descriptor):
CGAbstractMethod.__init__(self, descriptor,
'ConstructorEnabled', 'bool',
- [Argument("*mut JSContext", "aCx"),
- Argument("HandleObject", "aObj")],
- unsafe=True)
+ [Argument("SafeJSContext", "aCx"),
+ Argument("HandleObject", "aObj")])
def definition_body(self):
conditions = []
iface = self.descriptor.interface
bits = " | ".join(sorted(
- "InterfaceObjectMap::" + camel_to_upper_snake(i) for i in iface.exposureSet
+ "InterfaceObjectMap::Globals::" + camel_to_upper_snake(i) for i in iface.exposureSet
))
conditions.append("is_exposed_in(aObj, %s)" % bits)
pref = iface.getExtendedAttribute("Pref")
if pref:
assert isinstance(pref, list) and len(pref) == 1
- conditions.append('PREFS.get("%s").as_boolean().unwrap_or(false)' % pref[0])
+ conditions.append('pref!(%s)' % pref[0])
func = iface.getExtendedAttribute("Func")
if func:
@@ -2446,33 +2743,6 @@ class CGConstructorEnabled(CGAbstractMethod):
return CGList((CGGeneric(cond) for cond in conditions), " &&\n")
-def CreateBindingJSObject(descriptor, parent=None):
- assert not descriptor.isGlobal()
- create = "let raw = Box::into_raw(object);\nlet _rt = RootedTraceable::new(&*raw);\n"
- if descriptor.proxy:
- create += """
-let handler = RegisterBindings::PROXY_HANDLERS[PrototypeList::Proxies::%s as usize];
-rooted!(in(cx) let private = PrivateValue(raw as *const libc::c_void));
-let obj = NewProxyObject(cx, handler,
- private.handle(),
- proto.get(), %s.get(),
- ptr::null_mut(), ptr::null_mut());
-assert!(!obj.is_null());
-rooted!(in(cx) let obj = obj);\
-""" % (descriptor.name, parent)
- else:
- create += ("rooted!(in(cx) let obj = JS_NewObjectWithGivenProto(\n"
- " cx, &Class.base as *const JSClass, proto.handle()));\n"
- "assert!(!obj.is_null());\n"
- "\n"
- "JS_SetReservedSlot(obj.get(), DOM_OBJECT_SLOT,\n"
- " PrivateValue(raw as *const libc::c_void));")
- if descriptor.weakReferenceable:
- create += """
-JS_SetReservedSlot(obj.get(), DOM_WEAK_SLOT, PrivateValue(ptr::null()));"""
- return create
-
-
def InitUnforgeablePropertiesOnHolder(descriptor, properties):
"""
Define the unforgeable properties on the unforgeable holder for
@@ -2482,8 +2752,8 @@ def InitUnforgeablePropertiesOnHolder(descriptor, properties):
"""
unforgeables = []
- defineUnforgeableAttrs = "define_guarded_properties(cx, unforgeable_holder.handle(), %s);"
- defineUnforgeableMethods = "define_guarded_methods(cx, unforgeable_holder.handle(), %s);"
+ defineUnforgeableAttrs = "define_guarded_properties(cx, unforgeable_holder.handle(), %s, global);"
+ defineUnforgeableMethods = "define_guarded_methods(cx, unforgeable_holder.handle(), %s, global);"
unforgeableMembers = [
(defineUnforgeableAttrs, properties.unforgeable_attrs),
@@ -2508,8 +2778,8 @@ def CopyUnforgeablePropertiesToInstance(descriptor):
# reflector, so we can make sure we don't get confused by named getters.
if descriptor.proxy:
copyCode += """\
-rooted!(in(cx) let mut expando = ptr::null_mut());
-ensure_expando_object(cx, obj.handle(), expando.handle_mut());
+rooted!(in(*cx) let mut expando = ptr::null_mut::<JSObject>());
+ensure_expando_object(*cx, obj.handle().into(), expando.handle_mut());
"""
obj = "expando"
else:
@@ -2519,14 +2789,15 @@ ensure_expando_object(cx, obj.handle(), expando.handle_mut());
# unforgeable holder for those with the right JSClass. Luckily, there
# aren't too many globals being created.
if descriptor.isGlobal():
- copyFunc = "JS_CopyPropertiesFrom"
+ copyFunc = "JS_CopyOwnPropertiesAndPrivateFields"
else:
copyFunc = "JS_InitializePropertiesFromCompatibleNativeObject"
copyCode += """\
-rooted!(in(cx) let mut unforgeable_holder = ptr::null_mut());
-unforgeable_holder.handle_mut().set(
- JS_GetReservedSlot(proto.get(), DOM_PROTO_UNFORGEABLE_HOLDER_SLOT).to_object());
-assert!(%(copyFunc)s(cx, %(obj)s.handle(), unforgeable_holder.handle()));
+let mut slot = UndefinedValue();
+JS_GetReservedSlot(proto.get(), DOM_PROTO_UNFORGEABLE_HOLDER_SLOT, &mut slot);
+rooted!(in(*cx) let mut unforgeable_holder = ptr::null_mut::<JSObject>());
+unforgeable_holder.handle_mut().set(slot.to_object());
+assert!(%(copyFunc)s(*cx, %(obj)s.handle(), unforgeable_holder.handle()));
""" % {'copyFunc': copyFunc, 'obj': obj}
return copyCode
@@ -2540,32 +2811,74 @@ class CGWrapMethod(CGAbstractMethod):
def __init__(self, descriptor):
assert not descriptor.interface.isCallback()
assert not descriptor.isGlobal()
- args = [Argument('*mut JSContext', 'cx'),
+ args = [Argument('SafeJSContext', 'cx'),
Argument('&GlobalScope', 'scope'),
Argument("Box<%s>" % descriptor.concreteType, 'object')]
- retval = 'Root<%s>' % descriptor.concreteType
+ retval = 'DomRoot<%s>' % descriptor.concreteType
CGAbstractMethod.__init__(self, descriptor, 'Wrap', retval, args,
pub=True, unsafe=True)
def definition_body(self):
unforgeable = CopyUnforgeablePropertiesToInstance(self.descriptor)
- create = CreateBindingJSObject(self.descriptor, "scope")
+ if self.descriptor.proxy:
+ create = """
+let handler: *const libc::c_void =
+ RegisterBindings::proxy_handlers::%(concreteType)s
+ .load(std::sync::atomic::Ordering::Acquire);
+rooted!(in(*cx) let obj = NewProxyObject(
+ *cx,
+ handler,
+ Handle::from_raw(UndefinedHandleValue),
+ proto.get(),
+ ptr::null(),
+));
+assert!(!obj.is_null());
+SetProxyReservedSlot(
+ obj.get(),
+ 0,
+ &PrivateValue(raw.as_ptr() as *const %(concreteType)s as *const libc::c_void),
+);
+"""
+ else:
+ create = """
+rooted!(in(*cx) let obj = JS_NewObjectWithGivenProto(
+ *cx,
+ &Class.base,
+ proto.handle(),
+));
+assert!(!obj.is_null());
+JS_SetReservedSlot(
+ obj.get(),
+ DOM_OBJECT_SLOT,
+ &PrivateValue(raw.as_ptr() as *const %(concreteType)s as *const libc::c_void),
+);
+"""
+ create = create % {"concreteType": self.descriptor.concreteType}
+ if self.descriptor.weakReferenceable:
+ create += """
+let val = PrivateValue(ptr::null());
+JS_SetReservedSlot(obj.get(), DOM_WEAK_SLOT, &val);
+"""
+
return CGGeneric("""\
+let raw = Root::new(MaybeUnreflectedDom::from_box(object));
+
let scope = scope.reflector().get_jsobject();
assert!(!scope.get().is_null());
assert!(((*get_object_class(scope.get())).flags & JSCLASS_IS_GLOBAL) != 0);
+let _ac = JSAutoRealm::new(*cx, scope.get());
-rooted!(in(cx) let mut proto = ptr::null_mut());
-let _ac = JSAutoCompartment::new(cx, scope.get());
+rooted!(in(*cx) let mut proto = ptr::null_mut::<JSObject>());
GetProtoObject(cx, scope, proto.handle_mut());
assert!(!proto.is_null());
%(createObject)s
+let root = raw.reflect_with(obj.get());
%(copyUnforgeable)s
-(*raw).init_reflector(obj.get());
-Root::from_ref(&*raw)""" % {'copyUnforgeable': unforgeable, 'createObject': create})
+DomRoot::from_ref(&*root)\
+""" % {'copyUnforgeable': unforgeable, 'createObject': create})
class CGWrapGlobalMethod(CGAbstractMethod):
@@ -2575,15 +2888,16 @@ class CGWrapGlobalMethod(CGAbstractMethod):
def __init__(self, descriptor, properties):
assert not descriptor.interface.isCallback()
assert descriptor.isGlobal()
- args = [Argument('*mut JSContext', 'cx'),
+ args = [Argument('SafeJSContext', 'cx'),
Argument("Box<%s>" % descriptor.concreteType, 'object')]
- retval = 'Root<%s>' % descriptor.concreteType
+ retval = 'DomRoot<%s>' % descriptor.concreteType
CGAbstractMethod.__init__(self, descriptor, 'Wrap', retval, args,
pub=True, unsafe=True)
self.properties = properties
def definition_body(self):
values = {
+ "concreteType": self.descriptor.concreteType,
"unforgeable": CopyUnforgeablePropertiesToInstance(self.descriptor)
}
@@ -2592,40 +2906,39 @@ class CGWrapGlobalMethod(CGAbstractMethod):
("define_guarded_methods", self.properties.methods),
("define_guarded_constants", self.properties.consts)
]
- members = ["%s(cx, obj.handle(), %s);" % (function, array.variableName())
+ members = ["%s(cx, obj.handle(), %s, obj.handle());" % (function, array.variableName())
for (function, array) in pairs if array.length() > 0]
values["members"] = "\n".join(members)
return CGGeneric("""\
let origin = object.origin().clone();
-let raw = Box::into_raw(object);
-let _rt = RootedTraceable::new(&*raw);
+let raw = Root::new(MaybeUnreflectedDom::from_box(object));
-rooted!(in(cx) let mut obj = ptr::null_mut());
+rooted!(in(*cx) let mut obj = ptr::null_mut::<JSObject>());
create_global_object(
cx,
&Class.base,
- raw as *const libc::c_void,
+ raw.as_ptr() as *const %(concreteType)s as *const libc::c_void,
_trace,
obj.handle_mut(),
&origin);
assert!(!obj.is_null());
-(*raw).init_reflector(obj.get());
+let root = raw.reflect_with(obj.get());
-let _ac = JSAutoCompartment::new(cx, obj.get());
-rooted!(in(cx) let mut proto = ptr::null_mut());
+let _ac = JSAutoRealm::new(*cx, obj.get());
+rooted!(in(*cx) let mut proto = ptr::null_mut::<JSObject>());
GetProtoObject(cx, obj.handle(), proto.handle_mut());
-assert!(JS_SplicePrototype(cx, obj.handle(), proto.handle()));
+assert!(JS_SetPrototype(*cx, obj.handle(), proto.handle()));
let mut immutable = false;
-assert!(JS_SetImmutablePrototype(cx, obj.handle(), &mut immutable));
+assert!(JS_SetImmutablePrototype(*cx, obj.handle(), &mut immutable));
assert!(immutable);
%(members)s
%(unforgeable)s
-Root::from_ref(&*raw)\
+DomRoot::from_ref(&*root)\
""" % values)
@@ -2640,8 +2953,8 @@ class CGIDLInterface(CGThing):
def define(self):
interface = self.descriptor.interface
name = self.descriptor.concreteType
- if (interface.getUserData("hasConcreteDescendant", False) or
- interface.getUserData("hasProxyDescendant", False)):
+ if (interface.getUserData("hasConcreteDescendant", False)
+ or interface.getUserData("hasProxyDescendant", False)):
depth = self.descriptor.prototypeDepth
check = "class.interface_chain[%s] == PrototypeList::ID::%s" % (depth, name)
elif self.descriptor.proxy:
@@ -2664,6 +2977,50 @@ impl PartialEq for %(name)s {
""" % {'check': check, 'name': name}
+class CGDomObjectWrap(CGThing):
+ """
+ Class for codegen of an implementation of the DomObjectWrap trait.
+ """
+ def __init__(self, descriptor):
+ CGThing.__init__(self)
+ self.descriptor = descriptor
+
+ def define(self):
+ name = self.descriptor.concreteType
+ name = "dom::%s::%s" % (name.lower(), name)
+ return """\
+impl DomObjectWrap for %s {
+ const WRAP: unsafe fn(
+ SafeJSContext,
+ &GlobalScope,
+ Box<Self>,
+ ) -> Root<Dom<Self>> = Wrap;
+}
+""" % (name)
+
+
+class CGDomObjectIteratorWrap(CGThing):
+ """
+ Class for codegen of an implementation of the DomObjectIteratorWrap trait.
+ """
+ def __init__(self, descriptor):
+ CGThing.__init__(self)
+ self.descriptor = descriptor
+
+ def define(self):
+ assert self.descriptor.interface.isIteratorInterface()
+ name = self.descriptor.interface.iterableInterface.identifier.name
+ return """\
+impl DomObjectIteratorWrap for %s {
+ const ITER_WRAP: unsafe fn(
+ SafeJSContext,
+ &GlobalScope,
+ Box<IterableIterator<Self>>,
+ ) -> Root<Dom<IterableIterator<Self>>> = Wrap;
+}
+""" % (name)
+
+
class CGAbstractExternMethod(CGAbstractMethod):
"""
Abstract base class for codegen of implementation-only (no
@@ -2714,35 +3071,83 @@ class PropertyArrays():
return define
+class CGCollectJSONAttributesMethod(CGAbstractMethod):
+ """
+ Generate the CollectJSONAttributes method for an interface descriptor
+ """
+ def __init__(self, descriptor, toJSONMethod):
+ args = [Argument('*mut JSContext', 'cx'),
+ Argument('RawHandleObject', 'obj'),
+ Argument('*mut libc::c_void', 'this'),
+ Argument('&RootedGuard<*mut JSObject>', 'result')]
+ CGAbstractMethod.__init__(self, descriptor, 'CollectJSONAttributes',
+ 'bool', args, pub=True, unsafe=True)
+ self.toJSONMethod = toJSONMethod
+
+ def definition_body(self):
+ ret = """let incumbent_global = GlobalScope::incumbent().expect("no incumbent global");
+let global = incumbent_global.reflector().get_jsobject();\n"""
+ interface = self.descriptor.interface
+ for m in interface.members:
+ if m.isAttr() and not m.isStatic() and m.type.isJSONType():
+ name = m.identifier.name
+ conditions = MemberCondition(None, None, m.exposureSet, None)
+ ret_conditions = '&[' + ", ".join(conditions) + "]"
+ ret += fill(
+ """
+ let conditions = ${conditions};
+ let is_satisfied = conditions.iter().any(|c|
+ c.is_satisfied(
+ SafeJSContext::from_ptr(cx),
+ HandleObject::from_raw(obj),
+ global));
+ if is_satisfied {
+ rooted!(in(cx) let mut temp = UndefinedValue());
+ if !get_${name}(cx, obj, this, JSJitGetterCallArgs { _base: temp.handle_mut().into() }) {
+ return false;
+ }
+ if !JS_DefineProperty(cx, result.handle().into(),
+ ${nameAsArray} as *const u8 as *const libc::c_char,
+ temp.handle(), JSPROP_ENUMERATE as u32) {
+ return false;
+ }
+ }
+ """,
+ name=name, nameAsArray=str_to_const_array(name), conditions=ret_conditions)
+ ret += 'return true;\n'
+ return CGGeneric(ret)
+
+
class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
"""
Generate the CreateInterfaceObjects method for an interface descriptor.
properties should be a PropertyArrays instance.
"""
- def __init__(self, descriptor, properties, haveUnscopables):
- args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'global'),
+ def __init__(self, descriptor, properties, haveUnscopables, haveLegacyWindowAliases):
+ args = [Argument('SafeJSContext', 'cx'), Argument('HandleObject', 'global'),
Argument('*mut ProtoOrIfaceArray', 'cache')]
CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args,
unsafe=True)
self.properties = properties
self.haveUnscopables = haveUnscopables
+ self.haveLegacyWindowAliases = haveLegacyWindowAliases
def definition_body(self):
name = self.descriptor.interface.identifier.name
if self.descriptor.interface.isNamespace():
if self.descriptor.interface.getExtendedAttribute("ProtoObjectHack"):
- proto = "JS_GetObjectPrototype(cx, global)"
+ proto = "GetRealmObjectPrototype(*cx)"
else:
- proto = "JS_NewPlainObject(cx)"
+ proto = "JS_NewPlainObject(*cx)"
if self.properties.static_methods.length():
methods = self.properties.static_methods.variableName()
else:
methods = "&[]"
return CGGeneric("""\
-rooted!(in(cx) let proto = %(proto)s);
+rooted!(in(*cx) let proto = %(proto)s);
assert!(!proto.is_null());
-rooted!(in(cx) let mut namespace = ptr::null_mut());
+rooted!(in(*cx) let mut namespace = ptr::null_mut::<JSObject>());
create_namespace_object(cx, global, proto.handle(), &NAMESPACE_OBJECT_CLASS,
%(methods)s, %(name)s, namespace.handle_mut());
assert!(!namespace.is_null());
@@ -2755,7 +3160,7 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null());
if self.descriptor.interface.isCallback():
assert not self.descriptor.interface.ctor() and self.descriptor.interface.hasConstants()
return CGGeneric("""\
-rooted!(in(cx) let mut interface = ptr::null_mut());
+rooted!(in(*cx) let mut interface = ptr::null_mut::<JSObject>());
create_callback_interface_object(cx, global, sConstants, %(name)s, interface.handle_mut());
assert!(!interface.is_null());
assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null());
@@ -2768,23 +3173,25 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null());
parentName = self.descriptor.getParentName()
if not parentName:
if self.descriptor.interface.getExtendedAttribute("ExceptionClass"):
- getPrototypeProto = "prototype_proto.set(JS_GetErrorPrototype(cx))"
+ protoGetter = "GetRealmErrorPrototype"
elif self.descriptor.interface.isIteratorInterface():
- getPrototypeProto = "prototype_proto.set(JS_GetIteratorPrototype(cx))"
+ protoGetter = "GetRealmIteratorPrototype"
else:
- getPrototypeProto = "prototype_proto.set(JS_GetObjectPrototype(cx, global))"
+ protoGetter = "GetRealmObjectPrototype"
+ getPrototypeProto = "prototype_proto.set(%s(*cx))" % protoGetter
else:
getPrototypeProto = ("%s::GetProtoObject(cx, global, prototype_proto.handle_mut())" %
toBindingNamespace(parentName))
code = [CGGeneric("""\
-rooted!(in(cx) let mut prototype_proto = ptr::null_mut());
+rooted!(in(*cx) let mut prototype_proto = ptr::null_mut::<JSObject>());
%s;
assert!(!prototype_proto.is_null());""" % getPrototypeProto)]
properties = {
"id": name,
- "unscopables": "unscopable_names" if self.haveUnscopables else "&[]"
+ "unscopables": "unscopable_names" if self.haveUnscopables else "&[]",
+ "legacyWindowAliases": "legacy_window_aliases" if self.haveLegacyWindowAliases else "&[]"
}
for arrayName in self.properties.arrayNames():
array = getattr(self.properties, arrayName)
@@ -2806,15 +3213,16 @@ assert!(!prototype_proto.is_null());""" % getPrototypeProto)]
proto_properties = properties
code.append(CGGeneric("""
-rooted!(in(cx) let mut prototype = ptr::null_mut());
+rooted!(in(*cx) let mut prototype = ptr::null_mut::<JSObject>());
create_interface_prototype_object(cx,
- prototype_proto.handle(),
+ global.into(),
+ prototype_proto.handle().into(),
&PrototypeClass,
%(methods)s,
%(attrs)s,
%(consts)s,
%(unscopables)s,
- prototype.handle_mut());
+ prototype.handle_mut().into());
assert!(!prototype.is_null());
assert!((*cache)[PrototypeList::ID::%(id)s as usize].is_null());
(*cache)[PrototypeList::ID::%(id)s as usize] = prototype.get();
@@ -2830,20 +3238,19 @@ assert!((*cache)[PrototypeList::ID::%(id)s as usize].is_null());
else:
properties["length"] = 0
parentName = self.descriptor.getParentName()
+ code.append(CGGeneric("rooted!(in(*cx) let mut interface_proto = ptr::null_mut::<JSObject>());"))
if parentName:
parentName = toBindingNamespace(parentName)
code.append(CGGeneric("""
-rooted!(in(cx) let mut interface_proto = ptr::null_mut());
%s::GetConstructorObject(cx, global, interface_proto.handle_mut());""" % parentName))
else:
- code.append(CGGeneric("""
-rooted!(in(cx) let interface_proto = JS_GetFunctionPrototype(cx, global));"""))
+ code.append(CGGeneric("interface_proto.set(GetRealmFunctionPrototype(*cx));"))
code.append(CGGeneric("""\
assert!(!interface_proto.is_null());
-rooted!(in(cx) let mut interface = ptr::null_mut());
+rooted!(in(*cx) let mut interface = ptr::null_mut::<JSObject>());
create_noncallback_interface_object(cx,
- global,
+ global.into(),
interface_proto.handle(),
&INTERFACE_OBJECT_CLASS,
%(static_methods)s,
@@ -2852,9 +3259,10 @@ create_noncallback_interface_object(cx,
prototype.handle(),
%(name)s,
%(length)s,
+ %(legacyWindowAliases)s,
interface.handle_mut());
assert!(!interface.is_null());""" % properties))
- if self.descriptor.hasDescendants():
+ if self.descriptor.shouldCacheConstructor():
code.append(CGGeneric("""\
assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null());
(*cache)[PrototypeList::Constructor::%(id)s as usize] = interface.get();
@@ -2867,17 +3275,20 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null());
if aliasedMembers:
def defineAlias(alias):
if alias == "@@iterator":
- symbolJSID = "RUST_SYMBOL_TO_JSID(GetWellKnownSymbol(cx, SymbolCode::iterator))"
- getSymbolJSID = CGGeneric(fill("rooted!(in(cx) let iteratorId = ${symbolJSID});",
+ symbolJSID = "RUST_SYMBOL_TO_JSID(GetWellKnownSymbol(*cx, SymbolCode::iterator), \
+ iteratorId.handle_mut())"
+ getSymbolJSID = CGGeneric(fill("rooted!(in(*cx) let mut iteratorId: jsid);\n${symbolJSID};\n",
symbolJSID=symbolJSID))
defineFn = "JS_DefinePropertyById2"
prop = "iteratorId.handle()"
+ enumFlags = "0" # Not enumerable, per spec.
elif alias.startswith("@@"):
raise TypeError("Can't handle any well-known Symbol other than @@iterator")
else:
getSymbolJSID = None
defineFn = "JS_DefineProperty"
prop = '"%s"' % alias
+ enumFlags = "JSPROP_ENUMERATE"
return CGList([
getSymbolJSID,
# XXX If we ever create non-enumerable properties that can
@@ -2885,18 +3296,19 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null());
# match the enumerability of the property being aliased.
CGGeneric(fill(
"""
- assert!(${defineFn}(cx, prototype.handle(), ${prop}, aliasedVal.handle(),
- JSPROP_ENUMERATE, None, None));
+ assert!(${defineFn}(*cx, prototype.handle(), ${prop}, aliasedVal.handle(),
+ ${enumFlags} as u32));
""",
defineFn=defineFn,
- prop=prop))
+ prop=prop,
+ enumFlags=enumFlags))
], "\n")
def defineAliasesFor(m):
return CGList([
CGGeneric(fill(
"""
- assert!(JS_GetProperty(cx, prototype.handle(),
+ assert!(JS_GetProperty(*cx, prototype.handle(),
${prop} as *const u8 as *const _,
aliasedVal.handle_mut()));
""",
@@ -2908,7 +3320,7 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null());
// Set up aliases on the interface prototype object we just created.
""")),
- CGGeneric("rooted!(in(cx) let mut aliasedVal = UndefinedValue());\n\n")
+ CGGeneric("rooted!(in(*cx) let mut aliasedVal = UndefinedValue());\n\n")
] + [defineAliasesFor(m) for m in sorted(aliasedMembers)])
code.append(defineAliases)
@@ -2944,15 +3356,15 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null());
holderClass = "&Class.base as *const JSClass"
holderProto = "prototype.handle()"
code.append(CGGeneric("""
-rooted!(in(cx) let mut unforgeable_holder = ptr::null_mut());
+rooted!(in(*cx) let mut unforgeable_holder = ptr::null_mut::<JSObject>());
unforgeable_holder.handle_mut().set(
- JS_NewObjectWithoutMetadata(cx, %(holderClass)s, %(holderProto)s));
+ JS_NewObjectWithoutMetadata(*cx, %(holderClass)s, %(holderProto)s));
assert!(!unforgeable_holder.is_null());
""" % {'holderClass': holderClass, 'holderProto': holderProto}))
code.append(InitUnforgeablePropertiesOnHolder(self.descriptor, self.properties))
code.append(CGGeneric("""\
-JS_SetReservedSlot(prototype.get(), DOM_PROTO_UNFORGEABLE_HOLDER_SLOT,
- ObjectValue(unforgeable_holder.get()))"""))
+let val = ObjectValue(unforgeable_holder.get());
+JS_SetReservedSlot(prototype.get(), DOM_PROTO_UNFORGEABLE_HOLDER_SLOT, &val)"""))
return CGList(code, "\n")
@@ -2963,27 +3375,29 @@ class CGGetPerInterfaceObject(CGAbstractMethod):
constructor object).
"""
def __init__(self, descriptor, name, idPrefix="", pub=False):
- args = [Argument('*mut JSContext', 'cx'),
+ args = [Argument('SafeJSContext', 'cx'),
Argument('HandleObject', 'global'),
- Argument('MutableHandleObject', 'rval')]
+ Argument('MutableHandleObject', 'mut rval')]
CGAbstractMethod.__init__(self, descriptor, name,
- 'void', args, pub=pub, unsafe=True)
+ 'void', args, pub=pub)
self.id = idPrefix + "::" + MakeNativeName(self.descriptor.name)
def definition_body(self):
return CGGeneric("""
-assert!(((*get_object_class(global.get())).flags & JSCLASS_DOM_GLOBAL) != 0);
+unsafe {
+ assert!(((*get_object_class(global.get())).flags & JSCLASS_DOM_GLOBAL) != 0);
+
+ /* Check to see whether the interface objects are already installed */
+ let proto_or_iface_array = get_proto_or_iface_array(global.get());
+ rval.set((*proto_or_iface_array)[%(id)s as usize]);
+ if !rval.get().is_null() {
+ return;
+ }
-/* Check to see whether the interface objects are already installed */
-let proto_or_iface_array = get_proto_or_iface_array(global.get());
-rval.set((*proto_or_iface_array)[%(id)s as usize]);
-if !rval.get().is_null() {
- return;
+ CreateInterfaceObjects(cx, global, proto_or_iface_array);
+ rval.set((*proto_or_iface_array)[%(id)s as usize]);
+ assert!(!rval.get().is_null());
}
-
-CreateInterfaceObjects(cx, global, proto_or_iface_array);
-rval.set((*proto_or_iface_array)[%(id)s as usize]);
-assert!(!rval.get().is_null());
""" % {"id": self.id})
@@ -3072,7 +3486,6 @@ let traps = ProxyTraps {
set: None,
call: None,
construct: None,
- getPropertyDescriptor: Some(get_property_descriptor),
hasOwn: Some(hasOwn),
getOwnEnumerablePropertyKeys: Some(%(getOwnEnumerablePropertyKeys)s),
nativeCall: None,
@@ -3101,11 +3514,11 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
def __init__(self, descriptor):
assert descriptor.interface.hasInterfaceObject()
args = [
- Argument('*mut JSContext', 'cx'),
+ Argument('SafeJSContext', 'cx'),
Argument('HandleObject', 'global'),
]
CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface',
- 'void', args, pub=True, unsafe=True)
+ 'void', args, pub=True)
def define(self):
return CGAbstractMethod.define(self)
@@ -3122,15 +3535,15 @@ if !ConstructorEnabled(cx, global) {
return;
}
-rooted!(in(cx) let mut proto = ptr::null_mut());
+rooted!(in(*cx) let mut proto = ptr::null_mut::<JSObject>());
%s(cx, global, proto.handle_mut());
assert!(!proto.is_null());""" % (function,))
def needCx(returnType, arguments, considerTypes):
- return (considerTypes and
- (typeNeedsCx(returnType, True) or
- any(typeNeedsCx(a.type) for a in arguments)))
+ return (considerTypes
+ and (typeNeedsCx(returnType, True)
+ or any(typeNeedsCx(a.type) for a in arguments)))
class CGCallGenerator(CGThing):
@@ -3143,7 +3556,7 @@ class CGCallGenerator(CGThing):
"""
def __init__(self, errorResult, arguments, argsPre, returnType,
extendedAttributes, descriptor, nativeMethodName,
- static, object="this"):
+ static, object="this", hasCEReactions=False):
CGThing.__init__(self)
assert errorResult is None or isinstance(errorResult, str)
@@ -3165,6 +3578,8 @@ class CGCallGenerator(CGThing):
if "cx" not in argsPre and needsCx:
args.prepend(CGGeneric("cx"))
+ if nativeMethodName in descriptor.inRealmMethods:
+ args.append(CGGeneric("InRealm::in_realm(&AlreadyInRealm::assert_for_cx(cx))"))
# Build up our actual call
self.cgRoot = CGList([], "\n")
@@ -3176,6 +3591,9 @@ class CGCallGenerator(CGThing):
call = CGWrapper(call, pre="%s." % object)
call = CGList([call, CGWrapper(args, pre="(", post=")")])
+ if hasCEReactions:
+ self.cgRoot.append(CGGeneric("push_new_element_queue();\n"))
+
self.cgRoot.append(CGList([
CGGeneric("let result: "),
result,
@@ -3184,6 +3602,9 @@ class CGCallGenerator(CGThing):
CGGeneric(";"),
]))
+ if hasCEReactions:
+ self.cgRoot.append(CGGeneric("pop_current_element_queue();\n"))
+
if isFallible:
if static:
glob = "global.upcast::<GlobalScope>()"
@@ -3258,11 +3679,12 @@ class CGPerSignatureCall(CGThing):
idlNode.maplikeOrSetlikeOrIterable,
idlNode.identifier.name))
else:
+ hasCEReactions = idlNode.getExtendedAttribute("CEReactions")
cgThings.append(CGCallGenerator(
errorResult,
self.getArguments(), self.argsPre, returnType,
self.extendedAttributes, descriptor, nativeMethodName,
- static))
+ static, hasCEReactions=hasCEReactions))
self.cgRoot = CGList(cgThings, "\n")
@@ -3279,7 +3701,7 @@ class CGPerSignatureCall(CGThing):
return 'infallible' not in self.extendedAttributes
def wrap_return_value(self):
- return wrapForType('args.rval()')
+ return wrapForType('MutableHandleValue::from_raw(args.rval())')
def define(self):
return (self.cgRoot.define() + "\n" + self.wrap_return_value())
@@ -3354,9 +3776,6 @@ class FakeArgument():
self.variadic = False
self.defaultValue = None
self._allowTreatNonObjectAsNull = allowTreatNonObjectAsNull
- self.treatNullAs = interfaceMember.treatNullAs
- self.enforceRange = False
- self.clamp = False
def allowTreatNonCallableAsNull(self):
return self._allowTreatNonObjectAsNull
@@ -3399,9 +3818,13 @@ class CGAbstractStaticBindingMethod(CGAbstractMethod):
self.exposureSet = descriptor.interface.exposureSet
def definition_body(self):
- preamble = "let global = GlobalScope::from_object(JS_CALLEE(cx, vp).to_object());\n"
+ preamble = """\
+let args = CallArgs::from_vp(vp, argc);
+let global = GlobalScope::from_object(args.callee());
+"""
if len(self.exposureSet) == 1:
- preamble += "let global = Root::downcast::<dom::types::%s>(global).unwrap();\n" % list(self.exposureSet)[0]
+ preamble += ("let global = DomRoot::downcast::<dom::types::%s>(global).unwrap();\n" %
+ list(self.exposureSet)[0])
return CGList([CGGeneric(preamble), self.generate_code()])
def generate_code(self):
@@ -3416,8 +3839,9 @@ class CGSpecializedMethod(CGAbstractExternMethod):
def __init__(self, descriptor, method):
self.method = method
name = method.identifier.name
- args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', '_obj'),
- Argument('*const %s' % descriptor.concreteType, 'this'),
+ args = [Argument('*mut JSContext', 'cx'),
+ Argument('RawHandleObject', '_obj'),
+ Argument('*mut libc::c_void', 'this'),
Argument('*const JSJitMethodCallArgs', 'args')]
CGAbstractExternMethod.__init__(self, descriptor, name, 'bool', args)
@@ -3426,12 +3850,15 @@ class CGSpecializedMethod(CGAbstractExternMethod):
self.method)
return CGWrapper(CGMethodCall([], nativeName, self.method.isStatic(),
self.descriptor, self.method),
- pre="let this = &*this;\n"
- "let args = &*args;\n"
- "let argc = args._base.argc_;\n")
+ pre="let cx = SafeJSContext::from_ptr(cx);\n"
+ + ("let this = &*(this as *const %s);\n" % self.descriptor.concreteType)
+ + "let args = &*args;\n"
+ "let argc = args.argc_;\n")
@staticmethod
def makeNativeName(descriptor, method):
+ if method.underlyingAttr:
+ return CGSpecializedGetter.makeNativeName(descriptor, method.underlyingAttr)
name = method.identifier.name
nativeName = descriptor.binaryNameFor(name)
if nativeName == name:
@@ -3439,6 +3866,45 @@ class CGSpecializedMethod(CGAbstractExternMethod):
return MakeNativeName(nativeName)
+class CGDefaultToJSONMethod(CGSpecializedMethod):
+ def __init__(self, descriptor, method):
+ assert method.isDefaultToJSON()
+ CGSpecializedMethod.__init__(self, descriptor, method)
+
+ def definition_body(self):
+ ret = dedent("""
+ use crate::dom::bindings::inheritance::HasParent;
+ rooted!(in(cx) let result = JS_NewPlainObject(cx));
+ if result.is_null() {
+ return false;
+ }
+ """)
+
+ jsonDescriptors = [self.descriptor]
+ interface = self.descriptor.interface.parent
+ while interface:
+ descriptor = self.descriptor.getDescriptor(interface.identifier.name)
+ if descriptor.hasDefaultToJSON:
+ jsonDescriptors.append(descriptor)
+ interface = interface.parent
+
+ parents = len(jsonDescriptors) - 1
+ form = """
+ if !${parentclass}CollectJSONAttributes(cx, _obj, this, &result) {
+ return false;
+ }
+ """
+
+ # Iterate the array in reverse: oldest ancestor first
+ for descriptor in jsonDescriptors[:0:-1]:
+ ret += fill(form, parentclass=toBindingNamespace(descriptor.name) + "::")
+ parents -= 1
+ ret += fill(form, parentclass="")
+ ret += ('(*args).rval().set(ObjectValue(*result));\n'
+ 'return true;\n')
+ return CGGeneric(ret)
+
+
class CGStaticMethod(CGAbstractStaticBindingMethod):
"""
A class for generating the Rust code for an IDL static method.
@@ -3451,9 +3917,10 @@ class CGStaticMethod(CGAbstractStaticBindingMethod):
def generate_code(self):
nativeName = CGSpecializedMethod.makeNativeName(self.descriptor,
self.method)
+ safeContext = CGGeneric("let cx = SafeJSContext::from_ptr(cx);\n")
setupArgs = CGGeneric("let args = CallArgs::from_vp(vp, argc);\n")
call = CGMethodCall(["&global"], nativeName, True, self.descriptor, self.method)
- return CGList([setupArgs, call])
+ return CGList([safeContext, setupArgs, call])
class CGSpecializedGetter(CGAbstractExternMethod):
@@ -3465,8 +3932,8 @@ class CGSpecializedGetter(CGAbstractExternMethod):
self.attr = attr
name = 'get_' + descriptor.internalNameFor(attr.identifier.name)
args = [Argument('*mut JSContext', 'cx'),
- Argument('HandleObject', '_obj'),
- Argument('*const %s' % descriptor.concreteType, 'this'),
+ Argument('RawHandleObject', '_obj'),
+ Argument('*mut libc::c_void', 'this'),
Argument('JSJitGetterCallArgs', 'args')]
CGAbstractExternMethod.__init__(self, descriptor, name, "bool", args)
@@ -3476,7 +3943,8 @@ class CGSpecializedGetter(CGAbstractExternMethod):
return CGWrapper(CGGetterCall([], self.attr.type, nativeName,
self.descriptor, self.attr),
- pre="let this = &*this;\n")
+ pre="let cx = SafeJSContext::from_ptr(cx);\n"
+ + ("let this = &*(this as *const %s);\n" % self.descriptor.concreteType))
@staticmethod
def makeNativeName(descriptor, attr):
@@ -3505,10 +3973,11 @@ class CGStaticGetter(CGAbstractStaticBindingMethod):
def generate_code(self):
nativeName = CGSpecializedGetter.makeNativeName(self.descriptor,
self.attr)
+ safeContext = CGGeneric("let cx = SafeJSContext::from_ptr(cx);\n")
setupArgs = CGGeneric("let args = CallArgs::from_vp(vp, argc);\n")
call = CGGetterCall(["&global"], self.attr.type, nativeName, self.descriptor,
self.attr)
- return CGList([setupArgs, call])
+ return CGList([safeContext, setupArgs, call])
class CGSpecializedSetter(CGAbstractExternMethod):
@@ -3520,8 +3989,8 @@ class CGSpecializedSetter(CGAbstractExternMethod):
self.attr = attr
name = 'set_' + descriptor.internalNameFor(attr.identifier.name)
args = [Argument('*mut JSContext', 'cx'),
- Argument('HandleObject', 'obj'),
- Argument('*const %s' % descriptor.concreteType, 'this'),
+ Argument('RawHandleObject', 'obj'),
+ Argument('*mut libc::c_void', 'this'),
Argument('JSJitSetterCallArgs', 'args')]
CGAbstractExternMethod.__init__(self, descriptor, name, "bool", args)
@@ -3530,7 +3999,8 @@ class CGSpecializedSetter(CGAbstractExternMethod):
self.attr)
return CGWrapper(CGSetterCall([], self.attr.type, nativeName,
self.descriptor, self.attr),
- pre="let this = &*this;\n")
+ pre="let cx = SafeJSContext::from_ptr(cx);\n"
+ + ("let this = &*(this as *const %s);\n" % self.descriptor.concreteType))
@staticmethod
def makeNativeName(descriptor, attr):
@@ -3553,15 +4023,16 @@ class CGStaticSetter(CGAbstractStaticBindingMethod):
def generate_code(self):
nativeName = CGSpecializedSetter.makeNativeName(self.descriptor,
self.attr)
+ safeContext = CGGeneric("let cx = SafeJSContext::from_ptr(cx);\n")
checkForArg = CGGeneric(
"let args = CallArgs::from_vp(vp, argc);\n"
"if argc == 0 {\n"
- " throw_type_error(cx, \"Not enough arguments to %s setter.\");\n"
+ " throw_type_error(*cx, \"Not enough arguments to %s setter.\");\n"
" return false;\n"
"}" % self.attr.identifier.name)
call = CGSetterCall(["&global"], self.attr.type, nativeName, self.descriptor,
self.attr)
- return CGList([checkForArg, call])
+ return CGList([safeContext, checkForArg, call])
class CGSpecializedForwardingSetter(CGSpecializedSetter):
@@ -3578,16 +4049,17 @@ class CGSpecializedForwardingSetter(CGSpecializedSetter):
assert all(ord(c) < 128 for c in attrName)
assert all(ord(c) < 128 for c in forwardToAttrName)
return CGGeneric("""\
-rooted!(in(cx) let mut v = UndefinedValue());
-if !JS_GetProperty(cx, obj, %s as *const u8 as *const libc::c_char, v.handle_mut()) {
+let cx = SafeJSContext::from_ptr(cx);
+rooted!(in(*cx) let mut v = UndefinedValue());
+if !JS_GetProperty(*cx, HandleObject::from_raw(obj), %s as *const u8 as *const libc::c_char, v.handle_mut()) {
return false;
}
if !v.is_object() {
- throw_type_error(cx, "Value.%s is not an object.");
+ throw_type_error(*cx, "Value.%s is not an object.");
return false;
}
-rooted!(in(cx) let target_obj = v.to_object());
-JS_SetProperty(cx, target_obj.handle(), %s as *const u8 as *const libc::c_char, args.get(0))
+rooted!(in(*cx) let target_obj = v.to_object());
+JS_SetProperty(*cx, target_obj.handle(), %s as *const u8 as *const libc::c_char, HandleValue::from_raw(args.get(0)))
""" % (str_to_const_array(attrName), attrName, str_to_const_array(forwardToAttrName)))
@@ -3604,8 +4076,8 @@ class CGSpecializedReplaceableSetter(CGSpecializedSetter):
# JS_DefineProperty can only deal with ASCII.
assert all(ord(c) < 128 for c in name)
return CGGeneric("""\
-JS_DefineProperty(cx, obj, %s as *const u8 as *const libc::c_char,
- args.get(0), JSPROP_ENUMERATE, None, None)""" % name)
+JS_DefineProperty(cx, HandleObject::from_raw(obj), %s as *const u8 as *const libc::c_char,
+ HandleValue::from_raw(args.get(0)), JSPROP_ENUMERATE as u32)""" % name)
class CGMemberJITInfo(CGThing):
@@ -3634,11 +4106,16 @@ class CGMemberJITInfo(CGThing):
initializer = fill(
"""
JSJitInfo {
- call: ${opName} as *const os::raw::c_void,
- protoID: PrototypeList::ID::${name} as u16,
- depth: ${depth},
- _bitfield_1:
- JSJitInfo::new_bitfield_1(
+ __bindgen_anon_1: JSJitInfo__bindgen_ty_1 {
+ ${opKind}: Some(${opName})
+ },
+ __bindgen_anon_2: JSJitInfo__bindgen_ty_2 {
+ protoID: PrototypeList::ID::${name} as u16,
+ },
+ __bindgen_anon_3: JSJitInfo__bindgen_ty_3 { depth: ${depth} },
+ _bitfield_align_1: [],
+ _bitfield_1: __BindgenBitfieldUnit::new(
+ new_jsjitinfo_bitfield_1!(
JSJitInfo_OpType::${opType} as u8,
JSJitInfo_AliasSet::${aliasSet} as u8,
JSValueType::${returnType} as u8,
@@ -3648,17 +4125,19 @@ class CGMemberJITInfo(CGThing):
${isAlwaysInSlot},
${isLazilyCachedInSlot},
${isTypedMethod},
- ${slotIndex} as u16,
- )
+ ${slotIndex},
+ ).to_ne_bytes()
+ ),
}
""",
opName=opName,
name=self.descriptor.name,
depth=self.descriptor.interface.inheritanceDepth(),
opType=opType,
+ opKind=opType.lower(),
aliasSet=aliasSet,
- returnType=reduce(CGMemberJITInfo.getSingleReturnType, returnTypes,
- ""),
+ returnType=functools.reduce(CGMemberJITInfo.getSingleReturnType, returnTypes,
+ ""),
isInfallible=toStringBool(infallible),
isMovable=toStringBool(movable),
# FIXME(nox): https://github.com/servo/servo/issues/10991
@@ -3788,8 +4267,8 @@ class CGMemberJITInfo(CGThing):
# don't want them coalesced with each other or loop-hoisted, since
# their return value can change even if nothing is going on from our
# point of view.
- return (affects == "Nothing" and
- (dependsOn != "Everything" and dependsOn != "DeviceState"))
+ return (affects == "Nothing"
+ and (dependsOn != "Everything" and dependsOn != "DeviceState"))
def aliasSet(self):
"""Returns the alias set to store in the jitinfo. This may not be the
@@ -3821,7 +4300,9 @@ class CGMemberJITInfo(CGThing):
return "JSVAL_TYPE_UNDEFINED"
if t.isSequence():
return "JSVAL_TYPE_OBJECT"
- if t.isMozMap():
+ if t.isRecord():
+ return "JSVAL_TYPE_OBJECT"
+ if t.isPromise():
return "JSVAL_TYPE_OBJECT"
if t.isGeckoInterface():
return "JSVAL_TYPE_OBJECT"
@@ -3843,12 +4324,10 @@ class CGMemberJITInfo(CGThing):
if u.hasNullableType:
# Might be null or not
return "JSVAL_TYPE_UNKNOWN"
- return reduce(CGMemberJITInfo.getSingleReturnType,
- u.flatMemberTypes, "")
+ return functools.reduce(CGMemberJITInfo.getSingleReturnType,
+ u.flatMemberTypes, "")
if t.isDictionary():
return "JSVAL_TYPE_OBJECT"
- if t.isDate():
- return "JSVAL_TYPE_OBJECT"
if not t.isPrimitive():
raise TypeError("No idea what type " + str(t) + " is.")
tag = t.tag()
@@ -3879,10 +4358,10 @@ class CGMemberJITInfo(CGThing):
if type == existingType:
return existingType
- if ((type == "JSVAL_TYPE_DOUBLE" and
- existingType == "JSVAL_TYPE_INT32") or
- (existingType == "JSVAL_TYPE_DOUBLE" and
- type == "JSVAL_TYPE_INT32")):
+ if ((type == "JSVAL_TYPE_DOUBLE"
+ and existingType == "JSVAL_TYPE_INT32")
+ or (existingType == "JSVAL_TYPE_DOUBLE"
+ and type == "JSVAL_TYPE_INT32")):
# Promote INT32 to DOUBLE as needed
return "JSVAL_TYPE_DOUBLE"
# Different types
@@ -3913,13 +4392,11 @@ class CGMemberJITInfo(CGThing):
return "JSJitInfo_ArgType::Object as i32"
if t.isUnion():
u = t.unroll()
- type = "JSJitInfo::Null as i32" if u.hasNullableType else ""
- return reduce(CGMemberJITInfo.getSingleArgType,
- u.flatMemberTypes, type)
+ type = "JSJitInfo_ArgType::Null as i32" if u.hasNullableType else ""
+ return functools.reduce(CGMemberJITInfo.getSingleArgType,
+ u.flatMemberTypes, type)
if t.isDictionary():
return "JSJitInfo_ArgType::Object as i32"
- if t.isDate():
- return "JSJitInfo_ArgType::Object as i32"
if not t.isPrimitive():
raise TypeError("No idea what type " + str(t) + " is.")
tag = t.tag()
@@ -3963,7 +4440,7 @@ def getEnumValueName(value):
if re.match("[^\x20-\x7E]", value):
raise SyntaxError('Enum value "' + value + '" contains non-ASCII characters')
if re.match("^[0-9]", value):
- raise SyntaxError('Enum value "' + value + '" starts with a digit')
+ value = '_' + value
value = re.sub(r'[^0-9A-Za-z_]', '_', value)
if re.match("^_[A-Z]|__", value):
raise SyntaxError('Enum value "' + value + '" is reserved by the C++ spec')
@@ -3981,35 +4458,66 @@ class CGEnum(CGThing):
ident = enum.identifier.name
decl = """\
#[repr(usize)]
-#[derive(JSTraceable, PartialEq, Copy, Clone, HeapSizeOf, Debug)]
+#[derive(Copy, Clone, Debug, JSTraceable, MallocSizeOf, PartialEq)]
pub enum %s {
%s
}
-""" % (ident, ",\n ".join(map(getEnumValueName, enum.values())))
-
- pairs = ",\n ".join(['("%s", super::%s::%s)' % (val, ident, getEnumValueName(val)) for val in enum.values()])
-
- inner = """\
-use dom::bindings::conversions::ToJSValConvertible;
-use js::jsapi::{JSContext, MutableHandleValue};
+""" % (ident, ",\n ".join(map(getEnumValueName, list(enum.values()))))
+
+ pairs = ",\n ".join(['("%s", super::%s::%s)' % (val, ident, getEnumValueName(val))
+ for val in list(enum.values())])
+
+ inner = string.Template("""\
+use crate::dom::bindings::conversions::ConversionResult;
+use crate::dom::bindings::conversions::FromJSValConvertible;
+use crate::dom::bindings::conversions::ToJSValConvertible;
+use crate::dom::bindings::utils::find_enum_value;
+use js::jsapi::JSContext;
+use js::rust::HandleValue;
+use js::rust::MutableHandleValue;
use js::jsval::JSVal;
-pub const pairs: &'static [(&'static str, super::%s)] = &[
- %s,
+pub const pairs: &'static [(&'static str, super::${ident})] = &[
+ ${pairs},
];
-impl super::%s {
+impl super::${ident} {
pub fn as_str(&self) -> &'static str {
pairs[*self as usize].0
}
}
-impl ToJSValConvertible for super::%s {
+impl Default for super::${ident} {
+ fn default() -> super::${ident} {
+ pairs[0].1
+ }
+}
+
+impl ToJSValConvertible for super::${ident} {
unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
pairs[*self as usize].0.to_jsval(cx, rval);
}
}
- """ % (ident, pairs, ident, ident)
+
+impl FromJSValConvertible for super::${ident} {
+ type Config = ();
+ unsafe fn from_jsval(cx: *mut JSContext, value: HandleValue, _option: ())
+ -> Result<ConversionResult<super::${ident}>, ()> {
+ match find_enum_value(cx, value, pairs) {
+ Err(_) => Err(()),
+ Ok((None, search)) => {
+ Ok(ConversionResult::Failure(
+ format!("'{}' is not a valid enum value for enumeration '${ident}'.", search).into()
+ ))
+ }
+ Ok((Some(&value), _)) => Ok(ConversionResult::Success(value)),
+ }
+ }
+}
+ """).substitute({
+ 'ident': ident,
+ 'pairs': pairs
+ })
self.cgRoot = CGList([
CGGeneric(decl),
CGNamespace.build([ident + "Values"],
@@ -4044,7 +4552,17 @@ class CGConstant(CGThing):
def define(self):
name = self.constant.identifier.name
value = convertConstIDLValueToRust(self.constant.value)
- return "pub const %s: %s = %s;\n" % (name, builtinNames[self.constant.value.type.tag()], value)
+
+ tag = self.constant.value.type.tag()
+ const_type = builtinNames[self.constant.value.type.tag()]
+ # Finite<f32> or Finite<f64> cannot be used un a constant declaration.
+ # Remote the Finite type from restricted float and double tag declarations.
+ if tag == IDLType.Tags.float:
+ const_type = "f32"
+ elif tag == IDLType.Tags.double:
+ const_type = "f64"
+
+ return "pub const %s: %s = %s;\n" % (name, const_type, value)
def getUnionTypeTemplateVars(type, descriptorProvider):
@@ -4057,7 +4575,7 @@ def getUnionTypeTemplateVars(type, descriptorProvider):
elif type.isDictionary():
name = type.name
typeName = name
- elif type.isSequence() or type.isMozMap():
+ elif type.isSequence() or type.isRecord():
name = type.name
inner = getUnionTypeTemplateVars(innerContainerType(type), descriptorProvider)
typeName = wrapInNativeContainerType(type, CGGeneric(inner["typeName"])).define()
@@ -4076,6 +4594,15 @@ def getUnionTypeTemplateVars(type, descriptorProvider):
elif type.isObject():
name = type.name
typeName = "Heap<*mut JSObject>"
+ elif type.isReadableStream():
+ name = type.name
+ typeName = "DomRoot<ReadableStream>"
+ elif is_typed_array(type):
+ name = type.name
+ typeName = "typedarray::Heap" + name
+ elif type.isCallback():
+ name = type.name
+ typeName = name
else:
raise TypeError("Can't handle %s in unions yet" % type)
@@ -4107,15 +4634,29 @@ class CGUnionStruct(CGThing):
self.type = type
self.descriptorProvider = descriptorProvider
+ def membersNeedTracing(self):
+ for t in self.type.flatMemberTypes:
+ if type_needs_tracing(t):
+ return True
+ return False
+
def define(self):
- templateVars = map(lambda t: getUnionTypeTemplateVars(t, self.descriptorProvider),
- self.type.flatMemberTypes)
+ def getTypeWrapper(t):
+ if type_needs_tracing(t):
+ return "RootedTraceableBox"
+ if t.isCallback():
+ return "Rc"
+ return ""
+
+ templateVars = [(getUnionTypeTemplateVars(t, self.descriptorProvider),
+ getTypeWrapper(t)) for t in self.type.flatMemberTypes]
enumValues = [
- " %s(%s)," % (v["name"], v["typeName"]) for v in templateVars
+ " %s(%s)," % (v["name"], "%s<%s>" % (wrapper, v["typeName"]) if wrapper else v["typeName"])
+ for (v, wrapper) in templateVars
]
enumConversions = [
" %s::%s(ref inner) => inner.to_jsval(cx, rval),"
- % (self.type, v["name"]) for v in templateVars
+ % (self.type, v["name"]) for (v, _) in templateVars
]
return ("""\
#[derive(JSTraceable)]
@@ -4142,6 +4683,12 @@ class CGUnionConversionStruct(CGThing):
self.type = type
self.descriptorProvider = descriptorProvider
+ def membersNeedTracing(self):
+ for t in self.type.flatMemberTypes:
+ if type_needs_tracing(t):
+ return True
+ return False
+
def from_jsval(self):
memberTypes = self.type.flatMemberTypes
names = []
@@ -4155,13 +4702,13 @@ class CGUnionConversionStruct(CGThing):
def get_match(name):
return (
- "match %s::TryConvertTo%s(cx, value) {\n"
+ "match %s::TryConvertTo%s(SafeJSContext::from_ptr(cx), value) {\n"
" Err(_) => return Err(()),\n"
" Ok(Some(value)) => return Ok(ConversionResult::Success(%s::%s(value))),\n"
" Ok(None) => (),\n"
"}\n") % (self.type, name, self.type, name)
- interfaceMemberTypes = filter(lambda t: t.isNonCallbackInterface(), memberTypes)
+ interfaceMemberTypes = [t for t in memberTypes if t.isNonCallbackInterface()]
if len(interfaceMemberTypes) > 0:
typeNames = [get_name(memberType) for memberType in interfaceMemberTypes]
interfaceObject = CGList(CGGeneric(get_match(typeName)) for typeName in typeNames)
@@ -4169,7 +4716,7 @@ class CGUnionConversionStruct(CGThing):
else:
interfaceObject = None
- arrayObjectMemberTypes = filter(lambda t: t.isSequence(), memberTypes)
+ arrayObjectMemberTypes = [t for t in memberTypes if t.isSequence()]
if len(arrayObjectMemberTypes) > 0:
assert len(arrayObjectMemberTypes) == 1
typeName = arrayObjectMemberTypes[0].name
@@ -4178,21 +4725,15 @@ class CGUnionConversionStruct(CGThing):
else:
arrayObject = None
- dateObjectMemberTypes = filter(lambda t: t.isDate(), memberTypes)
- if len(dateObjectMemberTypes) > 0:
- assert len(dateObjectMemberTypes) == 1
- raise TypeError("Can't handle dates in unions.")
- else:
- dateObject = None
-
- callbackMemberTypes = filter(lambda t: t.isCallback() or t.isCallbackInterface(), memberTypes)
+ callbackMemberTypes = [t for t in memberTypes if t.isCallback() or t.isCallbackInterface()]
if len(callbackMemberTypes) > 0:
assert len(callbackMemberTypes) == 1
- raise TypeError("Can't handle callbacks in unions.")
+ typeName = callbackMemberTypes[0].name
+ callbackObject = CGGeneric(get_match(typeName))
else:
callbackObject = None
- dictionaryMemberTypes = filter(lambda t: t.isDictionary(), memberTypes)
+ dictionaryMemberTypes = [t for t in memberTypes if t.isDictionary()]
if len(dictionaryMemberTypes) > 0:
assert len(dictionaryMemberTypes) == 1
typeName = dictionaryMemberTypes[0].name
@@ -4201,7 +4742,7 @@ class CGUnionConversionStruct(CGThing):
else:
dictionaryObject = None
- objectMemberTypes = filter(lambda t: t.isObject(), memberTypes)
+ objectMemberTypes = [t for t in memberTypes if t.isObject()]
if len(objectMemberTypes) > 0:
assert len(objectMemberTypes) == 1
typeName = objectMemberTypes[0].name
@@ -4210,7 +4751,7 @@ class CGUnionConversionStruct(CGThing):
else:
object = None
- mozMapMemberTypes = filter(lambda t: t.isMozMap(), memberTypes)
+ mozMapMemberTypes = [t for t in memberTypes if t.isRecord()]
if len(mozMapMemberTypes) > 0:
assert len(mozMapMemberTypes) == 1
typeName = mozMapMemberTypes[0].name
@@ -4219,21 +4760,29 @@ class CGUnionConversionStruct(CGThing):
else:
mozMapObject = None
- hasObjectTypes = interfaceObject or arrayObject or dateObject or object or mozMapObject
+ hasObjectTypes = object or interfaceObject or arrayObject or callbackObject or mozMapObject
if hasObjectTypes:
# "object" is not distinguishable from other types
- assert not object or not (interfaceObject or arrayObject or dateObject or callbackObject or mozMapObject)
+ assert not object or not (interfaceObject or arrayObject or callbackObject or mozMapObject)
templateBody = CGList([], "\n")
+ if arrayObject 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
+ # because they are not distinguishable.
+ assert not (arrayObject and callbackObject)
+ templateBody.append(arrayObject if arrayObject else callbackObject)
if interfaceObject:
+ assert not object
templateBody.append(interfaceObject)
- if arrayObject:
- templateBody.append(arrayObject)
+ elif object:
+ templateBody.append(object)
if mozMapObject:
templateBody.append(mozMapObject)
+
conversions.append(CGIfWrapper("value.get().is_object()", templateBody))
if dictionaryObject:
- assert not hasObjectTypes
+ assert not object
conversions.append(dictionaryObject)
stringTypes = [t for t in memberTypes if t.isString() or t.isEnum()]
@@ -4248,9 +4797,9 @@ class CGUnionConversionStruct(CGThing):
typename = get_name(memberType)
return CGGeneric(get_match(typename))
other = []
- stringConversion = map(getStringOrPrimitiveConversion, stringTypes)
- numericConversion = map(getStringOrPrimitiveConversion, numericTypes)
- booleanConversion = map(getStringOrPrimitiveConversion, booleanTypes)
+ stringConversion = list(map(getStringOrPrimitiveConversion, stringTypes))
+ numericConversion = list(map(getStringOrPrimitiveConversion, numericTypes))
+ booleanConversion = list(map(getStringOrPrimitiveConversion, booleanTypes))
if stringConversion:
if booleanConversion:
other.append(CGIfWrapper("value.get().is_boolean()", booleanConversion[0]))
@@ -4266,8 +4815,8 @@ class CGUnionConversionStruct(CGThing):
other.append(booleanConversion[0])
conversions.append(CGList(other, "\n\n"))
conversions.append(CGGeneric(
- "throw_not_in_union(cx, \"%s\");\n"
- "Err(())" % ", ".join(names)))
+ "Ok(ConversionResult::Failure(\"argument could not be converted to any of: %s\".into()))" % ", ".join(names)
+ ))
method = CGWrapper(
CGIndenter(CGList(conversions, "\n\n")),
pre="unsafe fn from_jsval(cx: *mut JSContext,\n"
@@ -4285,13 +4834,17 @@ class CGUnionConversionStruct(CGThing):
def try_method(self, t):
templateVars = getUnionTypeTemplateVars(t, self.descriptorProvider)
- returnType = "Result<Option<%s>, ()>" % templateVars["typeName"]
+ actualType = templateVars["typeName"]
+ if type_needs_tracing(t):
+ actualType = "RootedTraceableBox<%s>" % actualType
+ if t.isCallback():
+ actualType = "Rc<%s>" % actualType
+ returnType = "Result<Option<%s>, ()>" % actualType
jsConversion = templateVars["jsConversion"]
return CGWrapper(
CGIndenter(jsConversion, 4),
- # TryConvertToObject is unused, but not generating it while generating others is tricky.
- pre="#[allow(dead_code)] unsafe fn TryConvertTo%s(cx: *mut JSContext, value: HandleValue) -> %s {\n"
+ pre="unsafe fn TryConvertTo%s(cx: SafeJSContext, value: HandleValue) -> %s {\n"
% (t.name, returnType),
post="\n}")
@@ -4338,7 +4891,7 @@ class ClassMethod(ClassItem):
def __init__(self, name, returnType, args, inline=False, static=False,
virtual=False, const=False, bodyInHeader=False,
templateArgs=None, visibility='public', body=None,
- breakAfterReturnDecl="\n",
+ breakAfterReturnDecl="\n", unsafe=False,
breakAfterSelf="\n", override=False):
"""
override indicates whether to flag the method as MOZ_OVERRIDE
@@ -4357,6 +4910,7 @@ class ClassMethod(ClassItem):
self.breakAfterReturnDecl = breakAfterReturnDecl
self.breakAfterSelf = breakAfterSelf
self.override = override
+ self.unsafe = unsafe
ClassItem.__init__(self, name, visibility)
def getDecorators(self, declaring):
@@ -4389,7 +4943,7 @@ class ClassMethod(ClassItem):
return string.Template(
"${decorators}%s"
- "${visibility}fn ${name}${templateClause}(${args})${returnType}${const}${override}${body}%s" %
+ "${visibility}${unsafe}fn ${name}${templateClause}(${args})${returnType}${const}${override}${body}%s" %
(self.breakAfterReturnDecl, self.breakAfterSelf)
).substitute({
'templateClause': templateClause,
@@ -4400,7 +4954,8 @@ class ClassMethod(ClassItem):
'override': ' MOZ_OVERRIDE' if self.override else '',
'args': args,
'body': body,
- 'visibility': self.visibility + ' ' if self.visibility != 'priv' else ''
+ 'visibility': self.visibility + ' ' if self.visibility != 'priv' else '',
+ 'unsafe': "unsafe " if self.unsafe else "",
})
def define(self, cgClass):
@@ -4470,7 +5025,7 @@ class ClassConstructor(ClassItem):
"});\n"
"// Note: callback cannot be moved after calling init.\n"
"match Rc::get_mut(&mut ret) {\n"
- " Some(ref mut callback) => unsafe { callback.parent.init(%s, %s) },\n"
+ " Some(ref mut callback) => callback.parent.init(%s, %s),\n"
" None => unreachable!(),\n"
"};\n"
"ret") % (cgClass.name, '\n'.join(initializers),
@@ -4485,7 +5040,7 @@ class ClassConstructor(ClassItem):
body = ' {\n' + body + '}'
return string.Template("""\
-pub fn ${decorators}new(${args}) -> Rc<${className}>${body}
+pub unsafe fn ${decorators}new(${args}) -> Rc<${className}>${body}
""").substitute({'decorators': self.getDecorators(True),
'className': cgClass.getNameString(),
'args': args,
@@ -4668,11 +5223,11 @@ class CGProxySpecialOperation(CGPerSignatureCall):
False, descriptor, operation,
len(arguments))
- if operation.isSetter() or operation.isCreator():
+ if operation.isSetter():
# arguments[0] is the index or name of the item that we're setting.
argument = arguments[1]
info = getJSToNativeConversionInfo(
- argument.type, descriptor, treatNullAs=argument.treatNullAs,
+ argument.type, descriptor,
exceptionCode="return false;")
template = info.template
declType = info.declType
@@ -4682,7 +5237,7 @@ class CGProxySpecialOperation(CGPerSignatureCall):
}
self.cgRoot.prepend(instantiateJSToNativeConversionTemplate(
template, templateValues, declType, argument.identifier.name))
- self.cgRoot.prepend(CGGeneric("rooted!(in(cx) let value = desc.value);"))
+ self.cgRoot.prepend(CGGeneric("rooted!(in(*cx) let value = desc.value);"))
def getArguments(self):
args = [(a, process_arg(a.identifier.name, a)) for a in self.arguments]
@@ -4725,10 +5280,10 @@ class CGProxyNamedOperation(CGProxySpecialOperation):
def define(self):
# Our first argument is the id we're getting.
argName = self.arguments[0].identifier.name
- return ("let %s = string_jsid_to_string(cx, id);\n"
+ return ("let %s = jsid_to_string(*cx, Handle::from_raw(id)).expect(\"Not a string-convertible JSID?\");\n"
"let this = UnwrapProxy(proxy);\n"
- "let this = &*this;\n" % argName +
- CGProxySpecialOperation.define(self))
+ "let this = &*this;\n" % argName
+ + CGProxySpecialOperation.define(self))
class CGProxyNamedGetter(CGProxyNamedOperation):
@@ -4768,56 +5323,52 @@ class CGProxyNamedDeleter(CGProxyNamedOperation):
class CGProxyUnwrap(CGAbstractMethod):
def __init__(self, descriptor):
- args = [Argument('HandleObject', 'obj')]
+ args = [Argument('RawHandleObject', 'obj')]
CGAbstractMethod.__init__(self, descriptor, "UnwrapProxy",
'*const ' + descriptor.concreteType, args,
alwaysInline=True, unsafe=True)
def definition_body(self):
return CGGeneric("""\
-/*if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
- obj = js::UnwrapObject(obj);
-}*/
-//MOZ_ASSERT(IsProxy(obj));
-let box_ = GetProxyPrivate(obj.get()).to_private() as *const %s;
+ let mut slot = UndefinedValue();
+ GetProxyReservedSlot(obj.get(), 0, &mut slot);
+ let box_ = slot.to_private() as *const %s;
return box_;""" % self.descriptor.concreteType)
class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod):
def __init__(self, descriptor):
- args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'),
- Argument('HandleId', 'id'),
- Argument('MutableHandle<PropertyDescriptor>', 'desc')]
+ args = [Argument('*mut JSContext', 'cx'), Argument('RawHandleObject', 'proxy'),
+ Argument('RawHandleId', 'id'),
+ Argument('RawMutableHandle<PropertyDescriptor>', 'mut desc')]
CGAbstractExternMethod.__init__(self, descriptor, "getOwnPropertyDescriptor",
"bool", args)
self.descriptor = descriptor
+ # https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty
def getBody(self):
indexedGetter = self.descriptor.operations['IndexedGetter']
- indexedSetter = self.descriptor.operations['IndexedSetter']
-
- get = ""
- if indexedGetter or indexedSetter:
- get = "let index = get_array_index_from_id(cx, id);\n"
+ get = "let cx = SafeJSContext::from_ptr(cx);\n"
if indexedGetter:
+ get += "let index = get_array_index_from_id(*cx, Handle::from_raw(id));\n"
+
attrs = "JSPROP_ENUMERATE"
if self.descriptor.operations['IndexedSetter'] is None:
attrs += " | JSPROP_READONLY"
- # FIXME(#11868) Should assign to desc.value, desc.get() is a copy.
- fillDescriptor = ("desc.get().value = result_root.get();\n"
- "fill_property_descriptor(desc, proxy.get(), %s);\n"
+ fillDescriptor = ("desc.value = result_root.get();\n"
+ "fill_property_descriptor(MutableHandle::from_raw(desc), proxy.get(), (%s) as u32);\n"
"return true;" % attrs)
templateValues = {
'jsvalRef': 'result_root.handle_mut()',
'successCode': fillDescriptor,
- 'pre': 'rooted!(in(cx) let mut result_root = UndefinedValue());'
+ 'pre': 'rooted!(in(*cx) let mut result_root = UndefinedValue());'
}
- get += ("if let Some(index) = index {\n" +
- " let this = UnwrapProxy(proxy);\n" +
- " let this = &*this;\n" +
- CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define() + "\n" +
- "}\n")
+ get += ("if let Some(index) = index {\n"
+ + " let this = UnwrapProxy(proxy);\n"
+ + " let this = &*this;\n"
+ + CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define() + "\n"
+ + "}\n")
namedGetter = self.descriptor.operations['NamedGetter']
if namedGetter:
@@ -4830,49 +5381,54 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod):
attrs = " | ".join(attrs)
else:
attrs = "0"
- # FIXME(#11868) Should assign to desc.value, desc.get() is a copy.
- fillDescriptor = ("desc.get().value = result_root.get();\n"
- "fill_property_descriptor(desc, proxy.get(), %s);\n"
+ fillDescriptor = ("desc.value = result_root.get();\n"
+ "fill_property_descriptor(MutableHandle::from_raw(desc), proxy.get(), (%s) as u32);\n"
"return true;" % attrs)
templateValues = {
'jsvalRef': 'result_root.handle_mut()',
'successCode': fillDescriptor,
- 'pre': 'rooted!(in(cx) let mut result_root = UndefinedValue());'
+ 'pre': 'rooted!(in(*cx) let mut result_root = UndefinedValue());'
}
+
+ # See the similar-looking in CGDOMJSProxyHandler_get for the spec quote.
+ condition = "RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id)"
+ if indexedGetter:
+ condition = "index.is_none() && (%s)" % condition
# Once we start supporting OverrideBuiltins we need to make
# ResolveOwnProperty or EnumerateOwnProperties filter out named
# properties that shadow prototype properties.
namedGet = """
-if RUST_JSID_IS_STRING(id) {
+if %s {
let mut has_on_proto = false;
- if !has_property_on_prototype(cx, proxy, id, &mut has_on_proto) {
+ if !has_property_on_prototype(*cx, proxy_lt, id_lt, &mut has_on_proto) {
return false;
}
if !has_on_proto {
%s
}
}
-""" % CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues), 8).define()
+""" % (condition, CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues), 8).define())
else:
namedGet = ""
- # FIXME(#11868) Should assign to desc.obj, desc.get() is a copy.
return get + """\
-rooted!(in(cx) let mut expando = ptr::null_mut());
+rooted!(in(*cx) let mut expando = ptr::null_mut::<JSObject>());
get_expando_object(proxy, expando.handle_mut());
//if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) {
+let proxy_lt = Handle::from_raw(proxy);
+let id_lt = Handle::from_raw(id);
if !expando.is_null() {
- if !JS_GetPropertyDescriptorById(cx, expando.handle(), id, desc) {
+ if !JS_GetPropertyDescriptorById(*cx, expando.handle().into(), id, desc) {
return false;
}
if !desc.obj.is_null() {
// Pretend the property lives on the wrapper.
- desc.get().obj = proxy.get();
+ desc.obj = proxy.get();
return true;
}
}
""" + namedGet + """\
-desc.get().obj = ptr::null_mut();
+desc.obj = ptr::null_mut();
return true;"""
def definition_body(self):
@@ -4881,28 +5437,28 @@ return true;"""
class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod):
def __init__(self, descriptor):
- args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'),
- Argument('HandleId', 'id'),
- Argument('Handle<PropertyDescriptor>', 'desc'),
+ args = [Argument('*mut JSContext', 'cx'), Argument('RawHandleObject', 'proxy'),
+ Argument('RawHandleId', 'id'),
+ Argument('RawHandle<PropertyDescriptor>', 'desc'),
Argument('*mut ObjectOpResult', 'opresult')]
CGAbstractExternMethod.__init__(self, descriptor, "defineProperty", "bool", args)
self.descriptor = descriptor
def getBody(self):
- set = ""
+ set = "let cx = SafeJSContext::from_ptr(cx);\n"
indexedSetter = self.descriptor.operations['IndexedSetter']
if indexedSetter:
- set += ("let index = get_array_index_from_id(cx, id);\n" +
- "if let Some(index) = index {\n" +
- " let this = UnwrapProxy(proxy);\n" +
- " let this = &*this;\n" +
- CGIndenter(CGProxyIndexedSetter(self.descriptor)).define() +
- " return (*opresult).succeed();\n" +
- "}\n")
+ set += ("let index = get_array_index_from_id(*cx, Handle::from_raw(id));\n"
+ + "if let Some(index) = index {\n"
+ + " let this = UnwrapProxy(proxy);\n"
+ + " let this = &*this;\n"
+ + CGIndenter(CGProxyIndexedSetter(self.descriptor)).define()
+ + " return (*opresult).succeed();\n"
+ + "}\n")
elif self.descriptor.operations['IndexedGetter']:
- set += ("if get_array_index_from_id(cx, id).is_some() {\n" +
- " return (*opresult).failNoIndexedSetter();\n" +
+ set += ("if get_array_index_from_id(*cx, Handle::from_raw(id)).is_some() {\n"
+ " return (*opresult).failNoIndexedSetter();\n"
"}\n")
namedSetter = self.descriptor.operations['NamedSetter']
@@ -4910,20 +5466,18 @@ class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod):
if self.descriptor.hasUnforgeableMembers:
raise TypeError("Can't handle a named setter on an interface that has "
"unforgeables. Figure out how that should work!")
- set += ("if RUST_JSID_IS_STRING(id) {\n" +
- CGIndenter(CGProxyNamedSetter(self.descriptor)).define() +
- " return (*opresult).succeed();\n" +
- "} else {\n" +
- " return false;\n" +
- "}\n")
- else:
- set += ("if RUST_JSID_IS_STRING(id) {\n" +
- CGIndenter(CGProxyNamedGetter(self.descriptor)).define() +
- " if result.is_some() {\n"
- " return (*opresult).failNoNamedSetter();\n"
- " }\n"
- "}\n")
- set += "return proxyhandler::define_property(%s);" % ", ".join(a.name for a in self.args)
+ set += ("if RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id) {\n"
+ + CGIndenter(CGProxyNamedSetter(self.descriptor)).define()
+ + " return (*opresult).succeed();\n"
+ + "}\n")
+ elif self.descriptor.operations['NamedGetter']:
+ set += ("if RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id) {\n"
+ + CGIndenter(CGProxyNamedGetter(self.descriptor)).define()
+ + " if result.is_some() {\n"
+ " return (*opresult).failNoNamedSetter();\n"
+ " }\n"
+ "}\n")
+ set += "return proxyhandler::define_property(*cx, %s);" % ", ".join(a.name for a in self.args[1:])
return set
def definition_body(self):
@@ -4932,20 +5486,20 @@ class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod):
class CGDOMJSProxyHandler_delete(CGAbstractExternMethod):
def __init__(self, descriptor):
- args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'),
- Argument('HandleId', 'id'),
+ args = [Argument('*mut JSContext', 'cx'), Argument('RawHandleObject', 'proxy'),
+ Argument('RawHandleId', 'id'),
Argument('*mut ObjectOpResult', 'res')]
CGAbstractExternMethod.__init__(self, descriptor, "delete", "bool", args)
self.descriptor = descriptor
def getBody(self):
- set = ""
+ set = "let cx = SafeJSContext::from_ptr(cx);\n"
if self.descriptor.operations['NamedDeleter']:
if self.descriptor.hasUnforgeableMembers:
raise TypeError("Can't handle a deleter on an interface that has "
"unforgeables. Figure out how that should work!")
set += CGProxyNamedDeleter(self.descriptor).define()
- set += "return proxyhandler::delete(%s);" % ", ".join(a.name for a in self.args)
+ set += "return proxyhandler::delete(*cx, %s);" % ", ".join(a.name for a in self.args[1:])
return set
def definition_body(self):
@@ -4955,14 +5509,15 @@ class CGDOMJSProxyHandler_delete(CGAbstractExternMethod):
class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod):
def __init__(self, descriptor):
args = [Argument('*mut JSContext', 'cx'),
- Argument('HandleObject', 'proxy'),
- Argument('*mut AutoIdVector', 'props')]
+ Argument('RawHandleObject', 'proxy'),
+ Argument('RawMutableHandleIdVector', 'props')]
CGAbstractExternMethod.__init__(self, descriptor, "own_property_keys", "bool", args)
self.descriptor = descriptor
def getBody(self):
body = dedent(
"""
+ let cx = SafeJSContext::from_ptr(cx);
let unwrapped_proxy = UnwrapProxy(proxy);
""")
@@ -4970,8 +5525,9 @@ class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod):
body += dedent(
"""
for i in 0..(*unwrapped_proxy).Length() {
- rooted!(in(cx) let rooted_jsid = int_to_jsid(i as i32));
- AppendToAutoIdVector(props, rooted_jsid.handle().get());
+ rooted!(in(*cx) let mut rooted_jsid: jsid);
+ int_to_jsid(i as i32, rooted_jsid.handle_mut());
+ AppendToIdVector(props, rooted_jsid.handle());
}
""")
@@ -4980,20 +5536,21 @@ class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod):
"""
for name in (*unwrapped_proxy).SupportedPropertyNames() {
let cstring = CString::new(name).unwrap();
- let jsstring = JS_AtomizeAndPinString(cx, cstring.as_ptr());
- rooted!(in(cx) let rooted = jsstring);
- let jsid = INTERNED_STRING_TO_JSID(cx, rooted.handle().get());
- rooted!(in(cx) let rooted_jsid = jsid);
- AppendToAutoIdVector(props, rooted_jsid.handle().get());
+ let jsstring = JS_AtomizeAndPinString(*cx, cstring.as_ptr());
+ rooted!(in(*cx) let rooted = jsstring);
+ rooted!(in(*cx) let mut rooted_jsid: jsid);
+ RUST_INTERNED_STRING_TO_JSID(*cx, rooted.handle().get(), rooted_jsid.handle_mut());
+ AppendToIdVector(props, rooted_jsid.handle());
}
""")
body += dedent(
"""
- rooted!(in(cx) let mut expando = ptr::null_mut());
+ rooted!(in(*cx) let mut expando = ptr::null_mut::<JSObject>());
get_expando_object(proxy, expando.handle_mut());
- if !expando.is_null() {
- GetPropertyKeys(cx, expando.handle(), JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
+ if !expando.is_null() &&
+ !GetPropertyKeys(*cx, expando.handle(), JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props) {
+ return false;
}
return true;
@@ -5007,11 +5564,11 @@ class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod):
class CGDOMJSProxyHandler_getOwnEnumerablePropertyKeys(CGAbstractExternMethod):
def __init__(self, descriptor):
- assert (descriptor.operations["IndexedGetter"] and
- descriptor.interface.getExtendedAttribute("LegacyUnenumerableNamedProperties"))
+ assert (descriptor.operations["IndexedGetter"]
+ and descriptor.interface.getExtendedAttribute("LegacyUnenumerableNamedProperties"))
args = [Argument('*mut JSContext', 'cx'),
- Argument('HandleObject', 'proxy'),
- Argument('*mut AutoIdVector', 'props')]
+ Argument('RawHandleObject', 'proxy'),
+ Argument('RawMutableHandleIdVector', 'props')]
CGAbstractExternMethod.__init__(self, descriptor,
"getOwnEnumerablePropertyKeys", "bool", args)
self.descriptor = descriptor
@@ -5019,6 +5576,7 @@ class CGDOMJSProxyHandler_getOwnEnumerablePropertyKeys(CGAbstractExternMethod):
def getBody(self):
body = dedent(
"""
+ let cx = SafeJSContext::from_ptr(cx);
let unwrapped_proxy = UnwrapProxy(proxy);
""")
@@ -5026,17 +5584,19 @@ class CGDOMJSProxyHandler_getOwnEnumerablePropertyKeys(CGAbstractExternMethod):
body += dedent(
"""
for i in 0..(*unwrapped_proxy).Length() {
- rooted!(in(cx) let rooted_jsid = int_to_jsid(i as i32));
- AppendToAutoIdVector(props, rooted_jsid.handle().get());
+ rooted!(in(*cx) let mut rooted_jsid: jsid);
+ int_to_jsid(i as i32, rooted_jsid.handle_mut());
+ AppendToIdVector(props, rooted_jsid.handle());
}
""")
body += dedent(
"""
- rooted!(in(cx) let mut expando = ptr::null_mut());
+ rooted!(in(*cx) let mut expando = ptr::null_mut::<JSObject>());
get_expando_object(proxy, expando.handle_mut());
- if !expando.is_null() {
- GetPropertyKeys(cx, expando.handle(), JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
+ if !expando.is_null() &&
+ !GetPropertyKeys(*cx, expando.handle(), JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props) {
+ return false;
}
return true;
@@ -5050,31 +5610,33 @@ class CGDOMJSProxyHandler_getOwnEnumerablePropertyKeys(CGAbstractExternMethod):
class CGDOMJSProxyHandler_hasOwn(CGAbstractExternMethod):
def __init__(self, descriptor):
- args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'),
- Argument('HandleId', 'id'), Argument('*mut bool', 'bp')]
+ args = [Argument('*mut JSContext', 'cx'), Argument('RawHandleObject', 'proxy'),
+ Argument('RawHandleId', 'id'), Argument('*mut bool', 'bp')]
CGAbstractExternMethod.__init__(self, descriptor, "hasOwn", "bool", args)
self.descriptor = descriptor
def getBody(self):
indexedGetter = self.descriptor.operations['IndexedGetter']
+ indexed = "let cx = SafeJSContext::from_ptr(cx);\n"
if indexedGetter:
- indexed = ("let index = get_array_index_from_id(cx, id);\n" +
- "if let Some(index) = index {\n" +
- " let this = UnwrapProxy(proxy);\n" +
- " let this = &*this;\n" +
- CGIndenter(CGProxyIndexedGetter(self.descriptor)).define() + "\n" +
- " *bp = result.is_some();\n" +
- " return true;\n" +
- "}\n\n")
- else:
- indexed = ""
+ indexed += ("let index = get_array_index_from_id(*cx, Handle::from_raw(id));\n"
+ + "if let Some(index) = index {\n"
+ + " let this = UnwrapProxy(proxy);\n"
+ + " let this = &*this;\n"
+ + CGIndenter(CGProxyIndexedGetter(self.descriptor)).define() + "\n"
+ + " *bp = result.is_some();\n"
+ + " return true;\n"
+ + "}\n\n")
namedGetter = self.descriptor.operations['NamedGetter']
+ condition = "RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id)"
+ if indexedGetter:
+ condition = "index.is_none() && (%s)" % condition
if namedGetter:
named = """\
-if RUST_JSID_IS_STRING(id) {
+if %s {
let mut has_on_proto = false;
- if !has_property_on_prototype(cx, proxy, id, &mut has_on_proto) {
+ if !has_property_on_prototype(*cx, proxy_lt, id_lt, &mut has_on_proto) {
return false;
}
if !has_on_proto {
@@ -5084,15 +5646,17 @@ if RUST_JSID_IS_STRING(id) {
}
}
-""" % CGIndenter(CGProxyNamedGetter(self.descriptor), 8).define()
+""" % (condition, CGIndenter(CGProxyNamedGetter(self.descriptor), 8).define())
else:
named = ""
return indexed + """\
-rooted!(in(cx) let mut expando = ptr::null_mut());
+rooted!(in(*cx) let mut expando = ptr::null_mut::<JSObject>());
+let proxy_lt = Handle::from_raw(proxy);
+let id_lt = Handle::from_raw(id);
get_expando_object(proxy, expando.handle_mut());
if !expando.is_null() {
- let ok = JS_HasPropertyById(cx, expando.handle(), id, bp);
+ let ok = JS_HasPropertyById(*cx, expando.handle().into(), id, bp);
if !ok || *bp {
return ok;
}
@@ -5107,39 +5671,40 @@ return true;"""
class CGDOMJSProxyHandler_get(CGAbstractExternMethod):
def __init__(self, descriptor):
- args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'),
- Argument('HandleValue', 'receiver'), Argument('HandleId', 'id'),
- Argument('MutableHandleValue', 'vp')]
+ args = [Argument('*mut JSContext', 'cx'), Argument('RawHandleObject', 'proxy'),
+ Argument('RawHandleValue', 'receiver'), Argument('RawHandleId', 'id'),
+ Argument('RawMutableHandleValue', 'vp')]
CGAbstractExternMethod.__init__(self, descriptor, "get", "bool", args)
self.descriptor = descriptor
+ # https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty
def getBody(self):
getFromExpando = """\
-rooted!(in(cx) let mut expando = ptr::null_mut());
+rooted!(in(*cx) let mut expando = ptr::null_mut::<JSObject>());
get_expando_object(proxy, expando.handle_mut());
if !expando.is_null() {
let mut hasProp = false;
- if !JS_HasPropertyById(cx, expando.handle(), id, &mut hasProp) {
+ if !JS_HasPropertyById(*cx, expando.handle().into(), id, &mut hasProp) {
return false;
}
if hasProp {
- return JS_ForwardGetPropertyTo(cx, expando.handle(), id, receiver, vp);
+ return JS_ForwardGetPropertyTo(*cx, expando.handle().into(), id, receiver, vp);
}
}"""
templateValues = {
- 'jsvalRef': 'vp',
+ 'jsvalRef': 'vp_lt',
'successCode': 'return true;',
}
indexedGetter = self.descriptor.operations['IndexedGetter']
if indexedGetter:
- getIndexedOrExpando = ("let index = get_array_index_from_id(cx, id);\n" +
- "if let Some(index) = index {\n" +
- " let this = UnwrapProxy(proxy);\n" +
- " let this = &*this;\n" +
- CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define())
+ getIndexedOrExpando = ("let index = get_array_index_from_id(*cx, id_lt);\n"
+ + "if let Some(index) = index {\n"
+ + " let this = UnwrapProxy(proxy);\n"
+ + " let this = &*this;\n"
+ + CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define())
getIndexedOrExpando += """\
// Even if we don't have this index, we don't forward the
// get on to our expando object.
@@ -5152,19 +5717,31 @@ if !expando.is_null() {
namedGetter = self.descriptor.operations['NamedGetter']
if namedGetter:
- getNamed = ("if RUST_JSID_IS_STRING(id) {\n" +
- CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() +
- "}\n")
+ condition = "RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id)"
+ # From step 1:
+ # If O supports indexed properties and P is an array index, then:
+ #
+ # 3. Set ignoreNamedProps to true.
+ if indexedGetter:
+ condition = "index.is_none() && (%s)" % condition
+ getNamed = ("if %s {\n"
+ + CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define()
+ + "}\n") % condition
else:
getNamed = ""
return """\
//MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
//"Should not have a XrayWrapper here");
+let cx = SafeJSContext::from_ptr(cx);
+let proxy_lt = Handle::from_raw(proxy);
+let vp_lt = MutableHandle::from_raw(vp);
+let id_lt = Handle::from_raw(id);
+let receiver_lt = Handle::from_raw(receiver);
%s
let mut found = false;
-if !get_property_on_prototype(cx, proxy, receiver, id, &mut found, vp) {
+if !get_property_on_prototype(*cx, proxy_lt, receiver_lt, id_lt, &mut found, vp_lt) {
return false;
}
@@ -5181,7 +5758,7 @@ return true;""" % (getIndexedOrExpando, getNamed)
class CGDOMJSProxyHandler_className(CGAbstractExternMethod):
def __init__(self, descriptor):
- args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', '_proxy')]
+ args = [Argument('*mut JSContext', 'cx'), Argument('RawHandleObject', '_proxy')]
CGAbstractExternMethod.__init__(self, descriptor, "className", "*const i8", args, doesNotPanic=True)
self.descriptor = descriptor
@@ -5203,7 +5780,7 @@ class CGAbstractClassHook(CGAbstractExternMethod):
def definition_body_prologue(self):
return CGGeneric("""
-let this = native_from_object::<%s>(obj).unwrap();
+let this = native_from_object_static::<%s>(obj).unwrap();
""" % self.descriptor.concreteType)
def definition_body(self):
@@ -5224,7 +5801,9 @@ finalize_global(obj);
"""
elif descriptor.weakReferenceable:
release += """\
-let weak_box_ptr = JS_GetReservedSlot(obj, DOM_WEAK_SLOT).to_private() as *mut WeakBox<%s>;
+let mut slot = UndefinedValue();
+JS_GetReservedSlot(obj, DOM_WEAK_SLOT, &mut slot);
+let weak_box_ptr = slot.to_private() as *mut WeakBox<%s>;
if !weak_box_ptr.is_null() {
let count = {
let weak_box = &*weak_box_ptr;
@@ -5285,16 +5864,30 @@ class CGClassConstructHook(CGAbstractExternMethod):
self.exposureSet = descriptor.interface.exposureSet
def definition_body(self):
- preamble = """let global = GlobalScope::from_object(JS_CALLEE(cx, vp).to_object());\n"""
+ preamble = """let cx = SafeJSContext::from_ptr(cx);
+let global = GlobalScope::from_object(JS_CALLEE(*cx, vp).to_object());
+"""
if len(self.exposureSet) == 1:
- preamble += "let global = Root::downcast::<dom::types::%s>(global).unwrap();\n" % list(self.exposureSet)[0]
+ preamble += """\
+let global = DomRoot::downcast::<dom::types::%s>(global).unwrap();
+""" % list(self.exposureSet)[0]
preamble += """let args = CallArgs::from_vp(vp, argc);\n"""
preamble = CGGeneric(preamble)
- name = self.constructor.identifier.name
- nativeName = MakeNativeName(self.descriptor.binaryNameFor(name))
- callGenerator = CGMethodCall(["&global"], nativeName, True,
- self.descriptor, self.constructor)
- return CGList([preamble, callGenerator])
+ if self.constructor.isHTMLConstructor():
+ signatures = self.constructor.signatures()
+ assert len(signatures) == 1
+ constructorCall = CGGeneric("""dom::bindings::htmlconstructor::call_html_constructor::<dom::types::%s>(
+ cx,
+ &args,
+ &*global,
+ GetProtoObject,
+ )""" % self.descriptor.name)
+ else:
+ name = self.constructor.identifier.name
+ nativeName = MakeNativeName(self.descriptor.binaryNameFor(name))
+ constructorCall = CGMethodCall(["&global"], nativeName, True,
+ self.descriptor, self.constructor)
+ return CGList([preamble, constructorCall])
class CGClassFinalizeHook(CGAbstractClassHook):
@@ -5323,29 +5916,37 @@ class CGInterfaceTrait(CGThing):
def __init__(self, descriptor):
CGThing.__init__(self)
- def attribute_arguments(needCx, argument=None):
+ def attribute_arguments(needCx, argument=None, inRealm=False):
if needCx:
- yield "cx", "*mut JSContext"
+ yield "cx", "SafeJSContext"
if argument:
yield "value", argument_type(descriptor, argument)
+ if inRealm:
+ yield "_comp", "InRealm"
+
def members():
for m in descriptor.interface.members:
- if (m.isMethod() and not m.isStatic() and
- not m.isMaplikeOrSetlikeOrIterableMethod() and
- (not m.isIdentifierLess() or m.isStringifier())):
+ if (m.isMethod() and not m.isStatic()
+ and not m.isMaplikeOrSetlikeOrIterableMethod()
+ and (not m.isIdentifierLess() or (m.isStringifier() and not m.underlyingAttr))
+ and not m.isDefaultToJSON()):
name = CGSpecializedMethod.makeNativeName(descriptor, m)
infallible = 'infallible' in descriptor.getExtendedAttributes(m)
for idx, (rettype, arguments) in enumerate(m.signatures()):
- arguments = method_arguments(descriptor, rettype, arguments)
+ arguments = method_arguments(descriptor, rettype, arguments,
+ inRealm=name in descriptor.inRealmMethods)
rettype = return_type(descriptor, rettype, infallible)
yield name + ('_' * idx), arguments, rettype
elif m.isAttr() and not m.isStatic():
name = CGSpecializedGetter.makeNativeName(descriptor, m)
infallible = 'infallible' in descriptor.getExtendedAttributes(m, getter=True)
yield (name,
- attribute_arguments(typeNeedsCx(m.type, True)),
+ attribute_arguments(
+ typeNeedsCx(m.type, True),
+ inRealm=name in descriptor.inRealmMethods
+ ),
return_type(descriptor, m.type, infallible))
if not m.readonly:
@@ -5355,10 +5956,16 @@ class CGInterfaceTrait(CGThing):
rettype = "()"
else:
rettype = "ErrorResult"
- yield name, attribute_arguments(typeNeedsCx(m.type, False), m.type), rettype
+ yield (name,
+ attribute_arguments(
+ typeNeedsCx(m.type, False),
+ m.type,
+ inRealm=name in descriptor.inRealmMethods
+ ),
+ rettype)
if descriptor.proxy:
- for name, operation in descriptor.operations.iteritems():
+ for name, operation in descriptor.operations.items():
if not operation or operation.isStringifier():
continue
@@ -5369,7 +5976,8 @@ class CGInterfaceTrait(CGThing):
if operation.isGetter():
if not rettype.nullable():
rettype = IDLNullableType(rettype.location, rettype)
- arguments = method_arguments(descriptor, rettype, arguments)
+ arguments = method_arguments(descriptor, rettype, arguments,
+ inRealm=name in descriptor.inRealmMethods)
# If this interface 'supports named properties', then we
# should be able to access 'supported property names'
@@ -5379,17 +5987,22 @@ class CGInterfaceTrait(CGThing):
if operation.isNamed():
yield "SupportedPropertyNames", [], "Vec<DOMString>"
else:
- arguments = method_arguments(descriptor, rettype, arguments)
+ arguments = method_arguments(descriptor, rettype, arguments,
+ inRealm=name in descriptor.inRealmMethods)
rettype = return_type(descriptor, rettype, infallible)
yield name, arguments, rettype
def fmt(arguments):
- return "".join(", %s: %s" % argument for argument in arguments)
+ keywords = {"async"}
+ return "".join(
+ ", %s: %s" % (name if name not in keywords else "r#" + name, type_)
+ for name, type_ in arguments
+ )
def contains_unsafe_arg(arguments):
if not arguments or len(arguments) == 0:
return False
- return reduce((lambda x, y: x or y[1] == '*mut JSContext'), arguments, False)
+ return functools.reduce((lambda x, y: x or y[1] == '*mut JSContext'), arguments, False)
methods = []
for name, arguments, rettype in members():
@@ -5421,16 +6034,17 @@ class CGWeakReferenceableTrait(CGThing):
return self.code
-def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries=None, enums=None):
+def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries=None, enums=None, typedefs=None):
if not callbacks:
callbacks = []
if not dictionaries:
dictionaries = []
if not enums:
enums = []
+ if not typedefs:
+ typedefs = []
- return CGImports(cgthings, descriptors, callbacks, dictionaries, enums, [
- 'core::nonzero::NonZero',
+ return CGImports(cgthings, descriptors, callbacks, dictionaries, enums, typedefs, [
'js',
'js::JSCLASS_GLOBAL_SLOT_COUNT',
'js::JSCLASS_IS_DOMJSCLASS',
@@ -5438,22 +6052,27 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
'js::JSCLASS_RESERVED_SLOTS_MASK',
'js::JS_CALLEE',
'js::error::throw_type_error',
- 'js::jsapi::AutoIdVector',
- 'js::jsapi::Call',
+ 'js::error::throw_internal_error',
+ 'js::rust::wrappers::Call',
+ 'js::jsapi::__BindgenBitfieldUnit',
'js::jsapi::CallArgs',
'js::jsapi::CurrentGlobalOrNull',
- 'js::jsapi::FreeOp',
- 'js::jsapi::GetPropertyKeys',
+ 'js::rust::wrappers::GetPropertyKeys',
'js::jsapi::GetWellKnownSymbol',
- 'js::jsapi::Handle',
- 'js::jsapi::HandleId',
- 'js::jsapi::HandleObject',
- 'js::jsapi::HandleValue',
+ 'js::rust::Handle',
+ 'js::jsapi::Handle as RawHandle',
+ 'js::rust::HandleId',
+ 'js::jsapi::HandleId as RawHandleId',
+ 'js::rust::HandleObject',
+ 'js::jsapi::HandleObject as RawHandleObject',
+ 'js::rust::HandleValue',
+ 'js::jsapi::HandleValue as RawHandleValue',
'js::jsapi::HandleValueArray',
'js::jsapi::Heap',
- 'js::jsapi::INTERNED_STRING_TO_JSID',
+ 'js::rust::wrappers::RUST_INTERNED_STRING_TO_JSID',
'js::jsapi::IsCallable',
- 'js::jsapi::JSAutoCompartment',
+ 'js::jsapi::JSAutoRealm',
+ 'js::jsapi::JSCLASS_FOREGROUND_FINALIZE',
'js::jsapi::JSCLASS_RESERVED_SLOTS_SHIFT',
'js::jsapi::JSClass',
'js::jsapi::JSContext',
@@ -5464,6 +6083,9 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
'js::jsapi::JSITER_SYMBOLS',
'js::jsapi::JSJitGetterCallArgs',
'js::jsapi::JSJitInfo',
+ 'js::jsapi::JSJitInfo__bindgen_ty_1',
+ 'js::jsapi::JSJitInfo__bindgen_ty_2',
+ 'js::jsapi::JSJitInfo__bindgen_ty_3',
'js::jsapi::JSJitInfo_AliasSet',
'js::jsapi::JSJitInfo_ArgType',
'js::jsapi::JSJitInfo_OpType',
@@ -5475,45 +6097,58 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
'js::jsapi::JSPROP_ENUMERATE',
'js::jsapi::JSPROP_PERMANENT',
'js::jsapi::JSPROP_READONLY',
- 'js::jsapi::JSPROP_SHARED',
'js::jsapi::JSPropertySpec',
+ 'js::jsapi::JSPropertySpec_Accessor',
+ 'js::jsapi::JSPropertySpec_AccessorsOrValue',
+ 'js::jsapi::JSPropertySpec_AccessorsOrValue_Accessors',
+ 'js::jsapi::JSPropertySpec_Name',
+ 'js::jsapi::JSPropertySpec_ValueWrapper',
+ 'js::jsapi::JSPropertySpec_ValueWrapper_Type',
+ 'js::jsapi::JSPropertySpec_ValueWrapper__bindgen_ty_1',
'js::jsapi::JSString',
'js::jsapi::JSTracer',
'js::jsapi::JSType',
'js::jsapi::JSTypedMethodJitInfo',
'js::jsapi::JSValueType',
'js::jsapi::JS_AtomizeAndPinString',
- 'js::jsapi::JS_CallFunctionValue',
- 'js::jsapi::JS_CopyPropertiesFrom',
- 'js::jsapi::JS_DefineProperty',
- 'js::jsapi::JS_DefinePropertyById2',
+ 'js::rust::wrappers::JS_CallFunctionValue',
+ 'js::rust::wrappers::JS_CopyOwnPropertiesAndPrivateFields',
+ 'js::rust::wrappers::JS_DefineProperty',
+ 'js::rust::wrappers::JS_DefinePropertyById2',
'js::jsapi::JS_ForwardGetPropertyTo',
- 'js::jsapi::JS_GetErrorPrototype',
- 'js::jsapi::JS_GetFunctionPrototype',
- 'js::jsapi::JS_GetGlobalForObject',
- 'js::jsapi::JS_GetIteratorPrototype',
- 'js::jsapi::JS_GetObjectPrototype',
- 'js::jsapi::JS_GetProperty',
+ 'js::jsapi::GetRealmErrorPrototype',
+ 'js::jsapi::GetRealmFunctionPrototype',
+ 'js::jsapi::GetRealmIteratorPrototype',
+ 'js::jsapi::GetRealmObjectPrototype',
+ 'js::rust::wrappers::JS_GetProperty',
'js::jsapi::JS_GetPropertyById',
'js::jsapi::JS_GetPropertyDescriptorById',
- 'js::jsapi::JS_GetReservedSlot',
+ 'js::glue::JS_GetReservedSlot',
'js::jsapi::JS_HasProperty',
'js::jsapi::JS_HasPropertyById',
- 'js::jsapi::JS_InitializePropertiesFromCompatibleNativeObject',
+ 'js::rust::wrappers::JS_InitializePropertiesFromCompatibleNativeObject',
+ 'js::jsapi::JS_NewPlainObject',
'js::jsapi::JS_NewObject',
- 'js::jsapi::JS_NewObjectWithGivenProto',
- 'js::jsapi::JS_NewObjectWithoutMetadata',
- 'js::jsapi::JS_ObjectIsDate',
- 'js::jsapi::JS_SetImmutablePrototype',
- 'js::jsapi::JS_SetProperty',
+ 'js::rust::RootedGuard',
+ 'js::rust::wrappers::JS_NewObjectWithGivenProto',
+ 'js::rust::wrappers::JS_NewObjectWithoutMetadata',
+ 'js::rust::wrappers::ObjectIsDate',
+ 'js::rust::wrappers::JS_SetImmutablePrototype',
+ 'js::rust::wrappers::JS_SetProperty',
+ 'js::rust::wrappers::JS_SetPrototype',
'js::jsapi::JS_SetReservedSlot',
- 'js::jsapi::JS_SplicePrototype',
- 'js::jsapi::JS_WrapValue',
- 'js::jsapi::MutableHandle',
- 'js::jsapi::MutableHandleObject',
- 'js::jsapi::MutableHandleValue',
+ 'js::rust::wrappers::JS_WrapValue',
+ 'js::rust::wrappers::JS_WrapObject',
+ 'js::rust::MutableHandle',
+ 'js::jsapi::MutableHandle as RawMutableHandle',
+ 'js::rust::MutableHandleObject',
+ 'js::jsapi::MutableHandleObject as RawMutableHandleObject',
+ 'js::rust::MutableHandleValue',
+ 'js::jsapi::MutableHandleValue as RawMutableHandleValue',
+ 'js::jsapi::MutableHandleIdVector as RawMutableHandleIdVector',
'js::jsapi::ObjectOpResult',
'js::jsapi::PropertyDescriptor',
+ 'js::jsapi::Rooted',
'js::jsapi::RootedId',
'js::jsapi::RootedObject',
'js::jsapi::RootedString',
@@ -5525,126 +6160,143 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
'js::jsval::ObjectOrNullValue',
'js::jsval::PrivateValue',
'js::jsval::UndefinedValue',
- 'js::glue::AppendToAutoIdVector',
+ 'js::jsapi::UndefinedHandleValue',
+ 'js::rust::wrappers::AppendToIdVector',
'js::glue::CallJitGetterOp',
'js::glue::CallJitMethodOp',
'js::glue::CallJitSetterOp',
'js::glue::CreateProxyHandler',
- 'js::glue::GetProxyPrivate',
- 'js::glue::NewProxyObject',
+ 'js::glue::GetProxyReservedSlot',
+ 'js::glue::SetProxyReservedSlot',
+ 'js::rust::wrappers::NewProxyObject',
'js::glue::ProxyTraps',
+ 'js::glue::RUST_JSID_IS_INT',
'js::glue::RUST_JSID_IS_STRING',
- 'js::glue::RUST_SYMBOL_TO_JSID',
- 'js::glue::int_to_jsid',
+ 'js::rust::wrappers::RUST_SYMBOL_TO_JSID',
+ 'js::rust::wrappers::int_to_jsid',
+ 'js::glue::UnwrapObjectDynamic',
'js::panic::maybe_resume_unwind',
'js::panic::wrap_panic',
'js::rust::GCMethods',
+ 'js::rust::CustomAutoRooterGuard',
'js::rust::define_methods',
'js::rust::define_properties',
'js::rust::get_object_class',
- 'dom',
- 'dom::bindings',
- 'dom::bindings::codegen::InterfaceObjectMap',
- 'dom::bindings::constant::ConstantSpec',
- 'dom::bindings::constant::ConstantVal',
- 'dom::bindings::interface::ConstructorClassHook',
- 'dom::bindings::interface::InterfaceConstructorBehavior',
- 'dom::bindings::interface::NonCallbackInterfaceObjectClass',
- 'dom::bindings::interface::create_callback_interface_object',
- 'dom::bindings::interface::create_global_object',
- 'dom::bindings::interface::create_interface_prototype_object',
- 'dom::bindings::interface::create_named_constructors',
- 'dom::bindings::interface::create_noncallback_interface_object',
- 'dom::bindings::interface::define_guarded_constants',
- 'dom::bindings::interface::define_guarded_methods',
- 'dom::bindings::interface::define_guarded_properties',
- 'dom::bindings::interface::is_exposed_in',
- 'dom::bindings::iterable::Iterable',
- 'dom::bindings::iterable::IteratorType',
- 'dom::bindings::js::JS',
- 'dom::bindings::js::Root',
- 'dom::bindings::js::RootedReference',
- 'dom::bindings::namespace::NamespaceObjectClass',
- 'dom::bindings::namespace::create_namespace_object',
- 'dom::bindings::reflector::MutDomObject',
- 'dom::bindings::reflector::DomObject',
- 'dom::bindings::utils::AsVoidPtr',
- 'dom::bindings::utils::DOMClass',
- 'dom::bindings::utils::DOMJSClass',
- 'dom::bindings::utils::DOM_PROTO_UNFORGEABLE_HOLDER_SLOT',
- 'dom::bindings::utils::JSCLASS_DOM_GLOBAL',
- 'dom::bindings::utils::ProtoOrIfaceArray',
- 'dom::bindings::utils::enumerate_global',
- 'dom::bindings::utils::finalize_global',
- 'dom::bindings::utils::find_enum_value',
- 'dom::bindings::utils::generic_getter',
- 'dom::bindings::utils::generic_lenient_getter',
- 'dom::bindings::utils::generic_lenient_setter',
- 'dom::bindings::utils::generic_method',
- 'dom::bindings::utils::generic_setter',
- 'dom::bindings::utils::get_array_index_from_id',
- 'dom::bindings::utils::get_dictionary_property',
- 'dom::bindings::utils::get_property_on_prototype',
- 'dom::bindings::utils::get_proto_or_iface_array',
- 'dom::bindings::utils::has_property_on_prototype',
- 'dom::bindings::utils::is_platform_object',
- 'dom::bindings::utils::resolve_global',
- 'dom::bindings::utils::set_dictionary_property',
- 'dom::bindings::utils::trace_global',
- 'dom::bindings::trace::JSTraceable',
- 'dom::bindings::trace::RootedTraceable',
- 'dom::bindings::trace::RootedTraceableBox',
- 'dom::bindings::callback::CallSetup',
- 'dom::bindings::callback::CallbackContainer',
- 'dom::bindings::callback::CallbackInterface',
- 'dom::bindings::callback::CallbackFunction',
- 'dom::bindings::callback::CallbackObject',
- 'dom::bindings::callback::ExceptionHandling',
- 'dom::bindings::callback::wrap_call_this_object',
- 'dom::bindings::conversions::ConversionBehavior',
- 'dom::bindings::conversions::ConversionResult',
- 'dom::bindings::conversions::DOM_OBJECT_SLOT',
- 'dom::bindings::conversions::FromJSValConvertible',
- 'dom::bindings::conversions::IDLInterface',
- 'dom::bindings::conversions::StringificationBehavior',
- 'dom::bindings::conversions::ToJSValConvertible',
- 'dom::bindings::conversions::is_array_like',
- 'dom::bindings::conversions::native_from_handlevalue',
- 'dom::bindings::conversions::native_from_object',
- 'dom::bindings::conversions::private_from_object',
- 'dom::bindings::conversions::root_from_handleobject',
- 'dom::bindings::conversions::root_from_handlevalue',
- 'dom::bindings::conversions::root_from_object',
- 'dom::bindings::conversions::string_jsid_to_string',
- 'dom::bindings::codegen::PrototypeList',
- 'dom::bindings::codegen::RegisterBindings',
- 'dom::bindings::codegen::UnionTypes',
- 'dom::bindings::error::Error',
- 'dom::bindings::error::ErrorResult',
- 'dom::bindings::error::Fallible',
- 'dom::bindings::error::Error::JSFailed',
- 'dom::bindings::error::throw_dom_exception',
- 'dom::bindings::guard::Condition',
- 'dom::bindings::guard::Guard',
- 'dom::bindings::inheritance::Castable',
- 'dom::bindings::proxyhandler',
- 'dom::bindings::proxyhandler::ensure_expando_object',
- 'dom::bindings::proxyhandler::fill_property_descriptor',
- 'dom::bindings::proxyhandler::get_expando_object',
- 'dom::bindings::proxyhandler::get_property_descriptor',
- 'dom::bindings::mozmap::MozMap',
- 'dom::bindings::num::Finite',
- 'dom::bindings::str::ByteString',
- 'dom::bindings::str::DOMString',
- 'dom::bindings::str::USVString',
- 'dom::bindings::weakref::DOM_WEAK_SLOT',
- 'dom::bindings::weakref::WeakBox',
- 'dom::bindings::weakref::WeakReferenceable',
- 'dom::browsingcontext::BrowsingContext',
- 'dom::globalscope::GlobalScope',
- 'mem::heap_size_of_raw_self_and_children',
+ 'js::typedarray',
+ 'crate::dom',
+ 'crate::dom::bindings',
+ 'crate::dom::bindings::codegen::InterfaceObjectMap',
+ 'crate::dom::bindings::constant::ConstantSpec',
+ 'crate::dom::bindings::constant::ConstantVal',
+ 'crate::dom::bindings::interface::ConstructorClassHook',
+ 'crate::dom::bindings::interface::InterfaceConstructorBehavior',
+ 'crate::dom::bindings::interface::NonCallbackInterfaceObjectClass',
+ 'crate::dom::bindings::interface::create_global_object',
+ 'crate::dom::bindings::interface::create_callback_interface_object',
+ 'crate::dom::bindings::interface::create_interface_prototype_object',
+ 'crate::dom::bindings::interface::create_named_constructors',
+ 'crate::dom::bindings::interface::create_noncallback_interface_object',
+ 'crate::dom::bindings::interface::define_guarded_constants',
+ 'crate::dom::bindings::interface::define_guarded_methods',
+ 'crate::dom::bindings::interface::define_guarded_properties',
+ 'crate::dom::bindings::interface::is_exposed_in',
+ 'crate::dom::bindings::htmlconstructor::pop_current_element_queue',
+ 'crate::dom::bindings::htmlconstructor::push_new_element_queue',
+ 'crate::dom::bindings::iterable::Iterable',
+ 'crate::dom::bindings::iterable::IteratorType',
+ 'crate::dom::bindings::namespace::NamespaceObjectClass',
+ 'crate::dom::bindings::namespace::create_namespace_object',
+ 'crate::dom::bindings::reflector::MutDomObject',
+ 'crate::dom::bindings::reflector::DomObject',
+ 'crate::dom::bindings::reflector::DomObjectWrap',
+ 'crate::dom::bindings::reflector::DomObjectIteratorWrap',
+ 'crate::dom::bindings::root::Dom',
+ 'crate::dom::bindings::root::DomRoot',
+ 'crate::dom::bindings::root::DomSlice',
+ 'crate::dom::bindings::root::MaybeUnreflectedDom',
+ 'crate::dom::bindings::root::OptionalHeapSetter',
+ 'crate::dom::bindings::root::Root',
+ 'crate::dom::bindings::utils::AsVoidPtr',
+ 'crate::dom::bindings::utils::DOMClass',
+ 'crate::dom::bindings::utils::DOMJSClass',
+ 'crate::dom::bindings::utils::DOM_PROTO_UNFORGEABLE_HOLDER_SLOT',
+ 'crate::dom::bindings::utils::JSCLASS_DOM_GLOBAL',
+ 'crate::dom::bindings::utils::ProtoOrIfaceArray',
+ 'crate::dom::bindings::utils::enumerate_global',
+ 'crate::dom::bindings::utils::finalize_global',
+ 'crate::dom::bindings::utils::generic_getter',
+ 'crate::dom::bindings::utils::generic_lenient_getter',
+ 'crate::dom::bindings::utils::generic_lenient_setter',
+ 'crate::dom::bindings::utils::generic_method',
+ 'crate::dom::bindings::utils::generic_setter',
+ 'crate::dom::bindings::utils::get_array_index_from_id',
+ 'crate::dom::bindings::utils::get_dictionary_property',
+ 'crate::dom::bindings::utils::get_property_on_prototype',
+ 'crate::dom::bindings::utils::get_proto_or_iface_array',
+ 'crate::dom::bindings::utils::has_property_on_prototype',
+ 'crate::dom::bindings::utils::is_platform_object_dynamic',
+ 'crate::dom::bindings::utils::is_platform_object_static',
+ 'crate::dom::bindings::utils::resolve_global',
+ 'crate::dom::bindings::utils::set_dictionary_property',
+ 'crate::dom::bindings::utils::trace_global',
+ 'crate::dom::bindings::trace::JSTraceable',
+ 'crate::dom::bindings::trace::RootedTraceableBox',
+ 'crate::dom::bindings::callback::CallSetup',
+ 'crate::dom::bindings::callback::CallbackContainer',
+ 'crate::dom::bindings::callback::CallbackInterface',
+ 'crate::dom::bindings::callback::CallbackFunction',
+ 'crate::dom::bindings::callback::CallbackObject',
+ 'crate::dom::bindings::callback::ExceptionHandling',
+ 'crate::dom::bindings::callback::wrap_call_this_object',
+ 'crate::dom::bindings::conversions::ConversionBehavior',
+ 'crate::dom::bindings::conversions::ConversionResult',
+ 'crate::dom::bindings::conversions::DOM_OBJECT_SLOT',
+ 'crate::dom::bindings::conversions::FromJSValConvertible',
+ 'crate::dom::bindings::conversions::IDLInterface',
+ 'crate::dom::bindings::conversions::StringificationBehavior',
+ 'crate::dom::bindings::conversions::ToJSValConvertible',
+ 'crate::dom::bindings::conversions::is_array_like',
+ 'crate::dom::bindings::conversions::native_from_handlevalue',
+ 'crate::dom::bindings::conversions::native_from_object',
+ 'crate::dom::bindings::conversions::native_from_object_static',
+ 'crate::dom::bindings::conversions::private_from_object',
+ 'crate::dom::bindings::conversions::root_from_handleobject',
+ 'crate::dom::bindings::conversions::root_from_handlevalue',
+ 'crate::dom::bindings::conversions::root_from_object',
+ 'crate::dom::bindings::conversions::jsid_to_string',
+ 'crate::dom::bindings::codegen::PrototypeList',
+ 'crate::dom::bindings::codegen::RegisterBindings',
+ 'crate::dom::bindings::codegen::UnionTypes',
+ 'crate::dom::bindings::error::Error',
+ 'crate::dom::bindings::error::ErrorResult',
+ 'crate::dom::bindings::error::Fallible',
+ 'crate::dom::bindings::error::Error::JSFailed',
+ 'crate::dom::bindings::error::throw_dom_exception',
+ 'crate::dom::bindings::guard::Condition',
+ 'crate::dom::bindings::guard::Guard',
+ 'crate::dom::bindings::inheritance::Castable',
+ 'crate::dom::bindings::proxyhandler',
+ 'crate::dom::bindings::proxyhandler::ensure_expando_object',
+ 'crate::dom::bindings::proxyhandler::fill_property_descriptor',
+ 'crate::dom::bindings::proxyhandler::get_expando_object',
+ 'crate::dom::bindings::record::Record',
+ 'std::ptr::NonNull',
+ 'crate::dom::bindings::num::Finite',
+ 'crate::dom::bindings::str::ByteString',
+ 'crate::dom::bindings::str::DOMString',
+ 'crate::dom::bindings::str::USVString',
+ 'crate::dom::bindings::weakref::DOM_WEAK_SLOT',
+ 'crate::dom::bindings::weakref::WeakBox',
+ 'crate::dom::bindings::weakref::WeakReferenceable',
+ 'crate::dom::windowproxy::WindowProxy',
+ 'crate::dom::globalscope::GlobalScope',
+ 'crate::mem::malloc_size_of_including_raw_self',
+ 'crate::realms::InRealm',
+ 'crate::realms::AlreadyInRealm',
+ 'crate::script_runtime::JSContext as SafeJSContext',
'libc',
- 'servo_config::prefs::PREFS',
+ 'servo_config::pref',
+ 'servo_config::prefs',
'std::borrow::ToOwned',
'std::cmp',
'std::mem',
@@ -5657,6 +6309,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
'std::rc::Rc',
'std::default::Default',
'std::ffi::CString',
+ 'std::ops::Deref',
], config)
@@ -5677,24 +6330,23 @@ class CGDescriptor(CGThing):
cgThings = []
+ defaultToJSONMethod = None
unscopableNames = []
for m in descriptor.interface.members:
- if (m.isMethod() and
- (not m.isIdentifierLess() or m == descriptor.operations["Stringifier"])):
+ if (m.isMethod()
+ and (not m.isIdentifierLess() or m == descriptor.operations["Stringifier"])):
if m.getExtendedAttribute("Unscopable"):
assert not m.isStatic()
unscopableNames.append(m.identifier.name)
- if m.isStatic():
+ if m.isDefaultToJSON():
+ defaultToJSONMethod = m
+ elif m.isStatic():
assert descriptor.interface.hasInterfaceObject()
cgThings.append(CGStaticMethod(descriptor, m))
elif not descriptor.interface.isCallback():
cgThings.append(CGSpecializedMethod(descriptor, m))
cgThings.append(CGMemberJITInfo(descriptor, m))
elif m.isAttr():
- if m.stringifier:
- raise TypeError("Stringifier attributes not supported yet. "
- "See https://github.com/servo/servo/issues/7590\n"
- "%s" % m.location)
if m.getExtendedAttribute("Unscopable"):
assert not m.isStatic()
unscopableNames.append(m.identifier.name)
@@ -5718,6 +6370,10 @@ class CGDescriptor(CGThing):
if (not m.isStatic() and not descriptor.interface.isCallback()):
cgThings.append(CGMemberJITInfo(descriptor, m))
+ if defaultToJSONMethod:
+ cgThings.append(CGDefaultToJSONMethod(descriptor, defaultToJSONMethod))
+ cgThings.append(CGMemberJITInfo(descriptor, defaultToJSONMethod))
+
if descriptor.concrete:
cgThings.append(CGClassFinalizeHook(descriptor))
cgThings.append(CGClassTraceHook(descriptor))
@@ -5735,6 +6391,9 @@ class CGDescriptor(CGThing):
properties = PropertyArrays(descriptor)
+ if defaultToJSONMethod:
+ cgThings.append(CGCollectJSONAttributesMethod(descriptor, defaultToJSONMethod))
+
if descriptor.concrete:
if descriptor.proxy:
# cgThings.append(CGProxyIsProxy(descriptor))
@@ -5762,12 +6421,18 @@ class CGDescriptor(CGThing):
pass
else:
cgThings.append(CGDOMJSClass(descriptor))
+ if not descriptor.interface.isIteratorInterface():
+ cgThings.append(CGAssertInheritance(descriptor))
pass
if descriptor.isGlobal():
cgThings.append(CGWrapGlobalMethod(descriptor, properties))
else:
cgThings.append(CGWrapMethod(descriptor))
+ if descriptor.interface.isIteratorInterface():
+ cgThings.append(CGDomObjectIteratorWrap(descriptor))
+ else:
+ cgThings.append(CGDomObjectWrap(descriptor))
reexports.append('Wrap')
haveUnscopables = False
@@ -5790,6 +6455,15 @@ class CGDescriptor(CGThing):
if descriptor.weakReferenceable:
cgThings.append(CGWeakReferenceableTrait(descriptor))
+ legacyWindowAliases = descriptor.interface.legacyWindowAliases
+ haveLegacyWindowAliases = len(legacyWindowAliases) != 0
+ if haveLegacyWindowAliases:
+ cgThings.append(
+ CGList([CGGeneric("const legacy_window_aliases: &'static [&'static [u8]] = &["),
+ CGIndenter(CGList([CGGeneric(str_to_const_array(name)) for
+ name in legacyWindowAliases], ",\n")),
+ CGGeneric("];\n")], "\n"))
+
cgThings.append(CGGeneric(str(properties)))
if not descriptor.interface.getExtendedAttribute("Inline"):
@@ -5811,7 +6485,8 @@ class CGDescriptor(CGThing):
cgThings.append(CGDefineDOMInterfaceMethod(descriptor))
reexports.append('DefineDOMInterface')
cgThings.append(CGConstructorEnabled(descriptor))
- cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties, haveUnscopables))
+ cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties, haveUnscopables,
+ haveLegacyWindowAliases))
cgThings = generate_imports(config, CGList(cgThings, '\n'), [descriptor])
cgThings = CGWrapper(CGNamespace(toBindingNamespace(descriptor.name),
@@ -5819,7 +6494,7 @@ class CGDescriptor(CGThing):
post='\n')
if reexports:
- reexports = ', '.join(map(lambda name: reexportedName(name), reexports))
+ reexports = ', '.join([reexportedName(name) for name in reexports])
cgThings = CGList([CGGeneric('pub use self::%s::{%s};' % (toBindingNamespace(descriptor.name), reexports)),
cgThings], '\n')
@@ -5879,7 +6554,7 @@ class CGDictionary(CGThing):
descriptorProvider,
isMember="Dictionary",
defaultValue=member.defaultValue,
- exceptionCode="return Err(());"))
+ exceptionCode="return Err(());\n"))
for member in dictionary.members]
def define(self):
@@ -5890,43 +6565,58 @@ class CGDictionary(CGThing):
def struct(self):
d = self.dictionary
if d.parent:
- inheritance = " pub parent: %s::%s,\n" % (self.makeModuleName(d.parent),
- self.makeClassName(d.parent))
+ typeName = "%s::%s" % (self.makeModuleName(d.parent),
+ self.makeClassName(d.parent))
+ if type_needs_tracing(d.parent):
+ typeName = "RootedTraceableBox<%s>" % typeName
+ inheritance = " pub parent: %s,\n" % typeName
else:
inheritance = ""
memberDecls = [" pub %s: %s," %
(self.makeMemberName(m[0].identifier.name), self.getMemberType(m))
for m in self.memberInfo]
+ derive = ["JSTraceable"]
+ mustRoot = ""
+ if self.membersNeedTracing():
+ mustRoot = "#[unrooted_must_root_lint::must_root]\n"
+ if not self.hasRequiredFields(self.dictionary):
+ derive += ["Default"]
+
return (string.Template(
- "#[derive(JSTraceable)]\n"
- "pub struct ${selfName} {\n" +
- "${inheritance}" +
- "\n".join(memberDecls) + "\n" +
- "}").substitute({"selfName": self.makeClassName(d),
- "inheritance": inheritance}))
+ "#[derive(${derive})]\n"
+ + "${mustRoot}"
+ + "pub struct ${selfName} {\n"
+ + "${inheritance}"
+ + "\n".join(memberDecls) + "\n"
+ + "}").substitute({"selfName": self.makeClassName(d),
+ "inheritance": inheritance,
+ "mustRoot": mustRoot,
+ "derive": ', '.join(derive)}))
def impl(self):
d = self.dictionary
if d.parent:
- initParent = ("parent: {\n"
- " match try!(%s::%s::new(cx, val)) {\n"
+ initParent = ("{\n"
+ " match %s::%s::new(cx, val)? {\n"
" ConversionResult::Success(v) => v,\n"
" ConversionResult::Failure(error) => {\n"
- " throw_type_error(cx, &error);\n"
+ " throw_type_error(*cx, &error);\n"
" return Err(());\n"
" }\n"
" }\n"
- "},\n" % (self.makeModuleName(d.parent),
- self.makeClassName(d.parent)))
+ "}" % (self.makeModuleName(d.parent),
+ self.makeClassName(d.parent)))
else:
initParent = ""
- def memberInit(memberInfo):
+ def memberInit(memberInfo, isInitial):
member, _ = memberInfo
name = self.makeMemberName(member.identifier.name)
conversion = self.getMemberConversion(memberInfo, member.type)
- return CGGeneric("%s: %s,\n" % (name, conversion.define()))
+ if isInitial:
+ return CGGeneric("%s: %s,\n" % (name, conversion.define()))
+ return CGGeneric("dictionary.%s = %s;\n" % (name, conversion.define()))
def varInsert(varName, dictionaryName):
insertion = ("rooted!(in(cx) let mut %s_js = UndefinedValue());\n"
@@ -5946,59 +6636,86 @@ class CGDictionary(CGThing):
(name, name, varInsert(name, member.identifier.name).define()))
return CGGeneric("%s\n" % insertion.define())
- memberInits = CGList([memberInit(m) for m in self.memberInfo])
- memberInserts = CGList([memberInsert(m) for m in self.memberInfo])
+ memberInserts = [memberInsert(m) for m in self.memberInfo]
+
+ if d.parent:
+ memberInserts = [CGGeneric("self.parent.to_jsobject(cx, obj);\n")] + memberInserts
+
+ selfName = self.makeClassName(d)
+ if self.membersNeedTracing():
+ actualType = "RootedTraceableBox<%s>" % selfName
+ preInitial = "let dictionary = RootedTraceableBox::new(%s {\n" % selfName
+ postInitial = "});\n"
+ else:
+ actualType = selfName
+ preInitial = "let dictionary = %s {\n" % selfName
+ postInitial = "};\n"
+ initParent = ("parent: %s,\n" % initParent) if initParent else ""
+ memberInits = CGList([memberInit(m, True) for m in self.memberInfo])
return string.Template(
"impl ${selfName} {\n"
- " pub unsafe fn empty(cx: *mut JSContext) -> ${selfName} {\n"
- " match ${selfName}::new(cx, HandleValue::null()) {\n"
- " Ok(ConversionResult::Success(v)) => v,\n"
- " _ => unreachable!(),\n"
- " }\n"
- " }\n"
- " pub unsafe fn new(cx: *mut JSContext, val: HandleValue) \n"
- " -> Result<ConversionResult<${selfName}>, ()> {\n"
- " let object = if val.get().is_null_or_undefined() {\n"
- " ptr::null_mut()\n"
- " } else if val.get().is_object() {\n"
- " val.get().to_object()\n"
- " } else {\n"
- " throw_type_error(cx, \"Value not an object.\");\n"
- " return Err(());\n"
- " };\n"
- " rooted!(in(cx) let object = object);\n"
- " Ok(ConversionResult::Success(${selfName} {\n"
+ "${empty}\n"
+ " pub fn new(cx: SafeJSContext, val: HandleValue) \n"
+ " -> Result<ConversionResult<${actualType}>, ()> {\n"
+ " unsafe {\n"
+ " let object = if val.get().is_null_or_undefined() {\n"
+ " ptr::null_mut()\n"
+ " } else if val.get().is_object() {\n"
+ " val.get().to_object()\n"
+ " } else {\n"
+ " return Ok(ConversionResult::Failure(\"Value is not an object.\".into()));\n"
+ " };\n"
+ " rooted!(in(*cx) let object = object);\n"
+ "${preInitial}"
"${initParent}"
"${initMembers}"
- " }))\n"
+ "${postInitial}"
+ " Ok(ConversionResult::Success(dictionary))\n"
+ " }\n"
" }\n"
"}\n"
"\n"
- "impl FromJSValConvertible for ${selfName} {\n"
+ "impl FromJSValConvertible for ${actualType} {\n"
" type Config = ();\n"
" unsafe fn from_jsval(cx: *mut JSContext, value: HandleValue, _option: ())\n"
- " -> Result<ConversionResult<${selfName}>, ()> {\n"
- " ${selfName}::new(cx, value)\n"
+ " -> Result<ConversionResult<${actualType}>, ()> {\n"
+ " ${selfName}::new(SafeJSContext::from_ptr(cx), value)\n"
" }\n"
"}\n"
"\n"
- "impl ToJSValConvertible for ${selfName} {\n"
- " unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {\n"
- " rooted!(in(cx) let obj = JS_NewObject(cx, ptr::null()));\n"
+ "impl ${selfName} {\n"
+ " pub(crate) unsafe fn to_jsobject(&self, cx: *mut JSContext, mut obj: MutableHandleObject) {\n"
"${insertMembers}"
+ " }\n"
+ "}\n"
+ "\n"
+ "impl ToJSValConvertible for ${selfName} {\n"
+ " unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {\n"
+ " rooted!(in(cx) let mut obj = JS_NewObject(cx, ptr::null()));\n"
+ " self.to_jsobject(cx, obj.handle_mut());\n"
" rval.set(ObjectOrNullValue(obj.get()))\n"
" }\n"
"}\n").substitute({
- "selfName": self.makeClassName(d),
- "initParent": CGIndenter(CGGeneric(initParent), indentLevel=12).define(),
- "initMembers": CGIndenter(memberInits, indentLevel=12).define(),
- "insertMembers": CGIndenter(memberInserts, indentLevel=8).define(),
+ "selfName": selfName,
+ "actualType": actualType,
+ "empty": CGIndenter(CGGeneric(self.makeEmpty()), indentLevel=4).define(),
+ "initParent": CGIndenter(CGGeneric(initParent), indentLevel=16).define(),
+ "initMembers": CGIndenter(memberInits, indentLevel=16).define(),
+ "insertMembers": CGIndenter(CGList(memberInserts), indentLevel=8).define(),
+ "preInitial": CGIndenter(CGGeneric(preInitial), indentLevel=8).define(),
+ "postInitial": CGIndenter(CGGeneric(postInitial), indentLevel=8).define(),
})
+ def membersNeedTracing(self):
+ return type_needs_tracing(self.dictionary)
+
@staticmethod
def makeDictionaryName(dictionary):
- return dictionary.identifier.name
+ if isinstance(dictionary, IDLWrapperType):
+ return CGDictionary.makeDictionaryName(dictionary.inner)
+ else:
+ return dictionary.identifier.name
def makeClassName(self, dictionary):
return self.makeDictionaryName(dictionary)
@@ -6027,7 +6744,7 @@ class CGDictionary(CGThing):
assert (member.defaultValue is None) == (default is None)
if not member.optional:
assert default is None
- default = ("throw_type_error(cx, \"Missing required member \\\"%s\\\".\");\n"
+ default = ("throw_type_error(*cx, \"Missing required member \\\"%s\\\".\");\n"
"return Err(());") % member.identifier.name
elif not default:
default = "None"
@@ -6035,19 +6752,61 @@ class CGDictionary(CGThing):
conversion = (
"{\n"
- " rooted!(in(cx) let mut rval = UndefinedValue());\n"
- " match try!(get_dictionary_property(cx, object.handle(), \"%s\", rval.handle_mut())) {\n"
- " true => {\n"
+ " rooted!(in(*cx) let mut rval = UndefinedValue());\n"
+ " if get_dictionary_property(*cx, object.handle(), \"%s\", rval.handle_mut())?"
+ " && !rval.is_undefined() {\n"
"%s\n"
- " },\n"
- " false => {\n"
+ " } else {\n"
"%s\n"
- " },\n"
" }\n"
"}") % (member.identifier.name, indent(conversion), indent(default))
return CGGeneric(conversion)
+ def makeEmpty(self):
+ if self.hasRequiredFields(self.dictionary):
+ return ""
+ parentTemplate = "parent: %s::%s::empty(),\n"
+ fieldTemplate = "%s: %s,\n"
+ functionTemplate = (
+ "pub fn empty() -> Self {\n"
+ " Self {\n"
+ "%s"
+ " }\n"
+ "}"
+ )
+ if self.membersNeedTracing():
+ parentTemplate = "dictionary.parent = %s::%s::empty();\n"
+ fieldTemplate = "dictionary.%s = %s;\n"
+ functionTemplate = (
+ "pub fn empty() -> RootedTraceableBox<Self> {\n"
+ " let mut dictionary = RootedTraceableBox::new(Self::default());\n"
+ "%s"
+ " dictionary\n"
+ "}"
+ )
+ s = ""
+ if self.dictionary.parent:
+ s += parentTemplate % (self.makeModuleName(self.dictionary.parent),
+ self.makeClassName(self.dictionary.parent))
+ for member, info in self.memberInfo:
+ if not member.optional:
+ return ""
+ default = info.default
+ if not default:
+ default = "None"
+ s += fieldTemplate % (self.makeMemberName(member.identifier.name), default)
+ return functionTemplate % CGIndenter(CGGeneric(s), 12).define()
+
+ def hasRequiredFields(self, dictionary):
+ if dictionary.parent:
+ if self.hasRequiredFields(dictionary.parent):
+ return True
+ for member in dictionary.members:
+ if not member.optional:
+ return True
+ return False
+
@staticmethod
def makeMemberName(name):
# Can't use Rust keywords as member names.
@@ -6075,7 +6834,10 @@ class CGRegisterProxyHandlersMethod(CGAbstractMethod):
def definition_body(self):
return CGList([
- CGGeneric("PROXY_HANDLERS[Proxies::%s as usize] = Bindings::%s::DefineProxyHandler();"
+ CGGeneric("proxy_handlers::%s.store(\n"
+ " Bindings::%s::DefineProxyHandler() as *mut _,\n"
+ " std::sync::atomic::Ordering::Release,\n"
+ ");"
% (desc.name, '::'.join([desc.name + 'Binding'] * 2)))
for desc in self.descriptors
], "\n")
@@ -6084,10 +6846,18 @@ class CGRegisterProxyHandlersMethod(CGAbstractMethod):
class CGRegisterProxyHandlers(CGThing):
def __init__(self, config):
descriptors = config.getDescriptors(proxy=True)
- length = len(descriptors)
self.root = CGList([
- CGGeneric("pub static mut PROXY_HANDLERS: [*const libc::c_void; %d] = [0 as *const libc::c_void; %d];"
- % (length, length)),
+ CGGeneric(
+ "#[allow(non_upper_case_globals)]\n"
+ + "pub mod proxy_handlers {\n"
+ + "".join(
+ " pub static %s: std::sync::atomic::AtomicPtr<libc::c_void> =\n"
+ " std::sync::atomic::AtomicPtr::new(std::ptr::null_mut());\n"
+ % desc.name
+ for desc in descriptors
+ )
+ + "}\n"
+ ),
CGRegisterProxyHandlersMethod(descriptors),
], "\n")
@@ -6097,7 +6867,7 @@ class CGRegisterProxyHandlers(CGThing):
class CGBindingRoot(CGThing):
"""
- Root codegen class for binding generation. Instantiate the class, and call
+ DomRoot codegen class for binding generation. Instantiate the class, and call
declare or define to generate header or cpp code (respectively).
"""
def __init__(self, config, prefix, webIDLFile):
@@ -6128,7 +6898,7 @@ class CGBindingRoot(CGThing):
# Do codegen for all the enums.
cgthings = [CGEnum(e) for e in enums]
- # Do codegen for all the typdefs
+ # Do codegen for all the typedefs
for t in typedefs:
typeName = getRetvalDeclarationForType(t.innerType, config.getDescriptorProvider())
substs = {
@@ -6166,7 +6936,7 @@ class CGBindingRoot(CGThing):
# Add imports
curr = generate_imports(config, curr, callbackDescriptors, mainCallbacks,
- dictionaries, enums)
+ dictionaries, enums, typedefs)
# Add the auto-generated comment.
curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
@@ -6202,6 +6972,9 @@ def type_needs_tracing(t):
if t.isUnion():
return any(type_needs_tracing(member) for member in t.flatMemberTypes)
+ if is_typed_array(t):
+ return True
+
return False
if t.isDictionary():
@@ -6222,9 +6995,33 @@ def type_needs_tracing(t):
assert False, (t, type(t))
+def is_typed_array(t):
+ assert isinstance(t, IDLObject), (t, type(t))
+
+ return t.isTypedArray() or t.isArrayBuffer() or t.isArrayBufferView()
+
+
+def type_needs_auto_root(t):
+ """
+ Certain IDL types, such as `sequence<any>` or `sequence<object>` need to be
+ traced and wrapped via (Custom)AutoRooter
+ """
+ assert isinstance(t, IDLObject), (t, type(t))
+
+ if t.isType():
+ if t.isSequence() and (t.inner.isAny() or t.inner.isObject()):
+ return True
+ # SpiderMonkey interfaces, we currently don't support any other except typed arrays
+ if is_typed_array(t):
+ return True
+
+ return False
+
+
def argument_type(descriptorProvider, ty, optional=False, defaultValue=None, variadic=False):
info = getJSToNativeConversionInfo(
- ty, descriptorProvider, isArgument=True)
+ ty, descriptorProvider, isArgument=True,
+ isAutoRooted=type_needs_auto_root(ty))
declType = info.declType
if variadic:
@@ -6238,12 +7035,15 @@ def argument_type(descriptorProvider, ty, optional=False, defaultValue=None, var
if ty.isDictionary() and not type_needs_tracing(ty):
declType = CGWrapper(declType, pre="&")
+ if type_needs_auto_root(ty):
+ declType = CGTemplatedType("CustomAutoRooterGuard", declType)
+
return declType.define()
-def method_arguments(descriptorProvider, returnType, arguments, passJSBits=True, trailing=None):
+def method_arguments(descriptorProvider, returnType, arguments, passJSBits=True, trailing=None, inRealm=False):
if needCx(returnType, arguments, passJSBits):
- yield "cx", "*mut JSContext"
+ yield "cx", "SafeJSContext"
for argument in arguments:
ty = argument_type(descriptorProvider, argument.type, argument.optional,
@@ -6253,6 +7053,9 @@ def method_arguments(descriptorProvider, returnType, arguments, passJSBits=True,
if trailing:
yield trailing
+ if inRealm:
+ yield "_comp", "InRealm"
+
def return_type(descriptorProvider, rettype, infallible):
result = getRetvalDeclarationForType(rettype, descriptorProvider)
@@ -6263,7 +7066,8 @@ def return_type(descriptorProvider, rettype, infallible):
class CGNativeMember(ClassMethod):
def __init__(self, descriptorProvider, member, name, signature, extendedAttrs,
- breakAfter=True, passJSBitsAsNeeded=True, visibility="public"):
+ breakAfter=True, passJSBitsAsNeeded=True, visibility="public",
+ unsafe=False):
"""
If passJSBitsAsNeeded is false, we don't automatically pass in a
JSContext* or a JSObject* based on the return and argument types.
@@ -6279,9 +7083,10 @@ class CGNativeMember(ClassMethod):
static=member.isStatic(),
# Mark our getters, which are attrs that
# have a non-void return type, as const.
- const=(not member.isStatic() and member.isAttr() and
- not signature[0].isVoid()),
+ const=(not member.isStatic() and member.isAttr()
+ and not signature[0].isVoid()),
breakAfterSelf=breakAfterSelf,
+ unsafe=unsafe,
visibility=visibility)
def getReturnType(self, type):
@@ -6297,8 +7102,7 @@ class CGNativeMember(ClassMethod):
class CGCallback(CGClass):
- def __init__(self, idlObject, descriptorProvider, baseName, methods,
- getters=[], setters=[]):
+ def __init__(self, idlObject, descriptorProvider, baseName, methods):
self.baseName = baseName
self._deps = idlObject.getDeps()
name = idlObject.identifier.name
@@ -6317,12 +7121,13 @@ class CGCallback(CGClass):
CGClass.__init__(self, name,
bases=[ClassBase(baseName)],
constructors=self.getConstructors(),
- methods=realMethods + getters + setters,
- decorators="#[derive(JSTraceable, PartialEq)]\n#[allow_unrooted_interior]")
+ methods=realMethods,
+ decorators="#[derive(JSTraceable, PartialEq)]\n"
+ "#[unrooted_must_root_lint::allow_unrooted_interior]")
def getConstructors(self):
return [ClassConstructor(
- [Argument("*mut JSContext", "aCx"), Argument("*mut JSObject", "aCallback")],
+ [Argument("SafeJSContext", "aCx"), Argument("*mut JSObject", "aCallback")],
bodyInHeader=True,
visibility="pub",
explicit=False,
@@ -6335,7 +7140,7 @@ class CGCallback(CGClass):
args = list(method.args)
# Strip out the JSContext*/JSObject* args
# that got added.
- assert args[0].name == "cx" and args[0].argType == "*mut JSContext"
+ assert args[0].name == "cx" and args[0].argType == "SafeJSContext"
assert args[1].name == "aThisObj" and args[1].argType == "HandleObject"
args = args[2:]
# Record the names of all the arguments, so we can use them when we call
@@ -6361,23 +7166,23 @@ class CGCallback(CGClass):
setupCall = "let s = CallSetup::new(self, aExceptionHandling);\n"
bodyWithThis = string.Template(
- setupCall +
- "rooted!(in(s.get_context()) let mut thisObjJS = ptr::null_mut());\n"
- "wrap_call_this_object(s.get_context(), thisObj, thisObjJS.handle_mut());\n"
- "if thisObjJS.is_null() {\n"
- " return Err(JSFailed);\n"
- "}\n"
- "return ${methodName}(${callArgs});").substitute({
- "callArgs": ", ".join(argnamesWithThis),
- "methodName": 'self.' + method.name,
- })
+ setupCall
+ + "rooted!(in(*s.get_context()) let mut thisObjJS = ptr::null_mut::<JSObject>());\n"
+ "wrap_call_this_object(s.get_context(), thisObj, thisObjJS.handle_mut());\n"
+ "if thisObjJS.is_null() {\n"
+ " return Err(JSFailed);\n"
+ "}\n"
+ "unsafe { ${methodName}(${callArgs}) }").substitute({
+ "callArgs": ", ".join(argnamesWithThis),
+ "methodName": 'self.' + method.name,
+ })
bodyWithoutThis = string.Template(
- setupCall +
- "rooted!(in(s.get_context()) let thisObjJS = ptr::null_mut());\n"
- "return ${methodName}(${callArgs});").substitute({
- "callArgs": ", ".join(argnamesWithoutThis),
- "methodName": 'self.' + method.name,
- })
+ setupCall
+ + "rooted!(in(*s.get_context()) let thisObjJS = ptr::null_mut::<JSObject>());\n"
+ "unsafe { ${methodName}(${callArgs}) }").substitute({
+ "callArgs": ", ".join(argnamesWithoutThis),
+ "methodName": 'self.' + method.name,
+ })
return [ClassMethod(method.name + '_', method.returnType, args,
bodyInHeader=True,
templateArgs=["T: DomObject"],
@@ -6418,7 +7223,7 @@ class CGCallbackFunctionImpl(CGGeneric):
def __init__(self, callback):
impl = string.Template("""\
impl CallbackContainer for ${type} {
- unsafe fn new(cx: *mut JSContext, callback: *mut JSObject) -> Rc<${type}> {
+ unsafe fn new(cx: SafeJSContext, callback: *mut JSObject) -> Rc<${type}> {
${type}::new(cx, callback)
}
@@ -6440,21 +7245,18 @@ class CGCallbackInterface(CGCallback):
def __init__(self, descriptor):
iface = descriptor.interface
attrs = [m for m in iface.members if m.isAttr() and not m.isStatic()]
- getters = [CallbackGetter(a, descriptor) for a in attrs]
- setters = [CallbackSetter(a, descriptor) for a in attrs
- if not a.readonly]
+ assert not attrs
methods = [m for m in iface.members
if m.isMethod() and not m.isStatic() and not m.isIdentifierLess()]
methods = [CallbackOperation(m, sig, descriptor) for m in methods
for sig in m.signatures()]
assert not iface.isJSImplemented() or not iface.ctor()
- CGCallback.__init__(self, iface, descriptor, "CallbackInterface",
- methods, getters=getters, setters=setters)
+ CGCallback.__init__(self, iface, descriptor, "CallbackInterface", methods)
class FakeMember():
def __init__(self):
- self.treatNullAs = "Default"
+ pass
def isStatic(self):
return False
@@ -6500,6 +7302,7 @@ class CallbackMember(CGNativeMember):
name, (self.retvalType, args),
extendedAttrs={},
passJSBitsAsNeeded=False,
+ unsafe=needThisHandling,
visibility=visibility)
# We have to do all the generation of our body now, because
# the caller relies on us throwing if we can't manage it.
@@ -6518,7 +7321,7 @@ class CallbackMember(CGNativeMember):
replacements["argCount"] = self.argCountStr
replacements["argvDecl"] = string.Template(
"rooted_vec!(let mut argv);\n"
- "argv.extend((0..${argCount}).map(|_| Heap::new(UndefinedValue())));\n"
+ "argv.extend((0..${argCount}).map(|_| Heap::default()));\n"
).substitute(replacements)
else:
# Avoid weird 0-sized arrays
@@ -6533,10 +7336,7 @@ class CallbackMember(CGNativeMember):
"${convertArgs}"
"${doCall}"
"${returnResult}").substitute(replacements)
- return CGWrapper(CGIndenter(CGList([
- CGGeneric(pre),
- CGGeneric(body),
- ], "\n"), 4), pre="unsafe {\n", post="\n}").define()
+ return pre + "\n" + body
def getResultConversion(self):
replacements = {
@@ -6593,24 +7393,28 @@ class CallbackMember(CGNativeMember):
conversion = wrapForType(
"argv_root.handle_mut()", result=argval,
- successCode="argv[%s] = Heap::new(argv_root.get());" % jsvalIndex,
- pre="rooted!(in(cx) let mut argv_root = UndefinedValue());")
+ successCode=("{\n"
+ "let arg = &mut argv[%s];\n"
+ "*arg = Heap::default();\n"
+ "arg.set(argv_root.get());\n"
+ "}") % jsvalIndex,
+ pre="rooted!(in(*cx) let mut argv_root = UndefinedValue());")
if arg.variadic:
conversion = string.Template(
- "for idx in 0..${arg}.len() {\n" +
- CGIndenter(CGGeneric(conversion)).define() + "\n"
- "}"
+ "for idx in 0..${arg}.len() {\n"
+ + CGIndenter(CGGeneric(conversion)).define() + "\n"
+ + "}"
).substitute({"arg": arg.identifier.name})
elif arg.optional and not arg.defaultValue:
conversion = (
CGIfWrapper("%s.is_some()" % arg.identifier.name,
- CGGeneric(conversion)).define() +
- " else if argc == %d {\n"
- " // This is our current trailing argument; reduce argc\n"
- " argc -= 1;\n"
- "} else {\n"
- " argv[%d] = Heap::new(UndefinedValue());\n"
- "}" % (i + 1, i))
+ CGGeneric(conversion)).define()
+ + " else if argc == %d {\n"
+ " // This is our current trailing argument; reduce argc\n"
+ " argc -= 1;\n"
+ "} else {\n"
+ " argv[%d] = Heap::default();\n"
+ "}" % (i + 1, i))
return conversion
def getArgs(self, returnType, argList):
@@ -6623,7 +7427,7 @@ class CallbackMember(CGNativeMember):
return args
# We want to allow the caller to pass in a "this" object, as
# well as a JSContext.
- return [Argument("*mut JSContext", "cx"),
+ return [Argument("SafeJSContext", "cx"),
Argument("HandleObject", "aThisObj")] + args
def getCallSetup(self):
@@ -6632,7 +7436,7 @@ class CallbackMember(CGNativeMember):
return ""
return (
"CallSetup s(CallbackPreserveColor(), aRv, aExceptionHandling);\n"
- "JSContext* cx = s.get_context();\n"
+ "JSContext* cx = *s.get_context();\n"
"if (!cx) {\n"
" return Err(JSFailed);\n"
"}\n")
@@ -6664,7 +7468,7 @@ class CallbackMethod(CallbackMember):
needThisHandling)
def getRvalDecl(self):
- return "rooted!(in(cx) let mut rval = UndefinedValue());\n"
+ return "rooted!(in(*cx) let mut rval = UndefinedValue());\n"
def getCall(self):
replacements = {
@@ -6680,9 +7484,9 @@ class CallbackMethod(CallbackMember):
replacements["argc"] = "0"
return string.Template(
"${getCallable}"
- "rooted!(in(cx) let rootedThis = ${thisObj});\n"
+ "rooted!(in(*cx) let rootedThis = ${thisObj});\n"
"let ok = ${callGuard}JS_CallFunctionValue(\n"
- " cx, rootedThis.handle(), callable.handle(),\n"
+ " *cx, rootedThis.handle(), callable.handle(),\n"
" &HandleValueArray {\n"
" length_: ${argc} as ::libc::size_t,\n"
" elements_: ${argv}\n"
@@ -6703,7 +7507,7 @@ class CallCallback(CallbackMethod):
return "aThisObj.get()"
def getCallableDecl(self):
- return "rooted!(in(cx) let callable = ObjectValue(self.callback()));\n"
+ return "rooted!(in(*cx) let callable = ObjectValue(self.callback()));\n"
def getCallGuard(self):
if self.callback._treatNonObjectAsNull:
@@ -6733,14 +7537,14 @@ class CallbackOperationBase(CallbackMethod):
"methodName": self.methodName
}
getCallableFromProp = string.Template(
- 'try!(self.parent.get_callable_property(cx, "${methodName}"))'
+ 'self.parent.get_callable_property(cx, "${methodName}")?'
).substitute(replacements)
if not self.singleOperation:
- return 'rooted!(in(cx) let callable =\n' + getCallableFromProp + ');\n'
+ return 'rooted!(in(*cx) let callable =\n' + getCallableFromProp + ');\n'
return (
'let isCallable = IsCallable(self.callback());\n'
- 'rooted!(in(cx) let callable =\n' +
- CGIndenter(
+ 'rooted!(in(*cx) let callable =\n'
+ + CGIndenter(
CGIfElseWrapper('isCallable',
CGGeneric('ObjectValue(self.callback())'),
CGGeneric(getCallableFromProp))).define() + ');\n')
@@ -6762,59 +7566,6 @@ class CallbackOperation(CallbackOperationBase):
descriptor, descriptor.interface.isSingleOperationInterface())
-class CallbackGetter(CallbackMember):
- def __init__(self, attr, descriptor):
- self.ensureASCIIName(attr)
- self.attrName = attr.identifier.name
- CallbackMember.__init__(self,
- (attr.type, []),
- callbackGetterName(attr),
- descriptor,
- needThisHandling=False)
-
- def getRvalDecl(self):
- return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n"
-
- def getCall(self):
- replacements = {
- "attrName": self.attrName
- }
- return string.Template(
- 'if (!JS_GetProperty(cx, mCallback, "${attrName}", &rval)) {\n'
- ' return Err(JSFailed);\n'
- '}\n').substitute(replacements)
-
-
-class CallbackSetter(CallbackMember):
- def __init__(self, attr, descriptor):
- self.ensureASCIIName(attr)
- self.attrName = attr.identifier.name
- CallbackMember.__init__(self,
- (BuiltinTypes[IDLBuiltinType.Types.void],
- [FakeArgument(attr.type, attr)]),
- callbackSetterName(attr),
- descriptor,
- needThisHandling=False)
-
- def getRvalDecl(self):
- # We don't need an rval
- return ""
-
- def getCall(self):
- replacements = {
- "attrName": self.attrName,
- "argv": "argv.handleAt(0)",
- }
- return string.Template(
- 'MOZ_ASSERT(argv.length() == 1);\n'
- 'if (!JS_SetProperty(cx, mCallback, "${attrName}", ${argv})) {\n'
- ' return Err(JSFailed);\n'
- '}\n').substitute(replacements)
-
- def getArgcDecl(self):
- return None
-
-
class CGIterableMethodGenerator(CGGeneric):
"""
Creates methods for iterable interfaces. Unwrapping/wrapping
@@ -6827,24 +7578,35 @@ class CGIterableMethodGenerator(CGGeneric):
CGGeneric.__init__(self, fill(
"""
if !IsCallable(arg0) {
- throw_type_error(cx, "Argument 1 of ${ifaceName}.forEach is not callable.");
+ throw_type_error(*cx, "Argument 1 of ${ifaceName}.forEach is not callable.");
return false;
}
- rooted!(in(cx) let arg0 = ObjectValue(arg0));
- rooted!(in(cx) let mut call_arg1 = UndefinedValue());
- rooted!(in(cx) let mut call_arg2 = UndefinedValue());
+ rooted!(in(*cx) let arg0 = ObjectValue(arg0));
+ rooted!(in(*cx) let mut call_arg1 = UndefinedValue());
+ rooted!(in(*cx) let mut call_arg2 = UndefinedValue());
let mut call_args = vec![UndefinedValue(), UndefinedValue(), ObjectValue(*_obj)];
- rooted!(in(cx) let mut ignoredReturnVal = UndefinedValue());
- for i in 0..(*this).get_iterable_length() {
- (*this).get_value_at_index(i).to_jsval(cx, call_arg1.handle_mut());
- (*this).get_key_at_index(i).to_jsval(cx, call_arg2.handle_mut());
+ rooted!(in(*cx) let mut ignoredReturnVal = UndefinedValue());
+
+ // This has to be a while loop since get_iterable_length() may change during
+ // the callback, and we need to avoid iterator invalidation.
+ //
+ // It is possible for this to loop infinitely, but that matches the spec
+ // and other browsers.
+ //
+ // https://heycam.github.io/webidl/#es-forEach
+ let mut i = 0;
+ while i < (*this).get_iterable_length() {
+ (*this).get_value_at_index(i).to_jsval(*cx, call_arg1.handle_mut());
+ (*this).get_key_at_index(i).to_jsval(*cx, call_arg2.handle_mut());
call_args[0] = call_arg1.handle().get();
call_args[1] = call_arg2.handle().get();
let call_args = HandleValueArray { length_: 3, elements_: call_args.as_ptr() };
- if !Call(cx, arg1, arg0.handle(), &call_args,
+ if !Call(*cx, arg1, arg0.handle(), &call_args,
ignoredReturnVal.handle_mut()) {
return false;
}
+
+ i += 1;
}
let result = ();
@@ -6853,9 +7615,7 @@ class CGIterableMethodGenerator(CGGeneric):
return
CGGeneric.__init__(self, fill(
"""
- let result = ${iterClass}::new(&*this,
- IteratorType::${itrMethod},
- super::${ifaceName}IteratorBinding::Wrap);
+ let result = ${iterClass}::new(&*this, IteratorType::${itrMethod});
""",
iterClass=iteratorNativeType(descriptor, True),
ifaceName=descriptor.interface.identifier.name,
@@ -6868,10 +7628,16 @@ def camel_to_upper_snake(s):
def process_arg(expr, arg):
if arg.type.isGeckoInterface() and not arg.type.unroll().inner.isCallback():
- if arg.type.nullable() or arg.type.isSequence() or arg.optional:
+ if arg.variadic or arg.type.isSequence():
expr += ".r()"
+ elif arg.type.nullable() and arg.optional and not arg.defaultValue:
+ expr += ".as_ref().map(Option::as_deref)"
+ elif arg.type.nullable() or arg.optional and not arg.defaultValue:
+ expr += ".as_deref()"
else:
expr = "&" + expr
+ elif isinstance(arg.type, IDLPromiseType):
+ expr = "&" + expr
return expr
@@ -6886,8 +7652,9 @@ class GlobalGenRoots():
@staticmethod
def InterfaceObjectMap(config):
mods = [
- "dom::bindings::codegen",
- "js::jsapi::{HandleObject, JSContext}",
+ "crate::dom::bindings::codegen",
+ "crate::script_runtime::JSContext",
+ "js::rust::HandleObject",
"phf",
]
imports = CGList([CGGeneric("use %s;" % mod) for mod in mods], "\n")
@@ -6899,9 +7666,9 @@ class GlobalGenRoots():
for (idx, d) in enumerate(global_descriptors)
)
global_flags = CGWrapper(CGIndenter(CGList([
- CGGeneric("const %s = %#x," % args)
+ CGGeneric("const %s = %#x;" % args)
for args in flags
- ], "\n")), pre="pub flags Globals: u8 {\n", post="\n}")
+ ], "\n")), pre="pub struct Globals: u8 {\n", post="\n}")
globals_ = CGWrapper(CGIndenter(global_flags), pre="bitflags! {\n", post="\n}")
phf = CGGeneric("include!(concat!(env!(\"OUT_DIR\"), \"/InterfaceObjectMapPhf.rs\"));")
@@ -6917,11 +7684,13 @@ class GlobalGenRoots():
for d in config.getDescriptors(hasInterfaceObject=True, isInline=False):
binding = toBindingNamespace(d.name)
pairs.append((d.name, binding, binding))
+ for alias in d.interface.legacyWindowAliases:
+ pairs.append((alias, binding, binding))
for ctor in d.interface.namedConstructors:
pairs.append((ctor.identifier.name, binding, binding))
pairs.sort(key=operator.itemgetter(0))
mappings = [
- CGGeneric('"%s": "codegen::Bindings::%s::%s::DefineDOMInterface as unsafe fn(_, _)"' % pair)
+ CGGeneric('"%s": "codegen::Bindings::%s::%s::DefineDOMInterface"' % pair)
for pair in pairs
]
return CGWrapper(
@@ -6938,8 +7707,6 @@ class GlobalGenRoots():
for d in config.getDescriptors(hasInterfaceObject=True)
if d.shouldHaveGetConstructorObjectMethod()])
- proxies = [d.name for d in config.getDescriptors(proxy=True)]
-
return CGList([
CGGeneric(AUTOGENERATED_WARNING_COMMENT),
CGGeneric("pub const PROTO_OR_IFACE_LENGTH: usize = %d;\n" % (len(protos) + len(constructors))),
@@ -6956,7 +7723,6 @@ class GlobalGenRoots():
" debug_assert!(proto_id < ID::Last as u16);\n"
" INTERFACES[proto_id as usize]\n"
"}\n\n"),
- CGNonNamespacedEnum('Proxies', proxies, 0, deriving="PartialEq, Copy, Clone"),
])
@staticmethod
@@ -6966,10 +7732,8 @@ class GlobalGenRoots():
CGRegisterProxyHandlers(config),
], "\n")
- return CGImports(code, descriptors=[], callbacks=[], dictionaries=[], enums=[], imports=[
- 'dom::bindings::codegen::Bindings',
- 'dom::bindings::codegen::PrototypeList::Proxies',
- 'libc',
+ return CGImports(code, descriptors=[], callbacks=[], dictionaries=[], enums=[], typedefs=[], imports=[
+ 'crate::dom::bindings::codegen::Bindings',
], config=config, ignored_warnings=[])
@staticmethod
@@ -6978,8 +7742,8 @@ class GlobalGenRoots():
for d in config.getDescriptors(register=True,
isCallback=False,
isIteratorInterface=False)])
- curr = CGList([CGGeneric("pub use dom::%s::%s;\n" % (name.lower(),
- MakeNativeName(name)))
+ curr = CGList([CGGeneric("pub use crate::dom::%s::%s;\n" % (name.lower(),
+ MakeNativeName(name)))
for name in descriptors])
curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
return curr
@@ -6991,9 +7755,9 @@ class GlobalGenRoots():
return getModuleFromObject(d).split('::')[-1]
descriptors = config.getDescriptors(register=True, isIteratorInterface=False)
- descriptors = (set(toBindingNamespace(d.name) for d in descriptors) |
- set(leafModule(d) for d in config.callbacks) |
- set(leafModule(d) for d in config.getDictionaries()))
+ descriptors = (set(toBindingNamespace(d.name) for d in descriptors)
+ | set(leafModule(d) for d in config.callbacks)
+ | set(leafModule(d) for d in config.getDictionaries()))
curr = CGList([CGGeneric("pub mod %s;\n" % name) for name in sorted(descriptors)])
curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
return curr
@@ -7002,12 +7766,12 @@ class GlobalGenRoots():
def InheritTypes(config):
descriptors = config.getDescriptors(register=True, isCallback=False)
- imports = [CGGeneric("use dom::types::*;\n"),
- CGGeneric("use dom::bindings::conversions::{DerivedFrom, get_dom_class};\n"),
- CGGeneric("use dom::bindings::inheritance::Castable;\n"),
- CGGeneric("use dom::bindings::js::{JS, LayoutJS, Root};\n"),
- CGGeneric("use dom::bindings::trace::JSTraceable;\n"),
- CGGeneric("use dom::bindings::reflector::DomObject;\n"),
+ imports = [CGGeneric("use crate::dom::types::*;\n"),
+ CGGeneric("use crate::dom::bindings::conversions::{DerivedFrom, get_dom_class};\n"),
+ CGGeneric("use crate::dom::bindings::inheritance::Castable;\n"),
+ CGGeneric("use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom};\n"),
+ CGGeneric("use crate::dom::bindings::trace::JSTraceable;\n"),
+ CGGeneric("use crate::dom::bindings::reflector::DomObject;\n"),
CGGeneric("use js::jsapi::JSTracer;\n\n"),
CGGeneric("use std::mem;\n\n")]
allprotos = []
@@ -7066,7 +7830,7 @@ impl Clone for TopTypeId {
# TypeId enum.
return "%s(%sTypeId)" % (name, name) if name in hierarchy else name
- for base, derived in hierarchy.iteritems():
+ for base, derived in hierarchy.items():
variants = []
if config.getDescriptor(base).concrete:
variants.append(CGGeneric(base))
@@ -7113,7 +7877,7 @@ impl %(base)s {
def SupportedDomApis(config):
descriptors = config.getDescriptors(isExposedConditionally=False)
- base_path = os.path.join('dom', 'bindings', 'codegen')
+ base_path = os.path.dirname(__file__)
with open(os.path.join(base_path, 'apis.html.template')) as f:
base_template = f.read()
with open(os.path.join(base_path, 'api.html.template')) as f:
@@ -7130,6 +7894,8 @@ impl %(base)s {
for m in descriptor.interface.members:
if PropertyDefiner.getStringAttr(m, 'Pref') or \
PropertyDefiner.getStringAttr(m, 'Func') or \
+ PropertyDefiner.getStringAttr(m, 'Exposed') or \
+ m.getExtendedAttribute('SecureContext') or \
(m.isMethod() and m.isIdentifierLess()):
continue
display = m.identifier.name + ('()' if m.isMethod() else '')