RESOLVED FIXED 96522
[V8] Give isolated shells a lifecycle like that of main shells
https://bugs.webkit.org/show_bug.cgi?id=96522
Summary [V8] Give isolated shells a lifecycle like that of main shells
Dan Carney
Reported Wednesday, September 12, 2012 4:24:17 PM UTC
Give isolated shells a lifecycle like that of main shells
Attachments
Patch (6.77 KB, patch)
2012-09-12 08:27 PDT, Dan Carney
abarth: review+
abarth: commit-queue-
Patch (9.08 KB, patch)
2012-09-14 05:30 PDT, Dan Carney
no flags
Patch (5.85 KB, patch)
2012-11-23 07:13 PST, Dan Carney
no flags
Dan Carney
Comment 1 Wednesday, September 12, 2012 4:27:51 PM UTC
Dan Carney
Comment 2 Wednesday, September 12, 2012 4:35:20 PM UTC
I don't fully trust this, as the context global object stores a raw pointer to the isolated shell, so a callback coming back after the death of the shell, which happens on ScriptController deletion would segfault. Is it possible for such a callback to happen?
Adam Barth
Comment 3 Wednesday, September 12, 2012 7:41:41 PM UTC
Comment on attachment 163637 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=163637&action=review > Source/WebCore/bindings/v8/ScriptController.cpp:115 > + for (IsolatedWorldMap::iterator iter = m_isolatedWorlds.begin(); > + iter != m_isolatedWorlds.end(); ++iter) { > + iter->second->destroyGlobal(); > + } Typically, we'd put the loop condition on one line and drop the { } > Source/WebCore/bindings/v8/ScriptController.cpp:337 > OwnPtr<V8DOMWindowShell> isolatedWorldShell = V8DOMWindowShell::create(m_frame, world); > - m_isolatedWorlds.set(world->worldId(), isolatedWorldShell.get()); > + m_isolatedWorlds.set(world->worldId(), adoptPtr(isolatedWorldShell.get())); > return isolatedWorldShell.leakPtr(); This isn't quite the right idiom. What we typically do in these cases is to introduce a local variable to hold a V8DOMWidowShell* like this: V8DOMWindowShell* result = isolatedWorldShell.get(); m_isolatedWorlds.set(world->worldId(), isolatedWorldShell.release()); return result; The reason we do this is because we use calls to leakPtr as a signal that we might have a memory leak. Keeping the call to leakPtr here will make this show up on our periodic leakPtr audits. > Source/WebCore/bindings/v8/ScriptController.cpp:360 > OwnPtr<V8DOMWindowShell> isolatedWorldShell = V8DOMWindowShell::create(m_frame, world); > - m_isolatedWorlds.set(world->worldId(), isolatedWorldShell.get()); > + m_isolatedWorlds.set(world->worldId(), adoptPtr(isolatedWorldShell.get())); > return isolatedWorldShell.leakPtr(); > } Same here. > Source/WebCore/bindings/v8/ScriptController.cpp:403 > + V8DOMWindowShell* ownedShell = it->second.leakPtr(); > + ASSERT(ownedShell == isolatedWorldShell); > + m_isolatedWorlds.remove(it); > + ownedShell->destroyIsolatedShell(); Again, we should avoid calling leakPtr. The point of OwnPtr is for the C++ type system to help us call new and delete exactly the right number of times. Calling leakPtr is fighting the type system rather than working with it. How about: OwnPtr<V8DOMWindowShell> windowShell = it->second.release(); m_isolatedWorlds.remove(it); windowShell->destroyIsolatedShell();
Adam Barth
Comment 4 Wednesday, September 12, 2012 7:45:45 PM UTC
Comment on attachment 163637 [details] Patch I don't understand how you avoided removing this line in V8DOMWindowShell: delete static_cast<V8DOMWindowShell*>(parameter); It seems like we're still managing the lifetime of the V8DOMWindowShell via the V8 GC.
Dan Carney
Comment 5 Wednesday, September 12, 2012 8:04:33 PM UTC
Comment on attachment 163637 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=163637&action=review >> Source/WebCore/bindings/v8/ScriptController.cpp:115 >> + } > > Typically, we'd put the loop condition on one line and drop the { } ok >> Source/WebCore/bindings/v8/ScriptController.cpp:337 >> return isolatedWorldShell.leakPtr(); > > This isn't quite the right idiom. What we typically do in these cases is to introduce a local variable to hold a V8DOMWidowShell* like this: > > V8DOMWindowShell* result = isolatedWorldShell.get(); > m_isolatedWorlds.set(world->worldId(), isolatedWorldShell.release()); > return result; > > The reason we do this is because we use calls to leakPtr as a signal that we might have a memory leak. Keeping the call to leakPtr here will make this show up on our periodic leakPtr audits. That makes sense. Okay, I wasn't sure what the typical usage was, and I was trying to avoid a local variable for something I already had. >> Source/WebCore/bindings/v8/ScriptController.cpp:360 >> } > > Same here. yep. >> Source/WebCore/bindings/v8/ScriptController.cpp:403 >> + ownedShell->destroyIsolatedShell(); > > Again, we should avoid calling leakPtr. The point of OwnPtr is for the C++ type system to help us call new and delete exactly the right number of times. Calling leakPtr is fighting the type system rather than working with it. > > How about: > > OwnPtr<V8DOMWindowShell> windowShell = it->second.release(); > m_isolatedWorlds.remove(it); > windowShell->destroyIsolatedShell(); Actually, here, we need to specifically take ownership and leak the pointer as this shell must remain weak. A strong deletion here is a bad thing because of callbacks.
Adam Barth
Comment 6 Wednesday, September 12, 2012 8:08:21 PM UTC
Comment on attachment 163637 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=163637&action=review >>> Source/WebCore/bindings/v8/ScriptController.cpp:403 >>> + ownedShell->destroyIsolatedShell(); >> >> Again, we should avoid calling leakPtr. The point of OwnPtr is for the C++ type system to help us call new and delete exactly the right number of times. Calling leakPtr is fighting the type system rather than working with it. >> >> How about: >> >> OwnPtr<V8DOMWindowShell> windowShell = it->second.release(); >> m_isolatedWorlds.remove(it); >> windowShell->destroyIsolatedShell(); > > Actually, here, we need to specifically take ownership and leak the pointer as this shell must remain weak. A strong deletion here is a bad thing because of callbacks. Why you say callbacks, what do you mean? If we're trying to make the lifetime of the isolated window shells the same as the main window shells, that means they need to live as long as the frame lives and not have their lifetime determined by the garbage collector.
Dan Carney
Comment 7 Wednesday, September 12, 2012 8:13:51 PM UTC
(In reply to comment #6) > (From update of attachment 163637 [details]) > View in context: https://bugs.webkit.org/attachment.cgi?id=163637&action=review > > >>> Source/WebCore/bindings/v8/ScriptController.cpp:403 > >>> + ownedShell->destroyIsolatedShell(); > >> > >> Again, we should avoid calling leakPtr. The point of OwnPtr is for the C++ type system to help us call new and delete exactly the right number of times. Calling leakPtr is fighting the type system rather than working with it. > >> > >> How about: > >> > >> OwnPtr<V8DOMWindowShell> windowShell = it->second.release(); > >> m_isolatedWorlds.remove(it); > >> windowShell->destroyIsolatedShell(); > > > > Actually, here, we need to specifically take ownership and leak the pointer as this shell must remain weak. A strong deletion here is a bad thing because of callbacks. > > Why you say callbacks, what do you mean? If we're trying to make the lifetime of the isolated window shells the same as the main window shells, that means they need to live as long as the frame lives and not have their lifetime determined by the garbage collector. Just for the single use shells. The ones that enter evaluateInIsolatedWorld with an uninitializedWorldId or in the test environment with a worldId of 0. I'm not exactly sure how to get one of them to execute outside of the test environment, but I know that PageGroup keeps a bunch of references to them. I 'm happy to remove all that code and leave the references alive until ScriptController deletion. It's just that those particular shell can't be accessed except from callbacks at that point, so we're keeping a lot of stuff alive unnecessarily.
Dan Carney
Comment 8 Wednesday, September 12, 2012 8:20:52 PM UTC
> Why you say callbacks, what do you mean? Sorry, asynchronous javascript callbacks. The shell needs to stay alive long enough for them not to segfault as a raw pointer to the shell exists in the context's global object.
Adam Barth
Comment 9 Wednesday, September 12, 2012 8:25:20 PM UTC
> Sorry, asynchronous javascript callbacks. The shell needs to stay alive long enough for them not to segfault as a raw pointer to the shell exists in the context's global object. Can we clear out their pointer to the WindowShell? In the main world, we detach the v8::Context from the WindowShell and it continues to function.
Adam Barth
Comment 10 Wednesday, September 12, 2012 8:27:06 PM UTC
Comment on attachment 163637 [details] Patch By the way, I think we should land this patch and then iterate on this temporary world issue. If they're only used in testing, then it is not super important that we'll keep them alive longer. It's important that we don't have a different code path for testing than in production. We want our testing to be as close to production as possible.
Dan Carney
Comment 11 Wednesday, September 12, 2012 8:45:27 PM UTC
(In reply to comment #9) > > Sorry, asynchronous javascript callbacks. The shell needs to stay alive long enough for them not to segfault as a raw pointer to the shell exists in the context's global object. > > Can we clear out their pointer to the WindowShell? In the main world, we detach the v8::Context from the WindowShell and it continues to function. It's a bit problematic. If it were cleared, the call to V8DOMWindowShell::entered() return null and which indicated that we're in the mainworld, which is not where the callbacks are suppose to execute.
Dan Carney
Comment 12 Wednesday, September 12, 2012 8:47:52 PM UTC
(In reply to comment #10) > (From update of attachment 163637 [details]) > By the way, I think we should land this patch and then iterate on this temporary world issue. If they're only used in testing, then it is not super important that we'll keep them alive longer. > > It's important that we don't have a different code path for testing than in production. We want our testing to be as close to production as possible. There's definitely used. But I think you need a particular extension property or maybe a platform app to hit the code path. I've tried a number of variants, but haven't found one that works. This code path trigger a canary crash a few weeks ago when I tried to remove IsolatedWorld, so it's definitely used.
Adam Barth
Comment 13 Wednesday, September 12, 2012 9:09:41 PM UTC
> It's a bit problematic. If it were cleared, the call to V8DOMWindowShell::entered() return null and which indicated that we're in the mainworld, which is not where the callbacks are suppose to execute. Yeah, we probably need to change that design as well. Ok, let's keep this for now. It shouldn't block the main thing you're trying to accomplish.
Dan Carney
Comment 14 Thursday, September 13, 2012 1:34:49 PM UTC
I was too worried about the raw pointer in the context global object, so I've refactored it out in another patch.
Dan Carney
Comment 15 Friday, September 14, 2012 1:30:00 PM UTC
WebKit Review Bot
Comment 16 Friday, September 14, 2012 2:28:24 PM UTC
Comment on attachment 164116 [details] Patch Rejecting attachment 164116 [details] from commit-queue. Failed to run "['/mnt/git/webkit-commit-queue/Tools/Scripts/webkit-patch', '--status-host=queues.webkit.org', '-..." exit_code: 2 Last 500 characters of output: 1 FAILED at 246. Hunk #2 succeeded at 264 (offset 1 line). 1 out of 3 hunks FAILED -- saving rejects to file Source/WebCore/bindings/v8/V8DOMWindowShell.cpp.rej patching file Source/WebCore/bindings/v8/V8DOMWindowShell.h Hunk #1 FAILED at 74. Hunk #2 FAILED at 104. 2 out of 2 hunks FAILED -- saving rejects to file Source/WebCore/bindings/v8/V8DOMWindowShell.h.rej Failed to run "[u'/mnt/git/webkit-commit-queue/Tools/Scripts/svn-apply', u'--force']" exit_code: 1 cwd: /mnt/git/webkit-commit-queue Full output: http://queues.webkit.org/results/13839932
Kentaro Hara
Comment 17 Friday, September 14, 2012 2:29:17 PM UTC
Looks like you need to rebase it.
Dan Carney
Comment 18 Friday, September 14, 2012 2:31:44 PM UTC
(In reply to comment #17) > Looks like you need to rebase it. No, it got applied just after a previous patch got reverted. I'll have to resubmit this once that patch goes through again.
Dan Carney
Comment 19 Friday, November 23, 2012 3:13:21 PM UTC
Kentaro Hara
Comment 20 Friday, November 23, 2012 3:17:23 PM UTC
Comment on attachment 175804 [details] Patch LGTM. abarth will want to look.
WebKit Review Bot
Comment 21 Monday, November 26, 2012 8:11:22 AM UTC
Comment on attachment 175804 [details] Patch Clearing flags on attachment: 175804 Committed r135687: <http://trac.webkit.org/changeset/135687>
WebKit Review Bot
Comment 22 Monday, November 26, 2012 8:11:27 AM UTC
All reviewed patches have been landed. Closing bug.
Note You need to log in before you can comment on or make changes to this bug.