diff --git a/dom/bindings/BindingDeclarations.h b/dom/bindings/BindingDeclarations.h index c6a096fb1db5..af141cfd8265 100644 --- a/dom/bindings/BindingDeclarations.h +++ b/dom/bindings/BindingDeclarations.h @@ -472,6 +472,49 @@ private: double mMsecSinceEpoch; }; +class NonNullLazyRootedObject : public Maybe > +{ +public: + operator JSObject&() const + { + MOZ_ASSERT(!empty() && ref(), "Can not alias null."); + return *ref(); + } + + operator JS::Rooted&() + { + // Assert if we're empty, on purpose + return ref(); + } + + JSObject** Slot() // To make us look like a NonNull + { + // Assert if we're empty, on purpose + return ref().address(); + } +}; + +class LazyRootedObject : public Maybe > +{ +public: + operator JSObject*() const + { + return empty() ? static_cast(nullptr) : ref(); + } + + operator JS::Rooted&() + { + // Assert if we're empty, on purpose + return ref(); + } + + JSObject** operator&() + { + // Assert if we're empty, on purpose + return ref().address(); + } +}; + } // namespace dom } // namespace mozilla diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index e64e337853e0..3d866e071af1 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -1430,34 +1430,6 @@ protected: #endif }; -class NonNullLazyRootedObject : public Maybe -{ -public: - operator JSObject&() const { - MOZ_ASSERT(!empty() && ref(), "Can not alias null."); - return *ref(); - } - - JSObject** Slot() { // To make us look like a NonNull - // Assert if we're empty, on purpose - return ref().address(); - } -}; - -class LazyRootedObject : public Maybe -{ -public: - operator JSObject*() const { - return empty() ? (JSObject*) nullptr : ref(); - } - - JSObject** operator&() - { - // Assert if we're empty, on purpose - return ref().address(); - } -}; - // A struct that has the same layout as an nsDependentString but much // faster constructor and destructor behavior struct FakeDependentString { diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 76f02e58a903..c1c148fae1a6 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -2537,6 +2537,33 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None, return templateBody + # A helper function for converting things that look like JSObject* + # when nullable and JSObject& when not nullable. + def handleJSObjectType(type, isMember, failureCode): + if type.nullable(): + declType = CGGeneric("LazyRootedObject") + else: + declType = CGGeneric("NonNullLazyRootedObject") + + # If cx is null then LazyRootedObject will not be + # constructed and behave as nullptr. + templateBody = "${declName}.construct(cx, &${val}.toObject());" + + # Cast of nullptr to (JSObject*) is required for template deduction. + setToNullCode = "${declName}.construct(cx, static_cast(nullptr));" + + if isMember == "Dictionary": + # If cx is null then LazyRootedObject will not be + # constructed and behave as nullptr. + templateBody = CGIfWrapper(CGGeneric(templateBody), "cx").define() + setToNullCode = CGIfWrapper(CGGeneric(setToNullCode), "cx").define() + + template = wrapObjectTemplate(templateBody, type, setToNullCode, + failureCode) + + return (template, declType, None, isOptional) + + assert not (isEnforceRange and isClamp) # These are mutually exclusive if type.isArray(): @@ -2717,7 +2744,7 @@ for (uint32_t i = 0; i < length; ++i) { objectMemberTypes = filter(lambda t: t.isObject(), memberTypes) if len(objectMemberTypes) > 0: - object = CGGeneric("%s.SetToObject(&argObj);\n" + object = CGGeneric("%s.SetToObject(cx, &argObj);\n" "done = true;" % unionArgumentObj) else: object = None @@ -2845,19 +2872,15 @@ for (uint32_t i = 0; i < length; ++i) { if (descriptor.interface.isCallback() and descriptor.interface.identifier.name != "EventListener"): if descriptor.workers: - if type.nullable() or isCallbackReturnValue: - declType = CGGeneric("JSObject*") - else: - declType = CGGeneric("NonNull") - conversion = " ${declName} = &${val}.toObject();\n" + return handleJSObjectType(type, isMember, failureCode) + + name = descriptor.interface.identifier.name + if type.nullable() or isCallbackReturnValue: + declType = CGGeneric("nsRefPtr<%s>" % name); else: - name = descriptor.interface.identifier.name - if type.nullable() or isCallbackReturnValue: - declType = CGGeneric("nsRefPtr<%s>" % name); - else: - declType = CGGeneric("OwningNonNull<%s>" % name) - conversion = ( - " ${declName} = new %s(&${val}.toObject());\n" % name) + declType = CGGeneric("OwningNonNull<%s>" % name) + conversion = ( + " ${declName} = new %s(&${val}.toObject());\n" % name) template = wrapObjectTemplate(conversion, type, "${declName} = nullptr", @@ -2922,7 +2945,7 @@ for (uint32_t i = 0; i < length; ++i) { "${declName}", exceptionCode)) elif descriptor.workers: - templateBody += "${declName} = &${val}.toObject();" + return handleJSObjectType(type, isMember, failureCode) else: # Either external, or new-binding non-castable. We always have a # holder for these, because we don't actually know whether we have @@ -3218,40 +3241,7 @@ for (uint32_t i = 0; i < length; ++i) { if type.isObject(): assert not isEnforceRange and not isClamp - - if isMember and isMember != "Dictionary": - raise TypeError("Can't handle member 'object' not in a dictionary;" - "need to sort out rooting issues") - - if isMember == "Dictionary": - if type.nullable(): - declType = CGGeneric("LazyRootedObject") - else: - declType = CGGeneric("NonNullLazyRootedObject") - - # If cx is null then LazyRootedObject will not be - # constructed and behave as nullptr. - templateBody = ("if (cx) {\n" - " ${declName}.construct(cx, &${val}.toObject());\n" - "}") - - # Cast of nullptr to (JSObject*) is required for template deduction. - setToNullCode = ("if (cx) {\n" - " ${declName}.construct(cx, (JSObject*) nullptr);\n" - "}") - else: - if type.nullable(): - declType = CGGeneric("JSObject*") - else: - declType = CGGeneric("NonNull") - - templateBody = "${declName} = &${val}.toObject();" - setToNullCode = "${declName} = NULL" - - template = wrapObjectTemplate(templateBody, type, setToNullCode, - failureCode) - - return (template, declType, None, isOptional) + return handleJSObjectType(type, isMember, failureCode) if type.isDictionary(): if failureCode is not None and not isDefinitelyObject: @@ -5478,9 +5468,9 @@ return true;""" externalType = getUnionAccessorSignatureType(type, descriptorProvider).define() if type.isObject(): - setter = CGGeneric("void SetToObject(JSObject* obj)\n" + setter = CGGeneric("void SetToObject(JSContext* cx, JSObject* obj)\n" "{\n" - " mUnion.mValue.mObject.SetValue() = obj;\n" + " mUnion.mValue.mObject.SetValue().construct(cx, obj);\n" " mUnion.mType = mUnion.eObject;\n" "}") else: @@ -5648,9 +5638,10 @@ ${doConversionsToJS} assert not type.nullable() # flatMemberTypes never has nullable types val = "mValue.m%(name)s.Value()" % templateVars if type.isObject(): - # We'll have a NonNull while the wrapping code - # wants a JSObject* - val = "%s.get()" % val + # We'll have a NonNullLazyRootedObject while the wrapping code wants + # a JSObject*. But our .ref() is a JS::Rooted, which can + # convert to a JSObject*. + val = "%s.ref()" % val elif type.isSpiderMonkeyInterface(): # We have a NonNull object while the wrapping code # wants a JSObject*. Cheat with .get() so we don't have to @@ -8055,7 +8046,7 @@ class CGNativeMember(ClassMethod): if type.nullable(): returnCode = "return ${declName};" else: - returnCode = "return ${declName}.Ptr();" + returnCode = "return ${declName}.ref();" return "JSObject*", "nullptr", returnCode if type.isSpiderMonkeyInterface(): if type.nullable(): @@ -8216,13 +8207,16 @@ class CGNativeMember(ClassMethod): return "JS::Value", False, False if type.isObject(): - if type.nullable() or self.jsObjectsArePtr: - declType = "%s*" - elif optional: - declType = "NonNull<%s>" + if optional: + if type.nullable(): + declType = "LazyRootedObject" + else: + declType = "NonNullLazyRootedObject" + elif type.nullable() or self.jsObjectsArePtr: + declType = "JSObject*" else: - declType = "%s&" - return (declType % "JSObject"), False, False + declType = "JSObject&" + return declType, False, False if type.isDictionary(): typeName = CGDictionary.makeDictionaryName(type.inner, diff --git a/dom/bindings/test/TestBindingHeader.h b/dom/bindings/test/TestBindingHeader.h index a6c9dc1886ca..227195746557 100644 --- a/dom/bindings/test/TestBindingHeader.h +++ b/dom/bindings/test/TestBindingHeader.h @@ -141,8 +141,8 @@ public: JSObject*, const Sequence&, const Optional&, - const Optional >&, - const Optional&, + const Optional&, + const Optional&, ErrorResult&); // Integer types @@ -436,8 +436,8 @@ public: // object types void PassObject(JSContext*, JSObject&); void PassNullableObject(JSContext*, JSObject*); - void PassOptionalObject(JSContext*, const Optional >&); - void PassOptionalNullableObject(JSContext*, const Optional&); + void PassOptionalObject(JSContext*, const Optional&); + void PassOptionalNullableObject(JSContext*, const Optional&); void PassOptionalNullableObjectWithDefaultValue(JSContext*, JSObject*); JSObject* ReceiveObject(JSContext*); JSObject* ReceiveNullableObject(JSContext*); diff --git a/dom/workers/FileReaderSync.cpp b/dom/workers/FileReaderSync.cpp index 5e24ba4cf9fd..8fea0233e657 100644 --- a/dom/workers/FileReaderSync.cpp +++ b/dom/workers/FileReaderSync.cpp @@ -71,10 +71,10 @@ FileReaderSync::Constructor(const WorkerGlobalObject& aGlobal, ErrorResult& aRv) } JSObject* -FileReaderSync::ReadAsArrayBuffer(JSContext* aCx, JSObject* aBlob, +FileReaderSync::ReadAsArrayBuffer(JSContext* aCx, JSObject& aBlob, ErrorResult& aRv) { - nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(aBlob); + nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(&aBlob); if (!blob) { aRv.Throw(NS_ERROR_INVALID_ARG); return nullptr; @@ -117,10 +117,10 @@ FileReaderSync::ReadAsArrayBuffer(JSContext* aCx, JSObject* aBlob, } void -FileReaderSync::ReadAsBinaryString(JSObject* aBlob, nsAString& aResult, +FileReaderSync::ReadAsBinaryString(JSObject& aBlob, nsAString& aResult, ErrorResult& aRv) { - nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(aBlob); + nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(&aBlob); if (!blob) { aRv.Throw(NS_ERROR_INVALID_ARG); return; @@ -152,12 +152,12 @@ FileReaderSync::ReadAsBinaryString(JSObject* aBlob, nsAString& aResult, } void -FileReaderSync::ReadAsText(JSObject* aBlob, +FileReaderSync::ReadAsText(JSObject& aBlob, const Optional& aEncoding, nsAString& aResult, ErrorResult& aRv) { - nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(aBlob); + nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(&aBlob); if (!blob) { aRv.Throw(NS_ERROR_INVALID_ARG); return; @@ -208,10 +208,10 @@ FileReaderSync::ReadAsText(JSObject* aBlob, } void -FileReaderSync::ReadAsDataURL(JSObject* aBlob, nsAString& aResult, +FileReaderSync::ReadAsDataURL(JSObject& aBlob, nsAString& aResult, ErrorResult& aRv) { - nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(aBlob); + nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(&aBlob); if (!blob) { aRv.Throw(NS_ERROR_INVALID_ARG); return; diff --git a/dom/workers/FileReaderSync.h b/dom/workers/FileReaderSync.h index 4a8dae24dd7f..d5263cf35f8d 100644 --- a/dom/workers/FileReaderSync.h +++ b/dom/workers/FileReaderSync.h @@ -42,13 +42,13 @@ public: FileReaderSync(JSContext* aCx); - JSObject* ReadAsArrayBuffer(JSContext* aCx, JSObject* aBlob, + JSObject* ReadAsArrayBuffer(JSContext* aCx, JSObject& aBlob, ErrorResult& aRv); - void ReadAsBinaryString(JSObject* aBlob, nsAString& aResult, + void ReadAsBinaryString(JSObject& aBlob, nsAString& aResult, ErrorResult& aRv); - void ReadAsText(JSObject* aBlob, const Optional& aEncoding, + void ReadAsText(JSObject& aBlob, const Optional& aEncoding, nsAString& aResult, ErrorResult& aRv); - void ReadAsDataURL(JSObject* aBlob, nsAString& aResult, ErrorResult& aRv); + void ReadAsDataURL(JSObject& aBlob, nsAString& aResult, ErrorResult& aRv); // From nsICharsetDetectionObserver NS_IMETHOD Notify(const char *aCharset, nsDetectionConfident aConf); diff --git a/dom/workers/XMLHttpRequest.h b/dom/workers/XMLHttpRequest.h index 8e10365fc557..bb33a6ac3593 100644 --- a/dom/workers/XMLHttpRequest.h +++ b/dom/workers/XMLHttpRequest.h @@ -241,7 +241,7 @@ public: } JS::Value - GetInterface(JSContext* cx, JSObject* aIID, ErrorResult& aRv) + GetInterface(JSContext* cx, JSObject& aIID, ErrorResult& aRv) { aRv.Throw(NS_ERROR_FAILURE); return JSVAL_NULL;