RESOLVED FIXED Bug 99178
[JSC] DOM URL is flaky when workers are used
https://bugs.webkit.org/show_bug.cgi?id=99178
Summary [JSC] DOM URL is flaky when workers are used
Allan Sandfeld Jensen
Reported 2012-10-12 07:46:11 PDT
When the DOM URL Constructor is used in both a main thread and a worker thread, the results becomes unstable. Specifically the methods will be likely to become undefined in one of the contexts (for JSC in V8 it seems to crash). The reason seems to be that HashTable::createTable in Lookup.h registers the method names, only in the current context, once another context accesses the same table, it will be unable to lookup the identifiers used to access the methods.
Attachments
TestCase (1.79 KB, application/octet-stream)
2012-10-12 07:52 PDT, Allan Sandfeld Jensen
no flags
Patch (1.48 KB, patch)
2012-10-12 08:31 PDT, Allan Sandfeld Jensen
no flags
Patch (8.04 KB, patch)
2012-10-15 02:50 PDT, Allan Sandfeld Jensen
no flags
Allan Sandfeld Jensen
Comment 1 2012-10-12 07:52:43 PDT
Created attachment 168420 [details] TestCase A simple test-case. Window.URL.createObjectURL will be undefined in the main-thread because the table for JSDOMURL was created in the worker thread context.
Allan Sandfeld Jensen
Comment 2 2012-10-12 08:17:23 PDT
Besides the attached test-case, this bug affects the existing tests fast/files/workers/worker-apply-blob-url-to-xhr.html and fast/files/workers/worker-read-blob-async.html
Allan Sandfeld Jensen
Comment 3 2012-10-12 08:31:47 PDT
Created attachment 168423 [details] Patch A proof-of-concept patch. The patch solves the issue, but I am guessing this solution could cause preformance regressions. Putting it for review anyway to get feedback on this tricky issue.
Allan Sandfeld Jensen
Comment 4 2012-10-12 08:52:51 PDT
Clarifying the descriptions. What happens is that the method names such "createObjectURL" becomes different StringImpl pointers in different threads. This is probably a good idea since StringImpl is not thread-safe. Unfortunately the HashTable uses the StringImpl pointer as the key in it table. This means it will fail to find the correct methods when asked to do a lookup with a StringImpl* from another thread than the one the table was instantiated in. The reason it causes flakiness is one, that the table is instantiated lazy, and two, that these tables can survive page-reload. Making it depend on both timing and what has been run before.
Geoffrey Garen
Comment 5 2012-10-12 09:03:40 PDT
Your instinct is right that comparing Strings instead of StringImpl*s is a performance issue. Typically, we solve threading problems with strings by making an isolatedCopy() before moving a string to another thread. Can you explain why that technique doesn't work in this case?
Allan Sandfeld Jensen
Comment 6 2012-10-12 09:49:34 PDT
(In reply to comment #5) > Your instinct is right that comparing Strings instead of StringImpl*s is a performance issue. > > Typically, we solve threading problems with strings by making an isolatedCopy() before moving a string to another thread. Can you explain why that technique doesn't work in this case? There are no string moved from one thread to another here. This is a special case of a DOM object that is shared between different threads. As far as I can tell there are almost no other global DOM objects shared the same way, the only ones I could find with a quick scan were the element factories and the Notifications API.
Geoffrey Garen
Comment 7 2012-10-12 10:55:16 PDT
> There are no string moved from one thread to another here. This is a special case of a DOM object that is shared between different threads. OK. It's invalid in WebKit to share a DOM object between threads. In addition to this specific JavaScript issue, all AtomicString usage will be broken, string reference counting will be broken, and reference counting of the DOM url object will be broken.
Allan Sandfeld Jensen
Comment 8 2012-10-12 11:06:24 PDT
(In reply to comment #7) > > There are no string moved from one thread to another here. This is a special case of a DOM object that is shared between different threads. > > OK. It's invalid in WebKit to share a DOM object between threads. In addition to this specific JavaScript issue, all AtomicString usage will be broken, string reference counting will be broken, and reference counting of the DOM url object will be broken. Yeah, it thought it was kinda of crazy too, but since is the first time I am in contact with this code I do not know what thoughts went into the current design. The commit that changed it from being dynamically allocated in the workers, state that it was changed to being a static object due to the specification; but I don't think that necessarily should require us to share the method tables between all users of the object.
Alexey Proskuryakov
Comment 9 2012-10-12 13:35:06 PDT
Comment on attachment 168423 [details] Patch As you are new to this code, I'll also mention that JSNoStaticTables is what prevents sharing tables between objects and workers and ones on main thread. Sharing a single object just isn't going to work for more reasons that just method tables, as Geoff explained.
Allan Sandfeld Jensen
Comment 10 2012-10-15 02:05:03 PDT
(In reply to comment #9) > (From update of attachment 168423 [details]) > As you are new to this code, I'll also mention that JSNoStaticTables is what prevents sharing tables between objects and workers and ones on main thread. > From inspecting the generated code it looks like JSNoStaticTables ensures that JSDOMURL::getOwnPropertySlot goes through separate tables for each GlobalData. The problem is then that these methods are accessed through JSDOMURLConstructor::getOwnPropertySlot which does not look up separate tables for each GlobalDAta. Compare: bool JSDOMURLConstructor::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { return getStaticPropertySlot<JSDOMURLConstructor, JSDOMWrapper>(exec, &JSDOMURLConstructorTable, jsCast<JSDOMURLConstructor*>(cell), propertyName, slot); } bool JSDOMURL::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { JSDOMURL* thisObject = jsCast<JSDOMURL*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info); return getStaticValueSlot<JSDOMURL, Base>(exec, getJSDOMURLTable(exec), thisObject, propertyName, slot); } If I instrument the source-code, I never see calls to JSDOMURL::getOwnPropertySlot, but accessing URL.createObjectURL will instead access JSValue JSDOMURL::getConstructor and then JSDOMURLConstructor::getOwnPropertySlot.
Allan Sandfeld Jensen
Comment 11 2012-10-15 02:50:34 PDT
Allan Sandfeld Jensen
Comment 12 2012-10-18 01:53:25 PDT
The attached patch trivially extends the JSNoStaticTable mechanism to also create separate static tables for constructor objects, and it solves this bug, but I need someone more experienced in this code to tell if there was a reason this had not already been done to constructor objects, or if it was just an oversight.
Alexey Proskuryakov
Comment 13 2012-10-18 08:16:32 PDT
Historically, this was an oversight - I know because I wrote it. But I'm not qualified enough to review.
Eric Seidel (no email)
Comment 14 2012-10-18 15:12:18 PDT
I'm certain one of the JSC ninjas can set you straight here.
Allan Sandfeld Jensen
Comment 15 2012-10-29 10:52:46 PDT
Ping, are none of JSC reviewers among the CC'ed able to review this patch?
Eric Seidel (no email)
Comment 16 2012-10-29 11:07:57 PDT
Add Papa JSC.
Geoffrey Garen
Comment 17 2012-10-30 16:49:36 PDT
Comment on attachment 168658 [details] Patch r=me
WebKit Review Bot
Comment 18 2012-10-30 18:43:21 PDT
Comment on attachment 168658 [details] Patch Clearing flags on attachment: 168658 Committed r132973: <http://trac.webkit.org/changeset/132973>
WebKit Review Bot
Comment 19 2012-10-30 18:43:26 PDT
All reviewed patches have been landed. Closing bug.
Csaba Osztrogonác
Comment 20 2012-10-30 23:53:46 PDT
(In reply to comment #18) > (From update of attachment 168658 [details]) > Clearing flags on attachment: 168658 > > Committed r132973: <http://trac.webkit.org/changeset/132973> It broke the bindings tests. Could you fix it?
Allan Sandfeld Jensen
Comment 21 2012-10-31 03:55:05 PDT
Needs to have a fixup on the bindings tests, since they compare generated CPP output instead of functionality change.
Allan Sandfeld Jensen
Comment 22 2012-10-31 04:00:25 PDT
Roger Fong
Comment 23 2012-10-31 18:10:28 PDT
Test fails on Apple Windows port. -PASS: window.URL.createObjectURL defined -PASS: window.URL.revokeObjectURL defined -PASS: URL.createObjectURL defined -PASS: URL.revokeObjectURL defined -PASS: window.URL.createObjectURL defined -PASS: window.URL.revokeObjectURL defined +CONSOLE MESSAGE: line 28: TypeError: 'undefined' is not an object (evaluating 'window.URL.createObjectURL') +FAIL: Timed out waiting for notifyDone to be called Looks like window.URL is null? I can't test further because DRT seems to be broken on Windows right now :/
Zan Dobersek
Comment 24 2012-11-01 02:40:42 PDT
*** Bug 100136 has been marked as a duplicate of this bug. ***
Allan Sandfeld Jensen
Comment 25 2012-11-01 04:28:35 PDT
(In reply to comment #23) > Test fails on Apple Windows port. > -PASS: window.URL.createObjectURL defined > -PASS: window.URL.revokeObjectURL defined > -PASS: URL.createObjectURL defined > -PASS: URL.revokeObjectURL defined > -PASS: window.URL.createObjectURL defined > -PASS: window.URL.revokeObjectURL defined > +CONSOLE MESSAGE: line 28: TypeError: 'undefined' is not an object (evaluating 'window.URL.createObjectURL') > +FAIL: Timed out waiting for notifyDone to be called > > Looks like window.URL is null? I can't test further because DRT seems to be broken on Windows right now :/ Maybe you do not have BLOB enabled? In that case you need to skip this test.
Roger Fong
Comment 26 2012-11-01 10:59:50 PDT
Ah yup, that would be it. Thanks, I'll add it on.
Note You need to log in before you can comment on or make changes to this bug.