{"id":276,"date":"2012-01-24T23:07:46","date_gmt":"2012-01-25T07:07:46","guid":{"rendered":"http:\/\/blog.mozilla.org\/luke\/?p=276"},"modified":"2020-09-28T14:18:57","modified_gmt":"2020-09-28T21:18:57","slug":"jsruntime-is-now-officially-single-threaded","status":"publish","type":"post","link":"https:\/\/blog.mozilla.org\/luke\/2012\/01\/24\/jsruntime-is-now-officially-single-threaded\/","title":{"rendered":"JSRuntime is now officially single-threaded"},"content":{"rendered":"<p>Given this title, a reasonable reaction would be:<\/p>\n<blockquote><p>\nWait, wait, <em>single<\/em> threaded?!\u00a0 But isn&#8217;t that, like, the wrong direction for the multicore present and manycore future?\n<\/p><\/blockquote>\n<p>so let me start by clearing this up:<br \/>\n<strong><br \/>\nA single SpiderMonkey runtime (that is, instance of <code>JSRuntime<\/code>) &#8212; and all the objects, strings and contexts associated with it &#8212; may only be accessed by a single thread at any given time.  However, a SpiderMonkey embedding may create multiple runtimes in the same process (each of which may be accessed by a different thread).<br \/>\n<\/strong><br \/>\nThat means it is up to the embedding to provide communication (if any) between the runtimes via <code>JSNative<\/code> or other SpiderMonkey hooks.  One working example is the <a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/source\/dom\/workers\/\">new implementation<\/a> of <a href=\"http:\/\/dev.w3.org\/html5\/workers\/\">web workers<\/a> in Firefox which uses a runtime per worker.  Niko Matsakis is experimenting with a different architecture in his new <a href=\"http:\/\/smallcultfollowing.com\/babysteps\/blog\/2012\/01\/09\/parallel-javascript\/\">parallel JS project<\/a>.<\/p>\n<p>So that&#8217;s the quick summary.  Now, for the interested, I&#8217;ll back up and explain the situation, how we got here, and where we are going in more detail.<\/p>\n<h3>Ghosts of SpiderMonkey past<\/h3>\n<p>In the beginning, as Brendan explains, Java-style big-shared-mutable-heap concurrency was all the rage and so, as Java&#8217;s kid brother, SpiderMonkey also had big-shared-mutable-heap concurrency.  Now, locks weren&#8217;t ever (afaik) exposed to JS as part of SpiderMonkey, but an embedding could add them easily with a <code>JSNative<\/code>.  However, SpiderMonkey did support concurrent atomic operations on objects with a clever (<a href=\"http:\/\/www.google.com\/patents\/US6892200\">patented<\/a>, even) locking scheme that avoided synchronization overhead for most operations.<\/p>\n<p>This initial threading design stayed in place until about a year before Firefox 4.0 when the <a href=\"http:\/\/andreasgal.com\/2010\/10\/13\/compartments\/\">compartments<\/a> project picked up steam.  The key new concept introduced by this project was, well, the <em>compartment<\/em>. A runtime contains a set of compartments and each compartment contains a set of objects.  Every object is in exactly one compartment and any reference between objects in different compartments must go through a wrapper.  With compartments and wrappers, you can implement a sort of membrane that is useful for all kinds of things: GC, security boundaries, JIT compilation invariants, memory accounting, and <a href=\"http:\/\/wiki.ecmascript.org\/doku.php?id=harmony:direct_proxies\">JS proxies<\/a>.  Overall, I would say that compartments are one honking great idea.<\/p>\n<p>The important thing about compartments for this story, though, is that the implementation effort really wanted single-threaded access to everything in a compartment.  To be honest, I don&#8217;t know the particular technical issue raised at the time, but it isn&#8217;t hard to see how single-threaded-ness was a necessary simplification for such a challenging plan (viz., shipping compartments with Firefox 4).  Anyway, the decision was made and compartments became single-threaded.<\/p>\n<p>After Firefox 4 another great choice was made to <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=649537\">rewrite Firefox&#8217;s implementation of web workers<\/a> to not use XPConnect and to instead create a new runtime per worker.  The choice was made because, even though a runtime allowed multi-threaded execution, there were still some <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=617569\">global<\/a> <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=654265\">bottlenecks<\/a> such as GC and allocation that were killing workers&#8217; parallelism.<\/p>\n<h3>I&#8217;m Talking About Drawing a Line in the Sand<\/h3>\n<p>With web workers in separate runtimes, there were no significant multi-threaded runtime uses remaining.  Furthermore, to achieve single-threaded compartments, the platform features that allowed JS to easily ship a closure off to another thread had been removed since closures fundamentally carry with them a reference to their original enclosing scope.  Even non-Mozilla SpiderMonkey embeddings had reportedly experienced problems that pushed them toward a similar shared-nothing design.  Thus, there was little reason to maintain the non-trivial complexity caused by multi-threading support.<\/p>\n<p>There are a lot of things that &#8220;would be nice&#8221; but what pushed us over the edge is that a single-threaded runtime allows us to hoist a lot data currently stored per-compartment into the runtime.  This provides <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=720753#c0\">immediate memory savings<\/a> and also enables another <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=650353\">big change<\/a> we want to make that would create a lot more compartments (and thus needs compartments to be lighter-weight).<\/p>\n<p>Thus, the decision was made to try to make SpiderMonkey single-threaded as an API requirement.  A <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=650411\">bug<\/a> was filed in April 2011 and an <a href=\"http:\/\/groups.google.com\/group\/mozilla.dev.tech.js-engine\/msg\/ae5f22f39e4fd150\">announcement<\/a> was made on dev.tech.js-engine a month after.<\/p>\n<h3>Across this line you do not&#8230;<\/h3>\n<p>April 2011 to&#8230; January 2012&#8230; what took so long?<\/p>\n<p>Well, to begin with, there were quite a few minor uses of <code>JSRuntime<\/code> off the main thread that had to be chased down.  Also, each of these cases required understanding new parts of the codebase and, in several cases, waiting a few months for other kind-hearted, but very busy, Mozillians to fix <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=679140\">things<\/a> for me.  The biggest problem was xpcom proxies (not to be confused with JS proxies, which are awesome).  Fortunately, Benjamin Smedberg already had a beef with <code>xpcom\/proxy<\/code> and (just recently) <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=675221\">nuked the whole directory from orbit<\/a>.<\/p>\n<p>After getting try server to pass without hitting any of the 10,000 places where single-thread-ness gets verified in debug builds, we couldn&#8217;t exactly just rip out the multi-threading support.  The worry we had was that some popular add-ons would break the whole browser and we&#8217;d be faced with an uncomfortable backout situation.  Thus, we landed a simple patch that asserts single-threaded-ness in a few pinch points <em>in release builds<\/em> and waited for the assert to make its way to a bigger audience.  (I think this is a great example of how the rapid-release process enables developers.)<\/p>\n<p>As of right now, the assert is in Firefox 10 Beta and slated to be released on January 31st.  There are <del datetime=\"2012-02-08T22:04:37+00:00\">three<\/del> four known offending extensions:<\/p>\n<ul>\n<li>The <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=704249\">IcedTea Java plugin<\/a> on Linux seems to hit the assert for some applets. [Update: this was reported fixed in version 1.2pre]<\/li>\n<li><a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=715744\">BExternal.dll<\/a> and <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=715748\">gemgecko.dll<\/a> are touching the main-thread only pref service off the main thread (already a bug) which ends up calling a JS observer.  [Update: Both Gemius and Babylon seem to have shipped fixes]\n<li>[UPDATE] The <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=715757#c9\">DivX plugin<\/a>.<\/li>\n<\/ul>\n<p>Based on these results, we are concluding that the invariant &#8220;stuck&#8221; and thus we can actually make changes that assume single-threaded-ness.  Indeed, the first <a href=\"https:\/\/hg.mozilla.org\/integration\/mozilla-inbound\/rev\/e517d4c43143\">bomb<\/a> has been dropped (taking along 2200 lines of code along with it, and <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=720045\">this<\/a> <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=720013\">is<\/a> <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=680562\">just<\/a> <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=720018\">the<\/a> <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=719858\">beginning<\/a>).<\/p>\n<h3>The single-threaded invariant in detail<\/h3>\n<p>Each runtime now has an &#8220;owner thread&#8221; (<code>JSRuntime::ownerThread<\/code>).  The &#8220;owner thread&#8221; is the id of the only OS thread allowed to touch the runtime.  This owner thread is set to the current thread (<code>PR_GetCurrentThread()<\/code>) from <code>JS_NewRuntime<\/code> and may only be changed &#8212; when no JS is executing in the runtime &#8212; via <code><a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/ident?i=JS_ClearRuntimeThread\">JS_ClearRuntimeThread<\/a><\/code>\/<code><a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/ident?i=JS_SetRuntimeThread\">JS_SetRuntimeThread<\/a><\/code>.  Virtually every JSAPI function that takes a <code>JSContext<\/code> parameter will assert that <code>PR_GetCurrentThread == cx->runtime->ownerThread()<\/code>.<\/p>\n<p>It should be mentioned that there are still a few remaining sources of concurrency:<\/p>\n<ul>\n<li>The <a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/ident?i=GCHelperThread\">background-sweeping thread<\/a> cleans up garbage objects which don&#8217;t have finalizers.  Its interaction with the VM is pretty well isolated to the GC.<\/li>\n<li>Pretty much the only JSAPI function that can be called off the main thread is <a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/search?string=JS_TriggerOperationCallback\">JS_TriggerOperationCallback<\/a>.  This is how the the <a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/ident?i=WatchdogMain\">watchdog thread<\/a> stops runaway JS.  Fortunately, the interaction with the VM is through a single field: <code>JSRuntime::interrupt<\/code>.<\/li>\n<\/ul>\n<p>One last thing to point out is that SpiderMonkey&#8217;s architecture will likely continue evolving to meet new concurrency needs.  Indeed, concurrent runtimes may one day return in a more restricted and structured form.  But maybe not; we&#8217;ll see.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Given this title, a reasonable reaction would be: Wait, wait, single threaded?!\u00a0 But isn&#8217;t that, like, the wrong direction for the multicore present and manycore future? so let me start by clearing this up: A single SpiderMonkey runtime (that is, &hellip; <a href=\"https:\/\/blog.mozilla.org\/luke\/2012\/01\/24\/jsruntime-is-now-officially-single-threaded\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":257,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[5],"tags":[],"_links":{"self":[{"href":"https:\/\/blog.mozilla.org\/luke\/wp-json\/wp\/v2\/posts\/276"}],"collection":[{"href":"https:\/\/blog.mozilla.org\/luke\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.mozilla.org\/luke\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/luke\/wp-json\/wp\/v2\/users\/257"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/luke\/wp-json\/wp\/v2\/comments?post=276"}],"version-history":[{"count":0,"href":"https:\/\/blog.mozilla.org\/luke\/wp-json\/wp\/v2\/posts\/276\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.mozilla.org\/luke\/wp-json\/wp\/v2\/media?parent=276"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mozilla.org\/luke\/wp-json\/wp\/v2\/categories?post=276"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mozilla.org\/luke\/wp-json\/wp\/v2\/tags?post=276"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}