Bug 145472 - NavigationAction constructor cleanup
Summary: NavigationAction constructor cleanup
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebCore Misc. (show other bugs)
Version: 528+ (Nightly build)
Hardware: All All
: P2 Normal
Assignee: Brady Eidson
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-05-29 14:42 PDT by Brady Eidson
Modified: 2015-05-30 18:32 PDT (History)
2 users (show)

See Also:


Attachments
More red than green. (5.62 KB, patch)
2015-05-29 14:44 PDT, Brady Eidson
achristensen: review+
Details | Formatted Diff | Diff
Proposed windows test fix (2.76 KB, patch)
2015-05-30 14:25 PDT, Brady Eidson
no flags Details | Formatted Diff | Diff
Alternate fix that should definitely work. (5.93 KB, patch)
2015-05-30 14:55 PDT, Brady Eidson
beidson: commit-queue+
Details | Formatted Diff | Diff
Fix for landing (5.93 KB, patch)
2015-05-30 15:05 PDT, Brady Eidson
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Brady Eidson 2015-05-29 14:42:16 PDT
NavigationAction constructor cleanup

Lot's of NavigationAction constructors, all subtley different.

An upcoming patch I'm working on will add another one.

Seemed like a good time to re-route them all to a central constructor via c'tor delegation.
Comment 1 Brady Eidson 2015-05-29 14:44:36 PDT
Created attachment 253916 [details]
More red than green.
Comment 2 Alex Christensen 2015-05-29 14:54:49 PDT
Comment on attachment 253916 [details]
More red than green.

View in context: https://bugs.webkit.org/attachment.cgi?id=253916&action=review

> Source/WebCore/loader/NavigationAction.h:47
> +    NavigationAction(const ResourceRequest&, NavigationType, PassRefPtr<Event>, ShouldOpenExternalURLsPolicy);

The new constructor could be private right now, but it might need to be public in a following patch.  Ok either way.
Comment 3 Brady Eidson 2015-05-29 15:01:55 PDT
http://trac.webkit.org/changeset/185007
Comment 4 Alexey Proskuryakov 2015-05-30 10:22:08 PDT
This broke four tests on Windows: <https://build.webkit.org/results/Apple%20Win%207%20Release%20(Tests)/r185031%20(52131)/results.html>.

