diff options
author | yvt <i@yvt.jp> | 2021-07-10 17:24:27 +0900 |
---|---|---|
committer | yvt <i@yvt.jp> | 2021-07-10 17:55:42 +0900 |
commit | 01a7de50ab1843d85295f9dccad7f4c099e7208c (patch) | |
tree | ee53fb6e8889deb7b880ee969e6c662e6128d210 /components/script/dom/bindings/codegen/CodegenRust.py | |
parent | ff8d2cdbbfc7a9dc7f38b7dd47cb350fde39388f (diff) | |
parent | 94b613fbdaa2b98f2179fc0bbda13c64e6fa0d38 (diff) | |
download | servo-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.py | 2948 |
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 '') |