Closed Bug 1332785 Opened 7 years ago Closed 7 years ago

MozPromiseHolder::Resolve and Reject should take references

Categories

(Core :: XPCOM, defect)

49 Branch
defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla54
Tracking Status
firefox54 --- fixed

People

(Reporter: mozbugz, Assigned: mozbugz)

References

Details

Attachments

(1 file)

MozPromiseHolder::Resolve and Reject currently take their argument by-value, which could add an unwanted copy.
In particular, it would prevent moving a temporary value into the function, if the value type prohibit implicit copies (e.g.: nsTArray).

So we should allow both copy and moves, by providing Resolve/Reject functions taking both 'const T&' and 'T&&'.

(Note that I won't just take forwarding references of any type, as this could lead to implicit conversions by bypassing the 'explicit' marker of the value type constructors, like in bug 1331137.)
Blocks: 1319987
Attachment #8829046 - Flags: review?(nfroyd) → review?(jwwang)
(In reply to Gerald Squelart [:gerald] from comment #0)
> (Note that I won't just take forwarding references of any type, as this
> could lead to implicit conversions by bypassing the 'explicit' marker of the
> value type constructors, like in bug 1331137.)

Can you give an example? I can't see how this is possible in MozPromise.
Here's a little test, just to see how things build:
https://hg.mozilla.org/try/rev/2cb8bd56627b

The most interesting lines are:
>  struct Other {};
>  struct Explicit { Explicit() {}; explicit Explicit(const Other&) {} };
>  typedef MozPromise<Explicit, Explicit, true> ExplicitPromise;
>  MozPromiseHolder<ExplicitPromise> holder;
>  holder.Resolve(Other{}, __func__);
The last line (and more similar ones under it) should fail to compile, because we are trying to build an ExplicitPromise::ResolveOrRejectValue::ResolveType (aka Explicit) from an 'Other{}', but the conversion constructor for that is marked 'explicit' and therefore should be ignored.

Here's a try with just that test on top of the current code (which takes ResolveType by value) :
https://treeherder.mozilla.org/#/jobs?repo=try&revision=42a6dbce20b1a345f67070b63a238bee914d4b9c
It fails as expected.

Here's a try with my proposed patch (which takes Resolve/RejectType by const&& or &&) :
https://treeherder.mozilla.org/#/jobs?repo=try&revision=c418b3a0e1aea2c5eb17b5b245919626d7d9f2be
It also fails for the same reason.

And this is a try with a patch where Resolve/Reject take forwarding references of any type:
https://treeherder.mozilla.org/#/jobs?repo=try&revision=dfceedabb6b095bbd5121f5959bebf1cd918dd00
It doesn't fail anymore, meaning the 'explicit' for the conversion constructor was ignored!
(Well, there's a failure in the static analysis build, but it's happening later and is unrelated to our 'explicit' issue.)

Does that convince you?
Thanks for the detailed explanation.
Comment on attachment 8829046 [details]
Bug 1332785 - Optimize MozPromiseHolder::Resolve and Reject -

https://reviewboard.mozilla.org/r/106246/#review107380

::: xpcom/threads/MozPromise.h:1028
(Diff revision 1)
>    {
>      if (!IsEmpty()) {
>        Resolve(aResolveValue, aMethodName);
>      }
>    }
> +  void ResolveIfExists(typename PromiseType::ResolveValueType&& aResolveValue,

I think we can use forwarding reference there because Resolve() takes either ResolveValueType&& or const ResolveValueType& and prevents implicit conversions.
Attachment #8829046 - Flags: review?(jwwang) → review+
Pushed by gsquelart@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/839e34051bf9
Optimize MozPromiseHolder::Resolve and Reject - r=jwwang
Comment on attachment 8829046 [details]
Bug 1332785 - Optimize MozPromiseHolder::Resolve and Reject -

https://reviewboard.mozilla.org/r/106246/#review107380

> I think we can use forwarding reference there because Resolve() takes either ResolveValueType&& or const ResolveValueType& and prevents implicit conversions.

(Sorry, forgot to publish this comment before pushing.)

Thank you for the review & suggestions.

You are correct that forwarding references would work in Resolve/RejectIfExists and would still prevent implicit conversions.
I even gave it a Try:
https://treeherder.mozilla.org/#/jobs?repo=try&revision=8fccce0eb1b0eefd987806f55560e1cc03266fbe

As I feared, it makes it harder to spot the location of the error, as the compiler first points at Resolve/Reject inside MozPromise.h, instead of the call site, which is only mentioned 13 lines after the error message!

So I'll keep the patch as-is: I prefer a small maintenance cost in one location (with the duplicated const&/&& functions) as a trade-off for more obvious error messages whenever something wrong is done.

(There may be a way to use templated functions that only accept the correct type, but it'd be quite a bit of work to get right; we can do that in a future bug if really deemed useful...)
https://hg.mozilla.org/mozilla-central/rev/839e34051bf9
Status: NEW → RESOLVED
Closed: 7 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla54
See Also: → 1504531
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: