Bug 184467

Summary: Introduce remote variants of Frame / DOMWindow classes
Product: WebKit Reporter: Chris Dumez <cdumez>
Component: Page LoadingAssignee: Chris Dumez <cdumez>
Status: RESOLVED FIXED    
Severity: Normal CC: achristensen, aestes, beidson, commit-queue, dbates, ews-watchlist, japhet, rniwa, sam, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: WebKit Nightly Build   
Hardware: Unspecified   
OS: Unspecified   
See Also: https://bugs.webkit.org/show_bug.cgi?id=184544
Bug Depends on:    
Bug Blocks: 184466, 184515, 184591    
Attachments:
Description Flags
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch none

Chris Dumez
Reported 2018-04-10 14:07:08 PDT
Introduce remote variants of Frame / DOMWindow classes, for when these frames / windows are hosted on another WebProcess.
Attachments
Patch (48.71 KB, patch)
2018-04-10 15:14 PDT, Chris Dumez
no flags
Patch (48.07 KB, patch)
2018-04-10 15:57 PDT, Chris Dumez
no flags
Patch (50.75 KB, patch)
2018-04-10 16:14 PDT, Chris Dumez
no flags
Patch (50.75 KB, patch)
2018-04-10 16:23 PDT, Chris Dumez
no flags
Patch (47.55 KB, patch)
2018-04-10 16:45 PDT, Chris Dumez
no flags
Patch (47.59 KB, patch)
2018-04-11 13:26 PDT, Chris Dumez
no flags
Patch (49.93 KB, patch)
2018-04-11 15:01 PDT, Chris Dumez
no flags
Chris Dumez
Comment 1 2018-04-10 14:07:38 PDT
Chris Dumez
Comment 2 2018-04-10 15:14:50 PDT
Chris Dumez
Comment 3 2018-04-10 15:57:53 PDT
Chris Dumez
Comment 4 2018-04-10 16:14:05 PDT
Chris Dumez
Comment 5 2018-04-10 16:23:02 PDT
Chris Dumez
Comment 6 2018-04-10 16:45:10 PDT
Chris Dumez
Comment 7 2018-04-11 13:26:12 PDT
Sam Weinig
Comment 8 2018-04-11 13:56:30 PDT
Comment on attachment 337729 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=337729&action=review > Source/WebCore/ChangeLog:10 > + Introduce remote variants of Frame / DOMWindow classes, for when these frames / windows > + are hosted on another WebProcess. Those will be used in a follow-up patch. Given what a fundamental change this is, I think this could use a more fleshed out ChangeLog. Specifically, I like to see an overview of how these remote variants will work, especially for things like the Frame/DOMWindow tree, openers, etc. > Source/WebCore/ChangeLog:66 > + * page/RemoteDOMWindow.cpp: Added. > + (WebCore::RemoteDOMWindow::RemoteDOMWindow): > + (WebCore::RemoteDOMWindow::~RemoteDOMWindow): > + (WebCore::RemoteDOMWindow::self const): > + (WebCore::RemoteDOMWindow::location const): > + (WebCore::RemoteDOMWindow::close): > + (WebCore::RemoteDOMWindow::closed const): > + (WebCore::RemoteDOMWindow::focus): > + (WebCore::RemoteDOMWindow::blur): > + (WebCore::RemoteDOMWindow::length const): > + (WebCore::RemoteDOMWindow::top const): > + (WebCore::RemoteDOMWindow::opener const): > + (WebCore::RemoteDOMWindow::parent const): > + (WebCore::RemoteDOMWindow::postMessage): > + * page/RemoteDOMWindow.h: Added. > + (isType): It would be nice to have an explanation of why this subset of the DOMWindow API is being exposed (presumably these are the functions/properties exposed cross origin). > Source/WebCore/loader/ContentFilter.cpp:234 > - static_assert(std::is_base_of<ThreadSafeRefCounted<Frame>, Frame>::value, "Frame must be ThreadSafeRefCounted."); > + static_assert(std::is_base_of<ThreadSafeRefCounted<AbstractFrame>, Frame>::value, "Frame must be ThreadSafeRefCounted."); Should probably update the comment too. > Source/WebCore/page/GlobalFrameIdentifier.h:32 > +struct GlobalFrameIdentifier { I think a comment explaining what this is for would be helpful. > Source/WebCore/page/GlobalWindowIdentifier.h:37 > +struct GlobalWindowIdentifier { I think a comment explaining what this is for would be helpful. > Source/WebCore/page/GlobalWindowIdentifier.h:58 > + unsigned hashes[2]; > + hashes[0] = WTF::intHash(processIdentifier.toUInt64()); > + hashes[1] = WTF::intHash(windowIdentifier.toUInt64()); > + > + return StringHasher::hashMemory(hashes, sizeof(hashes)); I believe we traditionally try not to hash hashes, though I do not remember the math behind that. > Source/WebCore/page/RemoteDOMWindow.cpp:44 > + m_frame->setWindow(nullptr); I'm not clear how/if m_frame can become null, but since you null check it in the functions below, it seems like you should either null check it here, or remove the null checks below and convert m_frame to Ref<RemoteFrame>. > Source/WebCore/page/RemoteDOMWindow.h:57 > + // DOM API. An explanation of why this subset is here would be useful.
Chris Dumez
Comment 9 2018-04-11 14:10:05 PDT
Comment on attachment 337729 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=337729&action=review >> Source/WebCore/ChangeLog:10 >> + are hosted on another WebProcess. Those will be used in a follow-up patch. > > Given what a fundamental change this is, I think this could use a more fleshed out ChangeLog. Specifically, I like to see an overview of how these remote variants will work, especially for things like the Frame/DOMWindow tree, openers, etc. Ok, I'll flesh out the changelog and upload the follow-up patch to a separate bug so you can see how it is used.
Chris Dumez
Comment 10 2018-04-11 14:17:36 PDT
Comment on attachment 337729 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=337729&action=review >>> Source/WebCore/ChangeLog:10 >>> + are hosted on another WebProcess. Those will be used in a follow-up patch. >> >> Given what a fundamental change this is, I think this could use a more fleshed out ChangeLog. Specifically, I like to see an overview of how these remote variants will work, especially for things like the Frame/DOMWindow tree, openers, etc. > > Ok, I'll flesh out the changelog and upload the follow-up patch to a separate bug so you can see how it is used. Note that short-term I only plan to implement window.open() cross origin, not out of process iframes. This makes things a bit simpler as only a top-level window/frame can be remote for now. >> Source/WebCore/ChangeLog:66 >> + (isType): > > It would be nice to have an explanation of why this subset of the DOMWindow API is being exposed (presumably these are the functions/properties exposed cross origin). Yes, this is the API subset that is exposed cross origin. It becomes more obvious in the next patch but I'll improve the changelog. >> Source/WebCore/loader/ContentFilter.cpp:234 >> + static_assert(std::is_base_of<ThreadSafeRefCounted<AbstractFrame>, Frame>::value, "Frame must be ThreadSafeRefCounted."); > > Should probably update the comment too. As you wish, it is still true though :) >> Source/WebCore/page/RemoteDOMWindow.cpp:44 >> + m_frame->setWindow(nullptr); > > I'm not clear how/if m_frame can become null, but since you null check it in the functions below, it seems like you should either null check it here, or remove the null checks below and convert m_frame to Ref<RemoteFrame>. Similarly as for regular DOMWindows, RemoteDOMWindows' frame can become null when that frame gets destroyed. Frameless windows behave very differently.
Chris Dumez
Comment 11 2018-04-11 14:25:13 PDT
Comment on attachment 337729 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=337729&action=review >>>> Source/WebCore/ChangeLog:10 >>>> + are hosted on another WebProcess. Those will be used in a follow-up patch. >>> >>> Given what a fundamental change this is, I think this could use a more fleshed out ChangeLog. Specifically, I like to see an overview of how these remote variants will work, especially for things like the Frame/DOMWindow tree, openers, etc. >> >> Ok, I'll flesh out the changelog and upload the follow-up patch to a separate bug so you can see how it is used. > > Note that short-term I only plan to implement window.open() cross origin, not out of process iframes. This makes things a bit simpler as only a top-level window/frame can be remote for now. I uploaded a more complete patch at https://bugs.webkit.org/show_bug.cgi?id=184515 where this code is used. Feedback is most welcome.
Chris Dumez
Comment 12 2018-04-11 15:01:18 PDT
Ryosuke Niwa
Comment 13 2018-04-11 21:00:09 PDT
Comment on attachment 337738 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=337738&action=review > Source/WebCore/page/DOMWindow.cpp:404 > + : AbstractDOMWindow(GlobalWindowIdentifier { Process::identifier(), generateObjectIdentifier<WindowIdentifierType>() }) Process::identifier() grabs a lock... Can we cache the result in a static local variable for the main thread? > Source/WebCore/page/GlobalFrameIdentifier.h:32 > +// Frame identifier that is unique across all WebContent processes. If this is the case, can't we just make DOMWindow identifier generated from frame ID & some monotonically increasing number? We can't have a DOMWindow without a frame, right? > Source/WebCore/page/GlobalWindowIdentifier.h:39 > + ProcessIdentifier processIdentifier; Can't we just use pageID here too?
Chris Dumez
Comment 14 2018-04-11 21:16:33 PDT
(In reply to Ryosuke Niwa from comment #13) > Comment on attachment 337738 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=337738&action=review > > > Source/WebCore/page/DOMWindow.cpp:404 > > + : AbstractDOMWindow(GlobalWindowIdentifier { Process::identifier(), generateObjectIdentifier<WindowIdentifierType>() }) > > Process::identifier() grabs a lock... Can we cache the result in a static > local variable for the main thread? > > > Source/WebCore/page/GlobalFrameIdentifier.h:32 > > +// Frame identifier that is unique across all WebContent processes. > > If this is the case, can't we just make DOMWindow identifier generated from > frame ID & some monotonically increasing number? > We can't have a DOMWindow without a frame, right? > We can totally have a window without a Frame. When a Frame gets navigated, the previous window gets detached from the frame and a new window gets created and attached to the frame. > > Source/WebCore/page/GlobalWindowIdentifier.h:39 > > + ProcessIdentifier processIdentifier; > > Can't we just use pageID here too?
Ryosuke Niwa
Comment 15 2018-04-11 22:02:37 PDT
(In reply to Chris Dumez from comment #14) > (In reply to Ryosuke Niwa from comment #13) > > Comment on attachment 337738 [details] > > Patch > > > > View in context: > > https://bugs.webkit.org/attachment.cgi?id=337738&action=review > > > > > Source/WebCore/page/DOMWindow.cpp:404 > > > + : AbstractDOMWindow(GlobalWindowIdentifier { Process::identifier(), generateObjectIdentifier<WindowIdentifierType>() }) > > > > Process::identifier() grabs a lock... Can we cache the result in a static > > local variable for the main thread? > > > > > Source/WebCore/page/GlobalFrameIdentifier.h:32 > > > +// Frame identifier that is unique across all WebContent processes. > > > > If this is the case, can't we just make DOMWindow identifier generated from > > frame ID & some monotonically increasing number? > > We can't have a DOMWindow without a frame, right? > > > > We can totally have a window without a Frame. When a Frame gets navigated, > the previous window gets detached from the frame and a new window gets > created and attached to the frame. That's fine. We have a frame when we create DOMWindow, and that detached DOMWindow can't inserted back into some other frame, right?
Chris Dumez
Comment 16 2018-04-12 09:06:25 PDT
(In reply to Ryosuke Niwa from comment #15) > (In reply to Chris Dumez from comment #14) > > (In reply to Ryosuke Niwa from comment #13) > > > Comment on attachment 337738 [details] > > > Patch > > > > > > View in context: > > > https://bugs.webkit.org/attachment.cgi?id=337738&action=review > > > > > > > Source/WebCore/page/DOMWindow.cpp:404 > > > > + : AbstractDOMWindow(GlobalWindowIdentifier { Process::identifier(), generateObjectIdentifier<WindowIdentifierType>() }) > > > > > > Process::identifier() grabs a lock... Can we cache the result in a static > > > local variable for the main thread? > > > > > > > Source/WebCore/page/GlobalFrameIdentifier.h:32 > > > > +// Frame identifier that is unique across all WebContent processes. > > > > > > If this is the case, can't we just make DOMWindow identifier generated from > > > frame ID & some monotonically increasing number? > > > We can't have a DOMWindow without a frame, right? > > > > > > > We can totally have a window without a Frame. When a Frame gets navigated, > > the previous window gets detached from the frame and a new window gets > > created and attached to the frame. > > That's fine. We have a frame when we create DOMWindow, and that detached > DOMWindow can't inserted back into some other frame, right? That's right. However, since a Window can exist without a Frame / Page. If I omit the Process Identifier, how do you suggest which WebProcess the DOMWindow is in? We cannot rely on the WebPage / WebFrame identifiers because they may no longer exist and therefore, I wouldn't be able to find them in the HashMaps on the UIProcess side. If anything, I think we may have to reconsider the GlobalFrameIdentifier at some point to start using a ProcessIdentifier too (rather than relying on the PageID), as a Frame can be detached from its page.
Chris Dumez
Comment 17 2018-04-12 09:42:41 PDT
Comment on attachment 337738 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=337738&action=review >>>>> Source/WebCore/page/DOMWindow.cpp:404 >>>>> + : AbstractDOMWindow(GlobalWindowIdentifier { Process::identifier(), generateObjectIdentifier<WindowIdentifierType>() }) >>>> >>>> Process::identifier() grabs a lock... Can we cache the result in a static local variable for the main thread? >>> >>> We can totally have a window without a Frame. When a Frame gets navigated, the previous window gets detached from the frame and a new window gets created and attached to the frame. >> >> That's fine. We have a frame when we create DOMWindow, and that detached DOMWindow can't inserted back into some other frame, right? > > That's right. However, since a Window can exist without a Frame / Page. If I omit the Process Identifier, how do you suggest which WebProcess the DOMWindow is in? We cannot rely on the WebPage / WebFrame identifiers because they may no longer exist and therefore, I wouldn't be able to find them in the HashMaps on the UIProcess side. > > If anything, I think we may have to reconsider the GlobalFrameIdentifier at some point to start using a ProcessIdentifier too (rather than relying on the PageID), as a Frame can be detached from its page. Regarding the locking, I'll talk with Brady since he wrote the Process Identifier code. As far as I can tell, there is no need for such locking and we could rewrite the code like so: void setIdentifier(ProcessIdentifier processIdentifier) { ASSERT(isMainThread()); globalIdentifier = processIdentifier; } ProcessIdentifier identifier() { static std::once_flag onceFlag; std::call_once(onceFlag, [] { if (!globalIdentifier) globalIdentifier = generateThreadSafeObjectIdentifier<ProcessIdentifierType>(); }); return *globalIdentifier; } Process::setIdentifier() gets called once, upon ChildProcess initialization, on the main thread. Then, it shouldn't matter that later on, Process::identifier() gets called on background thread since the variable has already been initialized. If it hasn't, then we can rely on the std::call_once() and generateThreadSafeObjectIdentifier for this uncommon case. At least, the common case (identifier has been initialized) would not do any locking.
Ryosuke Niwa
Comment 18 2018-04-12 11:10:04 PDT
Okay, then your current approach seems fine to me. We may want to add some DEBUG assertions to make sure the timing of setProcessIdentifier doesn't get changed e.g. to make process startup more lazy.
WebKit Commit Bot
Comment 19 2018-04-12 16:55:08 PDT
Comment on attachment 337738 [details] Patch Clearing flags on attachment: 337738 Committed r230613: <https://trac.webkit.org/changeset/230613>
WebKit Commit Bot
Comment 20 2018-04-12 16:55:10 PDT
All reviewed patches have been landed. Closing bug.
Chris Dumez
Comment 21 2018-04-20 11:44:33 PDT
*** Bug 184151 has been marked as a duplicate of this bug. ***
Note You need to log in before you can comment on or make changes to this bug.