Brady, are you available to investigate today?
Comment 5 Brady Eidson 2015-05-30 13:47:23 PDT
(In reply to comment #4)
> This broke four tests on Windows:
> <https://build.webkit.org/results/Apple%20Win%207%20Release%20(Tests)/
> r185031%20(52131)/results.html>.
> 
> Brady, are you available to investigate today?

...WHAT...?
Comment 6 Brady Eidson 2015-05-30 13:51:25 PDT
Okay, without actually being able to reproduce because I can't get to a windows setup right now...

4 tests all fail because NavigationType::LinkClicked became NavigationType::Other.

Why on Windows and not Mac? Who knows.

The only way this patch could've made LinkClicked become Other is if:
static NavigationType navigationType(FrameLoadType frameLoadType, bool isFormSubmission, bool haveEvent)
... is giving different results.

The only way it gives LinkClicked is if "haveEvent" is true.
So previously a called had an event, and now they don't.

Will explore...
Comment 7 Brady Eidson 2015-05-30 13:54:05 PDT
Only two of the ctor's called navigationType().

One was navigationType(frameLoadType, isFormSubmission, 0) (and is identical after the patch), and that call never could've given LinkClicked.

So it must be the other, which passes a PassRefPtr<Event>:

navigationType(frameLoadType, isFormSubmission, event)

It's identical afterwards, too. But maybe there's some weird PassRefPtr automatic assignment stuff that's killing the event ptr?
Comment 8 Brady Eidson 2015-05-30 13:58:34 PDT
Are constructor arguments evaluated in reverse, right to left? If so, the call to:

+    : NavigationAction(resourceRequest, navigationType(frameLoadType, isFormSubmission, event), event, ShouldOpenExternalURLsPolicy::ShouldNotAllow)

...might null-out the PassRefPtr for "event" before passing it into navigationType() as a bool argument...?

That's really my only guess here.
Comment 9 Brady Eidson 2015-05-30 14:05:51 PDT
Holy crap, I think that's totally it.

C++ spec says arguments in the order they appear, but non-clang compilers have gotten it wrong.

According to http://stackoverflow.com/questions/14060264/order-of-evaluation-of-elements-in-list-initialization gcc had it wrong for awhile... 

And visual studio still does in the context of initializer lists:
https://connect.microsoft.com/VisualStudio/feedbackdetail/view/976911/braced-initializer-list-not-evaluated-left-to-right

I'm guessing the VS bug is not strictly limited to initializer lists?

Unless there's something obvious that somebody else is seeing that I'm not, I think that might be it. o_O
Comment 10 Brady Eidson 2015-05-30 14:20:20 PDT
Actually, maybe this is bogus for all C++...

The C++11 standard demands in §8.5.4/4 that the items in a braced initializer list are evaluated left-to-right:

"Within the initializer-list of a braced-init-list, the initializer-clauses, including any that result from pack
expansions (14.5.3), are evaluated in the order in which they appear. That is, every value computation and
side effect associated with a given initializer-clause is sequenced before every value computation and side
effect associated with any initializer-clause that follows it in the comma-separated list of the initializer-list.
[Note: This evaluation ordering holds regardless of the semantics of the initialization; for example, it applies
when the elements of the initializer-list are interpreted as arguments of a constructor call, even though
ordinarily there are no sequencing constraints on the arguments of a call. — end note]"

The left-to-right evaluation sequencing is required for braced initialization lists, but not for "normal" constructor calls - "ordinarily there are no sequencing constraints on the arguments of a call."

So I wonder if clang just does LTR, but it's not required to be LTR. Maybe VS isn't "wrong" here, even if they are weird.
Comment 11 Brady Eidson 2015-05-30 14:25:24 PDT
Created attachment 253962 [details]
Proposed windows test fix

This is my proposed fix that I'm building on Mac right now.

Pros - It's not a dirty hack to work around a possible "weirdness" in the VS C++ compiler, it's cross platform, it simply turns these into braced initializer lists which the C++ spec requires to be evaluated left-to-right

Cons - If there *IS* a VS bug in evaluating initializer lists LTR... this still won't fix it.
Comment 12 Brady Eidson 2015-05-30 14:33:18 PDT
I'm not even going to mess with the initializer list version of this.

In reality, nobody should actually be passing ownership of the event, so a PassRefPtr makes no sense.

Raw ptrs make much more sense, and won't have this issue.
Comment 13 Brady Eidson 2015-05-30 14:55:40 PDT
Created attachment 253965 [details]
Alternate fix that should definitely work.
Comment 14 Brady Eidson 2015-05-30 15:05:30 PDT
Reopening for commit queue to work
Comment 15 Brady Eidson 2015-05-30 15:05:55 PDT
Created attachment 253966 [details]
Fix for landing
Comment 16 Brady Eidson 2015-05-30 15:06:59 PDT
NM, stupid commit queue...
Comment 17 Brady Eidson 2015-05-30 15:08:58 PDT
http://trac.webkit.org/changeset/185033
Comment 18 Brady Eidson 2015-05-30 18:20:43 PDT
Just for posterity, the even crazier thing was VS had this behavior in release builds, but not debug - the debug tests never broke!

Sigh

All fixed.
Comment 19 Alexey Proskuryakov 2015-05-30 18:24:40 PDT
Nice fix!

We should eliminate PassRefPtr<Event> from the callers too, we have atrocities there like 

    frame->loader().urlSelected(url, target(), PassRefPtr<Event>(&event), LockHistory::No, LockBackForwardList::No, MaybeSendReferrer);
Comment 20 Alexey Proskuryakov 2015-05-30 18:26:33 PDT
It is not very surprising that the failure was release only - evaluation reordering is an optimization. I wouldn't be too surprised if clang decided to do the same in some cases.
Comment 21 Brady Eidson 2015-05-30 18:32:31 PDT
(In reply to comment #19)
> Nice fix!
> 
> We should eliminate PassRefPtr<Event> from the callers too, we have
> atrocities there like 
> 
>     frame->loader().urlSelected(url, target(), PassRefPtr<Event>(&event),
> LockHistory::No, LockBackForwardList::No, MaybeSendReferrer);

Yup, definitely noticed that while deciding on the right fix, but it was out of scope from a test fix.

 I will followup some point soon!