Merge m-c to b2g-inbound
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 14 Feb 2014 15:32:34 -0500
changeset 169352 f76658f81e7db7c9c0c15bd6c220a94afb850dea
parent 169351 c2fe19e050cf7de9e89d0bd7d7b147099faf04e9 (current diff)
parent 169224 33b3248b4aa09fbaf85fdc5f4a72e67b0e79cdc9 (diff)
child 169353 4d5d2de3b156c7cc1a81091429e38d86398e139c
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
milestone30.0a1
Merge m-c to b2g-inbound
mobile/android/base/CameraImageResultHandler.java
mobile/android/base/CameraVideoResultHandler.java
mobile/android/base/FilePickerResultHandlerSync.java
mobile/android/base/util/EventDispatcher.java
mobile/android/base/util/GeckoEventResponder.java
--- a/accessible/src/base/TextAttrs.cpp
+++ b/accessible/src/base/TextAttrs.cpp
@@ -74,16 +74,19 @@ TextAttrsMgr::GetAttributes(nsIPersisten
   if (!rootFrame)
     return;
 
   nsIContent *offsetNode = nullptr, *offsetElm = nullptr;
   nsIFrame *frame = nullptr;
   if (mOffsetAcc) {
     offsetNode = mOffsetAcc->GetContent();
     offsetElm = nsCoreUtils::GetDOMElementFor(offsetNode);
+    NS_ASSERTION(offsetElm, "No element for offset accessible!");
+    if (!offsetElm)
+      return;
     frame = offsetElm->GetPrimaryFrame();
   }
 
   // "language" text attribute
   LangTextAttr langTextAttr(mHyperTextAcc, hyperTextElm, offsetNode);
 
   // "aria-invalid" text attribute
   InvalidTextAttr invalidTextAttr(hyperTextElm, offsetNode);
--- a/b2g/chrome/content/devtools.js
+++ b/b2g/chrome/content/devtools.js
@@ -10,16 +10,22 @@ XPCOMUtils.defineLazyGetter(this, 'Debug
   return Cu.import('resource://gre/modules/devtools/dbg-client.jsm', {}).DebuggerClient;
 });
 
 XPCOMUtils.defineLazyGetter(this, 'WebConsoleUtils', function() {
   let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
   return devtools.require("devtools/toolkit/webconsole/utils").Utils;
 });
 
+XPCOMUtils.defineLazyGetter(this, 'EventLoopLagFront', function() {
+  const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
+  return devtools.require("devtools/server/actors/eventlooplag").EventLoopLagFront;
+});
+
+
 /**
  * The Widget Panel is an on-device developer tool that displays widgets,
  * showing visual debug information about apps. Each widget corresponds to a
  * metric as tracked by a metric watcher (e.g. consoleWatcher).
  */
 let devtoolsWidgetPanel = {
 
   _apps: new Map(),
@@ -353,9 +359,72 @@ let consoleWatcher = {
     // Add function name and line number
     let {functionName, sourceLine} = packet;
     source = 'in ' + (functionName || '<anonymousFunction>') +
       ', ' + source + ':' + sourceLine;
 
     return source;
   }
 };
+
 devtoolsWidgetPanel.registerWatcher(consoleWatcher);
+
+
+let jankWatcher = {
+  _client: null,
+  _fronts: new Map(),
+  _active: false,
+
+  init: function(client) {
+    this._client = client;
+
+    SettingsListener.observe('devtools.hud.jank', false,
+      this.settingsListener.bind(this));
+  },
+
+  settingsListener: function(value) {
+    if (this._active == value) {
+      return;
+    }
+    this._active = value;
+
+    // Toggle the state of existing fronts.
+    let fronts = this._fronts;
+    for (let app of fronts.keys()) {
+      if (value) {
+        fronts.get(app).start();
+      } else {
+        fronts.get(app).stop();
+        app.metrics.set('jank', 0);
+        app.display();
+      }
+    }
+  },
+
+  trackApp: function(app) {
+    app.metrics.set('jank', 0);
+
+    let front = new EventLoopLagFront(this._client, app.actor);
+    this._fronts.set(app, front);
+
+    front.on('event-loop-lag', time => {
+      app.metrics.set('jank', time);
+
+      if (!app.display()) {
+        devtoolsWidgetPanel.log('jank: ' + time + 'ms');
+      }
+    });
+
+    if (this._active) {
+      front.start();
+    }
+  },
+
+  untrackApp: function(app) {
+    let fronts = this._fronts;
+    if (fronts.has(app)) {
+      fronts.get(app).destroy();
+      fronts.delete(app);
+    }
+  }
+};
+
+devtoolsWidgetPanel.registerWatcher(jankWatcher);
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -45,16 +45,19 @@
              oncommand="gFindBar.onFindCommand();"
              observes="isImage"/>
     <command id="cmd_findAgain"
              oncommand="gFindBar.onFindAgainCommand(false);"
              observes="isImage"/>
     <command id="cmd_findPrevious"
              oncommand="gFindBar.onFindAgainCommand(true);"
              observes="isImage"/>
+#ifdef XP_MACOSX
+    <command id="cmd_findSelection" oncommand="gFindBar.onFindSelectionCommand();"/>
+#endif
     <!-- work-around bug 392512 -->
     <command id="Browser:AddBookmarkAs"
              oncommand="PlacesCommandHook.bookmarkCurrentPage(true, PlacesUtils.bookmarksMenuFolderId);"/>
     <!-- The command disabled state must be manually updated through
          PlacesCommandHook.updateBookmarkAllTabsCommand() -->
     <command id="Browser:BookmarkAllTabs"
              oncommand="PlacesCommandHook.bookmarkCurrentPages();"/>
     <command id="Browser:Home"    oncommand="BrowserHome();"/>
@@ -345,16 +348,19 @@
     <key key="&reloadCmd.commandkey;" command="Browser:ReloadSkipCache" modifiers="accel,shift"/>
     <key id="key_viewSource" key="&pageSourceCmd.commandkey;" command="View:PageSource" modifiers="accel"/>
 #ifndef XP_WIN
     <key id="key_viewInfo"   key="&pageInfoCmd.commandkey;"   command="View:PageInfo"   modifiers="accel"/>
 #endif
     <key id="key_find" key="&findOnCmd.commandkey;" command="cmd_find" modifiers="accel"/>
     <key id="key_findAgain" key="&findAgainCmd.commandkey;" command="cmd_findAgain" modifiers="accel"/>
     <key id="key_findPrevious" key="&findAgainCmd.commandkey;" command="cmd_findPrevious" modifiers="accel,shift"/>
+#ifdef XP_MACOSX
+    <key id="key_findSelection" key="&findSelectionCmd.commandkey;" command="cmd_findSelection" modifiers="accel"/>
+#endif
     <key keycode="&findAgainCmd.commandkey2;" command="cmd_findAgain"/>
     <key keycode="&findAgainCmd.commandkey2;"  command="cmd_findPrevious" modifiers="shift"/>
 
     <key id="addBookmarkAsKb" key="&bookmarkThisPageCmd.commandkey;" command="Browser:AddBookmarkAs" modifiers="accel"/>
 # Accel+Shift+A-F are reserved on GTK
 #ifndef MOZ_WIDGET_GTK
     <key id="bookmarkAllTabsKb" key="&bookmarkThisPageCmd.commandkey;" oncommand="PlacesCommandHook.bookmarkCurrentPages();" modifiers="accel,shift"/>
     <key id="manBookmarkKb" key="&bookmarksCmd.commandkey;" command="Browser:ShowAllBookmarks" modifiers="accel,shift"/>
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3032,27 +3032,17 @@
           // Hook up the event listeners to the first browser
           var tabListener = this.mTabProgressListener(this.mCurrentTab, this.mCurrentBrowser, true);
           const nsIWebProgress = Components.interfaces.nsIWebProgress;
           const filter = Components.classes["@mozilla.org/appshell/component/browser-status-filter;1"]
                                    .createInstance(nsIWebProgress);
           filter.addProgressListener(tabListener, nsIWebProgress.NOTIFY_ALL);
           this.mTabListeners[0] = tabListener;
           this.mTabFilters[0] = filter;
-
-          try {
-            // We assume this can only fail because mCurrentBrowser's docShell
-            // hasn't been created, yet. This may be caused by code accessing
-            // gBrowser before the window has finished loading.
-            this._addProgressListenerForInitialTab();
-          } catch (e) {
-            // The binding was constructed too early, wait until the initial
-            // tab's document is ready, then add the progress listener.
-            this._waitForInitialContentDocument();
-          }
+          this.webProgress.addProgressListener(filter, nsIWebProgress.NOTIFY_ALL);
 
           this.style.backgroundColor =
             Services.prefs.getBoolPref("browser.display.use_system_colors") ?
               "-moz-default-background-color" :
               Services.prefs.getCharPref("browser.display.background_color");
 
           let remote = window.QueryInterface(Ci.nsIInterfaceRequestor)
             .getInterface(Ci.nsIWebNavigation)
@@ -3078,41 +3068,16 @@
 
           // We want panel IDs to be globally unique, that's why we include the
           // window ID. We switched to a monotonic counter as Date.now() lead
           // to random failures because of colliding IDs.
           return "panel-" + outerID + "-" + (++this._uniquePanelIDCounter);
         ]]></body>
       </method>
 
-      <method name="_addProgressListenerForInitialTab">
-        <body><![CDATA[
-          this.webProgress.addProgressListener(this.mTabFilters[0], Ci.nsIWebProgress.NOTIFY_ALL);
-        ]]></body>
-      </method>
-
-      <method name="_waitForInitialContentDocument">
-        <body><![CDATA[
-          let obs = (subject, topic) => {
-            if (this.browsers[0].contentWindow == subject) {
-              Services.obs.removeObserver(obs, topic);
-              this._addProgressListenerForInitialTab();
-            }
-          };
-
-          // We use content-document-global-created as an approximation for
-          // "docShell is initialized". We can do this because in the
-          // mTabProgressListener we care most about the STATE_STOP notification
-          // that will reset mBlank. That means it's important to at least add
-          // the progress listener before the initial about:blank load stops
-          // if we can't do it before the load starts.
-          Services.obs.addObserver(obs, "content-document-global-created", false);
-        ]]></body>
-      </method>
-
       <destructor>
         <![CDATA[
           for (var i = 0; i < this.mTabListeners.length; ++i) {
             let browser = this.getBrowserAtIndex(i);
             if (browser.registeredOpenURI) {
               this._placesAutocomplete.unregisterOpenPage(browser.registeredOpenURI);
               delete browser.registeredOpenURI;
             }
--- a/browser/base/content/test/general/browser_bug537013.js
+++ b/browser/base/content/test/general/browser_bug537013.js
@@ -6,16 +6,19 @@
 let tabs = [];
 let texts = [
   "This side up.",
   "The world is coming to an end. Please log off.",
   "Klein bottle for sale. Inquire within.",
   "To err is human; to forgive is not company policy."
 ];
 
+let Clipboard = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
+let HasFindClipboard = Clipboard.supportsFindClipboard();
+
 function addTabWithText(aText, aCallback) {
   let newTab = gBrowser.addTab("data:text/html,<h1 id='h1'>" + aText + "</h1>");
   tabs.push(newTab);
   gBrowser.selectedTab = newTab;
 }
 
 function setFindString(aString) {
   gFindBar.open();
@@ -56,17 +59,19 @@ function continueTests1() {
   gFindBar.open();
   is(gFindBar._findField.value, texts[0],
      "Second tab kept old find value for new initialization!");
   setFindString(texts[1]);
 
   // Confirm the first tab is still correct, ensure re-hiding works as expected
   gBrowser.selectedTab = tabs[0];
   ok(!gFindBar.hidden, "First tab shows find bar!");
-  is(gFindBar._findField.value, texts[0], "First tab persists find value!");
+  // When the Find Clipboard is supported, this test not relevant.
+  if (!HasFindClipboard)
+    is(gFindBar._findField.value, texts[0], "First tab persists find value!");
   ok(gFindBar.getElement("highlight").checked,
      "Highlight button state persists!");
 
   // While we're here, let's test bug 253793
   gBrowser.reload();
   gBrowser.addEventListener("DOMContentLoaded", continueTests2, true);
 }
 
@@ -89,25 +94,27 @@ function continueTests2() {
 
   // Now we jump to the second, then first, and then fourth
   gBrowser.selectedTab = tabs[1];
   gBrowser.selectedTab = tabs[0];
   gBrowser.selectedTab = tabs[3];
   ok(gFindBar.hidden, "Fourth tab doesn't show find bar!");
   is(gFindBar, gBrowser.getFindBar(), "Find bar is right one!");
   gFindBar.open();
-  is(gFindBar._findField.value, texts[1],
+  let toTest = HasFindClipboard ? texts[2] : texts[1];
+  is(gFindBar._findField.value, toTest,
      "Fourth tab has second tab's find value!");
 
   newWindow = gBrowser.replaceTabWithWindow(tabs.pop());
   whenDelayedStartupFinished(newWindow, checkNewWindow);
 }
 
 // Test that findbar gets restored when a tab is moved to a new window.
 function checkNewWindow() {
   ok(!newWindow.gFindBar.hidden, "New window shows find bar!");
-  is(newWindow.gFindBar._findField.value, texts[1],
+  let toTest = HasFindClipboard ? texts[2] : texts[1];
+  is(newWindow.gFindBar._findField.value, toTest,
      "New window find bar has correct find value!");
   ok(!newWindow.gFindBar.getElement("find-next").disabled,
      "New window findbar has enabled buttons!");
   newWindow.close();
   finish();
 }
--- a/browser/base/content/test/general/browser_bug567306.js
+++ b/browser/base/content/test/general/browser_bug567306.js
@@ -1,13 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-let Ci = Components.interfaces;
+const {Ci: interfaces, Cc: classes} = Components;
+
+let Clipboard = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
+let HasFindClipboard = Clipboard.supportsFindClipboard();
 
 function test() {
   waitForExplicitFinish();
 
   whenNewWindowLoaded(undefined, function (win) {
     whenDelayedStartupFinished(win, function () {
       let selectedBrowser = win.gBrowser.selectedBrowser;
       selectedBrowser.addEventListener("pageshow", function() {
@@ -32,13 +35,16 @@ function selectText(win) {
   selection.addRange(range);
 }
 
 function onFocus(win) {
   ok(!win.gFindBarInitialized, "find bar is not yet initialized");
   let findBar = win.gFindBar;
   selectText(win.content);
   findBar.onFindCommand();
-  is(findBar._findField.value, "Select Me", "Findbar is initialized with selection");
+  // When the OS supports the Find Clipboard (OSX), the find field value is
+  // persisted across Fx sessions, thus not useful to test.
+  if (!HasFindClipboard)
+    is(findBar._findField.value, "Select Me", "Findbar is initialized with selection");
   findBar.close();
   win.close();
   finish();
 }
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -609,16 +609,17 @@ you can use these alternative items. Oth
 
 <!ENTITY findOnCmd.label     "Find in This Page…">
 <!ENTITY findOnCmd.accesskey "F">
 <!ENTITY findOnCmd.commandkey "f">
 <!ENTITY findAgainCmd.label  "Find Again">
 <!ENTITY findAgainCmd.accesskey "g">
 <!ENTITY findAgainCmd.commandkey "g">
 <!ENTITY findAgainCmd.commandkey2 "VK_F3">
+<!ENTITY findSelectionCmd.commandkey "e">
 
 <!ENTITY spellAddDictionaries.label "Add Dictionaries…">
 <!ENTITY spellAddDictionaries.accesskey "A">
 
 <!ENTITY editBookmark.done.label                     "Done">
 <!ENTITY editBookmark.cancel.label                   "Cancel">
 <!ENTITY editBookmark.removeBookmark.accessKey       "R">
 
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -2429,21 +2429,21 @@ richlistitem[type~="action"][actiontype=
 
 .editBMPanel_rowLabel {
   text-align: end;
 }
 
 .panel-promo-box {
   margin: 8px -16px -16px -16px;
   padding: 8px 16px;
-  background: #e5e5e5;
-  border-top: 1px solid hsla(0,0%,0%,.1);
+  background-color: hsla(210,4%,10%,.07);
+  border-top: 1px solid hsla(210,4%,10%,.12);
   border-radius: 0 0 5px 5px;
   box-shadow: 0 -1px hsla(0,0%,100%,.5) inset, 0 1px 1px hsla(0,0%,0%,.03) inset;
-  color: #808080;
+  color: hsl(0,0%,30%);
 }
 
 .panel-promo-icon {
   list-style-image: url("chrome://browser/skin/sync-notification-24.png");
   -moz-margin-end: 10px;
   vertical-align: middle;
 }
 
@@ -3209,26 +3209,31 @@ toolbarbutton.chevron > .toolbarbutton-m
     width: 24px;
   }
 
   #identity-popup-help-icon {
     list-style-image: url("chrome://global/skin/icons/question-32.png");
   }
 }
 
+#identity-popup {
+  margin-top: 1px;
+}
+
 #identity-popup > .panel-arrowcontainer > .panel-arrowcontent {
   padding: 0;
 }
 
 #identity-popup-container {
   padding: 16px;
 }
 
 #identity-popup-button-container {
-  background: linear-gradient(to bottom, rgba(0,0,0,0.04) 60%, transparent);
+  background-color: hsla(210,4%,10%,.07);
+  border-top: 1px solid hsla(210,4%,10%,.12);
   padding: 16px;
   margin-top: 5px;
 }
 
 #notification-popup-box {
   position: relative;
   background-color: #fff;
   background-clip: padding-box;
@@ -4017,17 +4022,16 @@ toolbar[mode="icons"] > *|* > .toolbarbu
 }
 
 /* fixup rounded corners for osx panels */
 .social-panel > .social-panel-frame {
   border-radius: inherit;
 }
 
 #social-share-panel {
-  margin-top: 3px;
   max-height: 600px;
   min-height: 100px;
   max-width: 800px;
   min-width: 300px;
 }
 
 .social-share-frame:-moz-locale-dir(ltr) {
   border-top-left-radius: 0;
--- a/browser/themes/osx/downloads/downloads.css
+++ b/browser/themes/osx/downloads/downloads.css
@@ -1,71 +1,65 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*** Panel and outer controls ***/
 
+#downloadsPanel {
+  margin-top: -1px;
+}
+
 #downloadsPanel > .panel-arrowcontainer > .panel-arrowcontent {
   padding: 0;
 }
 
 #downloadsListBox {
   background: transparent;
   padding: 4px;
   color: inherit;
 }
 
 #downloadsPanel:not([hasdownloads]) > #downloadsListBox {
   display: none;
 }
 
 #downloadsFooter {
-  border-bottom-left-radius: 6px;
-  border-bottom-right-radius: 6px;
+  border-bottom-left-radius: 4px;
+  border-bottom-right-radius: 4px;
 }
 
 #downloadsHistory {
   background: transparent;
   color: hsl(210,100%,75%);
   cursor: pointer;
 }
 
-#downloadsPanel:not([hasdownloads]) > #downloadsFooter > #downloadsHistory {
-  border-top-left-radius: 6px;
-  border-top-right-radius: 6px;
-}
-
 #downloadsPanel[hasdownloads] > #downloadsFooter {
   background: #e5e5e5;
   border-top: 1px solid hsla(0,0%,0%,.1);
   box-shadow: 0 -1px hsla(0,0%,100%,.5) inset, 0 1px 1px hsla(0,0%,0%,.03) inset;
 }
 
 #downloadsHistory > .button-box {
   color: #808080;
   margin: 1em;
 }
 
 #downloadsPanel[keyfocus] > #downloadsFooter > #downloadsSummary:focus,
 #downloadsPanel[keyfocus] > #downloadsFooter > #downloadsHistory:focus {
   outline: 2px -moz-mac-focusring solid;
   outline-offset: -2px;
-  -moz-outline-radius-bottomleft: 5px;
-  -moz-outline-radius-bottomright: 5px;
+  -moz-outline-radius-bottomleft: 4px;
+  -moz-outline-radius-bottomright: 4px;
 }
 
 #downloadsPanel:not([hasdownloads]) > #downloadsFooter > #downloadsHistory:focus {
-  -moz-outline-radius-topleft: 5px;
-  -moz-outline-radius-topright: 5px;
-}
-
-#downloadsPanel:not([hasdownloads]) > #downloadsFooter > #downloadsHistory:focus > .button-box {
-  border-bottom-left-radius: 6px;
-  border-bottom-right-radius: 6px;
+  -moz-outline-radius-topleft: 4px;
+  -moz-outline-radius-topright: 4px;
 }
 
 /*** Downloads Summary and List items ***/
 
 #downloadsSummary,
 richlistitem[type="download"] {
   height: 7em;
   -moz-padding-end: 0;
--- a/browser/themes/shared/customizableui/panelUIOverlay.inc.css
+++ b/browser/themes/shared/customizableui/panelUIOverlay.inc.css
@@ -25,21 +25,20 @@
   background-position: 0px 0px, 1px 0px, 2px 0px;
   background-repeat: no-repeat;
 }
 
 .panel-subviews {
   padding: 4px;
   background-color: hsla(0,0%,100%,.97);
   background-clip: padding-box;
-  border-right: 1px solid hsla(210,4%,10%,.2);
-  border-left: 1px solid hsla(210,4%,10%,.2);
+  border-left: 1px solid hsla(210,4%,10%,.3);
   box-shadow: 0 3px 5px hsla(210,4%,10%,.1),
               0 0 7px hsla(210,4%,10%,.1);
-  color: #222426;
+  color: hsl(0,0%,15%);
   -moz-margin-start: @exitSubviewGutterWidth@;
 }
 
 .panel-viewstack[viewtype="main"] > .panel-subviews {
   transform: translateX(@menuPanelWidth@);
 }
 
 .panel-viewstack[viewtype="main"] > .panel-subviews:-moz-locale-dir(rtl) {
@@ -63,29 +62,23 @@
 #PanelUI-popup .panel-subview-body {
   margin: -4px;
   padding: 2px 4px;
 }
 
 .panel-subview-header,
 .subviewbutton.panel-subview-footer {
   padding: 12px;
-  background-color: hsla(210,4%,10%,.04);
 }
 
 .panel-subview-header {
   margin: -4px -4px 4px;
-  box-shadow: 0 -1px 0 hsla(210,4%,10%,.08) inset;
-  color: #797c80;
-}
-
-.subviewbutton.panel-subview-footer {
-  margin: 4px -4px -4px;
-  box-shadow: 0 1px 0 hsla(210,4%,10%,.08) inset;
-  border-radius: 0;
+  background-color: hsla(210,4%,10%,.05);
+  box-shadow: 0 -1px 0 hsla(210,4%,10%,.05) inset;
+  color: hsl(0,0%,50%);
 }
 
 .cui-widget-panelview .panel-subview-header {
   display: none;
 }
 
 .cui-widget-panelview .subviewbutton.panel-subview-footer {
   margin: 4px 0 0;
@@ -196,18 +189,18 @@ toolbaritem[cui-areatype="menu-panel"][s
 .panel-customization-placeholder-child {
   -moz-appearance: none;
   -moz-box-orient: vertical;
   width: calc(@menuPanelButtonWidth@);
   height: calc(40px + 4em);
 }
 
 /* Help SDK buttons fit in. */
-toolbarpaletteitem[place="palette"] > toolbarbutton[sdk-button="true"] > .toolbarbutton-icon,
-toolbarbutton[sdk-button="true"][cui-areatype="menu-panel"] > .toolbarbutton-icon {
+toolbarpaletteitem[place="palette"] > #personal-bookmarks > #bookmarks-toolbar-placeholder,
+#personal-bookmarks[cui-areatype="menu-panel"] > #bookmarks-toolbar-placeholder {
   height: 32px;
   width: 32px;
 }
 
 .customization-palette .toolbarbutton-1 {
   -moz-appearance: none;
   -moz-box-orient: vertical;
 }
@@ -315,30 +308,29 @@ toolbarpaletteitem[place="palette"] > to
 #zoom-reset-button > .toolbarbutton-icon {
   display: none;
 }
 
 #PanelUI-footer {
   display: flex;
   flex-shrink: 0;
   flex-direction: column;
-  background-color: rgba(0, 0, 0, 0.05);
-  box-shadow: 0 -1px 0 rgba(0,0,0,.15);
+  background-color: hsla(210,4%,10%,.07);
   padding: 0;
   margin: 0;
 }
 
 #PanelUI-footer-inner {
   display: flex;
-  box-shadow: 0 -1px 0 rgba(0,0,0,.15);
+  border-top: 1px solid hsla(210,4%,10%,.14);
 }
 
 #PanelUI-footer-inner > toolbarseparator {
   border: 0;
-  border-left: 1px solid rgba(0,0,0,0.1);
+  border-left: 1px solid hsla(210,4%,10%,.14);
   margin: 7px 0 7px;
   -moz-appearance: none;
 }
 
 #PanelUI-footer-inner:hover > toolbarseparator {
   margin: 0;
 }
 
@@ -347,25 +339,26 @@ toolbarpaletteitem[place="palette"] > to
 #PanelUI-customize,
 #PanelUI-quit {
   margin: 0;
   padding: 10px 0;
   min-height: 2em;
   -moz-appearance: none;
   box-shadow: none;
   background-image: none;
-  border: 1px solid transparent;
-  border-bottom-style: none;
+  border: none;  
   border-radius: 0;
   transition: background-color;
   -moz-box-orient: horizontal;
 }
 
 #PanelUI-fxa-status {
-  border-bottom-style: solid;
+  border-top: 1px solid hsla(210,4%,10%,.14);
+  border-bottom: 1px solid transparent;
+  margin-bottom: -1px;
 }
 
 #PanelUI-fxa-status > .toolbarbutton-text {
   width: 0; /* Fancy cropping solution for flexbox. */
 }
 
 #PanelUI-fxa-status[signedin] {
   font-weight: bold;
@@ -446,37 +439,46 @@ toolbarpaletteitem[place="palette"] > to
   -moz-image-region: rect(0, 48px, 16px, 32px);
 }
 
 #PanelUI-help[disabled],
 #PanelUI-quit[disabled] {
   opacity: 0.4;
 }
 
+#PanelUI-fxa-status:not([disabled]):hover,
 #PanelUI-help:not([disabled]):hover,
 #PanelUI-customize:hover,
 #PanelUI-quit:not([disabled]):hover {
-  outline: 1px solid rgba(0,0,0,0.1);
-  background-color: rgba(0,0,0,0.1);
-  box-shadow: none;
+  outline: 1px solid hsla(210,4%,10%,.07);
+  background-color: hsla(210,4%,10%,.07);
 }
 
-#PanelUI-fxa-status:not([disabled]):hover {
-  background-color: rgba(0,0,0,0.1);
-  border-bottom-color: rgba(0,0,0,0.1);
-  box-shadow: 0 -1px 0 rgba(0,0,0,0.2);
+#PanelUI-fxa-status:not([disabled]):hover:active,
+#PanelUI-help:not([disabled]):hover:active,
+#PanelUI-customize:hover:active,
+#PanelUI-quit:not([disabled]):hover:active {
+  outline: 1px solid hsla(210,4%,10%,.12);
+  background-color: hsla(210,4%,10%,.12);
+  box-shadow: 0 1px 0 hsla(210,4%,10%,.05) inset;
+}
+
+#PanelUI-fxa-status:not([disabled]):hover,
+#PanelUI-fxa-status:not([disabled]):hover:active {
+  outline: none;
 }
 
 #PanelUI-quit:not([disabled]):hover {
   background-color: #d94141;
   outline-color: #c23a3a;
 }
 
 #PanelUI-quit:not([disabled]):hover:active {
   background-color: #ad3434;
+  outline-color: #992e2e;
 }
 
 #customization-panelHolder #PanelUI-customize {
   color: white;
   background-color: rgb(116,191,67);
   text-shadow: none;
 }
 
@@ -547,32 +549,51 @@ panelview .toolbarbutton-1,
 }
 
 panelview .toolbarbutton-1@buttonStateHover@,
 .subviewbutton@buttonStateHover@,
 .widget-overflow-list .toolbarbutton-1@buttonStateHover@,
 #edit-controls@inAnyPanel@ > toolbarbutton@buttonStateHover@,
 #zoom-controls@inAnyPanel@ > toolbarbutton@buttonStateHover@ {
   background-color: hsla(210,4%,10%,.08);
-  border-color: hsla(210,4%,10%,.1);
+  border-color: hsla(210,4%,10%,.11);
 }
 
 #edit-controls@inAnyPanel@@buttonStateHover@,
 #zoom-controls@inAnyPanel@@buttonStateHover@ {
-  border-color: hsla(210,4%,10%,.1);
+  border-color: hsla(210,4%,10%,.11);
 }
 
 panelview .toolbarbutton-1@buttonStateActive@,
 .subviewbutton@buttonStateActive@,
 .widget-overflow-list .toolbarbutton-1@buttonStateActive@,
 #edit-controls@inAnyPanel@ > toolbarbutton@buttonStateActive@,
 #zoom-controls@inAnyPanel@ > toolbarbutton@buttonStateActive@ {
+  background-color: hsla(210,4%,10%,.12);
+  border-color: hsla(210,4%,10%,.14);
+  box-shadow: 0 1px 0 hsla(210,4%,10%,.03) inset;
+}
+
+.subviewbutton.panel-subview-footer {
+  margin: 4px -4px -4px;
+  background-color: hsla(210,4%,10%,.07);
+  border-top: 1px solid hsla(210,4%,10%,.12);
+  border-radius: 0;
+  color: hsl(0,0%,25%)
+}
+
+.subviewbutton.panel-subview-footer@buttonStateHover@ {
+  background-color: hsla(210,4%,10%,.1);
+  border-top: 1px solid hsla(210,4%,10%,.12);
+}
+
+.subviewbutton.panel-subview-footer@buttonStateActive@ {
   background-color: hsla(210,4%,10%,.15);
-  border-color: hsla(210,4%,10%,.15);
-  box-shadow: 0 1px 0 0 hsla(210,4%,10%,.05) inset;
+  border-top: 1px solid hsla(210,4%,10%,.12);
+  box-shadow: 0 1px 0 hsla(210,4%,10%,.05) inset;
 }
 
 #BMB_bookmarksPopup > .subviewbutton {
   font: inherit;
   font-weight: normal;
 }
 
 #BMB_bookmarksPopup > .subviewbutton:not([disabled="true"]) {
--- a/browser/themes/shared/devtools/dark-theme.css
+++ b/browser/themes/shared/devtools/dark-theme.css
@@ -170,22 +170,16 @@
 }
 
 .ruleview-colorswatch,
 .computedview-colorswatch,
 .markupview-colorswatch {
   box-shadow: 0 0 0 1px rgba(0,0,0,0.5);
 }
 
-.variables-view-scope:focus > .title,
-.variable-or-property:focus > .title {
-  background:  #3689b2; /* fg-color2 */
-  color: white;
-}
-
 /* CodeMirror specific styles.
  * Best effort to match the existing theme, some of the colors
  * are duplicated here to prevent weirdness in the main theme. */
 
 .CodeMirror { /* Inherit platform specific font sizing and styles */
   font-family: inherit;
   font-size: inherit;
   background: transparent;
--- a/browser/themes/shared/devtools/light-theme.css
+++ b/browser/themes/shared/devtools/light-theme.css
@@ -169,22 +169,16 @@
 }
 
 .ruleview-colorswatch,
 .computedview-colorswatch,
 .markupview-colorswatch {
   box-shadow: 0 0 0 1px #EFEFEF;
 }
 
-.variables-view-scope:focus > .title,
-.variable-or-property:focus > .title {
-  background:  #4c9ed9; /* fg-color2 */
-  color: #f5f7fa;
-}
-
 /* CodeMirror specific styles.
  * Best effort to match the existing theme, some of the colors
  * are duplicated here to prevent weirdness in the main theme. */
 
 .CodeMirror { /* Inherit platform specific font sizing and styles */
   font-family: inherit;
   font-size: inherit;
   background: transparent;
--- a/browser/themes/shared/devtools/widgets.inc.css
+++ b/browser/themes/shared/devtools/widgets.inc.css
@@ -556,16 +556,28 @@
 .theme-dark .variables-view-empty-notice {
   color: #b6babf; /* Foreground (Text) - Grey */
 }
 
 .theme-light .variables-view-empty-notice {
   color: #585959; /* Grey foreground text */
 }
 
+.theme-dark .variables-view-scope:focus > .title,
+.theme-dark .variable-or-property:focus > .title {
+  background-color: #1d4f73; /* Selection colors */
+  color: #f5f7fa;
+}
+
+.theme-light .variables-view-scope:focus > .title,
+.theme-light .variable-or-property:focus > .title {
+  background-color: #4c9ed9; /* Selection colors */
+  color: #f5f7fa;
+}
+
 .variables-view-scope > .title {
   border-top-width: 1px;
   border-top-style: solid;
   margin-top: -1px;
 }
 
 /* Generic variables traits */
 
--- a/browser/themes/shared/plugin-doorhanger.inc.css
+++ b/browser/themes/shared/plugin-doorhanger.inc.css
@@ -21,17 +21,18 @@
   background-image: url("chrome://mozapps/skin/extensions/alerticon-info-negative.png");
   background-repeat: no-repeat;
   width: 16px;
   height: 15px;
   -moz-margin-start: 6px;
 }
 
 .click-to-play-plugins-notification-button-container {
-  background: linear-gradient(rgba(0,0,0,0.04) 60%, transparent);
+  background-color: hsla(210,4%,10%,.07);
+  border-top: 1px solid hsla(210,4%,10%,.12);
   padding: 10px;
   margin-top: 5px;
 }
 
 .click-to-play-popup-button {
   width: 50%;
 }
 
--- a/content/media/webrtc/MediaEngineDefault.cpp
+++ b/content/media/webrtc/MediaEngineDefault.cpp
@@ -6,17 +6,19 @@
 
 #include "nsCOMPtr.h"
 #include "nsDOMFile.h"
 #include "nsILocalFile.h"
 #include "Layers.h"
 #include "ImageContainer.h"
 #include "ImageTypes.h"
 #include "prmem.h"
+#include "nsContentUtils.h"
 
+#include "nsIFilePicker.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidBridge.h"
 #include "nsISupportsUtils.h"
 #endif
 
@@ -159,28 +161,48 @@ MediaEngineDefaultVideoSource::Stop(Sour
 nsresult
 MediaEngineDefaultVideoSource::Snapshot(uint32_t aDuration, nsIDOMFile** aFile)
 {
   *aFile = nullptr;
 
 #ifndef MOZ_WIDGET_ANDROID
   return NS_ERROR_NOT_IMPLEMENTED;
 #else
-  if (!AndroidBridge::Bridge()) {
-    return NS_ERROR_UNEXPECTED;
+  nsAutoString filePath;
+  nsCOMPtr<nsIFilePicker> filePicker = do_CreateInstance("@mozilla.org/filepicker;1");
+  if (!filePicker)
+    return NS_ERROR_FAILURE;
+
+  nsXPIDLString title;
+  nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES, "Browse", title);
+  int16_t mode = static_cast<int16_t>(nsIFilePicker::modeOpen);
+
+  nsresult rv = filePicker->Init(nullptr, title, mode);
+  NS_ENSURE_SUCCESS(rv, rv);
+  filePicker->AppendFilters(nsIFilePicker::filterImages);
+
+  // XXX - This API should be made async
+  PRInt16 dialogReturn;
+  rv = filePicker->Show(&dialogReturn);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (dialogReturn == nsIFilePicker::returnCancel) {
+    *aFile = nullptr;
+    return NS_OK;
   }
 
-  nsAutoString filePath;
-  AndroidBridge::Bridge()->ShowFilePickerForMimeType(filePath, NS_LITERAL_STRING("image/*"));
+  nsCOMPtr<nsIFile> localFile;
+  filePicker->GetFile(getter_AddRefs(localFile));
 
-  nsCOMPtr<nsIFile> file;
-  nsresult rv = NS_NewLocalFile(filePath, false, getter_AddRefs(file));
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (!localFile) {
+    *aFile = nullptr;
+    return NS_OK;
+  }
 
-  NS_ADDREF(*aFile = new nsDOMFileFile(file));
+  nsCOMPtr<nsIDOMFile> domFile = new nsDOMFileFile(localFile);
+  domFile.forget(aFile);
   return NS_OK;
 #endif
 }
 
 NS_IMETHODIMP
 MediaEngineDefaultVideoSource::Notify(nsITimer* aTimer)
 {
   // Update the target color
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -25,19 +25,26 @@
 #include "mozilla/hal_sandbox/PHalChild.h"
 #include "mozilla/ipc/GeckoChildProcessHost.h"
 #include "mozilla/ipc/TestShellChild.h"
 #include "mozilla/layers/CompositorChild.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/layers/PCompositorChild.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/Preferences.h"
-#if defined(MOZ_CONTENT_SANDBOX) && defined(XP_UNIX) && !defined(XP_MACOSX)
+
+#if defined(MOZ_CONTENT_SANDBOX)
+#if defined(XP_WIN)
+#define TARGET_SANDBOX_EXPORTS
+#include "mozilla/sandboxTarget.h"
+#elif defined(XP_UNIX) && !defined(XP_MACOSX)
 #include "mozilla/Sandbox.h"
 #endif
+#endif
+
 #include "mozilla/unused.h"
 
 #include "nsIConsoleListener.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIMemoryReporter.h"
 #include "nsIMemoryInfoDumper.h"
 #include "nsIMutable.h"
 #include "nsIObserverService.h"
@@ -588,23 +595,28 @@ ContentChild::AllocPImageBridgeChild(moz
 bool
 ContentChild::RecvSetProcessPrivileges(const ChildPrivileges& aPrivs)
 {
   ChildPrivileges privs = (aPrivs == PRIVILEGES_DEFAULT) ?
                           GeckoChildProcessHost::DefaultChildPrivileges() :
                           aPrivs;
   // If this fails, we die.
   SetCurrentProcessPrivileges(privs);
-#if defined(MOZ_CONTENT_SANDBOX) && defined(XP_UNIX) && !defined(XP_MACOSX)
+
+#if defined(MOZ_CONTENT_SANDBOX)
+#if defined(XP_WIN)
+  mozilla::SandboxTarget::Instance()->StartSandbox();
+#else if defined(XP_UNIX) && !defined(XP_MACOSX)
   // SetCurrentProcessSandbox should be moved close to process initialization
   // time if/when possible. SetCurrentProcessPrivileges should probably be
   // moved as well. Right now this is set ONLY if we receive the
   // RecvSetProcessPrivileges message. See bug 880808.
   SetCurrentProcessSandbox();
 #endif
+#endif
   return true;
 }
 
 bool
 ContentChild::RecvSpeakerManagerNotify()
 {
 #ifdef MOZ_WIDGET_GONK
   nsRefPtr<SpeakerManagerService> service =
--- a/ipc/app/MozillaRuntimeMain.cpp
+++ b/ipc/app/MozillaRuntimeMain.cpp
@@ -20,16 +20,17 @@
 #include "nsWindowsWMain.cpp"
 #include "nsSetDllDirectory.h"
 #endif
 
 #if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
 #include "sandbox/chromium/base/basictypes.h"
 #include "sandbox/win/src/sandbox.h"
 #include "sandbox/win/src/sandbox_factory.h"
+#include "mozilla/sandboxTarget.h"
 #endif
 
 #ifdef MOZ_WIDGET_GONK
 # include <sys/time.h>
 # include <sys/resource.h> 
 
 # include <binder/ProcessState.h>
 
@@ -62,24 +63,37 @@ InitializeBinder(void *aDummy) {
     int err = setpriority(PRIO_PROCESS, 0, 0);
     MOZ_ASSERT(!err);
     LOGE_IF(err, "setpriority failed. Current process needs root permission.");
     android::ProcessState::self()->startThreadPool();
     setpriority(PRIO_PROCESS, 0, curPrio);
 }
 #endif
 
+#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
+static bool gIsSandboxEnabled = false;
+void StartSandboxCallback()
+{
+    if (gIsSandboxEnabled) {
+        sandbox::TargetServices* target_service =
+            sandbox::SandboxFactory::GetTargetServices();
+        target_service->LowerToken();
+    }
+}
+#endif
+
 int
 main(int argc, char* argv[])
 {
     bool isNuwa = false;
-    bool isSandboxEnabled = false;
     for (int i = 1; i < argc; i++) {
         isNuwa |= strcmp(argv[i], "-nuwa") == 0;
-        isSandboxEnabled |= strcmp(argv[i], "-sandbox") == 0;
+#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
+        gIsSandboxEnabled |= strcmp(argv[i], "-sandbox") == 0;
+#endif
     }
 
 #ifdef MOZ_NUWA_PROCESS
     if (isNuwa) {
         PrepareNuwaProcess();
     }
 #endif
 
@@ -95,47 +109,45 @@ main(int argc, char* argv[])
     } else {
         NuwaAddFinalConstructor(&InitializeBinder, nullptr);
     }
 #else
     InitializeBinder(nullptr);
 #endif
 #endif
 
-#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
-    if (isSandboxEnabled) {
-        sandbox::TargetServices* target_service =
-            sandbox::SandboxFactory::GetTargetServices();
-        if (!target_service) {
-            return 1;
-        }
-
-        sandbox::ResultCode result = target_service->Init();
-        if (result != sandbox::SBOX_ALL_OK) {
-            return 2;
-        }
-
-        // Initialization is finished, switch to the lowered token
-        target_service->LowerToken();
-    }
-#endif
-
     // Check for the absolute minimum number of args we need to move
     // forward here. We expect the last arg to be the child process type.
     if (argc < 1)
       return 3;
     GeckoProcessType proctype = XRE_StringToChildProcessType(argv[--argc]);
 
 #ifdef XP_WIN
     // For plugins, this is done in PluginProcessChild::Init, as we need to
     // avoid it for unsupported plugins.  See PluginProcessChild::Init for
     // the details.
     if (proctype != GeckoProcessType_Plugin) {
         mozilla::SanitizeEnvironmentVariables();
         SetDllDirectory(L"");
     }
+
+#ifdef MOZ_CONTENT_SANDBOX
+    if (gIsSandboxEnabled) {
+        sandbox::TargetServices* target_service =
+            sandbox::SandboxFactory::GetTargetServices();
+        if (!target_service) {
+            return 1;
+        }
+
+        sandbox::ResultCode result = target_service->Init();
+        if (result != sandbox::SBOX_ALL_OK) {
+           return 2;
+        }
+        mozilla::SandboxTarget::Instance()->SetStartSandboxCallback(StartSandboxCallback);
+    }
+#endif
 #endif
 
     nsresult rv = XRE_InitChildProcess(argc, argv, proctype);
     NS_ENSURE_SUCCESS(rv, 1);
 
     return 0;
 }
--- a/ipc/app/moz.build
+++ b/ipc/app/moz.build
@@ -16,8 +16,16 @@ else:
         'MozillaRuntimeMain.cpp',
     ]
 include('/ipc/chromium/chromium-config.mozbuild')
 
 LOCAL_INCLUDES += [
     '/toolkit/xre',
     '/xpcom/base',
 ]
+
+if CONFIG['MOZ_CONTENT_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT':
+    # For sandbox includes and the include dependencies those have
+    LOCAL_INCLUDES += [
+        '/security',
+        '/security/sandbox',
+        '/security/sandbox/chromium',
+    ]
--- a/js/src/builtin/TypeRepresentation.cpp
+++ b/js/src/builtin/TypeRepresentation.cpp
@@ -821,17 +821,16 @@ SizedTypeRepresentation::traceInstance(J
 const StructField *
 StructTypeRepresentation::fieldNamed(jsid id) const
 {
     if (!JSID_IS_ATOM(id))
         return nullptr;
 
     uint32_t unused;
     JSAtom *atom = JSID_TO_ATOM(id);
-    AutoThreadSafeAccess ts(atom);
 
     if (atom->isIndex(&unused))
         return nullptr;
 
     PropertyName *name = atom->asPropertyName();
 
     for (size_t i = 0; i < fieldCount(); i++) {
         if (field(i).propertyName.get() == name)
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -2860,22 +2860,20 @@ frontend::EmitFunctionScript(ExclusiveCo
         bce->script->setTreatAsRunOnce();
         JS_ASSERT(!bce->script->hasRunOnce());
     }
 
     /* Initialize fun->script() so that the debugger has a valid fun->script(). */
     RootedFunction fun(cx, bce->script->functionNonDelazifying());
     JS_ASSERT(fun->isInterpreted());
 
-    if (fun->isInterpretedLazy()) {
-        AutoLockForCompilation lock(cx);
+    if (fun->isInterpretedLazy())
         fun->setUnlazifiedScript(bce->script);
-    } else {
+    else
         fun->setScript(bce->script);
-    }
 
     bce->tellDebuggerAboutCompiledScript(cx);
 
     return true;
 }
 
 static bool
 MaybeEmitVarDecl(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn,
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -186,19 +186,16 @@ class BarrieredCell : public gc::Cell
     MOZ_ALWAYS_INLINE JS::shadow::Zone *shadowZone() const { return JS::shadow::Zone::asShadowZone(zone()); }
     MOZ_ALWAYS_INLINE JS::Zone *zoneFromAnyThread() const { return tenuredZoneFromAnyThread(); }
     MOZ_ALWAYS_INLINE JS::shadow::Zone *shadowZoneFromAnyThread() const {
         return JS::shadow::Zone::asShadowZone(zoneFromAnyThread());
     }
 
     static MOZ_ALWAYS_INLINE void readBarrier(T *thing) {
 #ifdef JSGC_INCREMENTAL
-        // Off thread Ion compilation never occurs when barriers are active.
-        js::AutoThreadSafeAccess ts(thing);
-
         JS::shadow::Zone *shadowZone = thing->shadowZoneFromAnyThread();
         if (shadowZone->needsBarrier()) {
             MOZ_ASSERT(!RuntimeFromMainThreadIsHeapMajorCollecting(shadowZone));
             T *tmp = thing;
             js::gc::MarkUnbarriered<T>(shadowZone->barrierTracer(), &tmp, "read barrier");
             JS_ASSERT(tmp == thing);
         }
 #endif
--- a/js/src/gc/Heap.h
+++ b/js/src/gc/Heap.h
@@ -1104,45 +1104,17 @@ InFreeList(ArenaHeader *aheader, void *t
          * span->end < thing < thingsEnd and so we must have more spans.
          */
         span = span->nextSpan();
     }
 }
 
 } /* namespace gc */
 
-// Ion compilation mainly occurs off the main thread, and may run while the
-// main thread is performing arbitrary VM operations, excepting GC activity.
-// The below class is used to mark functions and other operations which can
-// safely be performed off thread without racing. When running with thread
-// safety checking on, any access to a GC thing outside of AutoThreadSafeAccess
-// will cause an access violation.
-class MOZ_STACK_CLASS AutoThreadSafeAccess
-{
-public:
-#if defined(DEBUG) && defined(JS_CPU_X64) && !defined(XP_WIN)
-#define JS_CAN_CHECK_THREADSAFE_ACCESSES
-
-    JSRuntime *runtime;
-    gc::ArenaHeader *arena;
-
-    AutoThreadSafeAccess(const gc::Cell *cell MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
-    ~AutoThreadSafeAccess();
-#else
-    AutoThreadSafeAccess(const gc::Cell *cell MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-    {
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    }
-    ~AutoThreadSafeAccess() {}
-#endif
-    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
 gc::AllocKind
 gc::Cell::tenuredGetAllocKind() const
 {
-    AutoThreadSafeAccess ts(this);
     return arenaHeader()->getAllocKind();
 }
 
 } /* namespace js */
 
 #endif /* gc_Heap_h */
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -131,20 +131,17 @@ ICStubIterator::operator++()
 
 void
 ICStubIterator::unlink(JSContext *cx)
 {
     JS_ASSERT(currentStub_->next() != nullptr);
     JS_ASSERT(currentStub_ != fallbackStub_);
     JS_ASSERT(!unlinked_);
 
-    {
-        AutoLockForCompilation lock(cx);
-        fallbackStub_->unlinkStub(cx->zone(), previousStub_, currentStub_);
-    }
+    fallbackStub_->unlinkStub(cx->zone(), previousStub_, currentStub_);
 
     // Mark the current iterator position as unlinked, so operator++ works properly.
     unlinked_ = true;
 }
 
 
 void
 ICStub::markCode(JSTracer *trc, const char *name)
@@ -1061,17 +1058,17 @@ DoProfilerFallback(JSContext *cx, Baseli
     IonSpew(IonSpew_BaselineIC, "  Generating Profiler_PushFunction stub for %s:%d",
             script->filename(), script->lineno());
 
     // Create a new optimized stub.
     ICProfiler_PushFunction::Compiler compiler(cx, string, script);
     ICStub *optStub = compiler.getStub(compiler.getStubSpace(script));
     if (!optStub)
         return false;
-    stub->addNewStub(cx, optStub);
+    stub->addNewStub(optStub);
 
     return true;
 }
 
 typedef bool (*DoProfilerFallbackFn)(JSContext *, BaselineFrame *frame, ICProfiler_Fallback *);
 static const VMFunction DoProfilerFallbackInfo =
     FunctionInfo<DoProfilerFallbackFn>(DoProfilerFallback);
 
@@ -1792,17 +1789,17 @@ DoCompareFallback(JSContext *cx, Baselin
     // Try to generate new stubs.
     if (lhs.isInt32() && rhs.isInt32()) {
         IonSpew(IonSpew_BaselineIC, "  Generating %s(Int32, Int32) stub", js_CodeName[op]);
         ICCompare_Int32::Compiler compiler(cx, op);
         ICStub *int32Stub = compiler.getStub(compiler.getStubSpace(script));
         if (!int32Stub)
             return false;
 
-        stub->addNewStub(cx, int32Stub);
+        stub->addNewStub(int32Stub);
         return true;
     }
 
     if (!cx->runtime()->jitSupportsFloatingPoint && (lhs.isNumber() || rhs.isNumber()))
         return true;
 
     if (lhs.isNumber() && rhs.isNumber()) {
         IonSpew(IonSpew_BaselineIC, "  Generating %s(Number, Number) stub", js_CodeName[op]);
@@ -1810,80 +1807,80 @@ DoCompareFallback(JSContext *cx, Baselin
         // Unlink int32 stubs, it's faster to always use the double stub.
         stub->unlinkStubsWithKind(cx, ICStub::Compare_Int32);
 
         ICCompare_Double::Compiler compiler(cx, op);
         ICStub *doubleStub = compiler.getStub(compiler.getStubSpace(script));
         if (!doubleStub)
             return false;
 
-        stub->addNewStub(cx, doubleStub);
+        stub->addNewStub(doubleStub);
         return true;
     }
 
     if ((lhs.isNumber() && rhs.isUndefined()) ||
         (lhs.isUndefined() && rhs.isNumber()))
     {
         IonSpew(IonSpew_BaselineIC, "  Generating %s(%s, %s) stub", js_CodeName[op],
                     rhs.isUndefined() ? "Number" : "Undefined",
                     rhs.isUndefined() ? "Undefined" : "Number");
         ICCompare_NumberWithUndefined::Compiler compiler(cx, op, lhs.isUndefined());
         ICStub *doubleStub = compiler.getStub(compiler.getStubSpace(script));
         if (!doubleStub)
             return false;
 
-        stub->addNewStub(cx, doubleStub);
+        stub->addNewStub(doubleStub);
         return true;
     }
 
     if (lhs.isBoolean() && rhs.isBoolean()) {
         IonSpew(IonSpew_BaselineIC, "  Generating %s(Boolean, Boolean) stub", js_CodeName[op]);
         ICCompare_Boolean::Compiler compiler(cx, op);
         ICStub *booleanStub = compiler.getStub(compiler.getStubSpace(script));
         if (!booleanStub)
             return false;
 
-        stub->addNewStub(cx, booleanStub);
+        stub->addNewStub(booleanStub);
         return true;
     }
 
     if ((lhs.isBoolean() && rhs.isInt32()) || (lhs.isInt32() && rhs.isBoolean())) {
         IonSpew(IonSpew_BaselineIC, "  Generating %s(%s, %s) stub", js_CodeName[op],
                     rhs.isInt32() ? "Boolean" : "Int32",
                     rhs.isInt32() ? "Int32" : "Boolean");
         ICCompare_Int32WithBoolean::Compiler compiler(cx, op, lhs.isInt32());
         ICStub *optStub = compiler.getStub(compiler.getStubSpace(script));
         if (!optStub)
             return false;
 
-        stub->addNewStub(cx, optStub);
+        stub->addNewStub(optStub);
         return true;
     }
 
     if (IsEqualityOp(op)) {
         if (lhs.isString() && rhs.isString() && !stub->hasStub(ICStub::Compare_String)) {
             IonSpew(IonSpew_BaselineIC, "  Generating %s(String, String) stub", js_CodeName[op]);
             ICCompare_String::Compiler compiler(cx, op);
             ICStub *stringStub = compiler.getStub(compiler.getStubSpace(script));
             if (!stringStub)
                 return false;
 
-            stub->addNewStub(cx, stringStub);
+            stub->addNewStub(stringStub);
             return true;
         }
 
         if (lhs.isObject() && rhs.isObject()) {
             JS_ASSERT(!stub->hasStub(ICStub::Compare_Object));
             IonSpew(IonSpew_BaselineIC, "  Generating %s(Object, Object) stub", js_CodeName[op]);
             ICCompare_Object::Compiler compiler(cx, op);
             ICStub *objectStub = compiler.getStub(compiler.getStubSpace(script));
             if (!objectStub)
                 return false;
 
-            stub->addNewStub(cx, objectStub);
+            stub->addNewStub(objectStub);
             return true;
         }
 
         if ((lhs.isObject() || lhs.isNull() || lhs.isUndefined()) &&
             (rhs.isObject() || rhs.isNull() || rhs.isUndefined()) &&
             !stub->hasStub(ICStub::Compare_ObjectWithUndefined))
         {
             IonSpew(IonSpew_BaselineIC, "  Generating %s(Obj/Null/Undef, Obj/Null/Undef) stub",
@@ -1891,17 +1888,17 @@ DoCompareFallback(JSContext *cx, Baselin
             bool lhsIsUndefined = lhs.isNull() || lhs.isUndefined();
             bool compareWithNull = lhs.isNull() || rhs.isNull();
             ICCompare_ObjectWithUndefined::Compiler compiler(cx, op,
                                                              lhsIsUndefined, compareWithNull);
             ICStub *objectStub = compiler.getStub(compiler.getStubSpace(script));
             if (!objectStub)
                 return false;
 
-            stub->addNewStub(cx, objectStub);
+            stub->addNewStub(objectStub);
             return true;
         }
     }
 
     return true;
 }
 
 typedef bool (*DoCompareFallbackFn)(JSContext *, BaselineFrame *, ICCompare_Fallback *,
@@ -2202,60 +2199,60 @@ DoToBoolFallback(JSContext *cx, Baseline
     // Try to generate new stubs.
     if (arg.isInt32()) {
         IonSpew(IonSpew_BaselineIC, "  Generating ToBool(Int32) stub.");
         ICToBool_Int32::Compiler compiler(cx);
         ICStub *int32Stub = compiler.getStub(compiler.getStubSpace(script));
         if (!int32Stub)
             return false;
 
-        stub->addNewStub(cx, int32Stub);
+        stub->addNewStub(int32Stub);
         return true;
     }
 
     if (arg.isDouble() && cx->runtime()->jitSupportsFloatingPoint) {
         IonSpew(IonSpew_BaselineIC, "  Generating ToBool(Double) stub.");
         ICToBool_Double::Compiler compiler(cx);
         ICStub *doubleStub = compiler.getStub(compiler.getStubSpace(script));
         if (!doubleStub)
             return false;
 
-        stub->addNewStub(cx, doubleStub);
+        stub->addNewStub(doubleStub);
         return true;
     }
 
     if (arg.isString()) {
         IonSpew(IonSpew_BaselineIC, "  Generating ToBool(String) stub");
         ICToBool_String::Compiler compiler(cx);
         ICStub *stringStub = compiler.getStub(compiler.getStubSpace(script));
         if (!stringStub)
             return false;
 
-        stub->addNewStub(cx, stringStub);
+        stub->addNewStub(stringStub);
         return true;
     }
 
     if (arg.isNull() || arg.isUndefined()) {
         ICToBool_NullUndefined::Compiler compiler(cx);
         ICStub *nilStub = compiler.getStub(compiler.getStubSpace(script));
         if (!nilStub)
             return false;
 
-        stub->addNewStub(cx, nilStub);
+        stub->addNewStub(nilStub);
         return true;
     }
 
     if (arg.isObject()) {
         IonSpew(IonSpew_BaselineIC, "  Generating ToBool(Object) stub.");
         ICToBool_Object::Compiler compiler(cx);
         ICStub *objStub = compiler.getStub(compiler.getStubSpace(script));
         if (!objStub)
             return false;
 
-        stub->addNewStub(cx, objStub);
+        stub->addNewStub(objStub);
         return true;
     }
 
     return true;
 }
 
 typedef bool (*pf)(JSContext *, BaselineFrame *, ICToBool_Fallback *, HandleValue,
                    MutableHandleValue);
@@ -2537,69 +2534,69 @@ DoBinaryArithFallback(JSContext *cx, Bas
             return false;
         break;
       }
       default:
         MOZ_ASSUME_UNREACHABLE("Unhandled baseline arith op");
     }
 
     if (ret.isDouble())
-        stub->setSawDoubleResult(cx);
+        stub->setSawDoubleResult();
 
     // Check to see if a new stub should be generated.
     if (stub->numOptimizedStubs() >= ICBinaryArith_Fallback::MAX_OPTIMIZED_STUBS) {
-        stub->noteUnoptimizableOperands(cx);
+        stub->noteUnoptimizableOperands();
         return true;
     }
 
     // Handle string concat.
     if (op == JSOP_ADD) {
         if (lhs.isString() && rhs.isString()) {
             IonSpew(IonSpew_BaselineIC, "  Generating %s(String, String) stub", js_CodeName[op]);
             JS_ASSERT(ret.isString());
             ICBinaryArith_StringConcat::Compiler compiler(cx);
             ICStub *strcatStub = compiler.getStub(compiler.getStubSpace(script));
             if (!strcatStub)
                 return false;
-            stub->addNewStub(cx, strcatStub);
+            stub->addNewStub(strcatStub);
             return true;
         }
 
         if ((lhs.isString() && rhs.isObject()) || (lhs.isObject() && rhs.isString())) {
             IonSpew(IonSpew_BaselineIC, "  Generating %s(%s, %s) stub", js_CodeName[op],
                     lhs.isString() ? "String" : "Object",
                     lhs.isString() ? "Object" : "String");
             JS_ASSERT(ret.isString());
             ICBinaryArith_StringObjectConcat::Compiler compiler(cx, lhs.isString());
             ICStub *strcatStub = compiler.getStub(compiler.getStubSpace(script));
             if (!strcatStub)
                 return false;
-            stub->addNewStub(cx, strcatStub);
+            stub->addNewStub(strcatStub);
             return true;
         }
     }
 
     if (((lhs.isBoolean() && (rhs.isBoolean() || rhs.isInt32())) ||
          (rhs.isBoolean() && (lhs.isBoolean() || lhs.isInt32()))) &&
         (op == JSOP_ADD || op == JSOP_SUB || op == JSOP_BITOR || op == JSOP_BITAND ||
          op == JSOP_BITXOR))
     {
         IonSpew(IonSpew_BaselineIC, "  Generating %s(%s, %s) stub", js_CodeName[op],
                 lhs.isBoolean() ? "Boolean" : "Int32", rhs.isBoolean() ? "Boolean" : "Int32");
         ICBinaryArith_BooleanWithInt32::Compiler compiler(cx, op, lhs.isBoolean(), rhs.isBoolean());
         ICStub *arithStub = compiler.getStub(compiler.getStubSpace(script));
         if (!arithStub)
             return false;
-        stub->addNewStub(cx, arithStub);
+        stub->addNewStub(arithStub);
         return true;
     }
 
     // Handle only int32 or double.
     if (!lhs.isNumber() || !rhs.isNumber()) {
-        stub->noteUnoptimizableOperands(cx);
+        stub->noteUnoptimizableOperands();
         return true;
     }
 
     JS_ASSERT(ret.isNumber());
 
     if (lhs.isDouble() || rhs.isDouble() || ret.isDouble()) {
         if (!cx->runtime()->jitSupportsFloatingPoint)
             return true;
@@ -2613,17 +2610,17 @@ DoBinaryArithFallback(JSContext *cx, Bas
             // Unlink int32 stubs, it's faster to always use the double stub.
             stub->unlinkStubsWithKind(cx, ICStub::BinaryArith_Int32);
             IonSpew(IonSpew_BaselineIC, "  Generating %s(Double, Double) stub", js_CodeName[op]);
 
             ICBinaryArith_Double::Compiler compiler(cx, op);
             ICStub *doubleStub = compiler.getStub(compiler.getStubSpace(script));
             if (!doubleStub)
                 return false;
-            stub->addNewStub(cx, doubleStub);
+            stub->addNewStub(doubleStub);
             return true;
           }
           default:
             break;
         }
     }
 
     if (lhs.isInt32() && rhs.isInt32()) {
@@ -2631,17 +2628,17 @@ DoBinaryArithFallback(JSContext *cx, Bas
         if (allowDouble)
             stub->unlinkStubsWithKind(cx, ICStub::BinaryArith_Int32);
         IonSpew(IonSpew_BaselineIC, "  Generating %s(Int32, Int32%s) stub", js_CodeName[op],
                 allowDouble ? " => Double" : "");
         ICBinaryArith_Int32::Compiler compilerInt32(cx, op, allowDouble);
         ICStub *int32Stub = compilerInt32.getStub(compilerInt32.getStubSpace(script));
         if (!int32Stub)
             return false;
-        stub->addNewStub(cx, int32Stub);
+        stub->addNewStub(int32Stub);
         return true;
     }
 
     // Handle Double <BITOP> Int32 or Int32 <BITOP> Double case.
     if (((lhs.isDouble() && rhs.isInt32()) || (lhs.isInt32() && rhs.isDouble())) &&
         ret.isInt32())
     {
         switch(op) {
@@ -2650,25 +2647,25 @@ DoBinaryArithFallback(JSContext *cx, Bas
           case JSOP_BITAND: {
             IonSpew(IonSpew_BaselineIC, "  Generating %s(%s, %s) stub", js_CodeName[op],
                         lhs.isDouble() ? "Double" : "Int32",
                         lhs.isDouble() ? "Int32" : "Double");
             ICBinaryArith_DoubleWithInt32::Compiler compiler(cx, op, lhs.isDouble());
             ICStub *optStub = compiler.getStub(compiler.getStubSpace(script));
             if (!optStub)
                 return false;
-            stub->addNewStub(cx, optStub);
+            stub->addNewStub(optStub);
             return true;
           }
           default:
             break;
         }
     }
 
-    stub->noteUnoptimizableOperands(cx);
+    stub->noteUnoptimizableOperands();
     return true;
 }
 #if defined(_MSC_VER)
 # pragma optimize("", on)
 #endif
 
 typedef bool (*DoBinaryArithFallbackFn)(JSContext *, BaselineFrame *, ICBinaryArith_Fallback *,
                                         HandleValue, HandleValue, MutableHandleValue);
@@ -3053,31 +3050,31 @@ DoUnaryArithFallback(JSContext *cx, Base
     }
 
     if (val.isInt32() && res.isInt32()) {
         IonSpew(IonSpew_BaselineIC, "  Generating %s(Int32 => Int32) stub", js_CodeName[op]);
         ICUnaryArith_Int32::Compiler compiler(cx, op);
         ICStub *int32Stub = compiler.getStub(compiler.getStubSpace(script));
         if (!int32Stub)
             return false;
-        stub->addNewStub(cx, int32Stub);
+        stub->addNewStub(int32Stub);
         return true;
     }
 
     if (val.isNumber() && res.isNumber() && cx->runtime()->jitSupportsFloatingPoint) {
         IonSpew(IonSpew_BaselineIC, "  Generating %s(Number => Number) stub", js_CodeName[op]);
 
         // Unlink int32 stubs, the double stub handles both cases and TI specializes for both.
         stub->unlinkStubsWithKind(cx, ICStub::UnaryArith_Int32);
 
         ICUnaryArith_Double::Compiler compiler(cx, op);
         ICStub *doubleStub = compiler.getStub(compiler.getStubSpace(script));
         if (!doubleStub)
             return false;
-        stub->addNewStub(cx, doubleStub);
+        stub->addNewStub(doubleStub);
         return true;
     }
 
     return true;
 }
 #if defined(_MSC_VER)
 # pragma optimize("", on)
 #endif
@@ -3752,17 +3749,17 @@ static bool TryAttachNativeGetElemStub(J
         ICGetElemNativeStub::AccessType acctype = isFixedSlot ? ICGetElemNativeStub::FixedSlot
                                                               : ICGetElemNativeStub::DynamicSlot;
         ICGetElemNativeCompiler compiler(cx, kind, isCallElem, monitorStub, obj, holder, propName,
                                          acctype, needsAtomize, offset);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         return true;
     }
 
     bool getterIsScripted = false;
     if (IsCacheableGetPropCall(cx, obj, holder, shape, &getterIsScripted, /*isDOMProxy=*/false)) {
         RootedFunction getter(cx, &shape->getterObject()->as<JSFunction>());
 
 #if JS_HAS_NO_SUCH_METHOD
@@ -3804,17 +3801,17 @@ static bool TryAttachNativeGetElemStub(J
                                                            ? ICGetElemNativeStub::ScriptedGetter
                                                            : ICGetElemNativeStub::NativeGetter;
         ICGetElemNativeCompiler compiler(cx, kind, monitorStub, obj, holder, propName, acctype,
                                          needsAtomize, getter, script->pcToOffset(pc), isCallElem);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         return true;
     }
 
     return true;
 }
 
 static bool
 TypedArrayRequiresFloatingPoint(TypedArrayObject *tarr)
@@ -3838,17 +3835,17 @@ TryAttachGetElemStub(JSContext *cx, JSSc
         // NoSuchMethod handling doesn't apply to string targets.
 
         IonSpew(IonSpew_BaselineIC, "  Generating GetElem(String[Int32]) stub");
         ICGetElem_String::Compiler compiler(cx);
         ICStub *stringStub = compiler.getStub(compiler.getStubSpace(script));
         if (!stringStub)
             return false;
 
-        stub->addNewStub(cx, stringStub);
+        stub->addNewStub(stringStub);
         return true;
     }
 
     if (lhs.isMagic(JS_OPTIMIZED_ARGUMENTS) && rhs.isInt32() &&
         !ArgumentsGetElemStubExists(stub, ICGetElem_Arguments::Magic))
     {
         // Any script with a CALLPROP on arguments (arguments.foo())
         // should not have optimized arguments.
@@ -3856,17 +3853,17 @@ TryAttachGetElemStub(JSContext *cx, JSSc
 
         IonSpew(IonSpew_BaselineIC, "  Generating GetElem(MagicArgs[Int32]) stub");
         ICGetElem_Arguments::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
                                                ICGetElem_Arguments::Magic, false);
         ICStub *argsStub = compiler.getStub(compiler.getStubSpace(script));
         if (!argsStub)
             return false;
 
-        stub->addNewStub(cx, argsStub);
+        stub->addNewStub(argsStub);
         return true;
     }
 
     // Otherwise, GetElem is only optimized on objects.
     if (!lhs.isObject())
         return true;
     RootedObject obj(cx, &lhs.toObject());
 
@@ -3878,32 +3875,32 @@ TryAttachGetElemStub(JSContext *cx, JSSc
         if (!ArgumentsGetElemStubExists(stub, which)) {
             IonSpew(IonSpew_BaselineIC, "  Generating GetElem(ArgsObj[Int32]) stub");
             ICGetElem_Arguments::Compiler compiler(
                 cx, stub->fallbackMonitorStub()->firstMonitorStub(), which, isCallElem);
             ICStub *argsStub = compiler.getStub(compiler.getStubSpace(script));
             if (!argsStub)
                 return false;
 
-            stub->addNewStub(cx, argsStub);
+            stub->addNewStub(argsStub);
             return true;
         }
     }
 
     if (obj->isNative()) {
         // Check for NativeObject[int] dense accesses.
         if (rhs.isInt32() && rhs.toInt32() >= 0) {
             IonSpew(IonSpew_BaselineIC, "  Generating GetElem(Native[Int32] dense) stub");
             ICGetElem_Dense::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
                                                obj->lastProperty(), isCallElem);
             ICStub *denseStub = compiler.getStub(compiler.getStubSpace(script));
             if (!denseStub)
                 return false;
 
-            stub->addNewStub(cx, denseStub);
+            stub->addNewStub(denseStub);
             return true;
         }
 
         // Check for NativeObject[id] shape-optimizable accesses.
         if (rhs.isString()) {
             RootedScript rootedScript(cx, script);
             if (!TryAttachNativeGetElemStub(cx, rootedScript, pc, stub, obj, rhs))
                 return false;
@@ -3929,31 +3926,31 @@ TryAttachGetElemStub(JSContext *cx, JSSc
         }
 
         IonSpew(IonSpew_BaselineIC, "  Generating GetElem(TypedArray[Int32]) stub");
         ICGetElem_TypedArray::Compiler compiler(cx, tarr->lastProperty(), tarr->type());
         ICStub *typedArrayStub = compiler.getStub(compiler.getStubSpace(script));
         if (!typedArrayStub)
             return false;
 
-        stub->addNewStub(cx, typedArrayStub);
+        stub->addNewStub(typedArrayStub);
         return true;
     }
 
     // GetElem operations on non-native objects other than typed arrays cannot
     // be cached by either Baseline or Ion. Indicate this in the cache so that
     // Ion does not generate a cache for this op.
     if (!obj->isNative() && !obj->is<TypedArrayObject>())
-        stub->noteNonNativeAccess(cx);
+        stub->noteNonNativeAccess();
 
     // GetElem operations which could access negative indexes generally can't
     // be optimized without the potential for bailouts, as we can't statically
     // determine that an object has no properties on such indexes.
     if (rhs.isNumber() && rhs.toNumber() < 0)
-        stub->noteNegativeIndex(cx);
+        stub->noteNegativeIndex();
 
     return true;
 }
 
 static bool
 DoGetElemFallback(JSContext *cx, BaselineFrame *frame, ICGetElem_Fallback *stub, HandleValue lhs,
                   HandleValue rhs, MutableHandleValue res)
 {
@@ -5009,31 +5006,31 @@ DoSetElemFallback(JSContext *cx, Baselin
                         obj->lastProperty(), type.get(), protoDepth);
                 ICSetElemDenseAddCompiler compiler(cx, obj, protoDepth);
                 ICUpdatedStub *denseStub = compiler.getStub(compiler.getStubSpace(script));
                 if (!denseStub)
                     return false;
                 if (!denseStub->addUpdateStubForValue(cx, script, obj, JSID_VOIDHANDLE, rhs))
                     return false;
 
-                stub->addNewStub(cx, denseStub);
+                stub->addNewStub(denseStub);
             } else if (!addingCase &&
                        !DenseSetElemStubExists(cx, ICStub::SetElem_Dense, stub, obj))
             {
                 IonSpew(IonSpew_BaselineIC,
                         "  Generating SetElem_Dense stub (shape=%p, type=%p)",
                         obj->lastProperty(), type.get());
                 ICSetElem_Dense::Compiler compiler(cx, shape, type);
                 ICUpdatedStub *denseStub = compiler.getStub(compiler.getStubSpace(script));
                 if (!denseStub)
                     return false;
                 if (!denseStub->addUpdateStubForValue(cx, script, obj, JSID_VOIDHANDLE, rhs))
                     return false;
 
-                stub->addNewStub(cx, denseStub);
+                stub->addNewStub(denseStub);
             }
         }
 
         return true;
     }
 
     if (obj->is<TypedArrayObject>() && index.isNumber() && rhs.isNumber()) {
         Rooted<TypedArrayObject*> tarr(cx, &obj->as<TypedArrayObject>());
@@ -5056,17 +5053,17 @@ DoSetElemFallback(JSContext *cx, Baselin
                     "  Generating SetElem_TypedArray stub (shape=%p, type=%u, oob=%s)",
                     tarr->lastProperty(), tarr->type(), expectOutOfBounds ? "yes" : "no");
             ICSetElem_TypedArray::Compiler compiler(cx, tarr->lastProperty(), tarr->type(),
                                                     expectOutOfBounds);
             ICStub *typedArrayStub = compiler.getStub(compiler.getStubSpace(script));
             if (!typedArrayStub)
                 return false;
 
-            stub->addNewStub(cx, typedArrayStub);
+            stub->addNewStub(typedArrayStub);
             return true;
         }
     }
 
     return true;
 }
 
 typedef bool (*DoSetElemFallbackFn)(JSContext *, BaselineFrame *, ICSetElem_Fallback *, Value *,
@@ -5106,23 +5103,23 @@ ICSetElem_Fallback::Compiler::generateSt
 
     masm.push(BaselineStubReg);
     masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
 
     return tailCallVM(DoSetElemFallbackInfo, masm);
 }
 
 void
-BaselineScript::noteArrayWriteHole(JSContext *cx, uint32_t pcOffset)
+BaselineScript::noteArrayWriteHole(uint32_t pcOffset)
 {
     ICEntry &entry = icEntryFromPCOffset(pcOffset);
     ICFallbackStub *stub = entry.fallbackStub();
 
     if (stub->isSetElem_Fallback())
-        stub->toSetElem_Fallback()->noteArrayWriteHole(cx);
+        stub->toSetElem_Fallback()->noteArrayWriteHole();
 }
 
 //
 // SetElem_Dense
 //
 
 bool
 ICSetElem_Dense::Compiler::generateStubCode(MacroAssembler &masm)
@@ -5634,17 +5631,17 @@ TryAttachGlobalNameStub(JSContext *cx, H
 
     ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
     IonSpew(IonSpew_BaselineIC, "  Generating GetName(GlobalName) stub");
     ICGetName_Global::Compiler compiler(cx, monitorStub, global->lastProperty(), slot);
     ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
     if (!newStub)
         return false;
 
-    stub->addNewStub(cx, newStub);
+    stub->addNewStub(newStub);
     return true;
 }
 
 static bool
 TryAttachScopeNameStub(JSContext *cx, HandleScript script, ICGetName_Fallback *stub,
                        HandleObject initialScopeChain, HandlePropertyName name)
 {
     AutoShapeVector shapes(cx);
@@ -5724,17 +5721,17 @@ TryAttachScopeNameStub(JSContext *cx, Ha
       }
       default:
         return true;
     }
 
     if (!newStub)
         return false;
 
-    stub->addNewStub(cx, newStub);
+    stub->addNewStub(newStub);
     return true;
 }
 
 static bool
 DoGetNameFallback(JSContext *cx, BaselineFrame *frame, ICGetName_Fallback *stub,
                   HandleObject scopeChain, MutableHandleValue res)
 {
     RootedScript script(cx, frame->script());
@@ -5931,17 +5928,17 @@ DoGetIntrinsicFallback(JSContext *cx, Ba
     types::TypeScript::Monitor(cx, script, pc, res);
 
     IonSpew(IonSpew_BaselineIC, "  Generating GetIntrinsic optimized stub");
     ICGetIntrinsic_Constant::Compiler compiler(cx, res);
     ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
     if (!newStub)
         return false;
 
-    stub->addNewStub(cx, newStub);
+    stub->addNewStub(newStub);
     return true;
 }
 
 typedef bool (*DoGetIntrinsicFallbackFn)(JSContext *, BaselineFrame *, ICGetIntrinsic_Fallback *,
                                          MutableHandleValue);
 static const VMFunction DoGetIntrinsicFallbackInfo =
     FunctionInfo<DoGetIntrinsicFallbackFn>(DoGetIntrinsicFallback);
 
@@ -5979,74 +5976,74 @@ TryAttachLengthStub(JSContext *cx, JSScr
         JS_ASSERT(res.isInt32());
         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(String.length) stub");
         ICGetProp_StringLength::Compiler compiler(cx);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
         *attached = true;
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         return true;
     }
 
     if (val.isMagic(JS_OPTIMIZED_ARGUMENTS) && res.isInt32()) {
         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(MagicArgs.length) stub");
         ICGetProp_ArgumentsLength::Compiler compiler(cx, ICGetProp_ArgumentsLength::Magic);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
         *attached = true;
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         return true;
     }
 
     if (!val.isObject())
         return true;
 
     RootedObject obj(cx, &val.toObject());
 
     if (obj->is<ArrayObject>() && res.isInt32()) {
         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(Array.length) stub");
         ICGetProp_ArrayLength::Compiler compiler(cx);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
         *attached = true;
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         return true;
     }
     if (obj->is<TypedArrayObject>()) {
         JS_ASSERT(res.isInt32());
         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(TypedArray.length) stub");
         ICGetProp_TypedArrayLength::Compiler compiler(cx);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
         *attached = true;
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         return true;
     }
 
     if (obj->is<ArgumentsObject>() && res.isInt32()) {
         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(ArgsObj.length %s) stub",
                 obj->is<StrictArgumentsObject>() ? "Strict" : "Normal");
         ICGetProp_ArgumentsLength::Which which = ICGetProp_ArgumentsLength::Normal;
         if (obj->is<StrictArgumentsObject>())
             which = ICGetProp_ArgumentsLength::Strict;
         ICGetProp_ArgumentsLength::Compiler compiler(cx, which);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
         *attached = true;
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         return true;
     }
 
     return true;
 }
 
 static bool
 UpdateExistingGenerationalDOMProxyStub(ICGetProp_Fallback *stub,
@@ -6119,17 +6116,17 @@ TryAttachNativeGetPropStub(JSContext *cx
                     isDOMProxy ? "DOMProxy" : "Native",
                     (obj == holder) ? "direct" : "prototype");
         ICGetPropNativeCompiler compiler(cx, kind, isCallProp, monitorStub, obj, holder,
                                          name, isFixedSlot, offset);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         *attached = true;
         return true;
     }
 
     bool isScripted = false;
     bool cacheableCall = IsCacheableGetPropCall(cx, obj, holder, shape, &isScripted, isDOMProxy);
 
     // Try handling scripted getters.
@@ -6150,17 +6147,17 @@ TryAttachNativeGetPropStub(JSContext *cx
                     callee->nonLazyScript()->filename(), callee->nonLazyScript()->lineno());
 
         ICGetProp_CallScripted::Compiler compiler(cx, monitorStub, obj, holder, callee,
                                                   script->pcToOffset(pc));
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         *attached = true;
         return true;
     }
 
     // Try handling JSNative getters.
     if (cacheableCall && !isScripted) {
 #if JS_HAS_NO_SUCH_METHOD
         // It's unlikely that a getter function will be used to generate functions for calling
@@ -6197,17 +6194,17 @@ TryAttachNativeGetPropStub(JSContext *cx
             newStub = compiler.getStub(compiler.getStubSpace(script));
         } else {
             ICGetProp_CallNative::Compiler compiler(cx, monitorStub, obj, holder, callee,
                                                     script->pcToOffset(pc));
             newStub = compiler.getStub(compiler.getStubSpace(script));
         }
         if (!newStub)
             return false;
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         *attached = true;
         return true;
     }
 
     // If it's a shadowed listbase proxy property, attach stub to call Proxy::get instead.
     if (isDOMProxy && domProxyShadowsResult == Shadows) {
         JS_ASSERT(obj == holder);
 #if JS_HAS_NO_SUCH_METHOD
@@ -6217,17 +6214,17 @@ TryAttachNativeGetPropStub(JSContext *cx
 
         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(DOMProxyProxy) stub");
         Rooted<ProxyObject*> proxy(cx, &obj->as<ProxyObject>());
         ICGetProp_DOMProxyShadowed::Compiler compiler(cx, monitorStub, proxy, name,
                                                       script->pcToOffset(pc));
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         *attached = true;
         return true;
     }
 
     return true;
 }
 
 static bool
@@ -6272,17 +6269,17 @@ TryAttachPrimitiveGetPropStub(JSContext 
 
     IonSpew(IonSpew_BaselineIC, "  Generating GetProp_Primitive stub");
     ICGetProp_Primitive::Compiler compiler(cx, monitorStub, primitiveType, proto,
                                            isFixedSlot, offset);
     ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
     if (!newStub)
         return false;
 
-    stub->addNewStub(cx, newStub);
+    stub->addNewStub(newStub);
     *attached = true;
     return true;
 }
 
 static bool
 DoGetPropFallback(JSContext *cx, BaselineFrame *frame, ICGetProp_Fallback *stub,
                   MutableHandleValue val, MutableHandleValue res)
 {
@@ -6359,17 +6356,17 @@ DoGetPropFallback(JSContext *cx, Baselin
     if (val.isString() || val.isNumber() || val.isBoolean()) {
         if (!TryAttachPrimitiveGetPropStub(cx, script, pc, stub, name, val, res, &attached))
             return false;
         if (attached)
             return true;
     }
 
     JS_ASSERT(!attached);
-    stub->noteUnoptimizableAccess(cx);
+    stub->noteUnoptimizableAccess();
 
     return true;
 }
 
 typedef bool (*DoGetPropFallbackFn)(JSContext *, BaselineFrame *, ICGetProp_Fallback *,
                                     MutableHandleValue, MutableHandleValue);
 static const VMFunction DoGetPropFallbackInfo =
     FunctionInfo<DoGetPropFallbackFn>(DoGetPropFallback, PopValues(1));
@@ -7104,23 +7101,23 @@ ICGetProp_ArgumentsLength::Compiler::gen
     EmitReturnFromIC(masm);
 
     masm.bind(&failure);
     EmitStubGuardFailure(masm);
     return true;
 }
 
 void
-BaselineScript::noteAccessedGetter(JSContext *cx, uint32_t pcOffset)
+BaselineScript::noteAccessedGetter(uint32_t pcOffset)
 {
     ICEntry &entry = icEntryFromPCOffset(pcOffset);
     ICFallbackStub *stub = entry.fallbackStub();
 
     if (stub->isGetProp_Fallback())
-        stub->toGetProp_Fallback()->noteAccessedGetter(cx);
+        stub->toGetProp_Fallback()->noteAccessedGetter();
 }
 
 //
 // SetProp_Fallback
 //
 
 // Attach an optimized stub for a SETPROP/SETGNAME/SETNAME op.
 static bool
@@ -7151,17 +7148,17 @@ TryAttachSetPropStub(JSContext *cx, Hand
         IonSpew(IonSpew_BaselineIC, "  Generating SetProp(NativeObject.ADD) stub");
         ICSetPropNativeAddCompiler compiler(cx, obj, oldShape, chainDepth, isFixedSlot, offset);
         ICUpdatedStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
         if (!newStub->addUpdateStubForValue(cx, script, obj, id, rhs))
             return false;
 
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         *attached = true;
         return true;
     }
 
     if (IsCacheableSetPropWriteSlot(obj, oldShape, holder, shape)) {
         bool isFixedSlot;
         uint32_t offset;
         GetFixedOrDynamicSlotOffset(obj, shape->slot(), &isFixedSlot, &offset);
@@ -7169,17 +7166,17 @@ TryAttachSetPropStub(JSContext *cx, Hand
         IonSpew(IonSpew_BaselineIC, "  Generating SetProp(NativeObject.PROP) stub");
         ICSetProp_Native::Compiler compiler(cx, obj, isFixedSlot, offset);
         ICUpdatedStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
         if (!newStub->addUpdateStubForValue(cx, script, obj, id, rhs))
             return false;
 
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         *attached = true;
         return true;
     }
 
     bool isScripted = false;
     bool cacheableCall = IsCacheableSetPropCall(cx, obj, holder, shape, &isScripted);
 
     // Try handling scripted setters.
@@ -7191,17 +7188,17 @@ TryAttachSetPropStub(JSContext *cx, Hand
         IonSpew(IonSpew_BaselineIC, "  Generating SetProp(NativeObj/ScriptedSetter %s:%d) stub",
                     callee->nonLazyScript()->filename(), callee->nonLazyScript()->lineno());
 
         ICSetProp_CallScripted::Compiler compiler(cx, obj, holder, callee, script->pcToOffset(pc));
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         *attached = true;
         return true;
     }
 
     // Try handling JSNative setters.
     if (cacheableCall && !isScripted) {
         RootedFunction callee(cx, &shape->setterObject()->as<JSFunction>());
         JS_ASSERT(obj != holder);
@@ -7210,17 +7207,17 @@ TryAttachSetPropStub(JSContext *cx, Hand
         IonSpew(IonSpew_BaselineIC, "  Generating SetProp(NativeObj/NativeSetter %p) stub",
                     callee->native());
 
         ICSetProp_CallNative::Compiler compiler(cx, obj, holder, callee, script->pcToOffset(pc));
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         *attached = true;
         return true;
     }
 
     return true;
 }
 
 static bool
@@ -7285,17 +7282,17 @@ DoSetPropFallback(JSContext *cx, Baselin
          &attached))
     {
         return false;
     }
     if (attached)
         return true;
 
     JS_ASSERT(!attached);
-    stub->noteUnoptimizableAccess(cx);
+    stub->noteUnoptimizableAccess();
 
     return true;
 }
 
 typedef bool (*DoSetPropFallbackFn)(JSContext *, BaselineFrame *, ICSetProp_Fallback *,
                                     HandleValue, HandleValue, MutableHandleValue);
 static const VMFunction DoSetPropFallbackInfo =
     FunctionInfo<DoSetPropFallbackFn>(DoSetPropFallback, PopValues(2));
@@ -7791,34 +7788,34 @@ TryAttachFunApplyStub(JSContext *cx, ICC
             IonSpew(IonSpew_BaselineIC, "  Generating Call_ScriptedApplyArguments stub");
 
             ICCall_ScriptedApplyArguments::Compiler compiler(
                 cx, stub->fallbackMonitorStub()->firstMonitorStub(), script->pcToOffset(pc));
             ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
             if (!newStub)
                 return false;
 
-            stub->addNewStub(cx, newStub);
+            stub->addNewStub(newStub);
             return true;
         }
 
         // TODO: handle FUNAPPLY for native targets.
     }
 
     if (argv[1].isObject() && argv[1].toObject().is<ArrayObject>()) {
         if (isScripted && !stub->hasStub(ICStub::Call_ScriptedApplyArray)) {
             IonSpew(IonSpew_BaselineIC, "  Generating Call_ScriptedApplyArray stub");
 
             ICCall_ScriptedApplyArray::Compiler compiler(
                 cx, stub->fallbackMonitorStub()->firstMonitorStub(), script->pcToOffset(pc));
             ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
             if (!newStub)
                 return false;
 
-            stub->addNewStub(cx, newStub);
+            stub->addNewStub(newStub);
             return true;
         }
     }
     return true;
 }
 
 static bool
 GetTemplateObjectForNative(JSContext *cx, HandleScript script, jsbytecode *pc,
@@ -7952,17 +7949,17 @@ TryAttachCallStub(JSContext *cx, ICCall_
             ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
             if (!newStub)
                 return false;
 
             // Before adding new stub, unlink all previous Call_Scripted.
             stub->unlinkStubsWithKind(cx, ICStub::Call_Scripted);
 
             // Add new generalized stub.
-            stub->addNewStub(cx, newStub);
+            stub->addNewStub(newStub);
             return true;
         }
 
         // Keep track of the function's |prototype| property in type
         // information, for use during Ion compilation.
         if (IsIonEnabled(cx))
             types::EnsureTrackPropertyTypes(cx, fun, NameToId(cx->names().prototype));
 
@@ -7981,17 +7978,17 @@ TryAttachCallStub(JSContext *cx, ICCall_
                 constructing ? "yes" : "no");
         ICCallScriptedCompiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
                                         calleeScript, templateObject,
                                         constructing, script->pcToOffset(pc));
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         return true;
     }
 
     if (fun->isNative() && (!constructing || (constructing && fun->isNativeConstructor()))) {
         // Generalized native call stubs are not here yet!
         JS_ASSERT(!stub->nativeStubsAreGeneralized());
 
         // Check for JSOP_FUNAPPLY
@@ -8018,17 +8015,17 @@ TryAttachCallStub(JSContext *cx, ICCall_
         IonSpew(IonSpew_BaselineIC, "  Generating Call_Native stub (fun=%p, cons=%s)",
                 fun.get(), constructing ? "yes" : "no");
         ICCall_Native::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
                                          fun, templateObject, constructing, script->pcToOffset(pc));
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         return true;
     }
 
     return true;
 }
 
 static bool
 MaybeCloneFunctionAtCallsite(JSContext *cx, MutableHandleValue callee, HandleScript script,
@@ -9150,17 +9147,17 @@ DoIteratorMoreFallback(JSContext *cx, Ba
 
     if (iterValue.toObject().is<PropertyIteratorObject>() &&
         !stub->hasStub(ICStub::IteratorMore_Native))
     {
         ICIteratorMore_Native::Compiler compiler(cx);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(frame->script()));
         if (!newStub)
             return false;
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
     }
 
     return true;
 }
 
 typedef bool (*DoIteratorMoreFallbackFn)(JSContext *, BaselineFrame *, ICIteratorMore_Fallback *,
                                          HandleValue, MutableHandleValue);
 static const VMFunction DoIteratorMoreFallbackInfo =
@@ -9224,26 +9221,26 @@ DoIteratorNextFallback(JSContext *cx, Ba
 {
     FallbackICSpew(cx, stub, "IteratorNext");
 
     RootedObject iteratorObject(cx, &iterValue.toObject());
     if (!IteratorNext(cx, iteratorObject, res))
         return false;
 
     if (!res.isString() && !stub->hasNonStringResult())
-        stub->setHasNonStringResult(cx);
+        stub->setHasNonStringResult();
 
     if (iteratorObject->is<PropertyIteratorObject>() &&
         !stub->hasStub(ICStub::IteratorNext_Native))
     {
         ICIteratorNext_Native::Compiler compiler(cx);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(frame->script()));
         if (!newStub)
             return false;
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
     }
 
     return true;
 }
 
 typedef bool (*DoIteratorNextFallbackFn)(JSContext *, BaselineFrame *, ICIteratorNext_Fallback *,
                                          HandleValue, MutableHandleValue);
 static const VMFunction DoIteratorNextFallbackInfo =
@@ -9397,17 +9394,17 @@ DoTypeOfFallback(JSContext *cx, Baseline
     JS_ASSERT(type != JSTYPE_NULL);
     if (type != JSTYPE_OBJECT && type != JSTYPE_FUNCTION) {
         // Create a new TypeOf stub.
         IonSpew(IonSpew_BaselineIC, "  Generating TypeOf stub for JSType (%d)", (int) type);
         ICTypeOf_Typed::Compiler compiler(cx, type, string);
         ICStub *typeOfStub = compiler.getStub(compiler.getStubSpace(frame->script()));
         if (!typeOfStub)
             return false;
-        stub->addNewStub(cx, typeOfStub);
+        stub->addNewStub(typeOfStub);
     }
 
     return true;
 }
 
 typedef bool (*DoTypeOfFallbackFn)(JSContext *, BaselineFrame *frame, ICTypeOf_Fallback *,
                                    HandleValue, MutableHandleValue);
 static const VMFunction DoTypeOfFallbackInfo =
@@ -9484,17 +9481,17 @@ DoRetSubFallback(JSContext *cx, Baseline
 
     // Attach an optimized stub for this pc offset.
     IonSpew(IonSpew_BaselineIC, "  Generating RetSub stub for pc offset %u", offset);
     ICRetSub_Resume::Compiler compiler(cx, offset, *resumeAddr);
     ICStub *optStub = compiler.getStub(compiler.getStubSpace(script));
     if (!optStub)
         return false;
 
-    stub->addNewStub(cx, optStub);
+    stub->addNewStub(optStub);
     return true;
 }
 
 typedef bool(*DoRetSubFallbackFn)(JSContext *cx, BaselineFrame *, ICRetSub_Fallback *,
                                   HandleValue, uint8_t **);
 static const VMFunction DoRetSubFallbackInfo = FunctionInfo<DoRetSubFallbackFn>(DoRetSubFallback);
 
 typedef bool (*ThrowFn)(JSContext *, HandleValue);
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -830,18 +830,17 @@ class ICFallbackStub : public ICStub
     void fixupICEntry(ICEntry *icEntry) {
         JS_ASSERT(icEntry_ == nullptr);
         JS_ASSERT(lastStubPtrAddr_ == nullptr);
         icEntry_ = icEntry;
         lastStubPtrAddr_ = icEntry_->addressOfFirstStub();
     }
 
     // Add a new stub to the IC chain terminated by this fallback stub.
-    void addNewStub(JSContext *cx, ICStub *stub) {
-        AutoLockForCompilation lock(cx);
+    void addNewStub(ICStub *stub) {
         JS_ASSERT(*lastStubPtrAddr_ == this);
         JS_ASSERT(stub->next() == nullptr);
         stub->setNext(this);
         *lastStubPtrAddr_ = stub;
         lastStubPtrAddr_ = stub->addressOfNext();
         numOptimizedStubs_++;
     }
 
@@ -2437,25 +2436,23 @@ class ICBinaryArith_Fallback : public IC
         if (!code)
             return nullptr;
         return space->allocate<ICBinaryArith_Fallback>(code);
     }
 
     bool sawDoubleResult() const {
         return extra_ & SAW_DOUBLE_RESULT_BIT;
     }
-    void setSawDoubleResult(JSContext *cx) {
-        AutoLockForCompilation lock(cx);
+    void setSawDoubleResult() {
         extra_ |= SAW_DOUBLE_RESULT_BIT;
     }
     bool hadUnoptimizableOperands() const {
         return extra_ & UNOPTIMIZABLE_OPERANDS_BIT;
     }
-    void noteUnoptimizableOperands(JSContext *cx) {
-        AutoLockForCompilation lock(cx);
+    void noteUnoptimizableOperands() {
         extra_ |= UNOPTIMIZABLE_OPERANDS_BIT;
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICStubCompiler {
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
@@ -2846,26 +2843,24 @@ class ICGetElem_Fallback : public ICMoni
     static const uint32_t MAX_OPTIMIZED_STUBS = 16;
 
     static inline ICGetElem_Fallback *New(ICStubSpace *space, JitCode *code) {
         if (!code)
             return nullptr;
         return space->allocate<ICGetElem_Fallback>(code);
     }
 
-    void noteNonNativeAccess(JSContext *cx) {
-        AutoLockForCompilation lock(cx);
+    void noteNonNativeAccess() {
         extra_ |= EXTRA_NON_NATIVE;
     }
     bool hasNonNativeAccess() const {
         return extra_ & EXTRA_NON_NATIVE;
     }
 
-    void noteNegativeIndex(JSContext *cx) {
-        AutoLockForCompilation lock(cx);
+    void noteNegativeIndex() {
         extra_ |= EXTRA_NEGATIVE_INDEX;
     }
     bool hasNegativeIndex() const {
         return extra_ & EXTRA_NEGATIVE_INDEX;
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICStubCompiler {
@@ -3443,18 +3438,17 @@ class ICSetElem_Fallback : public ICFall
     static const uint32_t MAX_OPTIMIZED_STUBS = 8;
 
     static inline ICSetElem_Fallback *New(ICStubSpace *space, JitCode *code) {
         if (!code)
             return nullptr;
         return space->allocate<ICSetElem_Fallback>(code);
     }
 
-    void noteArrayWriteHole(JSContext *cx) {
-        AutoLockForCompilation lock(cx);
+    void noteArrayWriteHole() {
         extra_ = 1;
     }
     bool hasArrayWriteHole() const {
         return extra_;
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICStubCompiler {
@@ -4019,26 +4013,24 @@ class ICGetProp_Fallback : public ICMoni
         if (!code)
             return nullptr;
         return space->allocate<ICGetProp_Fallback>(code);
     }
 
     static const size_t UNOPTIMIZABLE_ACCESS_BIT = 0;
     static const size_t ACCESSED_GETTER_BIT = 1;
 
-    void noteUnoptimizableAccess(JSContext *cx) {
-        AutoLockForCompilation lock(cx);
+    void noteUnoptimizableAccess() {
         extra_ |= (1u << UNOPTIMIZABLE_ACCESS_BIT);
     }
     bool hadUnoptimizableAccess() const {
         return extra_ & (1u << UNOPTIMIZABLE_ACCESS_BIT);
     }
 
-    void noteAccessedGetter(JSContext *cx) {
-        AutoLockForCompilation lock(cx);
+    void noteAccessedGetter() {
         extra_ |= (1u << ACCESSED_GETTER_BIT);
     }
     bool hasAccessedGetter() const {
         return extra_ & (1u << ACCESSED_GETTER_BIT);
     }
 
     class Compiler : public ICStubCompiler {
       protected:
@@ -4835,18 +4827,17 @@ class ICSetProp_Fallback : public ICFall
 
     static inline ICSetProp_Fallback *New(ICStubSpace *space, JitCode *code) {
         if (!code)
             return nullptr;
         return space->allocate<ICSetProp_Fallback>(code);
     }
 
     static const size_t UNOPTIMIZABLE_ACCESS_BIT = 0;
-    void noteUnoptimizableAccess(JSContext *cx) {
-        AutoLockForCompilation lock(cx);
+    void noteUnoptimizableAccess() {
         extra_ |= (1u << UNOPTIMIZABLE_ACCESS_BIT);
     }
     bool hadUnoptimizableAccess() const {
         return extra_ & (1u << UNOPTIMIZABLE_ACCESS_BIT);
     }
 
     class Compiler : public ICStubCompiler {
       protected:
@@ -5737,18 +5728,17 @@ class ICIteratorNext_Fallback : public I
 
   public:
     static inline ICIteratorNext_Fallback *New(ICStubSpace *space, JitCode *code) {
         if (!code)
             return nullptr;
         return space->allocate<ICIteratorNext_Fallback>(code);
     }
 
-    void setHasNonStringResult(JSContext *cx) {
-        AutoLockForCompilation lock(cx);
+    void setHasNonStringResult() {
         JS_ASSERT(extra_ == 0);
         extra_ = 1;
     }
     bool hasNonStringResult() const {
         return extra_;
     }
 
     class Compiler : public ICStubCompiler {
--- a/js/src/jit/BaselineInspector.cpp
+++ b/js/src/jit/BaselineInspector.cpp
@@ -13,18 +13,16 @@
 using namespace js;
 using namespace js::jit;
 
 using mozilla::DebugOnly;
 
 bool
 SetElemICInspector::sawOOBDenseWrite() const
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     if (!icEntry_)
         return false;
 
     // Check for a SetElem_DenseAdd stub.
     for (ICStub *stub = icEntry_->firstStub(); stub; stub = stub->next()) {
         if (stub->isSetElem_DenseAdd())
             return true;
     }
@@ -35,68 +33,60 @@ SetElemICInspector::sawOOBDenseWrite() c
         return stub->toSetElem_Fallback()->hasArrayWriteHole();
 
     return false;
 }
 
 bool
 SetElemICInspector::sawOOBTypedArrayWrite() const
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     if (!icEntry_)
         return false;
 
     // Check for SetElem_TypedArray stubs with expectOutOfBounds set.
     for (ICStub *stub = icEntry_->firstStub(); stub; stub = stub->next()) {
         if (!stub->isSetElem_TypedArray())
             continue;
         if (stub->toSetElem_TypedArray()->expectOutOfBounds())
             return true;
     }
     return false;
 }
 
 bool
 SetElemICInspector::sawDenseWrite() const
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     if (!icEntry_)
         return false;
 
     // Check for a SetElem_DenseAdd or SetElem_Dense stub.
     for (ICStub *stub = icEntry_->firstStub(); stub; stub = stub->next()) {
         if (stub->isSetElem_DenseAdd() || stub->isSetElem_Dense())
             return true;
     }
     return false;
 }
 
 bool
 SetElemICInspector::sawTypedArrayWrite() const
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     if (!icEntry_)
         return false;
 
     // Check for a SetElem_TypedArray stub.
     for (ICStub *stub = icEntry_->firstStub(); stub; stub = stub->next()) {
         if (stub->isSetElem_TypedArray())
             return true;
     }
     return false;
 }
 
 bool
 BaselineInspector::maybeShapesForPropertyOp(jsbytecode *pc, ShapeVector &shapes)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     // Return a list of shapes seen by the baseline IC for the current op.
     // An empty list indicates no shapes are known, or there was an uncacheable
     // access.
     JS_ASSERT(shapes.empty());
 
     if (!hasBaselineScript())
         return true;
 
@@ -144,18 +134,16 @@ BaselineInspector::maybeShapesForPropert
         shapes.clear();
 
     return true;
 }
 
 ICStub *
 BaselineInspector::monomorphicStub(jsbytecode *pc)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     if (!hasBaselineScript())
         return nullptr;
 
     const ICEntry &entry = icEntryFromPC(pc);
 
     ICStub *stub = entry.firstStub();
     ICStub *next = stub->next();
 
@@ -163,18 +151,16 @@ BaselineInspector::monomorphicStub(jsbyt
         return nullptr;
 
     return stub;
 }
 
 bool
 BaselineInspector::dimorphicStub(jsbytecode *pc, ICStub **pfirst, ICStub **psecond)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     if (!hasBaselineScript())
         return false;
 
     const ICEntry &entry = icEntryFromPC(pc);
 
     ICStub *stub = entry.firstStub();
     ICStub *next = stub->next();
     ICStub *after = next ? next->next() : nullptr;
@@ -185,18 +171,16 @@ BaselineInspector::dimorphicStub(jsbytec
     *pfirst = stub;
     *psecond = next;
     return true;
 }
 
 MIRType
 BaselineInspector::expectedResultType(jsbytecode *pc)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     // Look at the IC entries for this op to guess what type it will produce,
     // returning MIRType_None otherwise.
 
     ICStub *stub = monomorphicStub(pc);
     if (!stub)
         return MIRType_None;
 
     switch (stub->kind()) {
@@ -233,18 +217,16 @@ static bool
 CanUseInt32Compare(ICStub::Kind kind)
 {
     return kind == ICStub::Compare_Int32 || kind == ICStub::Compare_Int32WithBoolean;
 }
 
 MCompare::CompareType
 BaselineInspector::expectedCompareType(jsbytecode *pc)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     ICStub *first = monomorphicStub(pc), *second = nullptr;
     if (!first && !dimorphicStub(pc, &first, &second))
         return MCompare::Compare_Unknown;
 
     if (CanUseInt32Compare(first->kind()) && (!second || CanUseInt32Compare(second->kind()))) {
         ICCompare_Int32WithBoolean *coerce =
             first->isCompare_Int32WithBoolean()
             ? first->toCompare_Int32WithBoolean()
@@ -317,18 +299,16 @@ TryToSpecializeBinaryArithOp(ICStub **st
     JS_ASSERT(sawInt32);
     *result = MIRType_Int32;
     return true;
 }
 
 MIRType
 BaselineInspector::expectedBinaryArithSpecialization(jsbytecode *pc)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     MIRType result;
     ICStub *stubs[2];
 
     const ICEntry &entry = icEntryFromPC(pc);
     ICStub *stub = entry.fallbackStub();
     if (stub->isBinaryArith_Fallback() &&
         stub->toBinaryArith_Fallback()->hadUnoptimizableOperands())
     {
@@ -347,82 +327,72 @@ BaselineInspector::expectedBinaryArithSp
     }
 
     return MIRType_None;
 }
 
 bool
 BaselineInspector::hasSeenNonNativeGetElement(jsbytecode *pc)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     if (!hasBaselineScript())
         return false;
 
     const ICEntry &entry = icEntryFromPC(pc);
     ICStub *stub = entry.fallbackStub();
 
     if (stub->isGetElem_Fallback())
         return stub->toGetElem_Fallback()->hasNonNativeAccess();
     return false;
 }
 
 bool
 BaselineInspector::hasSeenNegativeIndexGetElement(jsbytecode *pc)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     if (!hasBaselineScript())
         return false;
 
     const ICEntry &entry = icEntryFromPC(pc);
     ICStub *stub = entry.fallbackStub();
 
     if (stub->isGetElem_Fallback())
         return stub->toGetElem_Fallback()->hasNegativeIndex();
     return false;
 }
 
 bool
 BaselineInspector::hasSeenAccessedGetter(jsbytecode *pc)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     if (!hasBaselineScript())
         return false;
 
     const ICEntry &entry = icEntryFromPC(pc);
     ICStub *stub = entry.fallbackStub();
 
     if (stub->isGetProp_Fallback())
         return stub->toGetProp_Fallback()->hasAccessedGetter();
     return false;
 }
 
 bool
 BaselineInspector::hasSeenNonStringIterNext(jsbytecode *pc)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     JS_ASSERT(JSOp(*pc) == JSOP_ITERNEXT);
 
     if (!hasBaselineScript())
         return false;
 
     const ICEntry &entry = icEntryFromPC(pc);
     ICStub *stub = entry.fallbackStub();
 
     return stub->toIteratorNext_Fallback()->hasNonStringResult();
 }
 
 bool
 BaselineInspector::hasSeenDoubleResult(jsbytecode *pc)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     if (!hasBaselineScript())
         return false;
 
     const ICEntry &entry = icEntryFromPC(pc);
     ICStub *stub = entry.fallbackStub();
 
     JS_ASSERT(stub->isUnaryArith_Fallback() || stub->isBinaryArith_Fallback());
 
@@ -432,18 +402,16 @@ BaselineInspector::hasSeenDoubleResult(j
         return stub->toBinaryArith_Fallback()->sawDoubleResult();
 
     return false;
 }
 
 JSObject *
 BaselineInspector::getTemplateObject(jsbytecode *pc)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     if (!hasBaselineScript())
         return nullptr;
 
     const ICEntry &entry = icEntryFromPC(pc);
     for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
         switch (stub->kind()) {
           case ICStub::NewArray_Fallback:
             return stub->toNewArray_Fallback()->templateObject();
@@ -461,18 +429,16 @@ BaselineInspector::getTemplateObject(jsb
     }
 
     return nullptr;
 }
 
 JSObject *
 BaselineInspector::getTemplateObjectForNative(jsbytecode *pc, Native native)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     if (!hasBaselineScript())
         return nullptr;
 
     const ICEntry &entry = icEntryFromPC(pc);
     for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
         if (stub->isCall_Native() && stub->toCall_Native()->callee()->native() == native)
             return stub->toCall_Native()->templateObject();
     }
@@ -496,35 +462,31 @@ BaselineInspector::templateCallObject()
     JS_ASSERT(res);
 
     return &res->as<CallObject>();
 }
 
 JSObject *
 BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonGetter)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     const ICEntry &entry = icEntryFromPC(pc);
     for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
         if (stub->isGetProp_CallScripted() || stub->isGetProp_CallNative()) {
             ICGetPropCallGetter *nstub = static_cast<ICGetPropCallGetter *>(stub);
             *lastProperty = nstub->holderShape();
             *commonGetter = nstub->getter();
             return nstub->holder();
         }
     }
     return nullptr;
 }
 
 JSObject *
 BaselineInspector::commonSetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonSetter)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     const ICEntry &entry = icEntryFromPC(pc);
     for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
         if (stub->isSetProp_CallScripted() || stub->isSetProp_CallNative()) {
             ICSetPropCallSetter *nstub = static_cast<ICSetPropCallSetter *>(stub);
             *lastProperty = nstub->holderShape();
             *commonSetter = nstub->setter();
             return nstub->holder();
         }
--- a/js/src/jit/BaselineJIT.h
+++ b/js/src/jit/BaselineJIT.h
@@ -289,18 +289,18 @@ struct BaselineScript
 
     // Toggle debug traps (used for breakpoints and step mode) in the script.
     // If |pc| is nullptr, toggle traps for all ops in the script. Else, only
     // toggle traps at |pc|.
     void toggleDebugTraps(JSScript *script, jsbytecode *pc);
 
     void toggleSPS(bool enable);
 
-    void noteAccessedGetter(JSContext *cx, uint32_t pcOffset);
-    void noteArrayWriteHole(JSContext *cx, uint32_t pcOffset);
+    void noteAccessedGetter(uint32_t pcOffset);
+    void noteArrayWriteHole(uint32_t pcOffset);
 
     static size_t offsetOfFlags() {
         return offsetof(BaselineScript, flags_);
     }
 
     static void writeBarrierPre(Zone *zone, BaselineScript *script);
 
     uint32_t *bytecodeTypeMap() {
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -3563,17 +3563,16 @@ static const VMFunction NewCallObjectInf
     FunctionInfo<NewCallObjectFn>(NewCallObject);
 
 bool
 CodeGenerator::visitNewCallObject(LNewCallObject *lir)
 {
     Register obj = ToRegister(lir->output());
 
     JSObject *templateObj = lir->mir()->templateObject();
-    AutoThreadSafeAccess ts(templateObj);
 
     // If we have a template object, we can inline call object creation.
     OutOfLineCode *ool;
     if (lir->slots()->isRegister()) {
         ool = oolCallVM(NewCallObjectInfo, lir,
                         (ArgList(), ImmGCPtr(lir->mir()->block()->info().script()),
                                     ImmGCPtr(templateObj->lastProperty()),
                                     ImmGCPtr(templateObj->hasSingletonType() ? nullptr : templateObj->type()),
--- a/js/src/jit/CompileWrappers.cpp
+++ b/js/src/jit/CompileWrappers.cpp
@@ -247,25 +247,16 @@ CompileCompartment::hasObjectMetadataCal
 // and this would be an unfortunate allocation, but this will not change the
 // semantics of the JavaScript code which is executed.
 void
 CompileCompartment::setSingletonsAsValues()
 {
     return JS::CompartmentOptionsRef(compartment()).setSingletonsAsValues();
 }
 
-#ifdef JS_THREADSAFE
-AutoLockForCompilation::AutoLockForCompilation(CompileCompartment *compartment
-                                               MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
-{
-    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    init(compartment->compartment()->runtimeFromAnyThread());
-}
-#endif
-
 JitCompileOptions::JitCompileOptions()
   : cloneSingletons_(false),
     spsSlowAssertionsEnabled_(false)
 {
 }
 
 JitCompileOptions::JitCompileOptions(JSContext *cx)
 {
--- a/js/src/jit/CompileWrappers.h
+++ b/js/src/jit/CompileWrappers.h
@@ -97,18 +97,16 @@ class CompileZone
     const void *addressOfFreeListFirst(gc::AllocKind allocKind);
     const void *addressOfFreeListLast(gc::AllocKind allocKind);
 };
 
 class CompileCompartment
 {
     JSCompartment *compartment();
 
-    friend class js::AutoLockForCompilation;
-
   public:
     static CompileCompartment *get(JSCompartment *comp);
 
     CompileZone *zone();
     CompileRuntime *runtime();
 
     const void *addressOfEnumerators();
 
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -47,17 +47,16 @@
 #include "jscompartmentinlines.h"
 #include "jsgcinlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 
 using namespace js;
 using namespace js::jit;
 
-using mozilla::Maybe;
 using mozilla::ThreadLocal;
 
 // Assert that JitCode is gc::Cell aligned.
 JS_STATIC_ASSERT(sizeof(JitCode) % gc::CellSize == 0);
 
 static ThreadLocal<IonContext*> TlsIonContext;
 
 static IonContext *
@@ -487,18 +486,16 @@ JitCompartment::ensureIonStubsExist(JSCo
 #endif
 
     return true;
 }
 
 void
 jit::FinishOffThreadBuilder(IonBuilder *builder)
 {
-    builder->script()->runtimeFromMainThread()->removeCompilationThread();
-
     ExecutionMode executionMode = builder->info().executionMode();
 
     // Clear the recompiling flag if it would have failed.
     if (builder->script()->hasIonScript())
         builder->script()->ionScript()->clearRecompiling();
 
     // Clean up if compilation did not succeed.
     if (CompilingOffThread(builder->script(), executionMode))
@@ -1560,19 +1557,16 @@ AttachFinishedCompilations(JSContext *cx
                 success = codegen->link(cx, builder->constraints());
             }
 
             if (!success) {
                 // Silently ignore OOM during code generation, we're at an
                 // operation callback and can't propagate failures.
                 cx->clearPendingException();
             }
-        } else {
-            if (builder->abortReason() == AbortReason_Disable)
-                SetIonScript(builder->script(), builder->info().executionMode(), ION_DISABLED_SCRIPT);
         }
 
         FinishOffThreadBuilder(builder);
     }
 #endif
 }
 
 static const size_t BUILDER_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 1 << 12;
@@ -1717,16 +1711,24 @@ IonCompile(JSContext *cx, JSScript *scri
 
     RootedScript builderScript(cx, builder->script());
 
     if (recompile) {
         JS_ASSERT(executionMode == SequentialExecution);
         builderScript->ionScript()->setRecompiling();
     }
 
+    IonSpewNewFunction(graph, builderScript);
+
+    bool succeeded = builder->build();
+    builder->clearForBackEnd();
+
+    if (!succeeded)
+        return builder->abortReason();
+
     // If possible, compile the script off thread.
     if (OffThreadCompilationAvailable(cx)) {
         if (!recompile)
             SetIonScript(builderScript, executionMode, ION_COMPILING_SCRIPT);
 
         IonSpew(IonSpew_Logs, "Can't log script %s:%d. (Compiled on background thread.)",
                               builderScript->filename(), builderScript->lineno());
 
@@ -1737,52 +1739,22 @@ IonCompile(JSContext *cx, JSScript *scri
 
         // The allocator and associated data will be destroyed after being
         // processed in the finishedOffThreadCompilations list.
         autoDelete.forget();
 
         return AbortReason_NoAbort;
     }
 
-    Maybe<AutoEnterIonCompilation> ionCompiling;
-    if (!cx->runtime()->profilingScripts && !IonSpewEnabled(IonSpew_Logs)) {
-        // Compilation with script profiling is only done on the main thread,
-        // and may modify scripts directly. Same for logging. It is only
-        // enabled when offthread compilation is disabled. So don't watch for
-        // proper use of the compilation lock.
-        ionCompiling.construct();
-    }
-
-    Maybe<AutoProtectHeapForIonCompilation> protect;
-    if (js_JitOptions.checkThreadSafety &&
-        cx->runtime()->gcIncrementalState == gc::NO_INCREMENTAL &&
-        !cx->runtime()->profilingScripts)
-    {
-        protect.construct(cx->runtime());
-    }
-
-    IonSpewNewFunction(graph, builderScript);
-
-    bool succeeded = builder->build();
-    builder->clearForBackEnd();
-
-    if (!succeeded)
-        return builder->abortReason();
-
     ScopedJSDeletePtr<CodeGenerator> codegen(CompileBackEnd(builder));
     if (!codegen) {
         IonSpew(IonSpew_Abort, "Failed during back-end compilation.");
         return AbortReason_Disable;
     }
 
-    if (!protect.empty())
-        protect.destroy();
-    if (!ionCompiling.empty())
-        ionCompiling.destroy();
-
     bool success = codegen->link(cx, builder->constraints());
 
     IonSpewEndFunction();
 
     return success ? AbortReason_NoAbort : AbortReason_Disable;
 }
 
 static bool
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -135,31 +135,23 @@ IonBuilder::IonBuilder(JSContext *analys
     failedShapeGuard_(info->script()->failedShapeGuard()),
     nonStringIteration_(false),
     lazyArguments_(nullptr),
     inlineCallInfo_(nullptr)
 {
     script_ = info->script();
     pc = info->startPC();
 
-#ifdef DEBUG
-    lock();
     JS_ASSERT(script()->hasBaselineScript());
-    unlock();
-#endif
     JS_ASSERT(!!analysisContext == (info->executionMode() == DefinitePropertiesAnalysis));
 }
 
 void
 IonBuilder::clearForBackEnd()
 {
-    // This case should only be hit if there was a failure while building.
-    if (!lock_.empty())
-        lock_.destroy();
-
     JS_ASSERT(!analysisContext);
     baselineFrame_ = nullptr;
 
     // The caches below allocate data from the malloc heap. Release this before
     // later phases of compilation to avoid leaks, as the top level IonBuilder
     // is not explicitly destroyed. Note that builders for inner scripts are
     // constructed on the stack and will release this memory on destruction.
     gsn.purge();
@@ -287,18 +279,16 @@ IonBuilder::getPolyCallTargets(types::Te
         if (obj) {
             if (!obj->is<JSFunction>()) {
                 targets.clear();
                 return true;
             }
             fun = &obj->as<JSFunction>();
         } else {
             types::TypeObject *typeObj = calleeTypes->getTypeObject(i);
-            AutoThreadSafeAccess ts(typeObj);
-
             JS_ASSERT(typeObj);
             if (!typeObj->interpretedFunction) {
                 targets.clear();
                 return true;
             }
 
             fun = typeObj->interpretedFunction;
             *gotLambda = true;
@@ -588,26 +578,22 @@ IonBuilder::pushLoop(CFGState::State ini
     state.loop.initialStopAt = stopAt;
     state.loop.loopHead = loopHead;
     return cfgStack_.append(state);
 }
 
 bool
 IonBuilder::init()
 {
-    lock();
-
     if (!types::TypeScript::FreezeTypeSets(constraints(), script(),
                                            &thisTypes, &argTypes, &typeArray))
     {
         return false;
     }
 
-    unlock();
-
     if (!analysis().init(alloc(), gsn))
         return false;
 
     return true;
 }
 
 bool
 IonBuilder::build()
@@ -716,18 +702,16 @@ IonBuilder::build()
         current->add(lazyArguments_);
     }
 
     insertRecompileCheck();
 
     if (!traverseBytecode())
         return false;
 
-    unlock();
-
     if (!maybeAddOsrTypeBarriers())
         return false;
 
     if (!processIterators())
         return false;
 
     JS_ASSERT(loopDepth_ == 0);
     abortReason_ = AbortReason_NoAbort;
@@ -877,17 +861,16 @@ IonBuilder::buildInline(IonBuilder *call
         current->add(lazyArguments_);
     }
 
     insertRecompileCheck();
 
     if (!traverseBytecode())
         return false;
 
-    unlock();
     return true;
 }
 
 void
 IonBuilder::rewriteParameter(uint32_t slotIdx, MDefinition *param, int32_t argIndex)
 {
     JS_ASSERT(param->isParameter() || param->isGetArgumentsObjectArg());
 
@@ -932,19 +915,16 @@ IonBuilder::initParameters()
 {
     if (!info().funMaybeLazy())
         return true;
 
     // If we are doing OSR on a frame which initially executed in the
     // interpreter and didn't accumulate type information, try to use that OSR
     // frame to determine possible initial types for 'this' and parameters.
 
-    // For unknownProperties() tests under addType.
-    lock();
-
     if (thisTypes->empty() && baselineFrame_) {
         if (!thisTypes->addType(baselineFrame_->thisType, alloc_->lifoAlloc()))
             return false;
     }
 
     MParameter *param = MParameter::New(alloc(), MParameter::THIS_SLOT, thisTypes);
     current->add(param);
     current->initSlot(info().thisSlot(), param);
@@ -958,18 +938,16 @@ IonBuilder::initParameters()
                 return false;
         }
 
         param = MParameter::New(alloc(), i, types);
         current->add(param);
         current->initSlot(info().argSlotUnchecked(i), param);
     }
 
-    unlock();
-
     return true;
 }
 
 bool
 IonBuilder::initScopeChain(MDefinition *callee)
 {
     MInstruction *scope = nullptr;
 
@@ -982,18 +960,16 @@ IonBuilder::initScopeChain(MDefinition *
 
     // The scope chain is only tracked in scripts that have NAME opcodes which
     // will try to access the scope. For other scripts, the scope instructions
     // will be held live by resume points and code will still be generated for
     // them, so just use a constant undefined value.
     if (!script()->compileAndGo())
         return abort("non-CNG global scripts are not supported");
 
-    lock();
-
     if (JSFunction *fun = info().funMaybeLazy()) {
         if (!callee) {
             MCallee *calleeIns = MCallee::New(alloc());
             current->add(calleeIns);
             callee = calleeIns;
         }
         scope = MFunctionEnvironment::New(alloc(), callee);
         current->add(scope);
@@ -1009,18 +985,16 @@ IonBuilder::initScopeChain(MDefinition *
             scope = createCallObject(callee, scope);
             if (!scope)
                 return false;
         }
     } else {
         scope = constant(ObjectValue(script()->global()));
     }
 
-    unlock();
-
     current->setScopeChain(scope);
     return true;
 }
 
 bool
 IonBuilder::initArgumentsObject()
 {
     IonSpew(IonSpew_MIR, "%s:%d - Emitting code to initialize arguments object! block=%p",
@@ -1204,24 +1178,16 @@ IonBuilder::maybeAddOsrTypeBarriers()
 // that there is no active block.
 //
 // For normal diamond join points, we construct Phi nodes as we add
 // predecessors. For loops, care must be taken to propagate Phi nodes back
 // through uses in the loop body.
 bool
 IonBuilder::traverseBytecode()
 {
-    // Always hold the compilation lock when traversing bytecode, though release
-    // it before reacquiring it every few opcodes so that the main thread does not
-    // block for long when updating compilation data.
-    lock();
-
-    size_t lockOpcodeCount = 0;
-    static const size_t LOCK_OPCODE_GRANULARITY = 5;
-
     for (;;) {
         JS_ASSERT(pc < info().limitPC());
 
         for (;;) {
             if (!alloc().ensureBallast())
                 return false;
 
             // Check if we've hit an expected join point or edge in the bytecode.
@@ -1286,22 +1252,16 @@ IonBuilder::traverseBytecode()
         }
 #endif
 
         // Nothing in inspectOpcode() is allowed to advance the pc.
         JSOp op = JSOp(*pc);
         if (!inspectOpcode(op))
             return false;
 
-        if (++lockOpcodeCount == LOCK_OPCODE_GRANULARITY) {
-            unlock();
-            lock();
-            lockOpcodeCount = 0;
-        }
-
 #ifdef DEBUG
         for (size_t i = 0; i < popped.length(); i++) {
             switch (op) {
               case JSOP_POP:
               case JSOP_POPN:
               case JSOP_POPNV:
               case JSOP_DUP:
               case JSOP_DUP2:
@@ -3876,74 +3836,65 @@ IonBuilder::inlineScriptedCall(CallInfo 
 
     // Pop formals again, except leave |fun| on stack for duration of call.
     callInfo.popFormals(current);
     current->push(callInfo.fun());
 
     JSScript *calleeScript = target->nonLazyScript();
     BaselineInspector inspector(calleeScript);
 
+    // Improve type information of |this| when not set.
+    if (callInfo.constructing() &&
+        !callInfo.thisArg()->resultTypeSet() &&
+        calleeScript->types)
     {
-        AutoThreadSafeAccess ts(calleeScript);
-
-        // Improve type information of |this| when not set.
-        if (callInfo.constructing() &&
-            !callInfo.thisArg()->resultTypeSet() &&
-            calleeScript->types)
-        {
-            types::StackTypeSet *types = types::TypeScript::ThisTypes(calleeScript);
-            if (!types->unknown()) {
-                MTypeBarrier *barrier =
-                    MTypeBarrier::New(alloc(), callInfo.thisArg(), types->clone(alloc_->lifoAlloc()));
-                current->add(barrier);
-                callInfo.setThis(barrier);
-            }
+        types::StackTypeSet *types = types::TypeScript::ThisTypes(calleeScript);
+        if (!types->unknown()) {
+            MTypeBarrier *barrier =
+                MTypeBarrier::New(alloc(), callInfo.thisArg(), types->clone(alloc_->lifoAlloc()));
+            current->add(barrier);
+            callInfo.setThis(barrier);
         }
     }
 
     // Start inlining.
     LifoAlloc *lifoAlloc = alloc_->lifoAlloc();
     CompileInfo *info = lifoAlloc->new_<CompileInfo>(calleeScript, target,
                                                      (jsbytecode *)nullptr, callInfo.constructing(),
                                                      this->info().executionMode(),
                                                      /* needsArgsObj = */ false);
     if (!info)
         return false;
 
     MIRGraphReturns returns(alloc());
     AutoAccumulateReturns aar(graph(), returns);
 
-    unlock();
-
     // Build the graph.
     IonBuilder inlineBuilder(analysisContext, compartment, options, &alloc(), &graph(), constraints(),
                              &inspector, info, &optimizationInfo(), nullptr, inliningDepth_ + 1,
                              loopDepth_);
     if (!inlineBuilder.buildInline(this, outerResumePoint, callInfo)) {
         if (analysisContext && analysisContext->isExceptionPending()) {
             IonSpew(IonSpew_Abort, "Inline builder raised exception.");
             abortReason_ = AbortReason_Error;
             return false;
         }
 
         // Inlining the callee failed. Mark the callee as uninlineable only if
         // the inlining was aborted for a non-exception reason.
         if (inlineBuilder.abortReason_ == AbortReason_Disable) {
-            AutoThreadSafeAccess ts(calleeScript);
             calleeScript->setUninlineable();
             abortReason_ = AbortReason_Inlining;
         } else if (inlineBuilder.abortReason_ == AbortReason_Inlining) {
             abortReason_ = AbortReason_Inlining;
         }
 
         return false;
     }
 
-    lock();
-
     // Create return block.
     jsbytecode *postCall = GetNextPc(pc);
     MBasicBlock *returnBlock = newBlock(nullptr, postCall);
     if (!returnBlock)
         return false;
     returnBlock->setCallerResumePoint(callerResumePoint_);
 
     // When profiling add Inline_Exit instruction to indicate end of inlined function.
@@ -3952,17 +3903,16 @@ IonBuilder::inlineScriptedCall(CallInfo 
 
     // Inherit the slots from current and pop |fun|.
     returnBlock->inheritSlots(current);
     returnBlock->pop();
 
     // Accumulate return values.
     if (returns.empty()) {
         // Inlining of functions that have no exit is not supported.
-        AutoThreadSafeAccess ts(calleeScript);
         calleeScript->setUninlineable();
         abortReason_ = AbortReason_Inlining;
         return false;
     }
     MDefinition *retvalDefn = patchInlinedReturns(callInfo, returns, returnBlock);
     if (!retvalDefn)
         return false;
     returnBlock->push(retvalDefn);
@@ -4613,17 +4563,16 @@ IonBuilder::inlineCalls(CallInfo &callIn
 }
 
 MInstruction *
 IonBuilder::createDeclEnvObject(MDefinition *callee, MDefinition *scope)
 {
     // Get a template CallObject that we'll use to generate inline object
     // creation.
     DeclEnvObject *templateObj = inspector->templateDeclEnvObject();
-    AutoThreadSafeAccess ts(templateObj);
 
     // One field is added to the function to handle its name.  This cannot be a
     // dynamic slot because there is still plenty of room on the DeclEnv object.
     JS_ASSERT(!templateObj->hasDynamicSlots());
 
     // Allocate the actual object. It is important that no intervening
     // instructions could potentially bailout, thus leaking the dynamic slots
     // pointer.
@@ -4641,22 +4590,21 @@ IonBuilder::createDeclEnvObject(MDefinit
 }
 
 MInstruction *
 IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope)
 {
     // Get a template CallObject that we'll use to generate inline object
     // creation.
     CallObject *templateObj = inspector->templateCallObject();
-    AutoThreadSafeAccess ts(templateObj);
 
     // If the CallObject needs dynamic slots, allocate those now.
     MInstruction *slots;
     if (templateObj->hasDynamicSlots()) {
-        size_t nslots = JSObject::dynamicSlotsCount(templateObj->numFixedSlotsForCompilation(),
+        size_t nslots = JSObject::dynamicSlotsCount(templateObj->numFixedSlots(),
                                                     templateObj->lastProperty()->slotSpan(templateObj->getClass()),
                                                     templateObj->getClass());
         slots = MNewSlots::New(alloc(), nslots);
     } else {
         slots = MConstant::New(alloc(), NullValue());
     }
     current->add(slots);
 
@@ -4672,18 +4620,18 @@ IonBuilder::createCallObject(MDefinition
     current->add(MStoreFixedSlot::New(alloc(), callObj, CallObject::enclosingScopeSlot(), scope));
     current->add(MStoreFixedSlot::New(alloc(), callObj, CallObject::calleeSlot(), callee));
 
     // Initialize argument slots.
     for (AliasedFormalIter i(script()); i; i++) {
         unsigned slot = i.scopeSlot();
         unsigned formal = i.frameIndex();
         MDefinition *param = current->getSlot(info().argSlotUnchecked(formal));
-        if (slot >= templateObj->numFixedSlotsForCompilation())
-            current->add(MStoreSlot::New(alloc(), slots, slot - templateObj->numFixedSlotsForCompilation(), param));
+        if (slot >= templateObj->numFixedSlots())
+            current->add(MStoreSlot::New(alloc(), slots, slot - templateObj->numFixedSlots(), param));
         else
             current->add(MStoreFixedSlot::New(alloc(), callObj, slot, param));
     }
 
     return callObj;
 }
 
 MDefinition *
@@ -4745,23 +4693,20 @@ IonBuilder::createThisScriptedSingleton(
         return nullptr;
 
     JSObject *templateObject = inspector->getTemplateObject(pc);
     if (!templateObject || !templateObject->is<JSObject>())
         return nullptr;
     if (!templateObject->hasTenuredProto() || templateObject->getProto() != proto)
         return nullptr;
 
-    {
-        AutoThreadSafeAccess ts(target->nonLazyScript());
-        if (!target->nonLazyScript()->types)
-            return nullptr;
-        if (!types::TypeScript::ThisTypes(target->nonLazyScript())->hasType(types::Type::ObjectType(templateObject)))
-            return nullptr;
-    }
+    if (!target->nonLazyScript()->types)
+        return nullptr;
+    if (!types::TypeScript::ThisTypes(target->nonLazyScript())->hasType(types::Type::ObjectType(templateObject)))
+        return nullptr;
 
     // For template objects with NewScript info, the appropriate allocation
     // kind to use may change due to dynamic property adds. In these cases
     // calling Ion code will be invalidated, but any baseline template object
     // may be stale. Update to the correct template object in this case.
     types::TypeObject *templateType = templateObject->type();
     if (templateType->hasNewScript()) {
         templateObject = templateType->newScript()->templateObject;
@@ -5152,18 +5097,16 @@ IonBuilder::testNeedsArgumentCheck(JSFun
     // If we have a known target, check if the caller arg types are a subset of callee.
     // Since typeset accumulates and can't decrease that means we don't need to check
     // the arguments anymore.
     if (!target->hasScript())
         return true;
 
     JSScript *targetScript = target->nonLazyScript();
 
-    AutoThreadSafeAccess ts(targetScript);
-
     if (!targetScript->types)
         return true;
 
     if (!ArgumentTypesMatch(callInfo.thisArg(), types::TypeScript::ThisTypes(targetScript)))
         return true;
     uint32_t expected_args = Min<uint32_t>(callInfo.argc(), target->nargs());
     for (size_t i = 0; i < expected_args; i++) {
         if (!ArgumentTypesMatch(callInfo.getArg(i), types::TypeScript::ArgTypes(targetScript, i)))
@@ -5352,17 +5295,16 @@ IonBuilder::jsop_eval(uint32_t argc)
         // Try to pattern match 'eval(v + "()")'. In this case v is likely a
         // name on the scope chain and the eval is performing a call on that
         // value. Use a dynamic scope chain lookup rather than a full eval.
         if (string->isConcat() &&
             string->getOperand(1)->isConstant() &&
             string->getOperand(1)->toConstant()->value().isString())
         {
             JSAtom *atom = &string->getOperand(1)->toConstant()->value().toString()->asAtom();
-            AutoThreadSafeAccess ts(atom);
 
             if (StringEqualsAscii(atom, "()")) {
                 MDefinition *name = string->getOperand(0);
                 MInstruction *dynamicName = MGetDynamicName::New(alloc(), scopeChain, name);
                 current->add(dynamicName);
 
                 current->push(dynamicName);
                 current->push(thisValue);
@@ -5426,17 +5368,16 @@ IonBuilder::jsop_newarray(uint32_t count
                                     templateObject->type()->initialHeap(constraints()),
                                     MNewArray::NewArray_Allocating);
     current->add(ins);
     current->push(ins);
 
     types::TemporaryTypeSet::DoubleConversion conversion =
         ins->resultTypeSet()->convertDoubleElements(constraints());
 
-    AutoThreadSafeAccess ts(templateObject);
     if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles)
         templateObject->setShouldConvertDoubleElements();
     else
         templateObject->clearShouldConvertDoubleElements();
     return true;
 }
 
 bool
@@ -5509,17 +5450,16 @@ IonBuilder::jsop_initelem_array()
     MConstant *id = MConstant::New(alloc(), Int32Value(GET_UINT24(pc)));
     current->add(id);
 
     // Get the elements vector.
     MElements *elements = MElements::New(alloc(), obj);
     current->add(elements);
 
     JSObject *templateObject = obj->toNewArray()->templateObject();
-    AutoThreadSafeAccess ts(templateObject);
 
     if (templateObject->shouldConvertDoubleElements()) {
         MInstruction *valueDouble = MToDouble::New(alloc(), value);
         current->add(valueDouble);
         value = valueDouble;
     }
 
     // Store the value.
@@ -5551,17 +5491,16 @@ IonBuilder::jsop_mutateproto()
 
 bool
 IonBuilder::jsop_initprop(PropertyName *name)
 {
     MDefinition *value = current->pop();
     MDefinition *obj = current->peek(-1);
 
     JSObject *templateObject = obj->toNewObject()->templateObject();
-    AutoThreadSafeAccess ts(templateObject);
 
     Shape *shape = templateObject->lastProperty()->searchLinear(NameToId(name));
 
     if (!shape) {
         // JSOP_NEWINIT becomes an MNewObject without preconfigured properties.
         MInitProp *init = MInitProp::New(alloc(), obj, name, value);
         current->add(init);
         return resumeAfter(init);
@@ -9174,19 +9113,16 @@ IonBuilder::jsop_regexp(RegExpObject *re
     // objects every time they execute. We only need to do this cloning if the
     // script could actually observe the effect of such cloning, for instance
     // by getting or setting properties on it.
     //
     // First, make sure the regex is one we can safely optimize. Lowering can
     // then check if this regex object only flows into known natives and can
     // avoid cloning in this case.
 
-    // RegExpObjects embedded in scripts are immutable.
-    AutoThreadSafeAccess ts(reobj);
-
     bool mustClone = true;
     types::TypeObjectKey *typeObj = types::TypeObjectKey::get(&script()->global());
     if (!typeObj->hasFlags(constraints(), types::OBJECT_FLAG_REGEXP_FLAGS_SET)) {
         RegExpStatics *res = script()->global().getRegExpStatics();
 
         DebugOnly<uint32_t> origFlags = reobj->getFlags();
         DebugOnly<uint32_t> staticsFlags = res->getFlags();
         JS_ASSERT((origFlags & staticsFlags) == staticsFlags);
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -782,27 +782,16 @@ class IonBuilder : public MIRGenerator
     JSContext *analysisContext;
     BaselineFrameInspector *baselineFrame_;
     AbortReason abortReason_;
     TypeDescrSetHash *descrSetHash_;
 
     // Constraints for recording dependencies on type information.
     types::CompilerConstraintList *constraints_;
 
-    mozilla::Maybe<AutoLockForCompilation> lock_;
-
-    void lock() {
-        if (!analysisContext)
-            lock_.construct(compartment);
-    }
-    void unlock() {
-        if (!analysisContext)
-            lock_.destroy();
-    }
-
     // Basic analysis information about the script.
     BytecodeAnalysis analysis_;
     BytecodeAnalysis &analysis() {
         return analysis_;
     }
 
     types::TemporaryTypeSet *thisTypes, *argTypes, *typeArray;
     uint32_t typeArrayHint;
--- a/js/src/jit/IonCode.h
+++ b/js/src/jit/IonCode.h
@@ -77,17 +77,16 @@ class JitCode : public gc::BarrieredCell
         return jumpRelocTableOffset() + jumpRelocTableBytes_;
     }
     uint32_t preBarrierTableOffset() const {
         return dataRelocTableOffset() + dataRelocTableBytes_;
     }
 
   public:
     uint8_t *raw() const {
-        AutoThreadSafeAccess ts(this);
         return code_;
     }
     size_t instructionsSize() const {
         return insnSize_;
     }
     void trace(JSTracer *trc);
     void finalize(FreeOp *fop);
     void setInvalidated() {
--- a/js/src/jit/IonMacroAssembler.cpp
+++ b/js/src/jit/IonMacroAssembler.cpp
@@ -782,20 +782,16 @@ MacroAssembler::newGCShortStringPar(cons
     newGCThingPar(result, cx, tempReg1, tempReg2, js::gc::FINALIZE_SHORT_STRING, fail);
 }
 
 void
 MacroAssembler::initGCThing(const Register &obj, JSObject *templateObject)
 {
     // Fast initialization of an empty object returned by NewGCThing().
 
-    AutoThreadSafeAccess ts0(templateObject);
-    AutoThreadSafeAccess ts1(templateObject->lastProperty());
-    AutoThreadSafeAccess ts2(templateObject->lastProperty()->base()); // For isNative() assertions.
-
     JS_ASSERT(!templateObject->hasDynamicElements());
 
     storePtr(ImmGCPtr(templateObject->lastProperty()), Address(obj, JSObject::offsetOfShape()));
     storePtr(ImmGCPtr(templateObject->type()), Address(obj, JSObject::offsetOfType()));
     storePtr(ImmPtr(nullptr), Address(obj, JSObject::offsetOfSlots()));
 
     if (templateObject->is<ArrayObject>()) {
         JS_ASSERT(!templateObject->getDenseInitializedLength());
@@ -817,17 +813,17 @@ MacroAssembler::initGCThing(const Regist
                       ? ObjectElements::CONVERT_DOUBLE_ELEMENTS
                       : 0),
                 Address(obj, elementsOffset + ObjectElements::offsetOfFlags()));
     } else {
         storePtr(ImmPtr(emptyObjectElements), Address(obj, JSObject::offsetOfElements()));
 
         // Fixed slots of non-array objects are required to be initialized.
         // Use the values currently in the template object.
-        size_t nslots = Min(templateObject->numFixedSlotsForCompilation(),
+        size_t nslots = Min(templateObject->numFixedSlots(),
                             templateObject->lastProperty()->slotSpan(templateObject->getClass()));
         for (unsigned i = 0; i < nslots; i++) {
             storeValue(templateObject->getFixedSlot(i),
                        Address(obj, JSObject::getFixedSlotOffset(i)));
         }
     }
 
     if (templateObject->hasPrivate()) {
--- a/js/src/jit/JitOptions.cpp
+++ b/js/src/jit/JitOptions.cpp
@@ -28,20 +28,16 @@ JitOptions::JitOptions()
     // are not modified before its OsiPoint.
     checkOsiPointRegisters = false;
 #endif
 
     // Whether to enable extra code to perform dynamic validation of
     // RangeAnalysis results.
     checkRangeAnalysis = false;
 
-    // Whether to protect the GC heap during Ion compilation and ensure that
-    // only threadsafe operations are performed on it.
-    checkThreadSafety = false;
-
     // Whether Ion should compile try-catch statements.
     compileTryCatch = true;
 
     // Toggle whether global value numbering is globally disabled.
     disableGvn = false;
 
     // Toggles whether loop invariant code motion is globally disabled.
     disableLicm = false;
--- a/js/src/jit/JitOptions.h
+++ b/js/src/jit/JitOptions.h
@@ -40,17 +40,16 @@ enum IonGvnKind {
 
 struct JitOptions
 {
     bool checkGraphConsistency;
 #ifdef CHECK_OSIPOINT_REGISTERS
     bool checkOsiPointRegisters;
 #endif
     bool checkRangeAnalysis;
-    bool checkThreadSafety;
     bool compileTryCatch;
     bool disableGvn;
     bool disableLicm;
     bool disableInlining;
     bool disableEdgeCaseAnalysis;
     bool disableRangeAnalysis;
     bool disableUce;
     bool disableEaa;
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -252,23 +252,20 @@ IonBuilder::inlineArray(CallInfo &callIn
         if (initLength <= ArrayObject::EagerAllocationMaxLength)
             allocating = MNewArray::NewArray_Allocating;
     }
 
     callInfo.setImplicitlyUsedUnchecked();
 
     types::TemporaryTypeSet::DoubleConversion conversion =
         getInlineReturnTypeSet()->convertDoubleElements(constraints());
-    {
-        AutoThreadSafeAccess ts(templateObject);
-        if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles)
-            templateObject->setShouldConvertDoubleElements();
-        else
-            templateObject->clearShouldConvertDoubleElements();
-    }
+    if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles)
+        templateObject->setShouldConvertDoubleElements();
+    else
+        templateObject->clearShouldConvertDoubleElements();
 
     MNewArray *ins = MNewArray::New(alloc(), constraints(), initLength, templateObject,
                                     templateObject->type()->initialHeap(constraints()),
                                     allocating);
     current->add(ins);
     current->push(ins);
 
     if (callInfo.argc() >= 2) {
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -783,18 +783,16 @@ MApplyArgs::New(TempAllocator &alloc, JS
 }
 
 MDefinition*
 MStringLength::foldsTo(TempAllocator &alloc, bool useValueNumbers)
 {
     if ((type() == MIRType_Int32) && (string()->isConstant())) {
         Value value = string()->toConstant()->value();
         JSAtom *atom = &value.toString()->asAtom();
-
-        AutoThreadSafeAccess ts(atom);
         return MConstant::New(alloc, Int32Value(atom->length()));
     }
 
     return this;
 }
 
 void
 MFloor::trySpecializeFloat32(TempAllocator &alloc)
@@ -2602,17 +2600,16 @@ MBeta::printOpcode(FILE *fp) const
     sp.init();
     comparison_->print(sp);
     fprintf(fp, " %s", sp.string());
 }
 
 bool
 MNewObject::shouldUseVM() const
 {
-    AutoThreadSafeAccess ts(templateObject());
     return templateObject()->hasSingletonType() ||
            templateObject()->hasDynamicSlots();
 }
 
 bool
 MNewArray::shouldUseVM() const
 {
     JS_ASSERT(count() < JSObject::NELEMENTS_LIMIT);
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -274,17 +274,16 @@ CodeGeneratorShared::encode(LSnapshot *s
         // Ensure that all snapshot which are encoded can safely be used for
         // bailouts.
         DebugOnly<jsbytecode *> bailPC = pc;
         if (mir->mode() == MResumePoint::ResumeAfter)
           bailPC = GetNextPc(pc);
 
 #ifdef DEBUG
         if (GetIonContext()->cx) {
-            AutoThreadSafeAccess ts(script);
             uint32_t stackDepth;
             bool reachablePC;
             if (!ReconstructStackDepth(GetIonContext()->cx, script, bailPC, &stackDepth, &reachablePC))
                 return false;
 
             if (reachablePC) {
                 if (JSOp(*bailPC) == JSOP_FUNCALL) {
                     // For fun.call(this, ...); the reconstructStackDepth will
--- a/js/src/jsatominlines.h
+++ b/js/src/jsatominlines.h
@@ -26,17 +26,16 @@ js::AtomStateEntry::asPtr() const
     return atom;
 }
 
 namespace js {
 
 inline jsid
 AtomToId(JSAtom *atom)
 {
-    AutoThreadSafeAccess ts(atom);
     JS_STATIC_ASSERT(JSID_INT_MIN == 0);
 
     uint32_t index;
     if (atom->isIndex(&index) && index <= JSID_INT_MAX)
         return INT_TO_JSID(int32_t(index));
 
     return JSID_FROM_BITS(size_t(atom));
 }
--- a/js/src/jsboolinlines.h
+++ b/js/src/jsboolinlines.h
@@ -24,17 +24,15 @@ BooleanGetPrimitiveValue(HandleObject ob
         return obj->as<BooleanObject>().unbox();
 
     return BooleanGetPrimitiveValueSlow(obj, cx);
 }
 
 inline bool
 EmulatesUndefined(JSObject *obj)
 {
-    AutoThreadSafeAccess ts0(obj);
-    AutoThreadSafeAccess ts1(obj->typeRaw());
     JSObject *actual = MOZ_LIKELY(!obj->is<WrapperObject>()) ? obj : UncheckedUnwrap(obj);
     return actual->getClass()->emulatesUndefined();
 }
 
 } /* namespace js */
 
 #endif /* jsboolinlines_h */
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -111,17 +111,16 @@ JSCompartment::sweepCallsiteClones()
 
 JSFunction *
 js::ExistingCloneFunctionAtCallsite(const CallsiteCloneTable &table, JSFunction *fun,
                                     JSScript *script, jsbytecode *pc)
 {
     JS_ASSERT(fun->nonLazyScript()->shouldCloneAtCallsite());
     JS_ASSERT(!fun->nonLazyScript()->enclosingStaticScope());
     JS_ASSERT(types::UseNewTypeForClone(fun));
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
 
     /*
      * If we start allocating function objects in the nursery, then the callsite
      * clone table will need a postbarrier.
      */
     JS_ASSERT(fun->isTenured());
 
     if (!table.initialized())
@@ -149,18 +148,16 @@ js::CloneFunctionAtCallsite(JSContext *c
      * Store a link back to the original for function.caller and avoid cloning
      * clones.
      */
     clone->nonLazyScript()->setIsCallsiteClone(fun);
 
     typedef CallsiteCloneKey Key;
     typedef CallsiteCloneTable Table;
 
-    AutoLockForCompilation lock(cx);
-
     Table &table = cx->compartment()->callsiteClones;
     if (!table.initialized() && !table.init())
         return nullptr;
 
     if (!table.putNew(Key(fun, script, script->pcToOffset(pc)), clone))
         return nullptr;
 
     return clone;
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1082,78 +1082,15 @@ class AutoLockForExclusiveAccess
         // An empty destructor is needed to avoid warnings from clang about
         // unused local variables of this type.
     }
 #endif // JS_THREADSAFE
 
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
-class AutoLockForCompilation
-{
-#ifdef JS_THREADSAFE
-    JSRuntime *runtime;
-
-    void init(JSRuntime *rt) {
-        runtime = rt;
-        if (runtime->numCompilationThreads) {
-            runtime->assertCanLock(CompilationLock);
-            PR_Lock(runtime->compilationLock);
-#ifdef DEBUG
-            runtime->compilationLockOwner = PR_GetCurrentThread();
-#endif
-        } else {
-#ifdef DEBUG
-            JS_ASSERT(!runtime->mainThreadHasCompilationLock);
-            runtime->mainThreadHasCompilationLock = true;
-#endif
-        }
-    }
-
-  public:
-    AutoLockForCompilation(ExclusiveContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-        if (cx->isJSContext())
-            init(cx->asJSContext()->runtime());
-        else
-            runtime = nullptr;
-    }
-    AutoLockForCompilation(jit::CompileCompartment *compartment MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
-    ~AutoLockForCompilation() {
-        if (runtime) {
-            if (runtime->numCompilationThreads) {
-                JS_ASSERT(runtime->compilationLockOwner == PR_GetCurrentThread());
-#ifdef DEBUG
-                runtime->compilationLockOwner = nullptr;
-#endif
-                PR_Unlock(runtime->compilationLock);
-            } else {
-#ifdef DEBUG
-                JS_ASSERT(runtime->mainThreadHasCompilationLock);
-                runtime->mainThreadHasCompilationLock = false;
-#endif
-            }
-        }
-    }
-#else // JS_THREADSAFE
-  public:
-    AutoLockForCompilation(ExclusiveContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    }
-    AutoLockForCompilation(jit::CompileCompartment *compartment MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    }
-    ~AutoLockForCompilation() {
-        // An empty destructor is needed to avoid warnings from clang about
-        // unused local variables of this type.
-    }
-#endif // JS_THREADSAFE
-
-    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
 } /* namespace js */
 
 #ifdef _MSC_VER
 #pragma warning(pop)
 #endif
 
 #endif /* jscntxt_h */
--- a/js/src/jscompartmentinlines.h
+++ b/js/src/jscompartmentinlines.h
@@ -17,24 +17,17 @@ JSCompartment::initGlobal(js::GlobalObje
     JS_ASSERT(global.compartment() == this);
     JS_ASSERT(!global_);
     global_ = &global;
 }
 
 js::GlobalObject *
 JSCompartment::maybeGlobal() const
 {
-#ifdef DEBUG
-    if (global_) {
-        js::AutoThreadSafeAccess ts0(global_);
-        js::AutoThreadSafeAccess ts1(global_->lastProperty());
-        js::AutoThreadSafeAccess ts2(global_->lastProperty()->base());
-        JS_ASSERT(global_->compartment() == this);
-    }
-#endif
+    JS_ASSERT_IF(global_, global_->compartment() == this);
     return global_;
 }
 
 js::AutoCompartment::AutoCompartment(ExclusiveContext *cx, JSObject *target)
   : cx_(cx),
     origin_(cx->compartment_)
 {
     cx_->enterCompartment(target->compartment());
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1145,34 +1145,32 @@ JSFunction::createScriptForLazilyInterpr
         // Suppress GC for now although we should be able to remove this by
         // making 'lazy' a Rooted<LazyScript*> (which requires adding a
         // THING_ROOT_LAZY_SCRIPT).
         AutoSuppressGC suppressGC(cx);
 
         RootedScript script(cx, lazy->maybeScript());
 
         if (script) {
-            AutoLockForCompilation lock(cx);
             fun->setUnlazifiedScript(script);
             // Remember the lazy script on the compiled script, so it can be
             // stored on the function again in case of re-lazification.
             // Only functions without inner functions are re-lazified.
             if (!lazy->numInnerFunctions())
                 script->setLazyScript(lazy);
             return true;
         }
 
         if (fun != lazy->functionNonDelazifying()) {
             if (!lazy->functionDelazifying(cx))
                 return false;
             script = lazy->functionNonDelazifying()->nonLazyScript();
             if (!script)
                 return false;
 
-            AutoLockForCompilation lock(cx);
             fun->setUnlazifiedScript(script);
             return true;
         }
 
         // Lazy script caching is only supported for leaf functions. If a
         // script with inner functions was returned by the cache, those inner
         // functions would be delazified when deep cloning the script, even if
         // they have never executed.
@@ -1191,20 +1189,17 @@ JSFunction::createScriptForLazilyInterpr
             if (!clonedScript)
                 return false;
 
             clonedScript->setSourceObject(lazy->sourceObject());
 
             fun->initAtom(script->functionNonDelazifying()->displayAtom());
             clonedScript->setFunction(fun);
 
-            {
-                AutoLockForCompilation lock(cx);
-                fun->setUnlazifiedScript(clonedScript);
-            }
+            fun->setUnlazifiedScript(clonedScript);
 
             CallNewScriptHook(cx, clonedScript, fun);
 
             if (!lazy->maybeScript())
                 lazy->initScript(clonedScript);
             return true;
         }
 
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -100,22 +100,20 @@ class JSFunction : public JSObject
         // Note: this should be kept in sync with FunctionBox::isHeavyweight().
         return nonLazyScript()->hasAnyAliasedBindings() ||
                nonLazyScript()->funHasExtensibleScope() ||
                nonLazyScript()->funNeedsDeclEnvObject() ||
                isGenerator();
     }
 
     size_t nargs() const {
-        js::AutoThreadSafeAccess ts(this);
         return nargs_;
     }
 
     uint16_t flags() const {
-        js::AutoThreadSafeAccess ts(this);
         return flags_;
     }
 
     /* A function can be classified as either native (C++) or interpreted (JS): */
     bool isInterpreted()            const { return flags() & (INTERPRETED | INTERPRETED_LAZY); }
     bool isNative()                 const { return !isInterpreted(); }
 
     /* Possible attributes of a native function: */
@@ -129,24 +127,20 @@ class JSFunction : public JSObject
     bool isSelfHostedBuiltin()      const { return flags() & SELF_HOSTED; }
     bool isSelfHostedConstructor()  const { return flags() & SELF_HOSTED_CTOR; }
     bool hasRest()                  const { return flags() & HAS_REST; }
     bool isWrappable()              const {
         JS_ASSERT_IF(flags() & SH_WRAPPABLE, isSelfHostedBuiltin());
         return flags() & SH_WRAPPABLE;
     }
 
-    // Functions can change between being lazily interpreted and having scripts
-    // when under the compilation lock.
     bool isInterpretedLazy()        const {
-        JS_ASSERT(js::CurrentThreadCanReadCompilationData());
         return flags() & INTERPRETED_LAZY;
     }
     bool hasScript()                const {
-        JS_ASSERT(js::CurrentThreadCanReadCompilationData());
         return flags() & INTERPRETED;
     }
 
     bool hasJITCode() const {
         if (!hasScript())
             return false;
 
         return nonLazyScript()->hasBaselineScript() || nonLazyScript()->hasIonScript();
@@ -233,17 +227,16 @@ class JSFunction : public JSObject
         flags_ |= ARROW;
     }
 
     JSAtom *atom() const { return hasGuessedAtom() ? nullptr : atom_.get(); }
     js::PropertyName *name() const { return hasGuessedAtom() || !atom_ ? nullptr : atom_->asPropertyName(); }
     void initAtom(JSAtom *atom) { atom_.init(atom); }
 
     JSAtom *displayAtom() const {
-        js::AutoThreadSafeAccess ts(this);
         return atom_;
     }
 
     void setGuessedAtom(JSAtom *atom) {
         JS_ASSERT(atom_ == nullptr);
         JS_ASSERT(atom != nullptr);
         JS_ASSERT(!hasGuessedAtom());
         atom_ = atom;
@@ -253,17 +246,16 @@ class JSFunction : public JSObject
     /* uint16_t representation bounds number of call object dynamic slots. */
     enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) };
 
     /*
      * For an interpreted function, accessors for the initial scope object of
      * activations (stack frames) of the function.
      */
     JSObject *environment() const {
-        js::AutoThreadSafeAccess ts(this);
         JS_ASSERT(isInterpreted());
         return u.i.env_;
     }
 
     void setEnvironment(JSObject *obj) {
         JS_ASSERT(isInterpreted());
         *(js::HeapPtrObject *)&u.i.env_ = obj;
     }
@@ -327,18 +319,16 @@ class JSFunction : public JSObject
             flags_ &= ~INTERPRETED_LAZY;
             flags_ |= INTERPRETED;
             initScript(script);
         }
         return nonLazyScript();
     }
 
     JSScript *nonLazyScript() const {
-        js::AutoThreadSafeAccess ts(this);
-        JS_ASSERT(js::CurrentThreadCanReadCompilationData());
         JS_ASSERT(hasScript());
         JS_ASSERT(u.i.s.script_);
         return u.i.s.script_;
     }
 
     // Returns non-callsited-clone version of this.  Use when return
     // value can flow to arbitrary JS (see Bug 944975).
     JSFunction* originalFunction() {
@@ -350,26 +340,22 @@ class JSFunction : public JSObject
     }
 
     js::HeapPtrScript &mutableScript() {
         JS_ASSERT(isInterpreted());
         return *(js::HeapPtrScript *)&u.i.s.script_;
     }
 
     js::LazyScript *lazyScript() const {
-        js::AutoThreadSafeAccess ts(this);
         JS_ASSERT(isInterpretedLazy() && u.i.s.lazy_);
-        JS_ASSERT(js::CurrentThreadCanReadCompilationData());
         return u.i.s.lazy_;
     }
 
     js::LazyScript *lazyScriptOrNull() const {
-        js::AutoThreadSafeAccess ts(this);
         JS_ASSERT(isInterpretedLazy());
-        JS_ASSERT(js::CurrentThreadCanReadCompilationData());
         return u.i.s.lazy_;
     }
 
     js::GeneratorKind generatorKind() const {
         if (!isInterpreted())
             return js::NotGenerator;
         if (hasScript())
             return nonLazyScript()->generatorKind();
@@ -393,34 +379,32 @@ class JSFunction : public JSObject
     void initScript(JSScript *script_) {
         JS_ASSERT(hasScript());
         mutableScript().init(script_);
     }
 
     void setUnlazifiedScript(JSScript *script) {
         // Note: createScriptForLazilyInterpretedFunction triggers a barrier on
         // lazy script before it is overwritten here.
-        JS_ASSERT(js::CurrentThreadCanWriteCompilationData());
         JS_ASSERT(isInterpretedLazy());
         if (!lazyScript()->maybeScript())
             lazyScript()->initScript(script);
         flags_ &= ~INTERPRETED_LAZY;
         flags_ |= INTERPRETED;
         initScript(script);
     }
 
     void initLazyScript(js::LazyScript *lazy) {
         JS_ASSERT(isInterpreted());
         flags_ &= ~INTERPRETED;
         flags_ |= INTERPRETED_LAZY;
         u.i.s.lazy_ = lazy;
     }
 
     JSNative native() const {
-        js::AutoThreadSafeAccess ts(this);
         JS_ASSERT(isNative());
         return u.n.native;
     }
 
     JSNative maybeNative() const {
         return isInterpreted() ? nullptr : native();
     }
 
@@ -435,17 +419,16 @@ class JSFunction : public JSObject
 
     void initNative(js::Native native, const JSJitInfo *jitinfo) {
         JS_ASSERT(native);
         u.n.native = native;
         u.n.jitinfo = jitinfo;
     }
 
     const JSJitInfo *jitInfo() const {
-        js::AutoThreadSafeAccess ts(this);
         JS_ASSERT(isNative());
         return u.n.jitinfo;
     }
 
     void setJitInfo(const JSJitInfo *data) {
         JS_ASSERT(isNative());
         u.n.jitinfo = data;
     }
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -683,19 +683,16 @@ types::NewCompilerConstraintList(jit::Te
 }
 
 /* static */ bool
 TypeScript::FreezeTypeSets(CompilerConstraintList *constraints, JSScript *script,
                            TemporaryTypeSet **pThisTypes,
                            TemporaryTypeSet **pArgTypes,
                            TemporaryTypeSet **pBytecodeTypes)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-    AutoThreadSafeAccess ts(script);
-
     LifoAlloc *alloc = constraints->alloc();
     StackTypeSet *existing = script->types->typeArray();
 
     size_t count = NumTypeSets(script);
     TemporaryTypeSet *types = alloc->newArrayUninitialized<TemporaryTypeSet>(count);
     if (!types)
         return false;
     PodZero(types, count);
@@ -805,17 +802,16 @@ TypeObjectKey::proto()
 {
     JS_ASSERT(hasTenuredProto());
     return isTypeObject() ? asTypeObject()->proto() : asSingleObject()->getTaggedProto();
 }
 
 bool
 ObjectImpl::hasTenuredProto() const
 {
-    AutoThreadSafeAccess ts(this);
     return type_->hasTenuredProto();
 }
 
 bool
 TypeObjectKey::hasTenuredProto()
 {
     return isTypeObject() ? asTypeObject()->hasTenuredProto() : asSingleObject()->hasTenuredProto();
 }
@@ -851,17 +847,16 @@ TypeObjectKey::unknownProperties()
         return type->unknownProperties();
     return false;
 }
 
 HeapTypeSetKey
 TypeObjectKey::property(jsid id)
 {
     JS_ASSERT(!unknownProperties());
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
 
     HeapTypeSetKey property;
     property.object_ = this;
     property.id_ = id;
     if (TypeObject *type = maybeType())
         property.maybeTypes_ = type->maybeGetProperty(id);
 
     return property;
@@ -1508,20 +1503,18 @@ ObjectStateChange(ExclusiveContext *cxAr
 {
     if (object->unknownProperties())
         return;
 
     /* All constraints listening to state changes are on the empty id. */
     HeapTypeSet *types = object->maybeGetProperty(JSID_EMPTY);
 
     /* Mark as unknown after getting the types, to avoid assertion. */
-    if (markingUnknown) {
-        AutoLockForCompilation lock(cxArg);
+    if (markingUnknown)
         object->addFlags(OBJECT_FLAG_DYNAMIC_MASK | OBJECT_FLAG_UNKNOWN_PROPERTIES);
-    }
 
     if (types) {
         if (JSContext *cx = cxArg->maybeJSContext()) {
             TypeConstraint *constraint = types->constraintList;
             while (constraint) {
                 constraint->newObjectState(cx, object);
                 constraint = constraint->next;
             }
@@ -2331,17 +2324,16 @@ TypeCompartment::markSetsUnknown(JSConte
             StackTypeSet *typeArray = script->types->typeArray();
             for (unsigned i = 0; i < count; i++) {
                 if (typeArray[i].hasType(Type::ObjectType(target)))
                     typeArray[i].addType(cx, Type::AnyObjectType());
             }
         }
     }
 
-    AutoLockForCompilation lock(cx);
     target->addFlags(OBJECT_FLAG_SETS_MARKED_UNKNOWN);
 }
 
 void
 TypeCompartment::print(JSContext *cx, bool force)
 {
 #ifdef DEBUG
     gc::AutoSuppressGC suppressGC(cx);
@@ -2751,38 +2743,19 @@ TypeCompartment::newTypedObject(JSContex
     obj->setType(p->value().object);
     return obj;
 }
 
 /////////////////////////////////////////////////////////////////////
 // TypeObject
 /////////////////////////////////////////////////////////////////////
 
-#ifdef DEBUG
-void
-TypeObject::assertCanAccessProto() const
-{
-    // The proto pointer for type objects representing singletons may move.
-    JS_ASSERT_IF(singleton(), CurrentThreadCanReadCompilationData());
-
-    // Any proto pointer which is in the nursery may be moved, and may not be
-    // accessed during off thread compilation.
-#if defined(JSGC_GENERATIONAL) && defined(JS_THREADSAFE)
-    PerThreadData *pt = TlsPerThreadData.get();
-    TaggedProto proto(proto_);
-    JS_ASSERT_IF(proto.isObject() && !proto.toObject()->isTenured(),
-                 !pt || !pt->ionCompiling);
-#endif
-}
-#endif // DEBUG
-
 void
 TypeObject::setProto(JSContext *cx, TaggedProto proto)
 {
-    JS_ASSERT(CurrentThreadCanWriteCompilationData());
     JS_ASSERT(singleton());
 
     if (proto.isObject() && IsInsideNursery(cx->runtime(), proto.toObject()))
         addFlags(OBJECT_FLAG_NURSERY_PROTO);
 
     setProtoUnchecked(proto);
 }
 
@@ -3051,20 +3024,17 @@ TypeObject::setFlags(ExclusiveContext *c
     AutoEnterAnalysis enter(cx);
 
     if (singleton()) {
         /* Make sure flags are consistent with persistent object state. */
         JS_ASSERT_IF(flags & OBJECT_FLAG_ITERATED,
                      singleton()->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON));
     }
 
-    {
-        AutoLockForCompilation lock(cx);
-        addFlags(flags);
-    }
+    addFlags(flags);
 
     InferSpew(ISpewOps, "%s: setFlags 0x%x", TypeObjectString(this), flags);
 
     ObjectStateChange(cx, this, false);
 }
 
 void
 TypeObject::markUnknown(ExclusiveContext *cx)
@@ -3099,20 +3069,18 @@ TypeObject::markUnknown(ExclusiveContext
         }
     }
 }
 
 void
 TypeObject::clearAddendum(ExclusiveContext *cx)
 {
     JS_ASSERT(!(flags() & OBJECT_FLAG_ADDENDUM_CLEARED));
-    {
-        AutoLockForCompilation lock(cx);
-        addFlags(OBJECT_FLAG_ADDENDUM_CLEARED);
-    }
+
+    addFlags(OBJECT_FLAG_ADDENDUM_CLEARED);
 
     /*
      * It is possible for the object to not have a new script or other
      * addendum yet, but to have one added in the future. When
      * analyzing properties of new scripts we mix in adding
      * constraints to trigger clearNewScript with changes to the type
      * sets themselves (from breakTypeBarriers). It is possible that
      * we could trigger one of these constraints before
@@ -3516,20 +3484,17 @@ CheckNewScriptProperties(JSContext *cx, 
         p = cx->calloc_(numBytes);
     } while (IsPoisonedPtr(p));
     newScript = (TypeNewScript *) p;
 #else
     newScript = (TypeNewScript *) cx->calloc_(numBytes);
 #endif
     new (newScript) TypeNewScript();
 
-    {
-        AutoLockForCompilation lock(cx);
-        type->setAddendum(newScript);
-    }
+    type->setAddendum(newScript);
 
     if (!newScript) {
         cx->compartment()->types.setPendingNukeTypes(cx);
         return;
     }
 
     newScript->fun = fun;
     newScript->templateObject = baseobj;
@@ -3687,20 +3652,17 @@ JSScript::makeTypes(JSContext *cx)
 
     new(typeScript) TypeScript();
 
     TypeSet *typeArray = typeScript->typeArray();
 
     for (unsigned i = 0; i < count; i++)
         new (&typeArray[i]) StackTypeSet();
 
-    {
-        AutoLockForCompilation lock(cx);
-        types = typeScript;
-    }
+    types = typeScript;
 
 #ifdef DEBUG
     for (unsigned i = 0; i < nTypeSets(); i++) {
         InferSpew(ISpewOps, "typeSet: %sT%p%s bytecode%u #%u",
                   InferSpewColor(&typeArray[i]), &typeArray[i], InferSpewColorReset(),
                   i, id());
     }
     TypeSet *thisTypes = TypeScript::ThisTypes(this);
@@ -3820,22 +3782,18 @@ JSObject::splicePrototype(JSContext *cx,
     if (!cx->typeInferenceEnabled()) {
         TypeObject *type = cx->getNewType(clasp, proto);
         if (!type)
             return false;
         self->type_ = type;
         return true;
     }
 
-    {
-        AutoLockForCompilation lock(cx);
-        type->setClasp(clasp);
-        type->setProto(cx, proto);
-    }
-
+    type->setClasp(clasp);
+    type->setProto(cx, proto);
     return true;
 }
 
 /* static */ TypeObject *
 JSObject::makeLazyType(JSContext *cx, HandleObject obj)
 {
     JS_ASSERT(obj->hasLazyType());
     JS_ASSERT(cx->compartment() == obj->compartment());
@@ -3878,20 +3836,17 @@ JSObject::makeLazyType(JSContext *cx, Ha
 
     /* Fill in the type according to the state of this object. */
 
     type->initSingleton(obj);
 
     if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted())
         type->interpretedFunction = &obj->as<JSFunction>();
 
-    {
-        AutoLockForCompilation lock(cx);
-        obj->type_ = type;
-    }
+    obj->type_ = type;
 
     return type;
 }
 
 /* static */ inline HashNumber
 TypeObjectWithNewScriptEntry::hash(const Lookup &lookup)
 {
     return PointerHasher<JSObject *, 3>::hash(lookup.hashProto.raw()) ^
@@ -4623,17 +4578,16 @@ TypeScript::printTypes(JSContext *cx, Ha
 
 /////////////////////////////////////////////////////////////////////
 // Binary data
 /////////////////////////////////////////////////////////////////////
 
 void
 TypeObject::setAddendum(TypeObjectAddendum *addendum)
 {
-    JS_ASSERT(CurrentThreadCanWriteCompilationData());
     this->addendum = addendum;
 }
 
 bool
 TypeObject::addTypedObjectAddendum(JSContext *cx, Handle<TypeDescr*> descr)
 {
     if (!cx->typeInferenceEnabled())
         return true;
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -22,21 +22,16 @@
 #include "gc/Marking.h"
 #include "js/Utility.h"
 #include "js/Vector.h"
 
 namespace js {
 
 class TypeDescr;
 
-#ifdef DEBUG
-bool CurrentThreadCanWriteCompilationData();
-bool CurrentThreadCanReadCompilationData();
-#endif
-
 class TaggedProto
 {
   public:
     static JSObject * const LazyProto;
 
     TaggedProto() : proto(nullptr) {}
     TaggedProto(JSObject *proto) : proto(proto) {}
 
@@ -885,50 +880,39 @@ struct TypeObject : gc::BarrieredCell<Ty
 {
   private:
     /* Class shared by object using this type. */
     const Class *clasp_;
 
     /* Prototype shared by objects using this type. */
     HeapPtrObject proto_;
 
-#ifdef DEBUG
-    void assertCanAccessProto() const;
-#else
-    void assertCanAccessProto() const {}
-#endif
-
     /*
      * Whether there is a singleton JS object with this type. That JS object
      * must appear in type sets instead of this; we include the back reference
      * here to allow reverting the JS object to a lazy type.
      */
     HeapPtrObject singleton_;
 
   public:
 
     const Class *clasp() const {
-        AutoThreadSafeAccess ts(this);
         return clasp_;
     }
 
     void setClasp(const Class *clasp) {
-        JS_ASSERT(CurrentThreadCanWriteCompilationData());
         JS_ASSERT(singleton());
         clasp_ = clasp;
     }
 
     TaggedProto proto() const {
-        AutoThreadSafeAccess ts(this);
-        assertCanAccessProto();
         return TaggedProto(proto_);
     }
 
     JSObject *singleton() const {
-        AutoThreadSafeAccess ts(this);
         return singleton_;
     }
 
     // For use during marking, don't call otherwise.
     HeapPtrObject &protoRaw() { return proto_; }
     HeapPtrObject &singletonRaw() { return singleton_; }
 
     void setProto(JSContext *cx, TaggedProto proto);
@@ -960,52 +944,40 @@ struct TypeObject : gc::BarrieredCell<Ty
      *   constructed using 'new' on the specified script, which adds
      *   some number of properties to the object in a definite order
      *   before the object escapes.
      */
     HeapPtr<TypeObjectAddendum> addendum;
   public:
 
     TypeObjectFlags flags() const {
-        JS_ASSERT(CurrentThreadCanReadCompilationData());
-        AutoThreadSafeAccess ts(this);
         return flags_;
     }
 
     void addFlags(TypeObjectFlags flags) {
-        JS_ASSERT(CurrentThreadCanWriteCompilationData());
         flags_ |= flags;
     }
 
     void clearFlags(TypeObjectFlags flags) {
-        JS_ASSERT(CurrentThreadCanWriteCompilationData());
         flags_ &= ~flags;
     }
 
     bool hasNewScript() const {
-        JS_ASSERT(CurrentThreadCanReadCompilationData());
-        AutoThreadSafeAccess ts(this);
         return addendum && addendum->isNewScript();
     }
 
     TypeNewScript *newScript() {
-        JS_ASSERT(CurrentThreadCanReadCompilationData());
-        AutoThreadSafeAccess ts(this);
         return addendum->asNewScript();
     }
 
     bool hasTypedObject() {
-        JS_ASSERT(CurrentThreadCanReadCompilationData());
-        AutoThreadSafeAccess ts(this);
         return addendum && addendum->isTypedObject();
     }
 
     TypeTypedObject *typedObject() {
-        JS_ASSERT(CurrentThreadCanReadCompilationData());
-        AutoThreadSafeAccess ts(this);
         return addendum->asTypedObject();
     }
 
     void setAddendum(TypeObjectAddendum *addendum);
 
     /*
      * Tag the type object for a binary data type descriptor, instance,
      * or handle with the type representation of the data it points at.
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -82,17 +82,16 @@ Type::ObjectType(JSObject *obj)
     if (obj->hasSingletonType())
         return Type(uintptr_t(obj) | 1);
     return Type(uintptr_t(obj->type()));
 }
 
 /* static */ inline Type
 Type::ObjectType(TypeObject *obj)
 {
-    AutoThreadSafeAccess ts(obj);
     if (obj->singleton())
         return Type(uintptr_t(obj->singleton()) | 1);
     return Type(uintptr_t(obj));
 }
 
 /* static */ inline Type
 Type::ObjectType(TypeObjectKey *obj)
 {
@@ -173,17 +172,16 @@ IdToTypeId(jsid id)
         return JSID_VOID;
 
     /*
      * Check for numeric strings, as in js_StringIsIndex, but allow negative
      * and overflowing integers.
      */
     if (JSID_IS_STRING(id)) {
         JSAtom *atom = JSID_TO_ATOM(id);
-        js::AutoThreadSafeAccess ts(atom);
         JS::TwoByteChars cp = atom->range();
         if (cp.length() > 0 && (JS7_ISDEC(cp[0]) || cp[0] == '-')) {
             for (size_t i = 1; i < cp.length(); ++i) {
                 if (!JS7_ISDEC(cp[i]))
                     return id;
             }
             return JSID_VOID;
         }
@@ -560,31 +558,29 @@ extern void TypeDynamicResult(JSContext 
 TypeScript::NumTypeSets(JSScript *script)
 {
     return script->nTypeSets() + analyze::LocalSlot(script, 0);
 }
 
 /* static */ inline StackTypeSet *
 TypeScript::ThisTypes(JSScript *script)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
     return script->types->typeArray() + script->nTypeSets() + analyze::ThisSlot();
 }
 
 /*
  * Note: for non-escaping arguments and locals, argTypes/localTypes reflect
  * only the initial type of the variable (e.g. passed values for argTypes,
  * or undefined for localTypes) and not types from subsequent assignments.
  */
 
 /* static */ inline StackTypeSet *
 TypeScript::ArgTypes(JSScript *script, unsigned i)
 {
     JS_ASSERT(i < script->functionNonDelazifying()->nargs());
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
     return script->types->typeArray() + script->nTypeSets() + analyze::ArgSlot(i);
 }
 
 template <typename TYPESET>
 /* static */ inline TYPESET *
 TypeScript::BytecodeTypes(JSScript *script, jsbytecode *pc, uint32_t *hint, TYPESET *typeArray)
 {
     JS_ASSERT(js_CodeSpec[*pc].format & JOF_TYPESET);
@@ -1123,22 +1119,19 @@ TypeSet::addType(Type type, LifoAlloc *a
 inline void
 ConstraintTypeSet::addType(ExclusiveContext *cxArg, Type type)
 {
     JS_ASSERT(cxArg->compartment()->activeAnalysis);
 
     if (hasType(type))
         return;
 
-    {
-        AutoLockForCompilation lock(cxArg);
-        if (!TypeSet::addType(type, &cxArg->typeLifoAlloc())) {
-            cxArg->compartment()->types.setPendingNukeTypes(cxArg);
-            return;
-        }
+    if (!TypeSet::addType(type, &cxArg->typeLifoAlloc())) {
+        cxArg->compartment()->types.setPendingNukeTypes(cxArg);
+        return;
     }
 
     InferSpew(ISpewOps, "addType: %sT%p%s %s",
               InferSpewColor(this), this, InferSpewColorReset(),
               TypeString(type));
 
     /* Propagate the type to all constraints. */
     if (JSContext *cx = cxArg->maybeJSContext()) {
@@ -1272,17 +1265,16 @@ inline TypeObject::TypeObject(const Clas
     this->flags_ = initialFlags;
 
     InferSpew(ISpewOps, "newObject: %s", TypeObjectString(this));
 }
 
 inline uint32_t
 TypeObject::basePropertyCount() const
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
     return (flags() & OBJECT_FLAG_PROPERTY_COUNT_MASK) >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT;
 }
 
 inline void
 TypeObject::setBasePropertyCount(uint32_t count)
 {
     // Note: Callers must ensure they are performing threadsafe operations.
     JS_ASSERT(count <= OBJECT_FLAG_PROPERTY_COUNT_LIMIT);
@@ -1297,37 +1289,31 @@ TypeObject::getProperty(ExclusiveContext
 
     JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id));
     JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id));
     JS_ASSERT(!unknownProperties());
 
     if (HeapTypeSet *types = maybeGetProperty(id))
         return types;
 
-    uint32_t propertyCount;
-    Property **pprop;
-    {
-        AutoLockForCompilation lock(cx);
+    uint32_t propertyCount = basePropertyCount();
+    Property **pprop = HashSetInsert<jsid,Property,Property>
+        (cx->typeLifoAlloc(), propertySet, propertyCount, id);
+    if (!pprop) {
+        cx->compartment()->types.setPendingNukeTypes(cx);
+        return nullptr;
+    }
 
-        propertyCount = basePropertyCount();
-        pprop = HashSetInsert<jsid,Property,Property>
-            (cx->typeLifoAlloc(), propertySet, propertyCount, id);
-        if (!pprop) {
-            cx->compartment()->types.setPendingNukeTypes(cx);
-            return nullptr;
-        }
+    JS_ASSERT(!*pprop);
 
-        JS_ASSERT(!*pprop);
-
-        setBasePropertyCount(propertyCount);
-        if (!addProperty(cx, id, pprop)) {
-            setBasePropertyCount(0);
-            propertySet = nullptr;
-            return nullptr;
-        }
+    setBasePropertyCount(propertyCount);
+    if (!addProperty(cx, id, pprop)) {
+        setBasePropertyCount(0);
+        propertySet = nullptr;
+        return nullptr;
     }
 
     if (propertyCount == OBJECT_FLAG_PROPERTY_COUNT_LIMIT) {
         markUnknown(cx);
 
         /*
          * Return an arbitrary property in the object, as all have unknown
          * type and are treated as non-data properties.
@@ -1345,19 +1331,16 @@ TypeObject::getProperty(ExclusiveContext
 }
 
 inline HeapTypeSet *
 TypeObject::maybeGetProperty(jsid id)
 {
     JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id));
     JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id));
     JS_ASSERT(!unknownProperties());
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
-    AutoThreadSafeAccess ts(this);
 
     Property *prop = HashSetLookup<jsid,Property,Property>
         (propertySet, basePropertyCount(), id);
 
     return prop ? &prop->types : nullptr;
 }
 
 inline unsigned
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -2043,17 +2043,16 @@ GlobalObject::initIteratorClasses(JSCont
         RootedObject genFunction(cx, NewFunctionWithProto(cx, NullPtr(), Generator, 1,
                                                           JSFunction::NATIVE_CTOR, global, name,
                                                           &function.toObject()));
         if (!genFunction)
             return false;
         if (!LinkConstructorAndPrototype(cx, genFunction, genFunctionProto))
             return false;
 
-        AutoLockForCompilation lock(cx);
         global->setSlot(STAR_GENERATOR_OBJECT_PROTO, ObjectValue(*genObjectProto));
         global->setConstructor(JSProto_GeneratorFunction, ObjectValue(*genFunction));
         global->setPrototype(JSProto_GeneratorFunction, ObjectValue(*genFunctionProto));
     }
 
     if (global->getPrototype(JSProto_StopIteration).isUndefined()) {
         proto = global->createBlankPrototype(cx, &StopIterationObject::class_);
         if (!proto || !JSObject::freeze(cx, proto))
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2245,22 +2245,19 @@ JSObject::TradeGuts(JSContext *cx, JSObj
 {
     JS_ASSERT(a->compartment() == b->compartment());
     JS_ASSERT(a->is<JSFunction>() == b->is<JSFunction>());
 
     /*
      * Swap the object's types, to restore their initial type information.
      * The prototypes and classes of the objects were swapped in ReserveForTradeGuts.
      */
-    {
-        AutoLockForCompilation lock(cx);
-        TypeObject *tmp = a->type_;
-        a->type_ = b->type_;
-        b->type_ = tmp;
-    }
+    TypeObject *tmp = a->type_;
+    a->type_ = b->type_;
+    b->type_ = tmp;
 
     /* Don't try to swap a JSFunction for a plain function JSObject. */
     JS_ASSERT_IF(a->is<JSFunction>(), a->tenuredSizeOfThis() == b->tenuredSizeOfThis());
 
     /*
      * Regexp guts are more complicated -- we would need to migrate the
      * refcounted JIT code blob for them across compartments instead of just
      * swapping guts.
@@ -2282,22 +2279,19 @@ JSObject::TradeGuts(JSContext *cx, JSObj
         /*
          * If the objects are the same size, then we make no assumptions about
          * whether they have dynamically allocated slots and instead just copy
          * them over wholesale.
          */
         char tmp[mozilla::tl::Max<sizeof(JSFunction), sizeof(JSObject_Slots16)>::value];
         JS_ASSERT(size <= sizeof(tmp));
 
-        {
-            AutoLockForCompilation lock(cx);
-            js_memcpy(tmp, a, size);
-            js_memcpy(a, b, size);
-            js_memcpy(b, tmp, size);
-        }
+        js_memcpy(tmp, a, size);
+        js_memcpy(a, b, size);
+        js_memcpy(b, tmp, size);
 
 #ifdef JSGC_GENERATIONAL
         /*
          * Trigger post barriers for fixed slots. JSObject bits are barriered
          * below, in common with the other case.
          */
         for (size_t i = 0; i < a->numFixedSlots(); ++i) {
             HeapSlot::writeBarrierPost(cx->runtime(), a, HeapSlot::Slot, i, a->getSlot(i));
@@ -2325,22 +2319,19 @@ JSObject::TradeGuts(JSContext *cx, JSObj
             js_free(a->slots);
         if (b->hasDynamicSlots())
             js_free(b->slots);
 
         void *apriv = a->hasPrivate() ? a->getPrivate() : nullptr;
         void *bpriv = b->hasPrivate() ? b->getPrivate() : nullptr;
 
         char tmp[sizeof(JSObject)];
-        {
-            AutoLockForCompilation lock(cx);
-            js_memcpy(&tmp, a, sizeof tmp);
-            js_memcpy(a, b, sizeof tmp);
-            js_memcpy(b, &tmp, sizeof tmp);
-        }
+        js_memcpy(&tmp, a, sizeof tmp);
+        js_memcpy(a, b, sizeof tmp);
+        js_memcpy(b, &tmp, sizeof tmp);
 
         if (a->isNative())
             a->shape_->setNumFixedSlots(reserved.newafixed);
         else
             a->shape_ = reserved.newashape;
 
         a->slots = reserved.newaslots;
         a->initSlotRange(0, reserved.bvals.begin(), bcap);
@@ -2780,22 +2771,16 @@ JSObject::growSlots(ThreadSafeContext *c
             if (!reshapedObj)
                 return false;
 
             typeObj->newScript()->templateObject = reshapedObj;
             typeObj->markStateChange(ncx);
         }
     }
 
-    // Global slots may be read during off thread compilation, and updates to
-    // their slot pointers need to be synchronized.
-    Maybe<AutoLockForCompilation> lock;
-    if (obj->is<GlobalObject>())
-        lock.construct(cx->asExclusiveContext());
-
     if (!oldCount) {
         obj->slots = AllocateSlots(cx, obj, newCount);
         if (!obj->slots)
             return false;
         Debug_SetSlotRangeToCrashOnTouch(obj->slots, newCount);
         return true;
     }
 
@@ -2830,22 +2815,16 @@ JSObject::shrinkSlots(ThreadSafeContext 
     if (newCount == 0) {
         FreeSlots(cx, obj->slots);
         obj->slots = nullptr;
         return;
     }
 
     JS_ASSERT_IF(!obj->is<ArrayObject>(), newCount >= SLOT_CAPACITY_MIN);
 
-    // Global slots may be read during off thread compilation, and updates to
-    // their slot pointers need to be synchronized.
-    Maybe<AutoLockForCompilation> lock;
-    if (obj->is<GlobalObject>())
-        lock.construct(cx->asExclusiveContext());
-
     HeapSlot *newslots = ReallocateSlots(cx, obj, obj->slots, oldCount, newCount);
     if (!newslots)
         return;  /* Leave slots at its old size. */
 
     obj->slots = newslots;
 }
 
 /* static */ bool
@@ -3222,20 +3201,17 @@ js::SetClassAndProto(JSContext *cx, Hand
      * are unknown. Type sets containing this object will contain the original
      * type but not the new type of the object, so we need to go and scan the
      * entire compartment for type sets which have these objects and mark them
      * as containing generic objects.
      */
     MarkTypeObjectUnknownProperties(cx, obj->type(), true);
     MarkTypeObjectUnknownProperties(cx, type, true);
 
-    {
-        AutoLockForCompilation lock(cx);
-        obj->setType(type);
-    }
+    obj->setType(type);
 
     *succeeded = true;
     return true;
 }
 
 static bool
 MaybeResolveConstructor(ExclusiveContext *cxArg, Handle<GlobalObject*> global, JSProtoKey key)
 {
@@ -4298,17 +4274,17 @@ NativeGetInline(JSContext *cx,
         jsbytecode *pc;
         JSScript *script = cx->currentScript(&pc);
 #ifdef JS_ION
         if (script && script->hasBaselineScript()) {
             switch (JSOp(*pc)) {
               case JSOP_GETPROP:
               case JSOP_CALLPROP:
               case JSOP_LENGTH:
-                script->baselineScript()->noteAccessedGetter(cx, script->pcToOffset(pc));
+                script->baselineScript()->noteAccessedGetter(script->pcToOffset(pc));
                 break;
               default:
                 break;
             }
         }
 #endif
     }
 
@@ -5692,18 +5668,16 @@ DumpProperty(JSObject *obj, Shape &shape
         fprintf(stderr, " (INVALID!)");
     }
     fprintf(stderr, "\n");
 }
 
 bool
 JSObject::uninlinedIsProxy() const
 {
-    AutoThreadSafeAccess ts0(this);
-    AutoThreadSafeAccess ts1(type_);
     return is<ProxyObject>();
 }
 
 void
 JSObject::dump()
 {
     JSObject *obj = this;
     fprintf(stderr, "object %p\n", (void *) obj);
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -284,20 +284,16 @@ class JSObject : public js::ObjectImpl
     static const uint32_t NELEMENTS_LIMIT = JS_BIT(28);
 
   public:
     bool setDelegate(js::ExclusiveContext *cx) {
         return setFlag(cx, js::BaseShape::DELEGATE, GENERATE_SHAPE);
     }
 
     bool isBoundFunction() const {
-        // Note: This function can race when it is called during off thread compilation.
-        js::AutoThreadSafeAccess ts0(this);
-        js::AutoThreadSafeAccess ts1(lastProperty());
-        js::AutoThreadSafeAccess ts2(lastProperty()->base());
         return lastProperty()->hasObjectFlag(js::BaseShape::BOUND_FUNCTION);
     }
 
     inline bool hasSpecialEquality() const;
 
     bool watched() const {
         return lastProperty()->hasObjectFlag(js::BaseShape::WATCHED);
     }
@@ -349,20 +345,16 @@ class JSObject : public js::ObjectImpl
     bool isIndexed() const {
         return lastProperty()->hasObjectFlag(js::BaseShape::INDEXED);
     }
 
     uint32_t propertyCount() const {
         return lastProperty()->entryCount();
     }
 
-    uint32_t propertyCountForCompilation() const {
-        return lastProperty()->entryCountForCompilation();
-    }
-
     bool hasShapeTable() const {
         return lastProperty()->hasTable();
     }
 
     void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::ObjectsExtraSizes *sizes);
 
     bool hasIdempotentProtoChain() const;
 
@@ -371,23 +363,23 @@ class JSObject : public js::ObjectImpl
     static const uint32_t MAX_FIXED_SLOTS = 16;
 
   public:
 
     /* Accessors for properties. */
 
     /* Whether a slot is at a fixed offset from this object. */
     bool isFixedSlot(size_t slot) {
-        return slot < numFixedSlotsForCompilation();
+        return slot < numFixedSlots();
     }
 
     /* Index into the dynamic slots array to use for a dynamic slot. */
     size_t dynamicSlotIndex(size_t slot) {
-        JS_ASSERT(slot >= numFixedSlotsForCompilation());
-        return slot - numFixedSlotsForCompilation();
+        JS_ASSERT(slot >= numFixedSlots());
+        return slot - numFixedSlots();
     }
 
     /*
      * Grow or shrink slots immediately before changing the slot span.
      * The number of allocated slots is not stored explicitly, and changes to
      * the slots must track changes in the slot span.
      */
     static bool growSlots(js::ThreadSafeContext *cx, js::HandleObject obj, uint32_t oldCount,
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -395,19 +395,16 @@ JSObject::clearType(JSContext *cx, js::H
 
     obj->type_ = type;
     return true;
 }
 
 inline void
 JSObject::setType(js::types::TypeObject *newType)
 {
-    // Note: This is usually called for newly created objects that haven't
-    // escaped to script yet, so don't require that the compilation lock be
-    // held here.
     JS_ASSERT(newType);
     JS_ASSERT(!hasSingletonType());
     type_ = newType;
 }
 
 /* static */ inline bool
 JSObject::getProto(JSContext *cx, js::HandleObject obj, js::MutableHandleObject protop)
 {
@@ -994,21 +991,18 @@ DefineConstructorAndPrototype(JSContext 
     JS_ASSERT(!global->nativeEmpty()); /* reserved slots already allocated */
     JS_ASSERT(ctor);
     JS_ASSERT(proto);
 
     RootedId id(cx, NameToId(ClassName(key, cx)));
     JS_ASSERT(!global->nativeLookup(cx, id));
 
     /* Set these first in case AddTypePropertyId looks for this class. */
-    {
-        AutoLockForCompilation lock(cx);
-        global->setConstructor(key, ObjectValue(*ctor));
-        global->setPrototype(key, ObjectValue(*proto));
-    }
+    global->setConstructor(key, ObjectValue(*ctor));
+    global->setPrototype(key, ObjectValue(*proto));
     global->setConstructorPropertySlot(key, ObjectValue(*ctor));
 
     if (!global->addDataProperty(cx, id, GlobalObject::constructorPropertySlot(key), 0)) {
         global->setConstructor(key, UndefinedValue());
         global->setPrototype(key, UndefinedValue());
         global->setConstructorPropertySlot(key, UndefinedValue());
         return false;
     }
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -3162,20 +3162,17 @@ JSScript::argumentsOptimizationFailed(JS
      * is nothing to do; GuardFunApplySpeculation will patch in the real
      * argsobj.
      */
     if (script->needsArgsObj())
         return true;
 
     JS_ASSERT(!script->isGenerator());
 
-    {
-        AutoLockForCompilation lock(cx);
-        script->needsArgsObj_ = true;
-    }
+    script->needsArgsObj_ = true;
 
 #ifdef JS_ION
     /*
      * Since we can't invalidate baseline scripts, set a flag that's checked from
      * JIT code to indicate the arguments optimization failed and JSOP_ARGUMENTS
      * should create an arguments object next time.
      */
     if (script->hasBaselineScript())
@@ -3225,24 +3222,22 @@ JSScript::argumentsOptimizationFailed(JS
     }
 
     return true;
 }
 
 bool
 JSScript::varIsAliased(uint32_t varSlot)
 {
-    AutoThreadSafeAccess ts(this);
     return bindings.bindingIsAliased(bindings.numArgs() + varSlot);
 }
 
 bool
 JSScript::formalIsAliased(unsigned argSlot)
 {
-    AutoThreadSafeAccess ts(this);
     return bindings.bindingIsAliased(argSlot);
 }
 
 bool
 JSScript::formalLivesInArgumentsObject(unsigned argSlot)
 {
     return argsObjAliasesFormals() && !formalIsAliased(argSlot);
 }
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -244,18 +244,16 @@ class Bindings
     /* Return whether the binding at bindingIndex is aliased. */
     bool bindingIsAliased(uint32_t bindingIndex);
 
     /* Return whether this scope has any aliased bindings. */
     bool hasAnyAliasedBindings() const {
         if (!callObjShape_)
             return false;
 
-        // Binding shapes are immutable once constructed.
-        AutoThreadSafeAccess ts(callObjShape_);
         return !callObjShape_->isEmptyShape();
     }
 
     void trace(JSTracer *trc);
 };
 
 template <>
 struct GCMethods<Bindings> {
@@ -549,20 +547,16 @@ class ScriptSourceObject : public JSObje
   public:
     static const Class class_;
 
     static void finalize(FreeOp *fop, JSObject *obj);
     static ScriptSourceObject *create(ExclusiveContext *cx, ScriptSource *source,
                                       const ReadOnlyCompileOptions &options);
 
     ScriptSource *source() {
-        // Script source objects are immutable.
-        AutoThreadSafeAccess ts0(this);
-        AutoThreadSafeAccess ts1(lastProperty());
-        AutoThreadSafeAccess ts2(lastProperty()->base());
         return static_cast<ScriptSource *>(getReservedSlot(SOURCE_SLOT).toPrivate());
     }
 
     void setSource(ScriptSource *source);
 
     JSObject *element() const;
     void initElement(HandleObject element);
     const Value &elementAttributeName() const;
@@ -633,32 +627,28 @@ class JSScript : public js::gc::Barriere
 
     // Larger-than-word-sized fields.
 
   public:
     js::Bindings    bindings;   /* names of top-level variables in this script
                                    (and arguments if this is a function script) */
 
     bool hasAnyAliasedBindings() const {
-        js::AutoThreadSafeAccess ts(this);
         return bindings.hasAnyAliasedBindings();
     }
 
     js::Binding *bindingArray() const {
-        js::AutoThreadSafeAccess ts(this);
         return bindings.bindingArray();
     }
 
     unsigned numArgs() const {
-        js::AutoThreadSafeAccess ts(this);
         return bindings.numArgs();
     }
 
     js::Shape *callObjShape() const {
-        js::AutoThreadSafeAccess ts(this);
         return bindings.callObjShape();
     }
 
     // Word-sized fields.
 
   private:
     jsbytecode      *code_;     /* bytecodes and their immediate operands */
   public:
@@ -884,21 +874,19 @@ class JSScript : public js::gc::Barriere
     inline JSPrincipals *principals();
 
     JSCompartment *compartment() const { return compartment_; }
 
     void setVersion(JSVersion v) { version = v; }
 
     // Script bytecode is immutable after creation.
     jsbytecode *code() const {
-        js::AutoThreadSafeAccess ts(this);
         return code_;
     }
     size_t length() const {
-        js::AutoThreadSafeAccess ts(this);
         return length_;
     }
 
     void setCode(jsbytecode *code) { code_ = code; }
     void setLength(size_t length) { length_ = length; }
 
     jsbytecode *codeEnd() const { return code() + length(); }
 
@@ -912,104 +900,87 @@ class JSScript : public js::gc::Barriere
     }
 
     jsbytecode *offsetToPC(size_t offset) const {
         JS_ASSERT(offset < length());
         return code() + offset;
     }
 
     size_t mainOffset() const {
-        js::AutoThreadSafeAccess ts(this);
         return mainOffset_;
     }
 
     size_t lineno() const {
-        js::AutoThreadSafeAccess ts(this);
         return lineno_;
     }
 
     size_t column() const {
-        js::AutoThreadSafeAccess ts(this);
         return column_;
     }
 
     void setColumn(size_t column) { column_ = column; }
 
     size_t nfixed() const {
-        js::AutoThreadSafeAccess ts(this);
         return function_ ? bindings.numVars() : 0;
     }
 
     size_t nslots() const {
-        js::AutoThreadSafeAccess ts(this);
         return nslots_;
     }
 
     size_t staticLevel() const {
-        js::AutoThreadSafeAccess ts(this);
         return staticLevel_;
     }
 
     size_t nTypeSets() const {
-        js::AutoThreadSafeAccess ts(this);
         return nTypeSets_;
     }
 
     size_t funLength() const {
-        js::AutoThreadSafeAccess ts(this);
         return funLength_;
     }
 
     size_t sourceStart() const {
-        js::AutoThreadSafeAccess ts(this);
         return sourceStart_;
     }
 
     size_t sourceEnd() const {
-        js::AutoThreadSafeAccess ts(this);
         return sourceEnd_;
     }
 
     bool noScriptRval() const {
-        js::AutoThreadSafeAccess ts(this);
         return noScriptRval_;
     }
 
     bool savedCallerFun() const { return savedCallerFun_; }
 
     bool strict() const {
-        js::AutoThreadSafeAccess ts(this);
         return strict_;
     }
 
     bool explicitUseStrict() const { return explicitUseStrict_; }
 
     bool compileAndGo() const {
-        js::AutoThreadSafeAccess ts(this);
         return compileAndGo_;
     }
 
     bool selfHosted() const { return selfHosted_; }
     bool bindingsAccessedDynamically() const { return bindingsAccessedDynamically_; }
     bool funHasExtensibleScope() const {
-        js::AutoThreadSafeAccess ts(this);
         return funHasExtensibleScope_;
     }
     bool funNeedsDeclEnvObject() const {
-        js::AutoThreadSafeAccess ts(this);
         return funNeedsDeclEnvObject_;
     }
     bool funHasAnyAliasedFormal() const {
-        js::AutoThreadSafeAccess ts(this);
         return funHasAnyAliasedFormal_;
     }
 
     bool hasSingletons() const { return hasSingletons_; }
     bool treatAsRunOnce() const {
-        js::AutoThreadSafeAccess ts(this);
         return treatAsRunOnce_;
     }
     bool hasRunOnce() const { return hasRunOnce_; }
     bool hasBeenCloned() const { return hasBeenCloned_; }
 
     void setTreatAsRunOnce() { treatAsRunOnce_ = true; }
     void setHasRunOnce() { hasRunOnce_ = true; }
     void setHasBeenCloned() { hasBeenCloned_ = true; }
@@ -1029,57 +1000,48 @@ class JSScript : public js::gc::Barriere
         isCachedEval_ = false;
         isActiveEval_ = true;
     }
 
     void setActiveEval() { isActiveEval_ = true; }
     void setDirectlyInsideEval() { directlyInsideEval_ = true; }
 
     bool usesArgumentsAndApply() const {
-        js::AutoThreadSafeAccess ts(this);
         return usesArgumentsAndApply_;
     }
     void setUsesArgumentsAndApply() { usesArgumentsAndApply_ = true; }
 
     bool shouldCloneAtCallsite() const {
-        js::AutoThreadSafeAccess ts(this);
         return shouldCloneAtCallsite_;
     }
     bool shouldInline() const {
-        js::AutoThreadSafeAccess ts(this);
         return shouldInline_;
     }
 
     void setShouldCloneAtCallsite() { shouldCloneAtCallsite_ = true; }
     void setShouldInline() { shouldInline_ = true; }
 
     bool isCallsiteClone() const {
-        js::AutoThreadSafeAccess ts(this);
         return isCallsiteClone_;
     }
     bool isGeneratorExp() const { return isGeneratorExp_; }
 
     bool failedBoundsCheck() const {
-        js::AutoThreadSafeAccess ts(this);
         return failedBoundsCheck_;
     }
     bool failedShapeGuard() const {
-        js::AutoThreadSafeAccess ts(this);
         return failedShapeGuard_;
     }
     bool hadFrequentBailouts() const {
-        js::AutoThreadSafeAccess ts(this);
         return hadFrequentBailouts_;
     }
     bool uninlineable() const {
-        js::AutoThreadSafeAccess ts(this);
         return uninlineable_;
     }
     bool invalidatedIdempotentCache() const {
-        js::AutoThreadSafeAccess ts(this);
         return invalidatedIdempotentCache_;
     }
 
     void setFailedBoundsCheck() { failedBoundsCheck_ = true; }
     void setFailedShapeGuard() { failedShapeGuard_ = true; }
     void setHadFrequentBailouts() { hadFrequentBailouts_ = true; }
     void setUninlineable() { uninlineable_ = true; }
     void setInvalidatedIdempotentCache() { invalidatedIdempotentCache_ = true; }
@@ -1090,27 +1052,25 @@ class JSScript : public js::gc::Barriere
     void setHasFreezeConstraints() { hasFreezeConstraints_ = true; }
     void clearHasFreezeConstraints() { hasFreezeConstraints_ = false; }
 
     bool warnedAboutUndefinedProp() const { return warnedAboutUndefinedProp_; }
     void setWarnedAboutUndefinedProp() { warnedAboutUndefinedProp_ = true; }
 
     /* See ContextFlags::funArgumentsHasLocalBinding comment. */
     bool argumentsHasVarBinding() const {
-        js::AutoThreadSafeAccess ts(this);
         return argsHasVarBinding_;
     }
     jsbytecode *argumentsBytecode() const { JS_ASSERT(code()[0] == JSOP_ARGUMENTS); return code(); }
     void setArgumentsHasVarBinding();
     bool argumentsAliasesFormals() const {
         return argumentsHasVarBinding() && !strict();
     }
 
     js::GeneratorKind generatorKind() const {
-        js::AutoThreadSafeAccess ts(this);
         return js::GeneratorKindFromBits(generatorKindBits_);
     }
     bool isGenerator() const { return generatorKind() != js::NotGenerator; }
     bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; }
     bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
     void setGeneratorKind(js::GeneratorKind kind) {
         // A script only gets its generator kind set as part of initialization,
         // so it can only transition from not being a generator.
@@ -1125,18 +1085,16 @@ class JSScript : public js::gc::Barriere
      * the script the first time. When !needsArgsObj, the prologue may simply
      * write MagicValue(JS_OPTIMIZED_ARGUMENTS) to 'arguments's slot and any
      * uses of 'arguments' will be guaranteed to handle this magic value.
      * So avoid spurious arguments object creation, we maintain the invariant
      * that needsArgsObj is only called after the script has been analyzed.
      */
     bool analyzedArgsUsage() const { return !needsArgsAnalysis_; }
     bool needsArgsObj() const {
-        js::AutoThreadSafeAccess ts(this);
-        JS_ASSERT(js::CurrentThreadCanReadCompilationData());
         JS_ASSERT(analyzedArgsUsage());
         return needsArgsObj_;
     }
     void setNeedsArgsObj(bool needsArgsObj);
     static bool argumentsOptimizationFailed(JSContext *cx, js::HandleScript script);
 
     /*
      * Arguments access (via JSOP_*ARG* opcodes) must access the canonical
@@ -1151,27 +1109,19 @@ class JSScript : public js::gc::Barriere
         return needsArgsObj() && !strict();
     }
 
     bool hasAnyIonScript() const {
         return hasIonScript() || hasParallelIonScript();
     }
 
     bool hasIonScript() const {
-        // Note: While a script's baseline script is protected by the
-        // compilation lock, writes to the ion script are not. This helps lock
-        // ordering issues in CodeGenerator::link. Tests of script->ion during
-        // off thread compilation can therefore race, though these are fairly
-        // benign and the IonScript itself is never accessed.
-        js::AutoThreadSafeAccess ts(this);
         return ion && ion != ION_DISABLED_SCRIPT && ion != ION_COMPILING_SCRIPT;
     }
     bool canIonCompile() const {
-        // Note: see above comment.
-        js::AutoThreadSafeAccess ts(this);
         return ion != ION_DISABLED_SCRIPT;
     }
 
     bool isIonCompilingOffThread() const {
         return ion == ION_COMPILING_SCRIPT;
     }
 
     js::jit::IonScript *ionScript() const {
@@ -1187,38 +1137,34 @@ class JSScript : public js::gc::Barriere
     void setIonScript(js::jit::IonScript *ionScript) {
         if (hasIonScript())
             js::jit::IonScript::writeBarrierPre(tenuredZone(), ion);
         ion = ionScript;
         updateBaselineOrIonRaw();
     }
 
     bool hasBaselineScript() const {
-        JS_ASSERT(js::CurrentThreadCanReadCompilationData());
-        js::AutoThreadSafeAccess ts(this);
         return baseline && baseline != BASELINE_DISABLED_SCRIPT;
     }
     bool canBaselineCompile() const {
         return baseline != BASELINE_DISABLED_SCRIPT;
     }
     js::jit::BaselineScript *baselineScript() const {
         JS_ASSERT(hasBaselineScript());
-        js::AutoThreadSafeAccess ts(this);
         return baseline;
     }
     inline void setBaselineScript(JSContext *maybecx, js::jit::BaselineScript *baselineScript);
 
     void updateBaselineOrIonRaw();
 
     bool hasParallelIonScript() const {
         return parallelIon && parallelIon != ION_DISABLED_SCRIPT && parallelIon != ION_COMPILING_SCRIPT;
     }
 
     bool canParallelIonCompile() const {
-        js::AutoThreadSafeAccess ts(this);
         return parallelIon != ION_DISABLED_SCRIPT;
     }
 
     bool isParallelIonCompilingOffThread() const {
         return parallelIon == ION_COMPILING_SCRIPT;
     }
 
     js::jit::IonScript *parallelIonScript() const {
@@ -1259,47 +1205,44 @@ class JSScript : public js::gc::Barriere
     }
     js::LazyScript *maybeLazyScript() {
         return lazyScript;
     }
 
     /*
      * Original compiled function for the script, if it has a function.
      * nullptr for global and eval scripts.
-     * The delazifying variant ensures that the function isn't lazy, but can
-     * only be used under a compilation lock. The non-delazifying variant
-     * can be used off-thread and without the lock, but must only be used
-     * after earlier code has called ensureNonLazyCanonicalFunction and
-     * while the function can't have been relazified.
+     * The delazifying variant ensures that the function isn't lazy. The
+     * non-delazifying variant must only be used after earlier code has
+     * called ensureNonLazyCanonicalFunction and while the function can't
+     * have been relazified.
      */
     inline JSFunction *functionDelazifying() const;
     JSFunction *functionNonDelazifying() const {
-        js::AutoThreadSafeAccess ts(this);
         return function_;
     }
     inline void setFunction(JSFunction *fun);
     /*
-     * Takes a compilation lock and de-lazifies the canonical function. Must
-     * be called before entering code that expects the function to be non-lazy.
+     * De-lazifies the canonical function. Must be called before entering code
+     * that expects the function to be non-lazy.
      */
     inline void ensureNonLazyCanonicalFunction(JSContext *cx);
 
     /*
      * Donor provided itself to callsite clone; null if this is non-clone.
      */
     JSFunction *donorFunction() const;
     void setIsCallsiteClone(JSObject *fun);
 
     JSFlatString *sourceData(JSContext *cx);
 
     static bool loadSource(JSContext *cx, js::ScriptSource *ss, bool *worked);
 
     void setSourceObject(JSObject *object);
     JSObject *sourceObject() const {
-        js::AutoThreadSafeAccess ts(this);
         return sourceObject_;
     }
     js::ScriptSource *scriptSource() const;
     JSPrincipals *originPrincipals() const { return scriptSource()->originPrincipals(); }
     const char *filename() const { return scriptSource()->filename(); }
 
   public:
 
@@ -1330,28 +1273,25 @@ class JSScript : public js::gc::Barriere
 
     inline js::GlobalObject &global() const;
     js::GlobalObject &uninlinedGlobal() const;
 
     /* See StaticScopeIter comment. */
     JSObject *enclosingStaticScope() const {
         if (isCallsiteClone())
             return nullptr;
-        js::AutoThreadSafeAccess ts(this);
         return enclosingScopeOrOriginalFunction_;
     }
 
   private:
     bool makeTypes(JSContext *cx);
     bool makeAnalysis(JSContext *cx);
 
   public:
     uint32_t getUseCount() const {
-        // Note: We ignore races when reading the use count of a script off thread.
-        js::AutoThreadSafeAccess ts(this);
         return useCount;
     }
     uint32_t incUseCount(uint32_t amount = 1) { return useCount += amount; }
     uint32_t *addressOfUseCount() { return &useCount; }
     static size_t offsetOfUseCount() { return offsetof(JSScript, useCount); }
     void resetUseCount() { useCount = 0; }
 
   public:
@@ -1376,17 +1316,16 @@ class JSScript : public js::gc::Barriere
     size_t sizeOfTypeScript(mozilla::MallocSizeOf mallocSizeOf) const;
 
     uint32_t numNotes();  /* Number of srcnote slots in the srcnotes section */
 
     /* Script notes are allocated right after the code. */
     jssrcnote *notes() { return (jssrcnote *)(code() + length()); }
 
     bool hasArray(ArrayKind kind) {
-        js::AutoThreadSafeAccess ts(this);
         return (hasArrayBits & (1 << kind));
     }
     void setHasArray(ArrayKind kind) { hasArrayBits |= (1 << kind); }
     void cloneHasArray(JSScript *script) { hasArrayBits = script->hasArrayBits; }
 
     bool hasConsts()        { return hasArray(CONSTS);      }
     bool hasObjects()       { return hasArray(OBJECTS);     }
     bool hasRegexps()       { return hasArray(REGEXPS);     }
@@ -1400,50 +1339,44 @@ class JSScript : public js::gc::Barriere
     size_t regexpsOffset()    { return OFF(objectsOffset,    hasObjects,    js::ObjectArray);     }
     size_t trynotesOffset()   { return OFF(regexpsOffset,    hasRegexps,    js::ObjectArray);     }
     size_t blockScopesOffset(){ return OFF(trynotesOffset,   hasTrynotes,   js::TryNoteArray);    }
 
     size_t dataSize() const { return dataSize_; }
 
     js::ConstArray *consts() {
         JS_ASSERT(hasConsts());
-        js::AutoThreadSafeAccess ts(this);
         return reinterpret_cast<js::ConstArray *>(data + constsOffset());
     }
 
     js::ObjectArray *objects() {
         JS_ASSERT(hasObjects());
-        js::AutoThreadSafeAccess ts(this);
         return reinterpret_cast<js::ObjectArray *>(data + objectsOffset());
     }
 
     js::ObjectArray *regexps() {
         JS_ASSERT(hasRegexps());
-        js::AutoThreadSafeAccess ts(this);
         return reinterpret_cast<js::ObjectArray *>(data + regexpsOffset());
     }
 
     js::TryNoteArray *trynotes() {
         JS_ASSERT(hasTrynotes());
-        js::AutoThreadSafeAccess ts(this);
         return reinterpret_cast<js::TryNoteArray *>(data + trynotesOffset());
     }
 
     js::BlockScopeArray *blockScopes() {
         JS_ASSERT(hasBlockScopes());
-        js::AutoThreadSafeAccess ts(this);
         return reinterpret_cast<js::BlockScopeArray *>(data + blockScopesOffset());
     }
 
     bool hasLoops();
 
     size_t natoms() const { return natoms_; }
 
     js::HeapPtrAtom &getAtom(size_t index) const {
-        js::AutoThreadSafeAccess ts(this);
         JS_ASSERT(index < natoms());
         return atoms[index];
     }
 
     js::HeapPtrAtom &getAtom(jsbytecode *pc) const {
         JS_ASSERT(containsPC(pc) && containsPC(pc + sizeof(uint32_t)));
         return getAtom(GET_UINT32_INDEX(pc));
     }
@@ -1790,17 +1723,16 @@ class LazyScript : public gc::BarrieredC
     bool directlyInsideEval() const {
         return directlyInsideEval_;
     }
     void setDirectlyInsideEval() {
         directlyInsideEval_ = true;
     }
 
     bool usesArgumentsAndApply() const {
-        AutoThreadSafeAccess ts(this);
         return usesArgumentsAndApply_;
     }
     void setUsesArgumentsAndApply() {
         usesArgumentsAndApply_ = true;
     }
 
     bool hasBeenCloned() const {
         return hasBeenCloned_;
@@ -1815,21 +1747,19 @@ class LazyScript : public gc::BarrieredC
     void setTreatAsRunOnce() {
         treatAsRunOnce_ = true;
     }
 
     ScriptSource *source() const {
         return sourceObject()->source();
     }
     uint32_t begin() const {
-        AutoThreadSafeAccess ts(this);
         return begin_;
     }
     uint32_t end() const {
-        AutoThreadSafeAccess ts(this);
         return end_;
     }
     uint32_t lineno() const {
         return lineno_;
     }
     uint32_t column() const {
         return column_;
     }
--- a/js/src/jsscriptinlines.h
+++ b/js/src/jsscriptinlines.h
@@ -53,18 +53,16 @@ LazyScript::functionDelazifying(JSContex
     return function_;
 }
 
 } // namespace js
 
 inline JSFunction *
 JSScript::functionDelazifying() const
 {
-    js::AutoThreadSafeAccess ts(this);
-    JS_ASSERT(js::CurrentThreadCanWriteCompilationData());
     if (function_ && function_->isInterpretedLazy()) {
         function_->setUnlazifiedScript(const_cast<JSScript *>(this));
         // If this script has a LazyScript, make sure the LazyScript has a
         // reference to the script when delazifying its canonical function.
         if (lazyScript && !lazyScript->maybeScript())
             lazyScript->initScript(const_cast<JSScript *>(this));
     }
     return function_;
@@ -76,29 +74,25 @@ JSScript::setFunction(JSFunction *fun)
     JS_ASSERT(fun->isTenured());
     function_ = fun;
 }
 
 inline void
 JSScript::ensureNonLazyCanonicalFunction(JSContext *cx)
 {
     // Infallibly delazify the canonical script.
-    if (function_ && function_->isInterpretedLazy()) {
-        js::AutoLockForCompilation lock(cx);
+    if (function_ && function_->isInterpretedLazy())
         functionDelazifying();
-    }
 }
 
 inline JSFunction *
 JSScript::getFunction(size_t index)
 {
     JSFunction *fun = &getObject(index)->as<JSFunction>();
-#ifdef DEBUG
     JS_ASSERT_IF(fun->isNative(), IsAsmJSModuleNative(fun->native()));
-#endif
     return fun;
 }
 
 inline JSFunction *
 JSScript::getCallerFunction()
 {
     JS_ASSERT(savedCallerFun());
     return getFunction(0);
@@ -133,49 +127,48 @@ JSScript::getRegExp(jsbytecode *pc)
 
 inline js::GlobalObject &
 JSScript::global() const
 {
     /*
      * A JSScript always marks its compartment's global (via bindings) so we
      * can assert that maybeGlobal is non-null here.
      */
-    js::AutoThreadSafeAccess ts(this);
     return *compartment()->maybeGlobal();
 }
 
 inline JSPrincipals *
 JSScript::principals()
 {
     return compartment()->principals;
 }
 
 inline JSFunction *
-JSScript::donorFunction() const {
+JSScript::donorFunction() const
+{
     if (!isCallsiteClone())
         return nullptr;
     return &enclosingScopeOrOriginalFunction_->as<JSFunction>();
 }
 
 inline void
-JSScript::setIsCallsiteClone(JSObject *fun) {
+JSScript::setIsCallsiteClone(JSObject *fun)
+{
     JS_ASSERT(shouldCloneAtCallsite());
     shouldCloneAtCallsite_ = false;
     isCallsiteClone_ = true;
     JS_ASSERT(isCallsiteClone());
     JS_ASSERT(fun->is<JSFunction>());
     enclosingScopeOrOriginalFunction_ = fun;
 }
 
 inline void
-JSScript::setBaselineScript(JSContext *maybecx, js::jit::BaselineScript *baselineScript) {
+JSScript::setBaselineScript(JSContext *maybecx, js::jit::BaselineScript *baselineScript)
+{
 #ifdef JS_ION
     if (hasBaselineScript())
         js::jit::BaselineScript::writeBarrierPre(tenuredZone(), baseline);
 #endif
-    mozilla::Maybe<js::AutoLockForCompilation> lock;
-    if (maybecx)
-        lock.construct(maybecx);
     baseline = baselineScript;
     updateBaselineOrIonRaw();
 }
 
 #endif /* jsscriptinlines_h */
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -4249,18 +4249,16 @@ bool
 js::CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32_t *result)
 {
     return CompareStringsImpl(cx, str1, str2, result);
 }
 
 int32_t
 js::CompareAtoms(JSAtom *atom1, JSAtom *atom2)
 {
-    AutoThreadSafeAccess ts0(atom1);
-    AutoThreadSafeAccess ts1(atom2);
     return CompareChars(atom1->chars(), atom1->length(), atom2->chars(), atom2->length());
 }
 
 bool
 js::StringEqualsAscii(JSLinearString *str, const char *asciiBytes)
 {
     size_t length = strlen(asciiBytes);
 #ifdef DEBUG
--- a/js/src/jsworkers.cpp
+++ b/js/src/jsworkers.cpp
@@ -88,18 +88,16 @@ js::StartOffThreadIonCompile(JSContext *
     if (!EnsureWorkerThreadsInitialized(cx))
         return false;
 
     AutoLockWorkerThreadState lock;
 
     if (!WorkerThreadState().ionWorklist().append(builder))
         return false;
 
-    cx->runtime()->addCompilationThread();
-
     WorkerThreadState().notifyAll(GlobalWorkerThreadState::PRODUCER);
     return true;
 }
 
 /*
  * Move an IonBuilder for which compilation has either finished, failed, or
  * been cancelled into the global finished compilation list. All off thread
  * compilations which are started must eventually be finished.
@@ -644,18 +642,16 @@ GlobalWorkerThreadState::finishParseTask
 
         JSProtoKey key = js_IdentifyClassPrototype(proto.toObject());
         if (key == JSProto_Null)
             continue;
 
         JSObject *newProto = GetClassPrototypePure(&parseTask->scopeChain->global(), key);
         JS_ASSERT(newProto);
 
-        // Note: this is safe to do without requiring the compilation lock, as
-        // the new type is not yet available to compilation threads.
         object->setProtoUnchecked(newProto);
     }
 
     // Move the parsed script and all its contents into the desired compartment.
     gc::MergeCompartments(parseTask->cx->compartment(), parseTask->scopeChain->compartment());
     parseTask->finish();
 
     RootedScript script(rt, parseTask->script);
@@ -786,21 +782,17 @@ WorkerThread::handleIonWorkload()
 
     {
         AutoUnlockWorkerThreadState unlock;
         PerThreadData::AutoEnterRuntime enter(threadData.addr(),
                                               ionBuilder->script()->runtimeFromAnyThread());
         jit::IonContext ictx(jit::CompileRuntime::get(rt),
                              jit::CompileCompartment::get(ionBuilder->script()->compartment()),
                              &ionBuilder->alloc());
-        AutoEnterIonCompilation ionCompiling;
-        bool succeeded = ionBuilder->build();
-        ionBuilder->clearForBackEnd();
-        if (succeeded)
-            ionBuilder->setBackgroundCodegen(jit::CompileBackEnd(ionBuilder));
+        ionBuilder->setBackgroundCodegen(jit::CompileBackEnd(ionBuilder));
     }
 
     FinishOffThreadIonCompile(ionBuilder);
     ionBuilder = nullptr;
 
     // Ping the main thread so that the compiled code can be incorporated
     // at the next operation callback. Don't interrupt Ion code for this, as
     // this incorporation can be delayed indefinitely without affecting
--- a/js/src/jswrapper.cpp
+++ b/js/src/jswrapper.cpp
@@ -78,19 +78,16 @@ Wrapper::wrappedObject(JSObject *wrapper
     return wrapper->as<ProxyObject>().target();
 }
 
 JS_FRIEND_API(JSObject *)
 js::UncheckedUnwrap(JSObject *wrapped, bool stopAtOuter, unsigned *flagsp)
 {
     unsigned flags = 0;
     while (true) {
-        AutoThreadSafeAccess ts0(wrapped);
-        AutoThreadSafeAccess ts1(wrapped->typeRaw());
-        AutoThreadSafeAccess ts2(wrapped->lastProperty());
         if (!wrapped->is<WrapperObject>() ||
             MOZ_UNLIKELY(stopAtOuter && wrapped->getClass()->ext.innerObject))
         {
             break;
         }
         flags |= Wrapper::wrapperHandler(wrapped)->flags();
         wrapped = wrapped->as<ProxyObject>().private_().toObjectOrNull();
     }
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -5506,19 +5506,16 @@ ProcessArgs(JSContext *cx, JSObject *obj
              jit::js_JitOptions.disableRangeAnalysis = true;
          else
              return OptionFailure("ion-range-analysis", str);
      }
 
     if (op->getBoolOption("ion-check-range-analysis"))
         jit::js_JitOptions.checkRangeAnalysis = true;
 
-    if (op->getBoolOption("ion-check-thread-safety"))
-        jit::js_JitOptions.checkThreadSafety = true;
-
     if (const char *str = op->getStringOption("ion-inlining")) {
         if (strcmp(str, "on") == 0)
             jit::js_JitOptions.disableInlining = false;
         else if (strcmp(str, "off") == 0)
             jit::js_JitOptions.disableInlining = true;
         else
             return OptionFailure("ion-inlining", str);
     }
@@ -5783,18 +5780,16 @@ main(int argc, char **argv, char **envp)
         || !op.addStringOption('\0', "ion-licm", "on/off",
                                "Loop invariant code motion (default: on, off to disable)")
         || !op.addStringOption('\0', "ion-edgecase-analysis", "on/off",
                                "Find edge cases where Ion can avoid bailouts (default: on, off to disable)")
         || !op.addStringOption('\0', "ion-range-analysis", "on/off",
                                "Range analysis (default: on, off to disable)")
         || !op.addBoolOption('\0', "ion-check-range-analysis",
                                "Range analysis checking")
-        || !op.addBoolOption('\0', "ion-check-thread-safety",
-                             "IonBuilder thread safety checking")
         || !op.addStringOption('\0', "ion-inlining", "on/off",
                                "Inline methods where possible (default: on, off to disable)")
         || !op.addStringOption('\0', "ion-osr", "on/off",
                                "On-Stack Replacement (default: on, off to disable)")
         || !op.addStringOption('\0', "ion-limit-script-size", "on/off",
                                "Don't compile very large scripts (default: on, off to disable)")
         || !op.addIntOption('\0', "ion-uses-before-compile", "COUNT",
                             "Wait for COUNT calls or iterations before compiling "
@@ -5893,25 +5888,18 @@ main(int argc, char **argv, char **envp)
     if (stopAt >= 0)
         jit::Simulator::StopSimAt = stopAt;
 #endif
 
     // Start the engine.
     if (!JS_Init())
         return 1;
 
-    // When doing thread safety checks for VM accesses made during Ion compilation,
-    // we rely on protected memory and only the main thread should be active.
-    JSUseHelperThreads useHelperThreads =
-        op.getBoolOption("ion-check-thread-safety")
-        ? JS_NO_HELPER_THREADS
-        : JS_USE_HELPER_THREADS;
-
     /* Use the same parameters as the browser in xpcjsruntime.cpp. */
-    rt = JS_NewRuntime(32L * 1024L * 1024L, useHelperThreads);
+    rt = JS_NewRuntime(32L * 1024L * 1024L, JS_USE_HELPER_THREADS);
     if (!rt)
         return 1;
     gTimeoutFunc = NullValue();
     if (!JS_AddNamedValueRootRT(rt, &gTimeoutFunc, "gTimeoutFunc"))
         return 1;
 
     JS_SetGCParameter(rt, JSGC_MAX_BYTES, 0xffffffff);
 #ifdef JSGC_GENERATIONAL
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -549,24 +549,24 @@ GlobalObject::create(JSContext *cx, cons
 }
 
 /* static */ bool
 GlobalObject::getOrCreateEval(JSContext *cx, Handle<GlobalObject*> global,
                               MutableHandleObject eval)
 {
     if (!global->getOrCreateObjectPrototype(cx))
         return false;
-    eval.set(&global->getSlotForCompilation(EVAL).toObject());
+    eval.set(&global->getSlot(EVAL).toObject());
     return true;
 }
 
 bool
 GlobalObject::valueIsEval(Value val)
 {
-    Value eval = getSlotForCompilation(EVAL);
+    Value eval = getSlot(EVAL);
     return eval.isObject() && eval == val;
 }
 
 /* static */ bool
 GlobalObject::initStandardClasses(JSContext *cx, Handle<GlobalObject*> global)
 {
     /* Define a top-level property 'undefined' with the undefined value. */
     if (!JSObject::defineProperty(cx, global, cx->names().undefined, UndefinedHandleValue,
@@ -783,28 +783,23 @@ GlobalObject::getSelfHostedFunction(JSCo
     return cx->global()->addIntrinsicValue(cx, shId, funVal);
 }
 
 bool
 GlobalObject::addIntrinsicValue(JSContext *cx, HandleId id, HandleValue value)
 {
     RootedObject holder(cx, intrinsicsHolder());
 
-    // Work directly with the shape machinery underlying the object, so that we
-    // don't take the compilation lock until we are ready to update the object
-    // without triggering a GC.
-
     uint32_t slot = holder->slotSpan();
     RootedShape last(cx, holder->lastProperty());
     Rooted<UnownedBaseShape*> base(cx, last->base()->unowned());
 
     StackShape child(base, id, slot, 0, 0, 0);
     RootedShape shape(cx, cx->compartment()->propertyTree.getChild(cx, last, child));
     if (!shape)
         return false;
 
-    AutoLockForCompilation lock(cx);
     if (!JSObject::setLastProperty(cx, holder, shape))
         return false;
 
     holder->setSlot(shape->slot(), value);
     return true;
 }
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -153,29 +153,29 @@ class GlobalObject : public JSObject
     // for each global object it's called on, and every other call does
     // nothing.
     static bool
     warnOnceAbout(JSContext *cx, HandleObject obj, uint32_t slot, unsigned errorNumber);
 
   public:
     Value getConstructor(JSProtoKey key) const {
         JS_ASSERT(key <= JSProto_LIMIT);
-        return getSlotForCompilation(APPLICATION_SLOTS + key);
+        return getSlot(APPLICATION_SLOTS + key);
     }
     static bool ensureConstructor(JSContext *cx, Handle<GlobalObject*> global, JSProtoKey key);
     static bool initConstructor(JSContext *cx, Handle<GlobalObject*> global, JSProtoKey key);
 
     void setConstructor(JSProtoKey key, const Value &v) {
         JS_ASSERT(key <= JSProto_LIMIT);
         setSlot(APPLICATION_SLOTS + key, v);
     }
 
     Value getPrototype(JSProtoKey key) const {
         JS_ASSERT(key <= JSProto_LIMIT);
-        return getSlotForCompilation(APPLICATION_SLOTS + JSProto_LIMIT + key);
+        return getSlot(APPLICATION_SLOTS + JSProto_LIMIT + key);
     }
 
     void setPrototype(JSProtoKey key, const Value &value) {
         JS_ASSERT(key <= JSProto_LIMIT);
         setSlot(APPLICATION_SLOTS + JSProto_LIMIT + key, value);
     }
 
     static uint32_t constructorPropertySlot(JSProtoKey key) {
@@ -452,29 +452,16 @@ class GlobalObject : public JSObject
         if (v.isObject())
             return &v.toObject();
         Rooted<GlobalObject*> self(cx, this);
         if (!init(cx, self))
             return nullptr;
         return &self->getSlot(slot).toObject();
     }
 
-    Value getSlotForCompilation(uint32_t slot) const {
-        // This method should only be used for slots that are either eagerly
-        // initialized on creation of the global or only change under the
-        // compilation lock. Note that the dynamic slots pointer for global
-        // objects can only change under the compilation lock.
-        JS_ASSERT(slot < JSCLASS_RESERVED_SLOTS(getClass()));
-        uint32_t fixed = numFixedSlotsForCompilation();
-        AutoThreadSafeAccess ts(this);
-        if (slot < fixed)
-            return fixedSlots()[slot];
-        return slots[slot - fixed];
-    }
-
   public:
     static JSObject *getOrCreateIteratorPrototype(JSContext *cx,
                                                   Handle<GlobalObject*> global)
     {
         if (!ensureConstructor(cx, global, JSProto_Iterator))
             return nullptr;
         return &global->getSlot(APPLICATION_SLOTS + JSProto_LIMIT + JSProto_Iterator).toObject();
     }
@@ -542,28 +529,23 @@ class GlobalObject : public JSObject
     JSObject *getOrCreateDataViewPrototype(JSContext *cx) {
         Rooted<GlobalObject*> self(cx, this);
         if (!ensureConstructor(cx, self, JSProto_DataView))
             return nullptr;
         return &self->getPrototype(JSProto_DataView).toObject();
     }
 
     JSObject *intrinsicsHolder() {
-        JS_ASSERT(!getSlotForCompilation(INTRINSICS).isUndefined());
-        return &getSlotForCompilation(INTRINSICS).toObject();
+        JS_ASSERT(!getSlot(INTRINSICS).isUndefined());
+        return &getSlot(INTRINSICS).toObject();
     }
 
     bool maybeGetIntrinsicValue(jsid id, Value *vp) {
-        JS_ASSERT(CurrentThreadCanReadCompilationData());
         JSObject *holder = intrinsicsHolder();
 
-        AutoThreadSafeAccess ts0(holder);
-        AutoThreadSafeAccess ts1(holder->lastProperty());
-        AutoThreadSafeAccess ts2(holder->lastProperty()->base());
-
         if (Shape *shape = holder->nativeLookupPure(id)) {
             *vp = holder->getSlot(shape->slot());
             return true;
         }
         return false;
     }
     bool maybeGetIntrinsicValue(PropertyName *name, Value *vp) {
         return maybeGetIntrinsicValue(NameToId(name), vp);
@@ -591,18 +573,17 @@ class GlobalObject : public JSObject
         RootedValue valCopy(cx, value);
         return JSObject::setProperty(cx, holder, holder, name, &valCopy, false);
     }
 
     bool getSelfHostedFunction(JSContext *cx, HandleAtom selfHostedName, HandleAtom name,
                                unsigned nargs, MutableHandleValue funVal);
 
     RegExpStatics *getRegExpStatics() const {
-        JSObject &resObj = getSlotForCompilation(REGEXP_STATICS).toObject();
-        AutoThreadSafeAccess ts(&resObj);
+        JSObject &resObj = getSlot(REGEXP_STATICS).toObject();
         return static_cast<RegExpStatics *>(resObj.getPrivate(/* nfixed = */ 1));
     }
 
     JSObject *getThrowTypeError() const {
         JS_ASSERT(functionObjectClassesInitialized());
         return &getSlot(THROWTYPEERROR).toObject();
     }
 
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1315,17 +1315,17 @@ SetObjectElementOperation(JSContext *cx,
 
 #ifdef JS_ION
     if (obj->isNative() && JSID_IS_INT(id)) {
         uint32_t length = obj->getDenseInitializedLength();
         int32_t i = JSID_TO_INT(id);
         if ((uint32_t)i >= length) {
             // Annotate script if provided with information (e.g. baseline)
             if (script && script->hasBaselineScript() && *pc == JSOP_SETELEM)
-                script->baselineScript()->noteArrayWriteHole(cx, script->pcToOffset(pc));
+                script->baselineScript()->noteArrayWriteHole(script->pcToOffset(pc));
         }
     }
 #endif
 
     if (obj->isNative() && !JSID_IS_INT(id) && !obj->setHadElementsAccess(cx))
         return false;
 
     RootedValue tmp(cx, value);
--- a/js/src/vm/ObjectImpl.cpp
+++ b/js/src/vm/ObjectImpl.cpp
@@ -330,35 +330,16 @@ js::ObjectImpl::nativeLookup(ExclusiveCo
 Shape *
 js::ObjectImpl::nativeLookupPure(jsid id)
 {
     MOZ_ASSERT(isNative());
     return Shape::searchNoHashify(lastProperty(), id);
 }
 
 uint32_t
-js::ObjectImpl::numFixedSlotsForCompilation() const
-{
-    // This is an alternative method for getting the number of fixed slots
-    // in an object. It requires more logic and memory accesses than
-    // numFixedSlots() but is safe to be called from the compilation thread,
-    // even if the main thread is actively mutating the VM.
-    if (static_cast<const JSObject *>(this)->is<ArrayObject>())
-        return 0;
-#ifdef JSGC_GENERATIONAL
-    // The compiler does not have access to nursery things, so if this object
-    // is in the nursery we can fall back to numFixedSlots().
-    if (IsInsideNursery(GetGCThingRuntime(this), this))
-        return numFixedSlots();
-#endif
-    gc::AllocKind kind = tenuredGetAllocKind();
-    return gc::GetGCKindSlots(kind, getClass());
-}
-
-uint32_t
 js::ObjectImpl::dynamicSlotsCount(uint32_t nfixed, uint32_t span, const Class *clasp)
 {
     if (span <= nfixed)
         return 0;
     span -= nfixed;
 
     // Increase the slots to SLOT_CAPACITY_MIN to decrease the likelihood
     // the dynamic slots need to get increased again. ArrayObjects ignore
--- a/js/src/vm/ObjectImpl.h
+++ b/js/src/vm/ObjectImpl.h
@@ -979,24 +979,22 @@ class ObjectImpl : public gc::BarrieredC
     const JSObject * asObjectPtr() const { return reinterpret_cast<const JSObject *>(this); }
 
     friend inline Value ObjectValue(ObjectImpl &obj);
 
     /* These functions are public, and they should remain public. */
 
   public:
     TaggedProto getTaggedProto() const {
-        AutoThreadSafeAccess ts(this);
         return type_->proto();
     }
 
     bool hasTenuredProto() const;
 
     const Class *getClass() const {
-        AutoThreadSafeAccess ts(this);
         return type_->clasp();
     }
 
     static inline bool
     isExtensible(ExclusiveContext *cx, Handle<ObjectImpl*> obj, bool *extensible);
 
     // Indicates whether a non-proxy is extensible.  Don't call on proxies!
     // This method really shouldn't exist -- but there are a few internal
@@ -1201,42 +1199,36 @@ class ObjectImpl : public gc::BarrieredC
     }
 
     types::TypeObject *type() const {
         MOZ_ASSERT(!hasLazyType());
         return typeRaw();
     }
 
     types::TypeObject *typeRaw() const {
-        AutoThreadSafeAccess ts0(this);
-        AutoThreadSafeAccess ts1(type_);
         return type_;
     }
 
     uint32_t numFixedSlots() const {
         return reinterpret_cast<const shadow::Object *>(this)->numFixedSlots();
     }
 
-    uint32_t numFixedSlotsForCompilation() const;
-
     /*
      * Whether this is the only object which has its specified type. This
      * object will have its type constructed lazily as needed by analysis.
      */
     bool hasSingletonType() const {
-        AutoThreadSafeAccess ts(this);
         return !!type_->singleton();
     }
 
     /*
      * Whether the object's type has not been constructed yet. If an object
      * might have a lazy type, use getType() below, otherwise type().
      */
     bool hasLazyType() const {
-        AutoThreadSafeAccess ts(this);
         return type_->lazy();
     }
 
     uint32_t slotSpan() const {
         if (inDictionaryMode())
             return lastProperty()->base()->slotSpan();
         return lastProperty()->slotSpan();
     }
@@ -1386,17 +1378,17 @@ class ObjectImpl : public gc::BarrieredC
     /* For slots which are known to always be fixed, due to the way they are allocated. */
 
     HeapSlot &getFixedSlotRef(uint32_t slot) {
         MOZ_ASSERT(slot < numFixedSlots());
         return fixedSlots()[slot];
     }
 
     const Value &getFixedSlot(uint32_t slot) const {
-        MOZ_ASSERT(slot < numFixedSlotsForCompilation());
+        MOZ_ASSERT(slot < numFixedSlots());
         return fixedSlots()[slot];
     }
 
     void setFixedSlot(uint32_t slot, const Value &value) {
         MOZ_ASSERT(slot < numFixedSlots());
         fixedSlots()[slot].set(this->asObjectPtr(), HeapSlot::Slot, slot, value);
     }
 
@@ -1473,17 +1465,17 @@ class ObjectImpl : public gc::BarrieredC
     /* Private data accessors. */
 
     inline void *&privateRef(uint32_t nfixed) const { /* XXX should be private, not protected! */
         /*
          * The private pointer of an object can hold any word sized value.
          * Private pointers are stored immediately after the last fixed slot of
          * the object.
          */
-        MOZ_ASSERT(nfixed == numFixedSlotsForCompilation());
+        MOZ_ASSERT(nfixed == numFixedSlots());
         MOZ_ASSERT(hasPrivate());
         HeapSlot *end = &fixedSlots()[nfixed];
         return *reinterpret_cast<void**>(end);
     }
 
     bool hasPrivate() const {
         return getClass()->hasPrivate();
     }
@@ -1550,20 +1542,16 @@ BarrieredCell<ObjectImpl>::zone() const
     return zone;
 }
 
 template <>
 MOZ_ALWAYS_INLINE Zone *
 BarrieredCell<ObjectImpl>::zoneFromAnyThread() const
 {
     const ObjectImpl* obj = static_cast<const ObjectImpl*>(this);
-
-    // Note: This read of obj->shape_ may race, though the zone fetched will be the same.
-    AutoThreadSafeAccess ts(obj->shape_);
-
     return obj->shape_->zoneFromAnyThread();
 }
 
 // TypeScript::global uses 0x1 as a special value.
 template<>
 /* static */ inline bool
 BarrieredCell<ObjectImpl>::isNullLike(ObjectImpl *obj)
 {
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -75,19 +75,16 @@ PerThreadData::PerThreadData(JSRuntime *
     activation_(nullptr),
     asmJSActivationStack_(nullptr),
 #ifdef JS_ARM_SIMULATOR
     simulator_(nullptr),
     simulatorStackLimit_(0),
 #endif
     dtoaState(nullptr),
     suppressGC(0),
-#ifdef DEBUG
-    ionCompiling(false),
-#endif
     activeCompilations(0)
 {}
 
 PerThreadData::~PerThreadData()
 {
     if (dtoaState)
         js_DestroyDtoaState(dtoaState);
 
@@ -127,22 +124,16 @@ JSRuntime::JSRuntime(JSUseHelperThreads 
     operationCallback(nullptr),
 #ifdef JS_THREADSAFE
     operationCallbackLock(nullptr),
     operationCallbackOwner(nullptr),
     exclusiveAccessLock(nullptr),
     exclusiveAccessOwner(nullptr),
     mainThreadHasExclusiveAccess(false),
     numExclusiveThreads(0),
-    compilationLock(nullptr),
-#ifdef DEBUG
-    compilationLockOwner(nullptr),
-    mainThreadHasCompilationLock(false),
-#endif
-    numCompilationThreads(0),
 #else
     operationCallbackLockTaken(false),
 #endif
     systemZone(nullptr),
     numCompartments(0),
     localeCallbacks(nullptr),
     defaultLocale(nullptr),
     defaultVersion_(JSVERSION_DEFAULT),
@@ -275,17 +266,16 @@ JSRuntime::JSRuntime(JSUseHelperThreads 
     structuredCloneCallbacks(nullptr),
     telemetryCallback(nullptr),
     propertyRemovals(0),
 #if !EXPOSE_INTL_API
     thousandsSeparator(0),
     decimalSeparator(0),
     numGrouping(0),
 #endif
-    heapProtected_(false),
     mathCache_(nullptr),
     activeCompilations_(0),
     keepAtoms_(0),
     trustedPrincipals_(nullptr),
     atomsCompartment_(nullptr),
     beingDestroyed_(false),
     wrapObjectCallbacks(&DefaultWrapObjectCallbacks),
     preserveWrapperCallback(nullptr),
@@ -355,20 +345,16 @@ JSRuntime::init(uint32_t maxbytes)
 
     gcLock = PR_NewLock();
     if (!gcLock)
         return false;
 
     exclusiveAccessLock = PR_NewLock();
     if (!exclusiveAccessLock)
         return false;
-
-    compilationLock = PR_NewLock();
-    if (!compilationLock)
-        return false;
 #endif
 
     if (!mainThread.init())
         return false;
 
     js::TlsPerThreadData.set(&mainThread);
 
     if (!threadPool.init())
@@ -490,20 +476,16 @@ JSRuntime::~JSRuntime()
     JS_ASSERT(!exclusiveAccessOwner);
     if (exclusiveAccessLock)
         PR_DestroyLock(exclusiveAccessLock);
 
     // Avoid bogus asserts during teardown.
     JS_ASSERT(!numExclusiveThreads);
     mainThreadHasExclusiveAccess = true;
 
-    JS_ASSERT(!compilationLockOwner);
-    if (compilationLock)
-        PR_DestroyLock(compilationLock);
-
     JS_ASSERT(!operationCallbackOwner);
     if (operationCallbackLock)
         PR_DestroyLock(operationCallbackLock);
 #endif
 
     /*
      * Even though all objects in the compartment are dead, we may have keep
      * some filenames around because of gcKeepAtoms.
@@ -854,86 +836,16 @@ JSRuntime::onOutOfMemory(void *p, size_t
 
 bool
 JSRuntime::activeGCInAtomsZone()
 {
     Zone *zone = atomsCompartment_->zone();
     return zone->needsBarrier() || zone->isGCScheduled() || zone->wasGCStarted();
 }
 
-#ifdef JS_CAN_CHECK_THREADSAFE_ACCESSES
-
-AutoProtectHeapForIonCompilation::AutoProtectHeapForIonCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
-  : runtime(rt)
-{
-    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-
-    JS_ASSERT(!runtime->heapProtected_);
-    runtime->heapProtected_ = true;
-
-    for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) {
-        Chunk *chunk = r.front();
-        // Note: Don't protect the last page in the chunk, which stores
-        // immutable info and needs to be accessible for runtimeFromAnyThread()
-        // in AutoThreadSafeAccess.
-        if (mprotect(chunk, ChunkSize - sizeof(Arena), PROT_NONE))
-            MOZ_CRASH();
-    }
-}
-
-AutoProtectHeapForIonCompilation::~AutoProtectHeapForIonCompilation()
-{
-    JS_ASSERT(runtime->heapProtected_);
-    JS_ASSERT(runtime->unprotectedArenas.empty());
-    runtime->heapProtected_ = false;
-
-    for (GCChunkSet::Range r(runtime->gcChunkSet.all()); !r.empty(); r.popFront()) {
-        Chunk *chunk = r.front();
-        if (mprotect(chunk, ChunkSize - sizeof(Arena), PROT_READ | PROT_WRITE))
-            MOZ_CRASH();
-    }
-}
-
-AutoThreadSafeAccess::AutoThreadSafeAccess(const Cell *cell MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
-  : runtime(cell->runtimeFromAnyThread()), arena(nullptr)
-{
-    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-
-    if (!runtime->heapProtected_)
-        return;
-
-    ArenaHeader *base = cell->arenaHeader();
-    for (size_t i = 0; i < runtime->unprotectedArenas.length(); i++) {
-        if (base == runtime->unprotectedArenas[i])
-            return;
-    }
-
-    arena = base;
-
-    if (mprotect(arena, sizeof(Arena), PROT_READ | PROT_WRITE))
-        MOZ_CRASH();
-
-    if (!runtime->unprotectedArenas.append(arena))
-        MOZ_CRASH();
-}
-
-AutoThreadSafeAccess::~AutoThreadSafeAccess()
-{
-    if (!arena)
-        return;
-
-    if (mprotect(arena, sizeof(Arena), PROT_NONE))
-        MOZ_CRASH();
-
-    JS_ASSERT(arena == runtime->unprotectedArenas.back());
-    runtime->unprotectedArenas.popBack();
-}
-
-#endif // JS_CAN_CHECK_THREADSAFE_ACCESSES
-
 #ifdef JS_THREADSAFE
 
 void
 JSRuntime::setUsedByExclusiveThread(Zone *zone)
 {
     JS_ASSERT(!zone->usedByExclusiveThread);
     zone->usedByExclusiveThread = true;
     numExclusiveThreads++;
@@ -988,87 +900,27 @@ JSRuntime::assertCanLock(RuntimeLock whi
     // In the switch below, each case falls through to the one below it. None
     // of the runtime locks are reentrant, and when multiple locks are acquired
     // it must be done in the order below.
     switch (which) {
       case ExclusiveAccessLock:
         JS_ASSERT(exclusiveAccessOwner != PR_GetCurrentThread());
       case WorkerThreadStateLock:
         JS_ASSERT(!WorkerThreadState().isLocked());
-      case CompilationLock:
-        JS_ASSERT(compilationLockOwner != PR_GetCurrentThread());
       case OperationCallbackLock:
         JS_ASSERT(!currentThreadOwnsOperationCallbackLock());
       case GCLock:
         JS_ASSERT(gcLockOwner != PR_GetCurrentThread());
         break;
       default:
         MOZ_CRASH();
     }
 #endif // JS_THREADSAFE
 }
 
-AutoEnterIonCompilation::AutoEnterIonCompilation(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
-{
-    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-
-#ifdef JS_THREADSAFE
-    PerThreadData *pt = js::TlsPerThreadData.get();
-    JS_ASSERT(!pt->ionCompiling);
-    pt->ionCompiling = true;
-#endif
-}
-
-AutoEnterIonCompilation::~AutoEnterIonCompilation()
-{
-#ifdef JS_THREADSAFE
-    PerThreadData *pt = js::TlsPerThreadData.get();
-    JS_ASSERT(pt->ionCompiling);
-    pt->ionCompiling = false;
-#endif
-}
-
-bool
-js::CurrentThreadCanWriteCompilationData()
-{
-#ifdef JS_THREADSAFE
-    PerThreadData *pt = TlsPerThreadData.get();
-
-    // Data can only be read from during compilation.
-    if (pt->ionCompiling)
-        return false;
-
-    // Ignore what threads with exclusive contexts are doing; these never have
-    // run scripts or have associated compilation threads.
-    JSRuntime *rt = pt->runtimeIfOnOwnerThread();
-    if (!rt)
-        return true;
-
-    return rt->currentThreadHasCompilationLock();
-#else
-    return true;
-#endif
-}
-
-bool
-js::CurrentThreadCanReadCompilationData()
-{
-#ifdef JS_THREADSAFE
-    PerThreadData *pt = TlsPerThreadData.get();
-
-    // Data can always be read from freely outside of compilation.
-    if (!pt || !pt->ionCompiling)
-        return true;
-
-    return pt->runtime_->currentThreadHasCompilationLock();
-#else
-    return true;
-#endif
-}
-
 void
 js::AssertCurrentThreadCanLock(RuntimeLock which)
 {
 #ifdef JS_THREADSAFE
     PerThreadData *pt = TlsPerThreadData.get();
     if (pt && pt->runtime_)
         pt->runtime_->assertCanLock(which);
 #endif
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -478,17 +478,16 @@ AtomStateOffsetToName(const JSAtomState 
 }
 
 // There are several coarse locks in the enum below. These may be either
 // per-runtime or per-process. When acquiring more than one of these locks,
 // the acquisition must be done in the order below to avoid deadlocks.
 enum RuntimeLock {
     ExclusiveAccessLock,
     WorkerThreadStateLock,
-    CompilationLock,
     OperationCallbackLock,
     GCLock
 };
 
 #ifdef DEBUG
 void AssertCurrentThreadCanLock(RuntimeLock which);
 #else
 inline void AssertCurrentThreadCanLock(RuntimeLock which) {}
@@ -548,17 +547,16 @@ class PerThreadData : public PerThreadDa
      * synchronized (by rt->operationCallbackLock).
      */
   private:
     friend class js::Activation;
     friend class js::ActivationIterator;
     friend class js::jit::JitActivation;
     friend class js::AsmJSActivation;
 #ifdef DEBUG
-    friend bool js::CurrentThreadCanReadCompilationData();
     friend void js::AssertCurrentThreadCanLock(RuntimeLock which);
 #endif
 
     /*
      * Points to the most recent activation running on the thread.
      * See Activation comment in vm/Stack.h.
      */
     js::Activation *activation_;
@@ -598,21 +596,16 @@ class PerThreadData : public PerThreadDa
      * to suppress GC when reporting an OOM (see js_ReportOutOfMemory) and in
      * debugging facilities that cannot tolerate a GC and would rather OOM
      * immediately, such as utilities exposed to GDB. Setting this flag is
      * extremely dangerous and should only be used when in an OOM situation or
      * in non-exposed debugging facilities.
      */
     int32_t suppressGC;
 
-#ifdef DEBUG
-    // Whether this thread is actively Ion compiling.
-    bool ionCompiling;
-#endif
-
     // Number of active bytecode compilation on this thread.
     unsigned activeCompilations;
 
     PerThreadData(JSRuntime *runtime);
     ~PerThreadData();
 
     bool init();
 
@@ -653,18 +646,16 @@ class PerThreadData : public PerThreadDa
 
 namespace gc {
 class MarkingValidator;
 } // namespace gc
 
 typedef Vector<JS::Zone *, 4, SystemAllocPolicy> ZoneVector;
 
 class AutoLockForExclusiveAccess;
-class AutoLockForCompilation;
-class AutoProtectHeapForIonCompilation;
 
 void RecomputeStackLimit(JSRuntime *rt, StackKind kind);
 
 } // namespace js
 
 struct JSRuntime : public JS::shadow::Runtime,
                    public js::MallocProvider<JSRuntime>
 {
@@ -769,38 +760,16 @@ struct JSRuntime : public JS::shadow::Ru
     mozilla::DebugOnly<PRThread *> exclusiveAccessOwner;
     mozilla::DebugOnly<bool> mainThreadHasExclusiveAccess;
 
     /* Number of non-main threads with an ExclusiveContext. */
     size_t numExclusiveThreads;
 
     friend class js::AutoLockForExclusiveAccess;
 
-    /*
-     * Lock taken when using data that can be modified by the main thread but
-     * read by Ion compilation threads. Any time either the main thread writes
-     * such data or the compilation thread reads it, this lock must be taken.
-     * Note that no externally visible data is modified by the compilation
-     * thread, so the main thread never needs to take this lock when reading.
-     */
-    PRLock *compilationLock;
-#ifdef DEBUG
-    PRThread *compilationLockOwner;
-    bool mainThreadHasCompilationLock;
-#endif
-
-    /* Number of in flight Ion compilations. */
-    size_t numCompilationThreads;
-
-    friend class js::AutoLockForCompilation;
-#ifdef DEBUG
-    friend bool js::CurrentThreadCanWriteCompilationData();
-    friend bool js::CurrentThreadCanReadCompilationData();
-#endif
-
   public:
     void setUsedByExclusiveThread(JS::Zone *zone);
     void clearUsedByExclusiveThread(JS::Zone *zone);
 
 #endif // JS_THREADSAFE
 
 #ifdef DEBUG
     bool currentThreadHasExclusiveAccess() {
@@ -816,51 +785,16 @@ struct JSRuntime : public JS::shadow::Ru
     bool exclusiveThreadsPresent() const {
 #ifdef JS_THREADSAFE
         return numExclusiveThreads > 0;
 #else
         return false;
 #endif
     }
 
-    void addCompilationThread() {
-#ifdef JS_THREADSAFE
-        numCompilationThreads++;
-#else
-        MOZ_ASSUME_UNREACHABLE("No threads");
-#endif
-    }
-    void removeCompilationThread() {
-#ifdef JS_THREADSAFE
-        JS_ASSERT(numCompilationThreads);
-        numCompilationThreads--;
-#else
-        MOZ_ASSUME_UNREACHABLE("No threads");
-#endif
-    }
-
-    bool compilationThreadsPresent() const {
-#ifdef JS_THREADSAFE
-        return numCompilationThreads > 0;
-#else
-        return false;
-#endif
-    }
-
-#ifdef DEBUG
-    bool currentThreadHasCompilationLock() {
-#ifdef JS_THREADSAFE
-        return (!numCompilationThreads && mainThreadHasCompilationLock) ||
-               compilationLockOwner == PR_GetCurrentThread();
-#else
-        return true;
-#endif
-    }
-#endif // DEBUG
-
     /* Embedders can use this zone however they wish. */
     JS::Zone            *systemZone;
 
     /* List of compartments and zones (protected by the GC lock). */
     js::ZoneVector      zones;
 
     /* How many compartments there are across all zones. */
     size_t              numCompartments;
@@ -1469,28 +1403,16 @@ struct JSRuntime : public JS::shadow::Ru
 
 #if !EXPOSE_INTL_API
     /* Number localization, used by jsnum.cpp. */
     const char          *thousandsSeparator;
     const char          *decimalSeparator;
     const char          *numGrouping;
 #endif
 
-    friend class js::AutoProtectHeapForIonCompilation;
-    friend class js::AutoThreadSafeAccess;
-    mozilla::DebugOnly<bool> heapProtected_;
-#ifdef DEBUG
-    js::Vector<js::gc::ArenaHeader *, 0, js::SystemAllocPolicy> unprotectedArenas;
-
-  public:
-    bool heapProtected() {
-        return heapProtected_;
-    }
-#endif
-
   private:
     js::MathCache *mathCache_;
     js::MathCache *createMathCache(JSContext *cx);
   public:
     js::MathCache *getMathCache(JSContext *cx) {
         return mathCache_ ? mathCache_ : createMathCache(cx);
     }
     js::MathCache *maybeGetMathCache() {
@@ -2078,52 +2000,15 @@ class RuntimeAllocPolicy
     void *calloc_(size_t bytes) { return runtime->calloc_(bytes); }
     void *realloc_(void *p, size_t bytes) { return runtime->realloc_(p, bytes); }
     void free_(void *p) { js_free(p); }
     void reportAllocOverflow() const {}
 };
 
 extern const JSSecurityCallbacks NullSecurityCallbacks;
 
-// Debugging RAII class which marks the current thread as performing an Ion
-// compilation, for use by CurrentThreadCan{Read,Write}CompilationData
-class AutoEnterIonCompilation
-{
-  public:
-#ifdef DEBUG
-    AutoEnterIonCompilation(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
-    ~AutoEnterIonCompilation();
-#else
-    AutoEnterIonCompilation(MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-    {
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    }
-#endif
-    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
-// Debugging RAII class which protects the entire GC heap for the duration of an
-// Ion compilation. When used only the main thread will be active and all
-// accesses to GC things must be wrapped by an AutoThreadSafeAccess instance.
-class AutoProtectHeapForIonCompilation
-{
-  public:
-#ifdef JS_CAN_CHECK_THREADSAFE_ACCESSES
-    JSRuntime *runtime;
-
-    AutoProtectHeapForIonCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
-    ~AutoProtectHeapForIonCompilation();
-#else
-    AutoProtectHeapForIonCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-    {
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    }
-#endif
-    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
 } /* namespace js */
 
 #ifdef _MSC_VER
 #pragma warning(pop)
 #endif
 
 #endif /* vm_Runtime_h */
--- a/js/src/vm/ScopeObject-inl.h
+++ b/js/src/vm/ScopeObject-inl.h
@@ -71,20 +71,18 @@ StaticScopeIter<allowGC>::hasDynamicScop
 }
 
 template <AllowGC allowGC>
 inline Shape *
 StaticScopeIter<allowGC>::scopeShape() const
 {
     JS_ASSERT(hasDynamicScopeObject());
     JS_ASSERT(type() != NAMED_LAMBDA);
-    if (type() == BLOCK) {
-        AutoThreadSafeAccess ts(&block());
+    if (type() == BLOCK)
         return block().lastProperty();
-    }
     return funScript()->callObjShape();
 }
 
 template <AllowGC allowGC>
 inline typename StaticScopeIter<allowGC>::Type
 StaticScopeIter<allowGC>::type() const
 {
     if (onNamedLambda)
--- a/js/src/vm/ScopeObject.h
+++ b/js/src/vm/ScopeObject.h
@@ -195,17 +195,16 @@ class ScopeObject : public JSObject
 
   public:
     /*
      * Since every scope chain terminates with a global object and GlobalObject
      * does not derive ScopeObject (it has a completely different layout), the
      * enclosing scope of a ScopeObject is necessarily non-null.
      */
     inline JSObject &enclosingScope() const {
-        AutoThreadSafeAccess ts(this);
         return getFixedSlot(SCOPE_CHAIN_SLOT).toObject();
     }
 
     void setEnclosingScope(HandleObject obj);
 
     /*
      * Get or set an aliased variable contained in this scope. Unaliased
      * variables should instead access the StackFrame. Aliased variable access
@@ -247,29 +246,27 @@ class CallObject : public ScopeObject
 
     static CallObject *createForFunction(JSContext *cx, HandleObject enclosing, HandleFunction callee);
 
     static CallObject *createForFunction(JSContext *cx, AbstractFramePtr frame);
     static CallObject *createForStrictEval(JSContext *cx, AbstractFramePtr frame);
 
     /* True if this is for a strict mode eval frame. */
     bool isForEval() const {
-        AutoThreadSafeAccess ts(this);
         JS_ASSERT(getFixedSlot(CALLEE_SLOT).isObjectOrNull());
         JS_ASSERT_IF(getFixedSlot(CALLEE_SLOT).isObject(),
                      getFixedSlot(CALLEE_SLOT).toObject().is<JSFunction>());
         return getFixedSlot(CALLEE_SLOT).isNull();
     }
 
     /*
      * Returns the function for which this CallObject was created. (This may
      * only be called if !isForEval.)
      */
     JSFunction &callee() const {
-        AutoThreadSafeAccess ts(this);
         return getFixedSlot(CALLEE_SLOT).toObject().as<JSFunction>();
     }
 
     /* Get/set the aliased variable referred to by 'bi'. */
     const Value &aliasedVar(AliasedFormalIter fi) {
         return getSlot(fi.scopeSlot());
     }
 
@@ -405,17 +402,17 @@ class BlockObject : public NestedScopeOb
 
     /* Return the abstract stack depth right before entering this nested scope. */
     uint32_t stackDepth() const {
         return getReservedSlot(DEPTH_SLOT).toPrivateUint32();
     }
 
     /* Return the number of variables associated with this block. */
     uint32_t slotCount() const {
-        return propertyCountForCompilation();
+        return propertyCount();
     }
 
     /*
      * Return the local corresponding to the ith binding where i is in the
      * range [0, slotCount()) and the return local index is in the range
      * [script->nfixed, script->nfixed + script->nslots).
      */
     uint32_t slotToLocalIndex(const Bindings &bindings, uint32_t slot) {
@@ -459,19 +456,16 @@ class StaticBlockObject : public BlockOb
         return slotValue(i).isTrue();
     }
 
     /*
      * A static block object is cloned (when entering the block) iff some
      * variable of the block isAliased.
      */
     bool needsClone() {
-        // The first variable slot will always indicate whether the object has
-        // any aliased vars. Bypass slotValue() to allow testing this off thread.
-        AutoThreadSafeAccess ts(this);
         return !getFixedSlot(RESERVED_SLOTS).isFalse();
     }
 
     /* Frontend-only functions ***********************************************/
 
     /* Initialization functions for above fields. */
     void setAliased(unsigned i, bool aliased) {
         JS_ASSERT_IF(i > 0, slotValue(i-1).isBoolean());
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -1021,23 +1021,21 @@ class Shape : public gc::BarrieredCell<S
 
         Shape &front() const {
             JS_ASSERT(!empty());
             return *cursor;
         }
 
         void popFront() {
             JS_ASSERT(!empty());
-            AutoThreadSafeAccess ts(cursor);
             cursor = cursor->parent;
         }
     };
 
     const Class *getObjectClass() const {
-        AutoThreadSafeAccess ts(base());
         return base()->clasp;
     }
     JSObject *getObjectParent() const { return base()->parent; }
     JSObject *getObjectMetadata() const { return base()->metadata; }
 
     static Shape *setObjectParent(ExclusiveContext *cx,
                                   JSObject *obj, TaggedProto proto, Shape *last);
     static Shape *setObjectMetadata(JSContext *cx,
@@ -1087,17 +1085,16 @@ class Shape : public gc::BarrieredCell<S
   public:
     /* Public bits stored in shape->flags. */
     enum {
         HAS_SHORTID     = 0x40,
         PUBLIC_FLAGS    = HAS_SHORTID
     };
 
     bool inDictionary() const {
-        AutoThreadSafeAccess ts(this);
         return (flags & IN_DICTIONARY) != 0;
     }
     unsigned getFlags() const { return flags & PUBLIC_FLAGS; }
     bool hasShortID() const { return (flags & HAS_SHORTID) != 0; }
 
     PropertyOp getter() const { return base()->rawGetter; }
     bool hasDefaultGetter() const {return !base()->rawGetter; }
     PropertyOp getterOp() const { JS_ASSERT(!hasGetterValue()); return base()->rawGetter; }
@@ -1153,30 +1150,24 @@ class Shape : public gc::BarrieredCell<S
     }
 
     bool get(JSContext* cx, HandleObject receiver, JSObject *obj, JSObject *pobj, MutableHandleValue vp);
     bool set(JSContext* cx, HandleObject obj, HandleObject receiver, bool strict, MutableHandleValue vp);
 
     BaseShape *base() const { return base_.get(); }
 
     bool hasSlot() const {
-        AutoThreadSafeAccess ts(this);
         return (attrs & JSPROP_SHARED) == 0;
     }
     uint32_t slot() const { JS_ASSERT(hasSlot() && !hasMissingSlot()); return maybeSlot(); }
     uint32_t maybeSlot() const {
-        // Note: Reading a shape's slot off thread can race against main thread
-        // updates to the number of linear searches on the shape, which is
-        // stored in the same slotInfo field. We tolerate this.
-        AutoThreadSafeAccess ts(this);
         return slotInfo & SLOT_MASK;
     }
 
     bool isEmptyShape() const {
-        AutoThreadSafeAccess ts(this);
         JS_ASSERT_IF(JSID_IS_EMPTY(propid_), hasMissingSlot());
         return JSID_IS_EMPTY(propid_);
     }
 
     uint32_t slotSpan(const Class *clasp) const {
         JS_ASSERT(!inDictionary());
         uint32_t free = JSSLOT_FREE(clasp);
         return hasMissingSlot() ? free : Max(free, maybeSlot() + 1);
@@ -1188,18 +1179,16 @@ class Shape : public gc::BarrieredCell<S
 
     void setSlot(uint32_t slot) {
         JS_ASSERT(slot <= SHAPE_INVALID_SLOT);
         slotInfo = slotInfo & ~Shape::SLOT_MASK;
         slotInfo = slotInfo | slot;
     }
 
     uint32_t numFixedSlots() const {
-        // Note: The same race applies here as in maybeSlot().
-        AutoThreadSafeAccess ts(this);
         return (slotInfo >> FIXED_SLOTS_SHIFT);
     }
 
     void setNumFixedSlots(uint32_t nfixed) {
         JS_ASSERT(nfixed < FIXED_SLOTS_MAX);
         slotInfo = slotInfo & ~FIXED_SLOTS_MASK;
         slotInfo = slotInfo | (nfixed << FIXED_SLOTS_SHIFT);
     }
@@ -1211,43 +1200,39 @@ class Shape : public gc::BarrieredCell<S
     void incrementNumLinearSearches() {
         uint32_t count = numLinearSearches();
         JS_ASSERT(count < LINEAR_SEARCHES_MAX);
         slotInfo = slotInfo & ~LINEAR_SEARCHES_MASK;
         slotInfo = slotInfo | ((count + 1) << LINEAR_SEARCHES_SHIFT);
     }
 
     const EncapsulatedId &propid() const {
-        AutoThreadSafeAccess ts(this);
         JS_ASSERT(!isEmptyShape());
         JS_ASSERT(!JSID_IS_VOID(propid_));
         return propid_;
     }
     EncapsulatedId &propidRef() { JS_ASSERT(!JSID_IS_VOID(propid_)); return propid_; }
     jsid propidRaw() const {
         // Return the actual jsid, not an internal reference.
-        AutoThreadSafeAccess ts(this);
         return propid();
     }
 
     int16_t shortid() const { JS_ASSERT(hasShortID()); return maybeShortid(); }
     int16_t maybeShortid() const { return shortid_; }
 
     /*
      * If SHORTID is set in shape->flags, we use shape->shortid rather
      * than id when calling shape's getter or setter.
      */
     inline bool getUserId(JSContext *cx, MutableHandleId idp) const;
 
     uint8_t attributes() const { return attrs; }
     bool configurable() const { return (attrs & JSPROP_PERMANENT) == 0; }
     bool enumerable() const { return (attrs & JSPROP_ENUMERATE) != 0; }
     bool writable() const {
-        // JS_ASSERT(isDataDescriptor());
-        AutoThreadSafeAccess ts(this);
         return (attrs & JSPROP_READONLY) == 0;
     }
     bool hasGetterValue() const { return attrs & JSPROP_GETTER; }
     bool hasSetterValue() const { return attrs & JSPROP_SETTER; }
 
     bool isDataDescriptor() const {
         return (attrs & (JSPROP_SETTER | JSPROP_GETTER)) == 0;
     }
@@ -1274,20 +1259,16 @@ class Shape : public gc::BarrieredCell<S
     bool shadowable() const {
         JS_ASSERT_IF(isDataDescriptor(), writable());
         return hasSlot() || (attrs & JSPROP_SHADOWABLE);
     }
 
     uint32_t entryCount() {
         if (hasTable())
             return table().entryCount;
-        return entryCountForCompilation();
-    }
-
-    uint32_t entryCountForCompilation() {
         uint32_t count = 0;
         for (Shape::Range<NoGC> r(this); !r.empty(); r.popFront())
             ++count;
         return count;
     }
 
     bool isBigEnoughForAShapeTable() {
         JS_ASSERT(!hasTable());
@@ -1644,17 +1625,16 @@ Shape::searchLinear(jsid id)
      * Non-dictionary shapes can acquire a table at any point the main thread
      * is operating on it, so other threads inspecting such shapes can't use
      * their table without racing. This function can be called from any thread
      * on any non-dictionary shape.
      */
     JS_ASSERT(!inDictionary());
 
     for (Shape *shape = this; shape; ) {
-        AutoThreadSafeAccess ts(shape);
         if (shape->propidRef() == id)
             return shape;
         shape = shape->parent;
     }
 
     return nullptr;
 }
 
--- a/js/src/vm/String.h
+++ b/js/src/vm/String.h
@@ -377,17 +377,16 @@ class JSString : public js::gc::Barriere
 
     MOZ_ALWAYS_INLINE
     bool isAtom() const {
         return (d.lengthAndFlags & ATOM_BIT);
     }
 
     MOZ_ALWAYS_INLINE
     JSAtom &asAtom() const {
-        js::AutoThreadSafeAccess ts(this);
         JS_ASSERT(isAtom());
         return *(JSAtom *)this;
     }
 
     /* Only called by the GC for dependent or undepended strings. */
 
     inline bool hasBase() const {
         JS_STATIC_ASSERT((DEPENDENT_FLAGS | JS_BIT(1)) == UNDEPENDED_FLAGS);
@@ -1010,17 +1009,16 @@ JSString::base() const
     JS_ASSERT(hasBase());
     JS_ASSERT(!d.s.u2.base->isInline());
     return d.s.u2.base;
 }
 
 inline js::PropertyName *
 JSAtom::asPropertyName()
 {
-    js::AutoThreadSafeAccess ts(this);
 #ifdef DEBUG
     uint32_t dummy;
     JS_ASSERT(!isIndex(&dummy));
 #endif
     return static_cast<js::PropertyName *>(this);
 }
 
 #endif /* vm_String_h */
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -1190,18 +1190,16 @@ TypedArrayObject::isArrayIndex(jsid id, 
     }
 
     return false;
 }
 
 void
 TypedArrayObject::neuter(JSContext *cx)
 {
-    AutoLockForCompilation lock(cx);
-
     setSlot(LENGTH_SLOT, Int32Value(0));
     setSlot(BYTELENGTH_SLOT, Int32Value(0));
     setSlot(BYTEOFFSET_SLOT, Int32Value(0));
     setPrivate(nullptr);
 }
 
 bool
 TypedArrayObject::obj_lookupGeneric(JSContext *cx, HandleObject tarray, HandleId id,
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -306,21 +306,19 @@ class TypedArrayObject : public ArrayBuf
 
     static Value bufferValue(TypedArrayObject *tarr) {
         return tarr->getFixedSlot(BUFFER_SLOT);
     }
     static Value byteOffsetValue(TypedArrayObject *tarr) {
         return tarr->getFixedSlot(BYTEOFFSET_SLOT);
     }
     static Value byteLengthValue(TypedArrayObject *tarr) {
-        AutoThreadSafeAccess ts(tarr);
         return tarr->getFixedSlot(BYTELENGTH_SLOT);
     }
     static Value lengthValue(TypedArrayObject *tarr) {
-        AutoThreadSafeAccess ts(tarr);
         return tarr->getFixedSlot(LENGTH_SLOT);
     }
 
     ArrayBufferObject *buffer() const {
         return &bufferValue(const_cast<TypedArrayObject*>(this)).toObject().as<ArrayBufferObject>();
     }
     uint32_t byteOffset() const {
         return byteOffsetValue(const_cast<TypedArrayObject*>(this)).toInt32();
@@ -328,21 +326,19 @@ class TypedArrayObject : public ArrayBuf
     uint32_t byteLength() const {
         return byteLengthValue(const_cast<TypedArrayObject*>(this)).toInt32();
     }
     uint32_t length() const {
         return lengthValue(const_cast<TypedArrayObject*>(this)).toInt32();
     }
 
     uint32_t type() const {
-        AutoThreadSafeAccess ts(this);
         return getFixedSlot(TYPE_SLOT).toInt32();
     }
     void *viewData() const {
-        AutoThreadSafeAccess ts(this);
         return static_cast<void*>(getPrivate(DATA_SLOT));
     }
 
     inline bool isArrayIndex(jsid id, uint32_t *ip = nullptr);
     void copyTypedArrayElement(uint32_t index, MutableHandleValue vp);
 
     void neuter(JSContext *cx);
 
--- a/mobile/android/base/ActivityHandlerHelper.java
+++ b/mobile/android/base/ActivityHandlerHelper.java
@@ -233,92 +233,16 @@ public class ActivityHandlerHelper imple
         // context menu UI using the PromptService.
         ThreadUtils.postToUiThread(new Runnable() {
             @Override public void run() {
                 prompt.show(title, "", items, false);
             }
         });
     }
 
-    private Intent getFilePickerIntent(Context context, String aMimeType) {
-        ArrayList<Intent> intents = new ArrayList<Intent>();
-        final Prompt.PromptListItem[] items =
-            getItemsAndIntentsForFilePicker(context, aMimeType, intents);
-
-        if (intents.size() == 0) {
-            Log.i(LOGTAG, "no activities for the file picker!");
-            return null;
-        }
-
-        if (intents.size() == 1) {
-            return intents.get(0);
-        }
-
-        final PromptService ps = GeckoAppShell.getGeckoInterface().getPromptService();
-        final String title = getFilePickerTitle(context, aMimeType);
-
-        // Runnable has to be called to show an intent-like
-        // context menu UI using the PromptService.
-        ThreadUtils.postToUiThread(new Runnable() {
-            @Override public void run() {
-                ps.show(title, "", items, false, null);
-            }
-        });
-
-        String promptServiceResult = ps.getResponse(null);
-        int itemId = -1;
-        try {
-            itemId = new JSONObject(promptServiceResult).getInt("button");
-
-            if (itemId == -1) {
-                return null;
-            }
-        } catch (JSONException e) {
-            Log.e(LOGTAG, "result from promptservice was invalid: ", e);
-            return null;
-        }
-
-        return intents.get(itemId);
-    }
-
-    boolean showFilePicker(Activity parentActivity, String aMimeType, ActivityResultHandler handler) {
-        Intent intent = getFilePickerIntent(parentActivity, aMimeType);
-
-        if (intent == null) {
-            return false;
-        }
-        parentActivity.startActivityForResult(intent, mActivityResultHandlerMap.put(handler));
-        return true;
-    }
-
-    String showFilePicker(Activity parentActivity, String aMimeType) {
-        Intent intent = getFilePickerIntent(parentActivity, aMimeType);
-
-        if (intent == null) {
-            return "";
-        }
-
-        if (intent.getAction().equals(MediaStore.ACTION_IMAGE_CAPTURE)) {
-            parentActivity.startActivityForResult(intent, mActivityResultHandlerMap.put(mCameraImageResultHandler));
-        } else if (intent.getAction().equals(MediaStore.ACTION_VIDEO_CAPTURE)) {
-            parentActivity.startActivityForResult(intent, mActivityResultHandlerMap.put(mCameraVideoResultHandler));
-        } else if (intent.getAction().equals(Intent.ACTION_GET_CONTENT)) {
-            parentActivity.startActivityForResult(intent, mActivityResultHandlerMap.put(mFilePickerResultHandlerSync));
-        } else {
-            Log.e(LOGTAG, "We should not get an intent with another action!");
-            return "";
-        }
-
-        String filePickerResult;
-        while (null == (filePickerResult = mFilePickerResult.poll())) {
-            GeckoAppShell.processNextNativeEvent(true);
-        }
-        return filePickerResult;
-    }
-
     /* Allows the user to pick an activity to load files from using a list prompt. Then opens the activity and
      * sends the file returned to the passed in handler. If a null handler is passed in, will still
      * pick and launch the file picker, but will throw away the result.
      */
     public void showFilePickerAsync(final Activity parentActivity, String aMimeType, final FileResultHandler handler) {
         getFilePickerIntentAsync(parentActivity, aMimeType, new IntentHandler() {
             public void gotIntent(Intent intent) {
                 if (handler == null) {
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -26,17 +26,17 @@ import org.mozilla.gecko.home.HomePager;
 import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
 import org.mozilla.gecko.home.SearchEngine;
 import org.mozilla.gecko.menu.GeckoMenu;
 import org.mozilla.gecko.preferences.GeckoPreferences;
 import org.mozilla.gecko.prompts.Prompt;
 import org.mozilla.gecko.toolbar.AutocompleteHandler;
 import org.mozilla.gecko.toolbar.BrowserToolbar;
 import org.mozilla.gecko.util.Clipboard;
-import org.mozilla.gecko.util.EventDispatcher;
+import org.mozilla.gecko.EventDispatcher;
 import org.mozilla.gecko.util.GamepadUtils;
 import org.mozilla.gecko.util.HardwareUtils;
 import org.mozilla.gecko.util.MenuUtils;
 import org.mozilla.gecko.util.StringUtils;
 import org.mozilla.gecko.util.ThreadUtils;
 import org.mozilla.gecko.util.UiAsyncTask;
 import org.mozilla.gecko.widget.GeckoActionProvider;
 import org.mozilla.gecko.widget.ButtonToast;
--- a/mobile/android/base/ContactService.java
+++ b/mobile/android/base/ContactService.java
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.gfx.Layer;
 import org.mozilla.gecko.gfx.LayerView;
-import org.mozilla.gecko.util.EventDispatcher;
+import org.mozilla.gecko.EventDispatcher;
 import org.mozilla.gecko.util.GeckoEventListener;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import android.accounts.Account;
rename from mobile/android/base/util/EventDispatcher.java
rename to mobile/android/base/EventDispatcher.java
--- a/mobile/android/base/util/EventDispatcher.java
+++ b/mobile/android/base/EventDispatcher.java
@@ -1,24 +1,29 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-package org.mozilla.gecko.util;
+package org.mozilla.gecko;
+
+import org.mozilla.gecko.GeckoAppShell;
+import org.mozilla.gecko.GeckoEvent;
+import org.mozilla.gecko.util.GeckoEventListener;
 
 import org.json.JSONObject;
 
 import android.util.Log;
 
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 public final class EventDispatcher {
     private static final String LOGTAG = "GeckoEventDispatcher";
+    private static final String GUID = "__guid__";
 
     private final Map<String, CopyOnWriteArrayList<GeckoEventListener>> mEventListeners
                   = new HashMap<String, CopyOnWriteArrayList<GeckoEventListener>>();
 
     public void registerEventListener(String event, GeckoEventListener listener) {
         synchronized (mEventListeners) {
             CopyOnWriteArrayList<GeckoEventListener> listeners = mEventListeners.get(event);
             if (listeners == null) {
@@ -47,28 +52,26 @@ public final class EventDispatcher {
                               "for event '" + event + "'");
             }
             if (listeners.size() == 0) {
                 mEventListeners.remove(event);
             }
         }
     }
 
-    public String dispatchEvent(String message) {
+    public void dispatchEvent(String message) {
         try {
             JSONObject json = new JSONObject(message);
-            return dispatchEvent(json);
+            dispatchEvent(json);
         } catch (Exception e) {
             Log.e(LOGTAG, "dispatchEvent: malformed JSON.", e);
         }
-
-        return "";
     }
 
-    public String dispatchEvent(JSONObject json) {
+    public void dispatchEvent(JSONObject json) {
         // {
         //   "type": "value",
         //   "event_specific": "value",
         //   ...
         try {
             JSONObject gecko = json.has("gecko") ? json.getJSONObject("gecko") : null;
             if (gecko != null) {
                 json = gecko;
@@ -82,34 +85,34 @@ public final class EventDispatcher {
 
             CopyOnWriteArrayList<GeckoEventListener> listeners;
             synchronized (mEventListeners) {
                 listeners = mEventListeners.get(type);
             }
 
             if (listeners == null || listeners.size() == 0) {
                 Log.d(LOGTAG, "dispatchEvent: no listeners registered for event '" + type + "'");
-                return "";
+                return;
             }
 
-            String response = null;
-
             for (GeckoEventListener listener : listeners) {
                 listener.handleMessage(type, json);
-                if (listener instanceof GeckoEventResponder) {
-                    String newResponse = ((GeckoEventResponder)listener).getResponse(json);
-                    if (response != null && newResponse != null) {
-                        Log.e(LOGTAG, "Received two responses for message of type " + type);
-                    }
-                    response = newResponse;
-                }
             }
-
-            if (response != null)
-                return response;
-
         } catch (Exception e) {
             Log.e(LOGTAG, "handleGeckoMessage throws " + e, e);
         }
 
-        return "";
+    }
+
+    public static void sendResponse(JSONObject message, JSONObject response) {
+        try {
+            response.put(GUID, message.getString(GUID));
+            GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent(message.getString("type") + ":Return", response.toString()));
+        } catch(Exception ex) { }
+    }
+
+    public static void sendError(JSONObject message, JSONObject error) {
+        try {
+            error.put(GUID, message.getString(GUID));
+            GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent(message.getString("type") + ":Error", error.toString()));
+        } catch(Exception ex) { }
     }
 }
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -18,19 +18,17 @@ import org.mozilla.gecko.menu.GeckoMenuI
 import org.mozilla.gecko.menu.MenuPanel;
 import org.mozilla.gecko.health.HealthRecorder;
 import org.mozilla.gecko.health.SessionInformation;
 import org.mozilla.gecko.health.StubbedHealthRecorder;
 import org.mozilla.gecko.preferences.GeckoPreferences;
 import org.mozilla.gecko.updater.UpdateService;
 import org.mozilla.gecko.updater.UpdateServiceHelper;
 import org.mozilla.gecko.util.ActivityResultHandler;
-import org.mozilla.gecko.util.EventDispatcher;
 import org.mozilla.gecko.util.GeckoEventListener;
-import org.mozilla.gecko.util.GeckoEventResponder;
 import org.mozilla.gecko.util.HardwareUtils;
 import org.mozilla.gecko.util.ThreadUtils;
 import org.mozilla.gecko.util.UiAsyncTask;
 import org.mozilla.gecko.webapp.UninstallListener;
 import org.mozilla.gecko.webapp.EventListener;
 import org.mozilla.gecko.widget.ButtonToast;
 
 import org.json.JSONArray;
@@ -129,17 +127,16 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 public abstract class GeckoApp
     extends GeckoActivity 
     implements
     ContextGetter,
     GeckoAppShell.GeckoInterface,
     GeckoEventListener,
-    GeckoEventResponder,
     GeckoMenu.Callback,
     GeckoMenu.MenuPresenter,
     LocationListener,
     SensorEventListener,
     Tabs.OnTabsChangedListener
 {
     private static final String LOGTAG = "GeckoApp";
 
@@ -182,17 +179,16 @@ public abstract class GeckoApp
     private OrientationEventListener mCameraOrientationEventListener;
     public List<GeckoAppShell.AppStateListener> mAppStateListeners;
     private static GeckoApp sAppContext;
     protected MenuPanel mMenuPanel;
     protected Menu mMenu;
     protected GeckoProfile mProfile;
     public static int mOrientation;
     protected boolean mIsRestoringActivity;
-    private String mCurrentResponse = "";
 
     private ContactService mContactService;
     private PromptService mPromptService;
     private TextSelection mTextSelection;
 
     protected DoorHangerPopup mDoorHangerPopup;
     protected FormAssistPopup mFormAssistPopup;
     protected ButtonToast mToast;
@@ -680,39 +676,35 @@ public abstract class GeckoApp
                     message.optString("mime"), message.optString("action"), message.optString("title"));
                 String[] handlers = GeckoAppShell.getHandlersForIntent(intent);
                 ArrayList<String> appList = new ArrayList<String>(handlers.length);
                 for (int i = 0; i < handlers.length; i++) {
                     appList.add(handlers[i]);
                 }
                 JSONObject handlersJSON = new JSONObject();
                 handlersJSON.put("apps", new JSONArray(appList));
-                mCurrentResponse = handlersJSON.toString();
+                EventDispatcher.sendResponse(message, handlersJSON);
             } else if (event.equals("Intent:Open")) {
                 GeckoAppShell.openUriExternal(message.optString("url"),
                     message.optString("mime"), message.optString("packageName"),
                     message.optString("className"), message.optString("action"), message.optString("title"));
             } else if (event.equals("Locale:Set")) {
                 setLocale(message.getString("locale"));
             } else if (event.equals("NativeApp:IsDebuggable")) {
-                mCurrentResponse = getIsDebuggable() ? "true" : "false";
+                JSONObject ret = new JSONObject();
+                ret.put("isDebuggable", getIsDebuggable() ? "true" : "false");
+                EventDispatcher.sendResponse(message, ret);
             } else if (event.equals("SystemUI:Visibility")) {
                 setSystemUiVisible(message.getBoolean("visible"));
             }
         } catch (Exception e) {
             Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
         }
     }
 
-    public String getResponse(JSONObject origMessage) {
-        String res = mCurrentResponse;
-        mCurrentResponse = "";
-        return res;
-    }
-
     void onStatePurged() { }
 
     /**
      * @param aPermissions
      *        Array of JSON objects to represent site permissions.
      *        Example: { type: "offline-app", setting: "Store Offline Data", value: "Allow" }
      */
     private void showSiteSettingsDialog(String aHost, JSONArray aPermissions) {
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -13,17 +13,16 @@ import org.mozilla.gecko.gfx.LayerView;
 import org.mozilla.gecko.gfx.PanZoomController;
 import org.mozilla.gecko.mozglue.GeckoLoader;
 import org.mozilla.gecko.mozglue.generatorannotations.OptionalGeneratedParameter;
 import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
 import org.mozilla.gecko.mozglue.JNITarget;
 import org.mozilla.gecko.mozglue.RobocopTarget;
 import org.mozilla.gecko.prompts.PromptService;
 import org.mozilla.gecko.util.ActivityResultHandler;
-import org.mozilla.gecko.util.EventDispatcher;
 import org.mozilla.gecko.util.GeckoEventListener;
 import org.mozilla.gecko.util.HardwareUtils;
 import org.mozilla.gecko.util.ProxySelector;
 import org.mozilla.gecko.util.ThreadUtils;
 import org.mozilla.gecko.webapp.Allocator;
 import org.mozilla.gecko.webapp.InstallListener;
 
 import org.json.JSONException;
@@ -1422,30 +1421,16 @@ public class GeckoAppShell
     }
 
     @WrapElementForJNI
     public static void setFullScreen(boolean fullscreen) {
         if (getGeckoInterface() != null)
             getGeckoInterface().setFullScreen(fullscreen);
     }
 
-    @WrapElementForJNI(stubName = "ShowFilePickerForExtensionsWrapper")
-    public static String showFilePickerForExtensions(String aExtensions) {
-        if (getGeckoInterface() != null)
-            return sActivityHelper.showFilePicker(getGeckoInterface().getActivity(), getMimeTypeFromExtensions(aExtensions));
-        return "";
-    }
-
-    @WrapElementForJNI(stubName = "ShowFilePickerForMimeTypeWrapper")
-    public static String showFilePickerForMimeType(String aMimeType) {
-        if (getGeckoInterface() != null)
-            return sActivityHelper.showFilePicker(getGeckoInterface().getActivity(), aMimeType);
-        return "";
-    }
-
     @WrapElementForJNI
     public static void performHapticFeedback(boolean aIsLongPress) {
         // Don't perform haptic feedback if a vibration is currently playing,
         // because the haptic feedback will nuke the vibration.
         if (!sVibrationMaybePlaying || System.nanoTime() >= sVibrationEndTime) {
             LayerView layerView = getLayerView();
             layerView.performHapticFeedback(aIsLongPress ?
                                             HapticFeedbackConstants.LONG_PRESS :
@@ -2340,18 +2325,18 @@ public class GeckoAppShell
      * Battery API related methods.
      */
     @WrapElementForJNI
     public static void enableBatteryNotifications() {
         GeckoBatteryManager.enableNotifications();
     }
 
     @WrapElementForJNI(stubName = "HandleGeckoMessageWrapper")
-    public static String handleGeckoMessage(String message) {
-        return sEventDispatcher.dispatchEvent(message);
+    public static void handleGeckoMessage(String message) {
+        sEventDispatcher.dispatchEvent(message);
     }
 
     @WrapElementForJNI
     public static void disableBatteryNotifications() {
         GeckoBatteryManager.disableNotifications();
     }
 
     @WrapElementForJNI(stubName = "GetCurrentBatteryInformationWrapper")
@@ -2625,27 +2610,16 @@ public class GeckoAppShell
         if (msg.getTarget() == null) 
             Looper.myLooper().quit();
         else
             msg.getTarget().dispatchMessage(msg);
         msg.recycle();
         return true;
     }
 
-    static native void notifyFilePickerResult(String filePath, long id);
-
-    @WrapElementForJNI(stubName = "ShowFilePickerAsyncWrapper")
-    public static void showFilePickerAsync(String aMimeType, final long id) {
-        sActivityHelper.showFilePickerAsync(getGeckoInterface().getActivity(), aMimeType, new ActivityHandlerHelper.FileResultHandler() {
-            public void gotFile(String filename) {
-                GeckoAppShell.notifyFilePickerResult(filename, id);
-            }
-        });
-    }
-
     @WrapElementForJNI
     public static void notifyWakeLockChanged(String topic, String state) {
         if (getGeckoInterface() != null)
             getGeckoInterface().notifyWakeLockChanged(topic, state);
     }
 
     @WrapElementForJNI
     public static void registerSurfaceTextureFrameListener(Object surfaceTexture, final int id) {
--- a/mobile/android/base/JavaAddonManager.java
+++ b/mobile/android/base/JavaAddonManager.java
@@ -1,18 +1,16 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
-import org.mozilla.gecko.util.EventDispatcher;
 import org.mozilla.gecko.util.GeckoEventListener;
-import org.mozilla.gecko.util.GeckoEventResponder;
 
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import android.content.Context;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
@@ -135,17 +133,17 @@ class JavaAddonManager implements GeckoE
             Log.w(LOGTAG, "Attempting to unregister callbacks from zipfile [" + zipFile + "] which has no callbacks registered.");
             return;
         }
         for (String event : callbacks.keySet()) {
             mDispatcher.unregisterEventListener(event, callbacks.get(event));
         }
     }
 
-    private static class CallbackWrapper implements GeckoEventResponder {
+    private static class CallbackWrapper implements GeckoEventListener {
         private final Handler.Callback mDelegate;
         private Bundle mBundle;
 
         CallbackWrapper(Handler.Callback delegate) {
             mDelegate = delegate;
         }
 
         private Bundle jsonToBundle(JSONObject json) {
@@ -179,21 +177,19 @@ class JavaAddonManager implements GeckoE
             try {
                 if (mBundle != null) {
                     Log.w(LOGTAG, "Event [" + event + "] handler is re-entrant; response messages may be lost");
                 }
                 mBundle = jsonToBundle(json);
                 Message msg = new Message();
                 msg.setData(mBundle);
                 mDelegate.handleMessage(msg);
+
+                JSONObject obj = new JSONObject();
+                obj.put("response", mBundle.getString("response"));
+                EventDispatcher.sendResponse(json, obj);
+                mBundle = null;
             } catch (Exception e) {
                 Log.e(LOGTAG, "Caught exception thrown from wrapped addon message handler", e);
             }
         }
-
-        @Override
-        public String getResponse(JSONObject origMessage) {
-            String response = mBundle.getString("response");
-            mBundle = null;
-            return response;
-        }
     }
 }
--- a/mobile/android/base/OrderedBroadcastHelper.java
+++ b/mobile/android/base/OrderedBroadcastHelper.java
@@ -1,17 +1,17 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.background.common.GlobalConstants;
-import org.mozilla.gecko.util.EventDispatcher;
+import org.mozilla.gecko.EventDispatcher;
 import org.mozilla.gecko.util.GeckoEventListener;
 
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import android.app.Activity;
 
 import android.content.BroadcastReceiver;
--- a/mobile/android/base/SharedPreferencesHelper.java
+++ b/mobile/android/base/SharedPreferencesHelper.java
@@ -1,17 +1,17 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
-import org.mozilla.gecko.util.EventDispatcher;
-import org.mozilla.gecko.util.GeckoEventResponder;
+import org.mozilla.gecko.EventDispatcher;
+import org.mozilla.gecko.util.GeckoEventListener;
 
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.preference.PreferenceManager;
@@ -19,24 +19,22 @@ import android.util.Log;
 
 import java.util.Map;
 import java.util.HashMap;
 
 /**
  * Helper class to get, set, and observe Android Shared Preferences.
  */
 public final class SharedPreferencesHelper
-             implements GeckoEventResponder
+             implements GeckoEventListener
 {
     public static final String LOGTAG = "GeckoAndSharedPrefs";
 
     protected final Context mContext;
 
-    protected String mResponse;
-
     // mListeners is not synchronized because it is only updated in
     // handleObserve, which is called from Gecko serially.
     protected final Map<String, SharedPreferences.OnSharedPreferenceChangeListener> mListeners;
 
     public SharedPreferencesHelper(Context context) {
         mContext = context;
 
         mListeners = new HashMap<String, SharedPreferences.OnSharedPreferenceChangeListener>();
@@ -112,17 +110,17 @@ public final class SharedPreferencesHelp
      * Get many SharedPreferences from Android.
      *
      * message.branch must exist, and should be a String SharedPreferences
      * branch name, or null for the default branch.
      * message.preferences should be an array of preferences.  Each preference
      * must include a String name, and a String type in ["bool", "int",
      * "string"].
      */
-    private String handleGet(JSONObject message) throws JSONException {
+    private JSONArray handleGet(JSONObject message) throws JSONException {
         if (!message.has("branch")) {
             Log.e(LOGTAG, "No branch specified for SharedPreference:Get; aborting.");
             return null;
         }
 
         String branch = message.isNull("branch") ? null : message.getString("branch");
         SharedPreferences prefs = getSharedPreferences(branch);
         JSONArray jsonPrefs = message.getJSONArray("preferences");
@@ -151,17 +149,17 @@ public final class SharedPreferencesHelp
             } catch (ClassCastException e) {
                 // Thrown if there is a preference with the given name that is
                 // not the right type.
                 Log.w(LOGTAG, "Wrong pref value type [" + type + "] for pref [" + name + "]");
             }
             jsonValues.put(jsonValue);
         }
 
-        return jsonValues.toString();
+        return jsonValues;
     }
 
     private static class ChangeListener
         implements SharedPreferences.OnSharedPreferenceChangeListener {
         public final String branch;
 
         public ChangeListener(final String branch) {
             this.branch = branch;
@@ -220,43 +218,36 @@ public final class SharedPreferencesHelp
             prefs.unregisterOnSharedPreferenceChangeListener(listener);
         }
     }
 
     @Override
     public void handleMessage(String event, JSONObject message) {
         // Everything here is synchronous and serial, so we need not worry about
         // overwriting an in-progress response.
-        mResponse = null;
-
         try {
             if (event.equals("SharedPreferences:Set")) {
                 if (Log.isLoggable(LOGTAG, Log.VERBOSE)) {
                     Log.v(LOGTAG, "Got SharedPreferences:Set message.");
                 }
                 handleSet(message);
             } else if (event.equals("SharedPreferences:Get")) {
                 if (Log.isLoggable(LOGTAG, Log.VERBOSE)) {
                     Log.v(LOGTAG, "Got SharedPreferences:Get message.");
                 }
-                // Synchronous and serial, so we are the only consumer of
-                // mResponse and can write to it freely.
-                mResponse = handleGet(message);
+                JSONObject obj = new JSONObject();
+                obj.put("values", handleGet(message));
+                EventDispatcher.sendResponse(message, obj);
             } else if (event.equals("SharedPreferences:Observe")) {
                 if (Log.isLoggable(LOGTAG, Log.VERBOSE)) {
                     Log.v(LOGTAG, "Got SharedPreferences:Observe message.");
                 }
                 handleObserve(message);
             } else {
                 Log.e(LOGTAG, "SharedPreferencesHelper got unexpected message " + event);
                 return;
             }
         } catch (JSONException e) {
             Log.e(LOGTAG, "Got exception in handleMessage handling event " + event, e);
             return;
         }
     }
-
-    @Override
-    public String getResponse(JSONObject origMessage) {
-        return mResponse;
-    }
 }
--- a/mobile/android/base/TextSelection.java
+++ b/mobile/android/base/TextSelection.java
@@ -5,17 +5,17 @@
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.gfx.BitmapUtils;
 import org.mozilla.gecko.gfx.BitmapUtils.BitmapLoader;
 import org.mozilla.gecko.gfx.Layer;
 import org.mozilla.gecko.gfx.LayerView;
 import org.mozilla.gecko.menu.GeckoMenu;
 import org.mozilla.gecko.menu.GeckoMenuItem;
-import org.mozilla.gecko.util.EventDispatcher;
+import org.mozilla.gecko.EventDispatcher;
 import org.mozilla.gecko.util.FloatUtils;
 import org.mozilla.gecko.util.GeckoEventListener;
 import org.mozilla.gecko.util.ThreadUtils;
 import org.mozilla.gecko.ActionModeCompat.Callback;
 
 import android.content.Context;
 import android.app.Activity;
 import android.graphics.drawable.Drawable;
--- a/mobile/android/base/db/BrowserContract.java
+++ b/mobile/android/base/db/BrowserContract.java
@@ -96,37 +96,45 @@ public class BrowserContract {
         public static final String GUID = "guid";
         public static final String TIME_DELETED = "timeDeleted";
     }
 
     @RobocopTarget
     public static final class Favicons implements CommonColumns, DateSyncColumns {
         private Favicons() {}
 
+        public static final String TABLE_NAME = "favicons";
+
         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "favicons");
 
         public static final String URL = "url";
         public static final String DATA = "data";
         public static final String PAGE_URL = "page_url";
     }
 
     @RobocopTarget
     public static final class Thumbnails implements CommonColumns {
         private Thumbnails() {}
 
+        public static final String TABLE_NAME = "thumbnails";
+
         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "thumbnails");
 
         public static final String URL = "url";
         public static final String DATA = "data";
     }
 
     @RobocopTarget
     public static final class Bookmarks implements CommonColumns, URLColumns, FaviconColumns, SyncColumns {
         private Bookmarks() {}
 
+        public static final String TABLE_NAME = "bookmarks";
+
+        public static final String VIEW_WITH_FAVICONS = "bookmarks_with_favicons";
+
         public static final int FIXED_ROOT_ID = 0;
         public static final int FAKE_DESKTOP_FOLDER_ID = -1;
         public static final int FIXED_READING_LIST_ID = -2;
         public static final int FIXED_PINNED_LIST_ID = -3;
 
         public static final String MOBILE_FOLDER_GUID = "mobile";
         public static final String PLACES_FOLDER_GUID = "places";
         public static final String MENU_FOLDER_GUID = "menu";
@@ -168,26 +176,36 @@ public class BrowserContract {
         public static final String TAGS = "tags";
         public static final String DESCRIPTION = "description";
         public static final String KEYWORD = "keyword";
     }
 
     @RobocopTarget
     public static final class History implements CommonColumns, URLColumns, HistoryColumns, FaviconColumns, SyncColumns {
         private History() {}
+
+        public static final String TABLE_NAME = "history";
+
+        public static final String VIEW_WITH_FAVICONS = "history_with_favicons";
+
         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "history");
         public static final Uri CONTENT_OLD_URI = Uri.withAppendedPath(AUTHORITY_URI, "history/old");
         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/browser-history";
         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/browser-history";
     }
 
     // Combined bookmarks and history
     @RobocopTarget
     public static final class Combined implements CommonColumns, URLColumns, HistoryColumns, FaviconColumns  {
         private Combined() {}
+
+        public static final String VIEW_NAME = "combined";
+
+        public static final String VIEW_WITH_FAVICONS = "combined_with_favicons";
+
         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "combined");
 
         public static final int DISPLAY_NORMAL = 0;
         public static final int DISPLAY_READER = 1;
 
         public static final String BOOKMARK_ID = "bookmark_id";
         public static final String HISTORY_ID = "history_id";
         public static final String DISPLAY = "display";
@@ -311,9 +329,52 @@ public class BrowserContract {
 
         public static final String DATASET_ID = "dataset_id";
         public static final String URL = "url";
         public static final String TITLE = "title";
         public static final String DESCRIPTION = "description";
         public static final String IMAGE_URL = "image_url";
         public static final String CREATED = "created";
     }
+
+    /*
+     * Contains names and schema definitions for tables and views
+     * no longer being used by current ContentProviders. These values are used
+     * to make incremental updates to the schema during a database upgrade. Will be
+     * removed with bug 947018.
+     */
+    static final class Obsolete {
+        public static final String TABLE_IMAGES = "images";
+        public static final String VIEW_BOOKMARKS_WITH_IMAGES = "bookmarks_with_images";
+        public static final String VIEW_HISTORY_WITH_IMAGES = "history_with_images";
+        public static final String VIEW_COMBINED_WITH_IMAGES = "combined_with_images";
+
+        public static final class Images implements CommonColumns, SyncColumns {
+            private Images() {}
+
+            public static final String URL = "url_key";
+            public static final String FAVICON_URL = "favicon_url";
+            public static final String FAVICON = "favicon";
+            public static final String THUMBNAIL = "thumbnail";
+            public static final String _ID = "_id";
+            public static final String GUID = "guid";
+            public static final String DATE_CREATED = "created";
+            public static final String DATE_MODIFIED = "modified";
+            public static final String IS_DELETED = "deleted";
+        }
+
+        public static final class Combined {
+            private Combined() {}
+
+            public static final String THUMBNAIL = "thumbnail";
+        }
+
+        static final String TABLE_BOOKMARKS_JOIN_IMAGES = Bookmarks.TABLE_NAME + " LEFT OUTER JOIN " +
+                Obsolete.TABLE_IMAGES + " ON " + DBUtils.qualifyColumn(Bookmarks.TABLE_NAME, Bookmarks.URL) + " = " +
+                DBUtils.qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.URL);
+
+        static final String TABLE_HISTORY_JOIN_IMAGES = History.TABLE_NAME + " LEFT OUTER JOIN " +
+                Obsolete.TABLE_IMAGES + " ON " + DBUtils.qualifyColumn(Bookmarks.TABLE_NAME, History.URL) + " = " +
+                DBUtils.qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.URL);
+
+        static final String FAVICON_DB = "favicon_urls.db";
+    }
 }
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/db/BrowserDatabaseHelper.java
@@ -0,0 +1,1748 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.db;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.mozilla.gecko.AppConstants;
+import org.mozilla.gecko.Distribution;
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.db.BrowserContract.Bookmarks;
+import org.mozilla.gecko.db.BrowserContract.Combined;
+import org.mozilla.gecko.db.BrowserContract.FaviconColumns;
+import org.mozilla.gecko.db.BrowserContract.Favicons;
+import org.mozilla.gecko.db.BrowserContract.History;
+import org.mozilla.gecko.db.BrowserContract.Obsolete;
+import org.mozilla.gecko.db.BrowserContract.Thumbnails;
+import org.mozilla.gecko.gfx.BitmapUtils;
+import org.mozilla.gecko.sync.Utils;
+import org.mozilla.gecko.util.GeckoJarReader;
+import org.mozilla.gecko.util.ThreadUtils;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.database.SQLException;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.os.Build;
+import android.text.TextUtils;
+import android.util.Log;
+
+
+final class BrowserDatabaseHelper extends SQLiteOpenHelper {
+
+    private static final String LOGTAG = "GeckoBrowserDBHelper";
+    public static final int DATABASE_VERSION = 17;
+    public static final String DATABASE_NAME = "browser.db";
+
+    final protected Context mContext;
+
+    static final String TABLE_BOOKMARKS = Bookmarks.TABLE_NAME;
+    static final String TABLE_HISTORY = History.TABLE_NAME;
+    static final String TABLE_FAVICONS = Favicons.TABLE_NAME;
+    static final String TABLE_THUMBNAILS = Thumbnails.TABLE_NAME;
+
+    static final String VIEW_COMBINED = Combined.VIEW_NAME;
+    static final String VIEW_BOOKMARKS_WITH_FAVICONS = Bookmarks.VIEW_WITH_FAVICONS;
+    static final String VIEW_HISTORY_WITH_FAVICONS = History.VIEW_WITH_FAVICONS;
+    static final String VIEW_COMBINED_WITH_FAVICONS = Combined.VIEW_WITH_FAVICONS;
+
+    static final String TABLE_BOOKMARKS_JOIN_FAVICONS = TABLE_BOOKMARKS + " LEFT OUTER JOIN " +
+            TABLE_FAVICONS + " ON " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.FAVICON_ID) + " = " +
+            qualifyColumn(TABLE_FAVICONS, Favicons._ID);
+
+    static final String TABLE_HISTORY_JOIN_FAVICONS = TABLE_HISTORY + " LEFT OUTER JOIN " +
+            TABLE_FAVICONS + " ON " + qualifyColumn(TABLE_HISTORY, History.FAVICON_ID) + " = " +
+            qualifyColumn(TABLE_FAVICONS, Favicons._ID);
+
+    static final String TABLE_BOOKMARKS_TMP = TABLE_BOOKMARKS + "_tmp";
+    static final String TABLE_HISTORY_TMP = TABLE_HISTORY + "_tmp";
+    static final String TABLE_IMAGES_TMP = Obsolete.TABLE_IMAGES + "_tmp";
+
+    private static final String[] mobileIdColumns = new String[] { Bookmarks._ID };
+    private static final String[] mobileIdSelectionArgs = new String[] { Bookmarks.MOBILE_FOLDER_GUID };
+
+    public BrowserDatabaseHelper(Context context, String databasePath) {
+        super(context, databasePath, null, DATABASE_VERSION);
+        mContext = context;
+    }
+
+    private void createBookmarksTable(SQLiteDatabase db) {
+        debug("Creating " + TABLE_BOOKMARKS + " table");
+
+        // Android versions older than Froyo ship with an sqlite
+        // that doesn't support foreign keys.
+        String foreignKeyOnParent = null;
+        if (Build.VERSION.SDK_INT >= 8) {
+            foreignKeyOnParent = ", FOREIGN KEY (" + Bookmarks.PARENT +
+                ") REFERENCES " + TABLE_BOOKMARKS + "(" + Bookmarks._ID + ")";
+        }
+
+        db.execSQL("CREATE TABLE " + TABLE_BOOKMARKS + "(" +
+                Bookmarks._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
+                Bookmarks.TITLE + " TEXT," +
+                Bookmarks.URL + " TEXT," +
+                Bookmarks.TYPE + " INTEGER NOT NULL DEFAULT " + Bookmarks.TYPE_BOOKMARK + "," +
+                Bookmarks.PARENT + " INTEGER," +
+                Bookmarks.POSITION + " INTEGER NOT NULL," +
+                Bookmarks.KEYWORD + " TEXT," +
+                Bookmarks.DESCRIPTION + " TEXT," +
+                Bookmarks.TAGS + " TEXT," +
+                Bookmarks.DATE_CREATED + " INTEGER," +
+                Bookmarks.DATE_MODIFIED + " INTEGER," +
+                Bookmarks.GUID + " TEXT NOT NULL," +
+                Bookmarks.IS_DELETED + " INTEGER NOT NULL DEFAULT 0" +
+                (foreignKeyOnParent != null ? foreignKeyOnParent : "") +
+                ");");
+
+        db.execSQL("CREATE INDEX bookmarks_url_index ON " + TABLE_BOOKMARKS + "("
+                + Bookmarks.URL + ")");
+        db.execSQL("CREATE INDEX bookmarks_type_deleted_index ON " + TABLE_BOOKMARKS + "("
+                + Bookmarks.TYPE + ", " + Bookmarks.IS_DELETED + ")");
+        db.execSQL("CREATE UNIQUE INDEX bookmarks_guid_index ON " + TABLE_BOOKMARKS + "("
+                + Bookmarks.GUID + ")");
+        db.execSQL("CREATE INDEX bookmarks_modified_index ON " + TABLE_BOOKMARKS + "("
+                + Bookmarks.DATE_MODIFIED + ")");
+    }
+
+    private void createBookmarksTableOn13(SQLiteDatabase db) {
+        debug("Creating " + TABLE_BOOKMARKS + " table");
+
+        // Android versions older than Froyo ship with an sqlite
+        // that doesn't support foreign keys.
+        String foreignKeyOnParent = null;
+        if (Build.VERSION.SDK_INT >= 8) {
+            foreignKeyOnParent = ", FOREIGN KEY (" + Bookmarks.PARENT +
+                ") REFERENCES " + TABLE_BOOKMARKS + "(" + Bookmarks._ID + ")";
+        }
+
+        db.execSQL("CREATE TABLE " + TABLE_BOOKMARKS + "(" +
+                Bookmarks._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
+                Bookmarks.TITLE + " TEXT," +
+                Bookmarks.URL + " TEXT," +
+                Bookmarks.TYPE + " INTEGER NOT NULL DEFAULT " + Bookmarks.TYPE_BOOKMARK + "," +
+                Bookmarks.PARENT + " INTEGER," +
+                Bookmarks.POSITION + " INTEGER NOT NULL," +
+                Bookmarks.KEYWORD + " TEXT," +
+                Bookmarks.DESCRIPTION + " TEXT," +
+                Bookmarks.TAGS + " TEXT," +
+                Bookmarks.FAVICON_ID + " INTEGER," +
+                Bookmarks.DATE_CREATED + " INTEGER," +
+                Bookmarks.DATE_MODIFIED + " INTEGER," +
+                Bookmarks.GUID + " TEXT NOT NULL," +
+                Bookmarks.IS_DELETED + " INTEGER NOT NULL DEFAULT 0" +
+                (foreignKeyOnParent != null ? foreignKeyOnParent : "") +
+                ");");
+
+        db.execSQL("CREATE INDEX bookmarks_url_index ON " + TABLE_BOOKMARKS + "("
+                + Bookmarks.URL + ")");
+        db.execSQL("CREATE INDEX bookmarks_type_deleted_index ON " + TABLE_BOOKMARKS + "("
+                + Bookmarks.TYPE + ", " + Bookmarks.IS_DELETED + ")");
+        db.execSQL("CREATE UNIQUE INDEX bookmarks_guid_index ON " + TABLE_BOOKMARKS + "("
+                + Bookmarks.GUID + ")");
+        db.execSQL("CREATE INDEX bookmarks_modified_index ON " + TABLE_BOOKMARKS + "("
+                + Bookmarks.DATE_MODIFIED + ")");
+    }
+
+    private void createHistoryTable(SQLiteDatabase db) {
+        debug("Creating " + TABLE_HISTORY + " table");
+        db.execSQL("CREATE TABLE " + TABLE_HISTORY + "(" +
+                History._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
+                History.TITLE + " TEXT," +
+                History.URL + " TEXT NOT NULL," +
+                History.VISITS + " INTEGER NOT NULL DEFAULT 0," +
+                History.DATE_LAST_VISITED + " INTEGER," +
+                History.DATE_CREATED + " INTEGER," +
+                History.DATE_MODIFIED + " INTEGER," +
+                History.GUID + " TEXT NOT NULL," +
+                History.IS_DELETED + " INTEGER NOT NULL DEFAULT 0" +
+                ");");
+
+        db.execSQL("CREATE INDEX history_url_index ON " + TABLE_HISTORY + "("
+                + History.URL + ")");
+        db.execSQL("CREATE UNIQUE INDEX history_guid_index ON " + TABLE_HISTORY + "("
+                + History.GUID + ")");
+        db.execSQL("CREATE INDEX history_modified_index ON " + TABLE_HISTORY + "("
+                + History.DATE_MODIFIED + ")");
+        db.execSQL("CREATE INDEX history_visited_index ON " + TABLE_HISTORY + "("
+                + History.DATE_LAST_VISITED + ")");
+    }
+
+    private void createHistoryTableOn13(SQLiteDatabase db) {
+        debug("Creating " + TABLE_HISTORY + " table");
+        db.execSQL("CREATE TABLE " + TABLE_HISTORY + "(" +
+                History._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
+                History.TITLE + " TEXT," +
+                History.URL + " TEXT NOT NULL," +
+                History.VISITS + " INTEGER NOT NULL DEFAULT 0," +
+                History.FAVICON_ID + " INTEGER," +
+                History.DATE_LAST_VISITED + " INTEGER," +
+                History.DATE_CREATED + " INTEGER," +
+                History.DATE_MODIFIED + " INTEGER," +
+                History.GUID + " TEXT NOT NULL," +
+                History.IS_DELETED + " INTEGER NOT NULL DEFAULT 0" +
+                ");");
+
+        db.execSQL("CREATE INDEX history_url_index ON " + TABLE_HISTORY + "("
+                + History.URL + ")");
+        db.execSQL("CREATE UNIQUE INDEX history_guid_index ON " + TABLE_HISTORY + "("
+                + History.GUID + ")");
+        db.execSQL("CREATE INDEX history_modified_index ON " + TABLE_HISTORY + "("
+                + History.DATE_MODIFIED + ")");
+        db.execSQL("CREATE INDEX history_visited_index ON " + TABLE_HISTORY + "("
+                + History.DATE_LAST_VISITED + ")");
+    }
+
+    private void createImagesTable(SQLiteDatabase db) {
+        debug("Creating " + Obsolete.TABLE_IMAGES + " table");
+        db.execSQL("CREATE TABLE " + Obsolete.TABLE_IMAGES + " (" +
+                Obsolete.Images._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
+                Obsolete.Images.URL + " TEXT UNIQUE NOT NULL," +
+                Obsolete.Images.FAVICON + " BLOB," +
+                Obsolete.Images.FAVICON_URL + " TEXT," +
+                Obsolete.Images.THUMBNAIL + " BLOB," +
+                Obsolete.Images.DATE_CREATED + " INTEGER," +
+                Obsolete.Images.DATE_MODIFIED + " INTEGER," +
+                Obsolete.Images.GUID + " TEXT NOT NULL," +
+                Obsolete.Images.IS_DELETED + " INTEGER NOT NULL DEFAULT 0" +
+                ");");
+
+        db.execSQL("CREATE INDEX images_url_index ON " + Obsolete.TABLE_IMAGES + "("
+                + Obsolete.Images.URL + ")");
+        db.execSQL("CREATE UNIQUE INDEX images_guid_index ON " + Obsolete.TABLE_IMAGES + "("
+                + Obsolete.Images.GUID + ")");
+        db.execSQL("CREATE INDEX images_modified_index ON " + Obsolete.TABLE_IMAGES + "("
+                + Obsolete.Images.DATE_MODIFIED + ")");
+    }
+
+    private void createFaviconsTable(SQLiteDatabase db) {
+        debug("Creating " + TABLE_FAVICONS + " table");
+        db.execSQL("CREATE TABLE " + TABLE_FAVICONS + " (" +
+                Favicons._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
+                Favicons.URL + " TEXT UNIQUE," +
+                Favicons.DATA + " BLOB," +
+                Favicons.DATE_CREATED + " INTEGER," +
+                Favicons.DATE_MODIFIED + " INTEGER" +
+                ");");
+
+        db.execSQL("CREATE INDEX favicons_url_index ON " + TABLE_FAVICONS + "("
+                + Favicons.URL + ")");
+        db.execSQL("CREATE INDEX favicons_modified_index ON " + TABLE_FAVICONS + "("
+                + Favicons.DATE_MODIFIED + ")");
+    }
+
+    private void createThumbnailsTable(SQLiteDatabase db) {
+        debug("Creating " + TABLE_THUMBNAILS + " table");
+        db.execSQL("CREATE TABLE " + TABLE_THUMBNAILS + " (" +
+                Thumbnails._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
+                Thumbnails.URL + " TEXT UNIQUE," +
+                Thumbnails.DATA + " BLOB" +
+                ");");
+
+        db.execSQL("CREATE INDEX thumbnails_url_index ON " + TABLE_THUMBNAILS + "("
+                + Thumbnails.URL + ")");
+    }
+
+    private void createBookmarksWithImagesView(SQLiteDatabase db) {
+        debug("Creating " + Obsolete.VIEW_BOOKMARKS_WITH_IMAGES + " view");
+
+        db.execSQL("CREATE VIEW IF NOT EXISTS " + Obsolete.VIEW_BOOKMARKS_WITH_IMAGES + " AS " +
+                "SELECT " + qualifyColumn(TABLE_BOOKMARKS, "*") +
+                ", " + Obsolete.Images.FAVICON + ", " + Obsolete.Images.THUMBNAIL + " FROM " +
+                Obsolete.TABLE_BOOKMARKS_JOIN_IMAGES);
+    }
+
+    private void createBookmarksWithFaviconsView(SQLiteDatabase db) {
+        debug("Creating " + VIEW_BOOKMARKS_WITH_FAVICONS + " view");
+
+        db.execSQL("CREATE VIEW IF NOT EXISTS " + VIEW_BOOKMARKS_WITH_FAVICONS + " AS " +
+                "SELECT " + qualifyColumn(TABLE_BOOKMARKS, "*") +
+                ", " + qualifyColumn(TABLE_FAVICONS, Favicons.DATA) + " AS " + Bookmarks.FAVICON +
+                ", " + qualifyColumn(TABLE_FAVICONS, Favicons.URL) + " AS " + Bookmarks.FAVICON_URL +
+                " FROM " + TABLE_BOOKMARKS_JOIN_FAVICONS);
+    }
+
+    private void createHistoryWithImagesView(SQLiteDatabase db) {
+        debug("Creating " + Obsolete.VIEW_HISTORY_WITH_IMAGES + " view");
+
+        db.execSQL("CREATE VIEW IF NOT EXISTS " + Obsolete.VIEW_HISTORY_WITH_IMAGES + " AS " +
+                "SELECT " + qualifyColumn(TABLE_HISTORY, "*") +
+                ", " + Obsolete.Images.FAVICON + ", " + Obsolete.Images.THUMBNAIL + " FROM " +
+                Obsolete.TABLE_HISTORY_JOIN_IMAGES);
+    }
+
+    private void createHistoryWithFaviconsView(SQLiteDatabase db) {
+        debug("Creating " + VIEW_HISTORY_WITH_FAVICONS + " view");
+
+        db.execSQL("CREATE VIEW IF NOT EXISTS " + VIEW_HISTORY_WITH_FAVICONS + " AS " +
+                "SELECT " + qualifyColumn(TABLE_HISTORY, "*") +
+                ", " + qualifyColumn(TABLE_FAVICONS, Favicons.DATA) + " AS " + History.FAVICON +
+                ", " + qualifyColumn(TABLE_FAVICONS, Favicons.URL) + " AS " + History.FAVICON_URL +
+                " FROM " + TABLE_HISTORY_JOIN_FAVICONS);
+    }
+
+    private void createCombinedWithImagesView(SQLiteDatabase db) {
+        debug("Creating " + Obsolete.VIEW_COMBINED_WITH_IMAGES + " view");
+
+        db.execSQL("CREATE VIEW IF NOT EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES + " AS" +
+                " SELECT " + Combined.BOOKMARK_ID + ", " +
+                             Combined.HISTORY_ID + ", " +
+                             // We need to return an _id column because CursorAdapter requires it for its
+                             // default implementation for the getItemId() method. However, since
+                             // we're not using this feature in the parts of the UI using this view,
+                             // we can just use 0 for all rows.
+                             "0 AS " + Combined._ID + ", " +
+                             Combined.URL + ", " +
+                             Combined.TITLE + ", " +
+                             Combined.VISITS + ", " +
+                             Combined.DATE_LAST_VISITED + ", " +
+                             qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.FAVICON) + " AS " + Combined.FAVICON + ", " +
+                             qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.THUMBNAIL) + " AS " + Obsolete.Combined.THUMBNAIL +
+                " FROM (" +
+                    // Bookmarks without history.
+                    " SELECT " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " AS " + Combined.BOOKMARK_ID + ", " +
+                                 qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " AS " + Combined.URL + ", " +
+                                 qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + " AS " + Combined.TITLE + ", " +
+                                 "-1 AS " + Combined.HISTORY_ID + ", " +
+                                 "-1 AS " + Combined.VISITS + ", " +
+                                 "-1 AS " + Combined.DATE_LAST_VISITED +
+                    " FROM " + TABLE_BOOKMARKS +
+                    " WHERE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE)  + " = " + Bookmarks.TYPE_BOOKMARK + " AND " +
+                                qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED)  + " = 0 AND " +
+                                qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) +
+                                    " NOT IN (SELECT " + History.URL + " FROM " + TABLE_HISTORY + ")" +
+                    " UNION ALL" +
+                    // History with and without bookmark.
+                    " SELECT " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " AS " + Combined.BOOKMARK_ID + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History.URL) + " AS " + Combined.URL + ", " +
+                                 // Prioritze bookmark titles over history titles, since the user may have
+                                 // customized the title for a bookmark.
+                                 "COALESCE(" + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + ", " +
+                                               qualifyColumn(TABLE_HISTORY, History.TITLE) +")" + " AS " + Combined.TITLE + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History._ID) + " AS " + Combined.HISTORY_ID + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History.VISITS) + " AS " + Combined.VISITS + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History.DATE_LAST_VISITED) + " AS " + Combined.DATE_LAST_VISITED +
+                    " FROM " + TABLE_HISTORY + " LEFT OUTER JOIN " + TABLE_BOOKMARKS +
+                        " ON " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " = " + qualifyColumn(TABLE_HISTORY, History.URL) +
+                    " WHERE " + qualifyColumn(TABLE_HISTORY, History.URL) + " IS NOT NULL AND " +
+                                qualifyColumn(TABLE_HISTORY, History.IS_DELETED)  + " = 0 AND (" +
+                                    qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " IS NULL OR " +
+                                    qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE)  + " = " + Bookmarks.TYPE_BOOKMARK + ")" +
+                ") LEFT OUTER JOIN " + Obsolete.TABLE_IMAGES +
+                    " ON " + Combined.URL + " = " + qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.URL));
+    }
+
+    private void createCombinedWithImagesViewOn9(SQLiteDatabase db) {
+        debug("Creating " + Obsolete.VIEW_COMBINED_WITH_IMAGES + " view");
+
+        db.execSQL("CREATE VIEW IF NOT EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES + " AS" +
+                " SELECT " + Combined.BOOKMARK_ID + ", " +
+                             Combined.HISTORY_ID + ", " +
+                             // We need to return an _id column because CursorAdapter requires it for its
+                             // default implementation for the getItemId() method. However, since
+                             // we're not using this feature in the parts of the UI using this view,
+                             // we can just use 0 for all rows.
+                             "0 AS " + Combined._ID + ", " +
+                             Combined.URL + ", " +
+                             Combined.TITLE + ", " +
+                             Combined.VISITS + ", " +
+                             Combined.DISPLAY + ", " +
+                             Combined.DATE_LAST_VISITED + ", " +
+                             qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.FAVICON) + " AS " + Combined.FAVICON + ", " +
+                             qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.THUMBNAIL) + " AS " + Obsolete.Combined.THUMBNAIL +
+                " FROM (" +
+                    // Bookmarks without history.
+                    " SELECT " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " AS " + Combined.BOOKMARK_ID + ", " +
+                                 qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " AS " + Combined.URL + ", " +
+                                 qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + " AS " + Combined.TITLE + ", " +
+                                 "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " +
+                                    Bookmarks.FIXED_READING_LIST_ID + " THEN " + Combined.DISPLAY_READER + " ELSE " +
+                                    Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " +
+                                 "-1 AS " + Combined.HISTORY_ID + ", " +
+                                 "-1 AS " + Combined.VISITS + ", " +
+                                 "-1 AS " + Combined.DATE_LAST_VISITED +
+                    " FROM " + TABLE_BOOKMARKS +
+                    " WHERE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE)  + " = " + Bookmarks.TYPE_BOOKMARK + " AND " +
+                                qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED)  + " = 0 AND " +
+                                qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) +
+                                    " NOT IN (SELECT " + History.URL + " FROM " + TABLE_HISTORY + ")" +
+                    " UNION ALL" +
+                    // History with and without bookmark.
+                    " SELECT " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " AS " + Combined.BOOKMARK_ID + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History.URL) + " AS " + Combined.URL + ", " +
+                                 // Prioritze bookmark titles over history titles, since the user may have
+                                 // customized the title for a bookmark.
+                                 "COALESCE(" + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + ", " +
+                                               qualifyColumn(TABLE_HISTORY, History.TITLE) +")" + " AS " + Combined.TITLE + ", " +
+                                 "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " +
+                                    Bookmarks.FIXED_READING_LIST_ID + " THEN " + Combined.DISPLAY_READER + " ELSE " +
+                                    Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History._ID) + " AS " + Combined.HISTORY_ID + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History.VISITS) + " AS " + Combined.VISITS + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History.DATE_LAST_VISITED) + " AS " + Combined.DATE_LAST_VISITED +
+                    " FROM " + TABLE_HISTORY + " LEFT OUTER JOIN " + TABLE_BOOKMARKS +
+                        " ON " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " = " + qualifyColumn(TABLE_HISTORY, History.URL) +
+                    " WHERE " + qualifyColumn(TABLE_HISTORY, History.URL) + " IS NOT NULL AND " +
+                                qualifyColumn(TABLE_HISTORY, History.IS_DELETED)  + " = 0 AND (" +
+                                    qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " IS NULL OR " +
+                                    qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE)  + " = " + Bookmarks.TYPE_BOOKMARK + ")" +
+                ") LEFT OUTER JOIN " + Obsolete.TABLE_IMAGES +
+                    " ON " + Combined.URL + " = " + qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.URL));
+    }
+
+    private void createCombinedWithImagesViewOn10(SQLiteDatabase db) {
+        debug("Creating " + Obsolete.VIEW_COMBINED_WITH_IMAGES + " view");
+
+        db.execSQL("CREATE VIEW IF NOT EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES + " AS" +
+                " SELECT " + Combined.BOOKMARK_ID + ", " +
+                             Combined.HISTORY_ID + ", " +
+                             // We need to return an _id column because CursorAdapter requires it for its
+                             // default implementation for the getItemId() method. However, since
+                             // we're not using this feature in the parts of the UI using this view,
+                             // we can just use 0 for all rows.
+                             "0 AS " + Combined._ID + ", " +
+                             Combined.URL + ", " +
+                             Combined.TITLE + ", " +
+                             Combined.VISITS + ", " +
+                             Combined.DISPLAY + ", " +
+                             Combined.DATE_LAST_VISITED + ", " +
+                             qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.FAVICON) + " AS " + Combined.FAVICON + ", " +
+                             qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.THUMBNAIL) + " AS " + Obsolete.Combined.THUMBNAIL +
+                " FROM (" +
+                    // Bookmarks without history.
+                    " SELECT " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " AS " + Combined.BOOKMARK_ID + ", " +
+                                 qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " AS " + Combined.URL + ", " +
+                                 qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + " AS " + Combined.TITLE + ", " +
+                                 "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " +
+                                    Bookmarks.FIXED_READING_LIST_ID + " THEN " + Combined.DISPLAY_READER + " ELSE " +
+                                    Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " +
+                                 "-1 AS " + Combined.HISTORY_ID + ", " +
+                                 "-1 AS " + Combined.VISITS + ", " +
+                                 "-1 AS " + Combined.DATE_LAST_VISITED +
+                    " FROM " + TABLE_BOOKMARKS +
+                    " WHERE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE)  + " = " + Bookmarks.TYPE_BOOKMARK + " AND " +
+                                qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED)  + " = 0 AND " +
+                                qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) +
+                                    " NOT IN (SELECT " + History.URL + " FROM " + TABLE_HISTORY + ")" +
+                    " UNION ALL" +
+                    // History with and without bookmark.
+                    " SELECT " + "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " WHEN 0 THEN " +
+                                 qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) +  " ELSE NULL END AS " + Combined.BOOKMARK_ID + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History.URL) + " AS " + Combined.URL + ", " +
+                                 // Prioritze bookmark titles over history titles, since the user may have
+                                 // customized the title for a bookmark.
+                                 "COALESCE(" + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + ", " +
+                                               qualifyColumn(TABLE_HISTORY, History.TITLE) +")" + " AS " + Combined.TITLE + ", " +
+                                 "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " +
+                                    Bookmarks.FIXED_READING_LIST_ID + " THEN " + Combined.DISPLAY_READER + " ELSE " +
+                                    Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History._ID) + " AS " + Combined.HISTORY_ID + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History.VISITS) + " AS " + Combined.VISITS + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History.DATE_LAST_VISITED) + " AS " + Combined.DATE_LAST_VISITED +
+                    " FROM " + TABLE_HISTORY + " LEFT OUTER JOIN " + TABLE_BOOKMARKS +
+                        " ON " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " = " + qualifyColumn(TABLE_HISTORY, History.URL) +
+                    " WHERE " + qualifyColumn(TABLE_HISTORY, History.URL) + " IS NOT NULL AND " +
+                                qualifyColumn(TABLE_HISTORY, History.IS_DELETED)  + " = 0 AND (" +
+                                    qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " IS NULL OR " +
+                                    qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE)  + " = " + Bookmarks.TYPE_BOOKMARK + ")" +
+                ") LEFT OUTER JOIN " + Obsolete.TABLE_IMAGES +
+                    " ON " + Combined.URL + " = " + qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.URL));
+    }
+
+    private void createCombinedWithImagesViewOn11(SQLiteDatabase db) {
+        debug("Creating " + Obsolete.VIEW_COMBINED_WITH_IMAGES + " view");
+
+        db.execSQL("CREATE VIEW IF NOT EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES + " AS" +
+                " SELECT " + Combined.BOOKMARK_ID + ", " +
+                             Combined.HISTORY_ID + ", " +
+                             // We need to return an _id column because CursorAdapter requires it for its
+                             // default implementation for the getItemId() method. However, since
+                             // we're not using this feature in the parts of the UI using this view,
+                             // we can just use 0 for all rows.
+                             "0 AS " + Combined._ID + ", " +
+                             Combined.URL + ", " +
+                             Combined.TITLE + ", " +
+                             Combined.VISITS + ", " +
+                             Combined.DISPLAY + ", " +
+                             Combined.DATE_LAST_VISITED + ", " +
+                             qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.FAVICON) + " AS " + Combined.FAVICON + ", " +
+                             qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.THUMBNAIL) + " AS " + Obsolete.Combined.THUMBNAIL +
+                " FROM (" +
+                    // Bookmarks without history.
+                    " SELECT " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " AS " + Combined.BOOKMARK_ID + ", " +
+                                 qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " AS " + Combined.URL + ", " +
+                                 qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + " AS " + Combined.TITLE + ", " +
+                                 "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " +
+                                    Bookmarks.FIXED_READING_LIST_ID + " THEN " + Combined.DISPLAY_READER + " ELSE " +
+                                    Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " +
+                                 "-1 AS " + Combined.HISTORY_ID + ", " +
+                                 "-1 AS " + Combined.VISITS + ", " +
+                                 "-1 AS " + Combined.DATE_LAST_VISITED +
+                    " FROM " + TABLE_BOOKMARKS +
+                    " WHERE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE)  + " = " + Bookmarks.TYPE_BOOKMARK + " AND " +
+                                qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED)  + " = 0 AND " +
+                                qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) +
+                                    " NOT IN (SELECT " + History.URL + " FROM " + TABLE_HISTORY + ")" +
+                    " UNION ALL" +
+                    // History with and without bookmark.
+                    " SELECT " + "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " WHEN 0 THEN " +
+                                 qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) +  " ELSE NULL END AS " + Combined.BOOKMARK_ID + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History.URL) + " AS " + Combined.URL + ", " +
+                                 // Prioritze bookmark titles over history titles, since the user may have
+                                 // customized the title for a bookmark.
+                                 "COALESCE(" + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + ", " +
+                                               qualifyColumn(TABLE_HISTORY, History.TITLE) +")" + " AS " + Combined.TITLE + ", " +
+                                 // Only use DISPLAY_READER if the matching bookmark entry inside reading
+                                 // list folder is not marked as deleted.
+                                 "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " WHEN 0 THEN CASE " +
+                                    qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " + Bookmarks.FIXED_READING_LIST_ID +
+                                    " THEN " + Combined.DISPLAY_READER + " ELSE " + Combined.DISPLAY_NORMAL + " END ELSE " +
+                                    Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History._ID) + " AS " + Combined.HISTORY_ID + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History.VISITS) + " AS " + Combined.VISITS + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History.DATE_LAST_VISITED) + " AS " + Combined.DATE_LAST_VISITED +
+                    " FROM " + TABLE_HISTORY + " LEFT OUTER JOIN " + TABLE_BOOKMARKS +
+                        " ON " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " = " + qualifyColumn(TABLE_HISTORY, History.URL) +
+                    " WHERE " + qualifyColumn(TABLE_HISTORY, History.URL) + " IS NOT NULL AND " +
+                                qualifyColumn(TABLE_HISTORY, History.IS_DELETED)  + " = 0 AND (" +
+                                    qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " IS NULL OR " +
+                                    qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE)  + " = " + Bookmarks.TYPE_BOOKMARK + ") " +
+                ") LEFT OUTER JOIN " + Obsolete.TABLE_IMAGES +
+                    " ON " + Combined.URL + " = " + qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.URL));
+    }
+
+    private void createCombinedViewOn12(SQLiteDatabase db) {
+        debug("Creating " + VIEW_COMBINED + " view");
+
+        db.execSQL("CREATE VIEW IF NOT EXISTS " + VIEW_COMBINED + " AS" +
+                " SELECT " + Combined.BOOKMARK_ID + ", " +
+                             Combined.HISTORY_ID + ", " +
+                             // We need to return an _id column because CursorAdapter requires it for its
+                             // default implementation for the getItemId() method. However, since
+                             // we're not using this feature in the parts of the UI using this view,
+                             // we can just use 0 for all rows.
+                             "0 AS " + Combined._ID + ", " +
+                             Combined.URL + ", " +
+                             Combined.TITLE + ", " +
+                             Combined.VISITS + ", " +
+                             Combined.DISPLAY + ", " +
+                             Combined.DATE_LAST_VISITED +
+                " FROM (" +
+                    // Bookmarks without history.
+                    " SELECT " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " AS " + Combined.BOOKMARK_ID + ", " +
+                                 qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " AS " + Combined.URL + ", " +
+                                 qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + " AS " + Combined.TITLE + ", " +
+                                 "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " +
+                                    Bookmarks.FIXED_READING_LIST_ID + " THEN " + Combined.DISPLAY_READER + " ELSE " +
+                                    Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " +
+                                 "-1 AS " + Combined.HISTORY_ID + ", " +
+                                 "-1 AS " + Combined.VISITS + ", " +
+                                 "-1 AS " + Combined.DATE_LAST_VISITED +
+                    " FROM " + TABLE_BOOKMARKS +
+                    " WHERE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE)  + " = " + Bookmarks.TYPE_BOOKMARK + " AND " +
+                                qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED)  + " = 0 AND " +
+                                qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) +
+                                    " NOT IN (SELECT " + History.URL + " FROM " + TABLE_HISTORY + ")" +
+                    " UNION ALL" +
+                    // History with and without bookmark.
+                    " SELECT " + "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " WHEN 0 THEN " +
+                                 qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) +  " ELSE NULL END AS " + Combined.BOOKMARK_ID + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History.URL) + " AS " + Combined.URL + ", " +
+                                 // Prioritze bookmark titles over history titles, since the user may have
+                                 // customized the title for a bookmark.
+                                 "COALESCE(" + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + ", " +
+                                               qualifyColumn(TABLE_HISTORY, History.TITLE) +")" + " AS " + Combined.TITLE + ", " +
+                                 // Only use DISPLAY_READER if the matching bookmark entry inside reading
+                                 // list folder is not marked as deleted.
+                                 "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " WHEN 0 THEN CASE " +
+                                    qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " + Bookmarks.FIXED_READING_LIST_ID +
+                                    " THEN " + Combined.DISPLAY_READER + " ELSE " + Combined.DISPLAY_NORMAL + " END ELSE " +
+                                    Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History._ID) + " AS " + Combined.HISTORY_ID + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History.VISITS) + " AS " + Combined.VISITS + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History.DATE_LAST_VISITED) + " AS " + Combined.DATE_LAST_VISITED +
+                    " FROM " + TABLE_HISTORY + " LEFT OUTER JOIN " + TABLE_BOOKMARKS +
+                        " ON " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " = " + qualifyColumn(TABLE_HISTORY, History.URL) +
+                    " WHERE " + qualifyColumn(TABLE_HISTORY, History.URL) + " IS NOT NULL AND " +
+                                qualifyColumn(TABLE_HISTORY, History.IS_DELETED)  + " = 0 AND (" +
+                                    qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " IS NULL OR " +
+                                    qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE)  + " = " + Bookmarks.TYPE_BOOKMARK + ") " +
+                ")");
+
+        debug("Creating " + Obsolete.VIEW_COMBINED_WITH_IMAGES + " view");
+
+        db.execSQL("CREATE VIEW IF NOT EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES + " AS" +
+                " SELECT *, " +
+                    qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.FAVICON) + " AS " + Combined.FAVICON + ", " +
+                    qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.THUMBNAIL) + " AS " + Obsolete.Combined.THUMBNAIL +
+                " FROM " + VIEW_COMBINED + " LEFT OUTER JOIN " + Obsolete.TABLE_IMAGES +
+                    " ON " + Combined.URL + " = " + qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.URL));
+    }
+
+    private void createCombinedViewOn13(SQLiteDatabase db) {
+        debug("Creating " + VIEW_COMBINED + " view");
+
+        db.execSQL("CREATE VIEW IF NOT EXISTS " + VIEW_COMBINED + " AS" +
+                " SELECT " + Combined.BOOKMARK_ID + ", " +
+                             Combined.HISTORY_ID + ", " +
+                             // We need to return an _id column because CursorAdapter requires it for its
+                             // default implementation for the getItemId() method. However, since
+                             // we're not using this feature in the parts of the UI using this view,
+                             // we can just use 0 for all rows.
+                             "0 AS " + Combined._ID + ", " +
+                             Combined.URL + ", " +
+                             Combined.TITLE + ", " +
+                             Combined.VISITS + ", " +
+                             Combined.DISPLAY + ", " +
+                             Combined.DATE_LAST_VISITED + ", " +
+                             Combined.FAVICON_ID +
+                " FROM (" +
+                    // Bookmarks without history.
+                    " SELECT " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " AS " + Combined.BOOKMARK_ID + ", " +
+                                 qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " AS " + Combined.URL + ", " +
+                                 qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + " AS " + Combined.TITLE + ", " +
+                                 "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " +
+                                    Bookmarks.FIXED_READING_LIST_ID + " THEN " + Combined.DISPLAY_READER + " ELSE " +
+                                    Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " +
+                                 "-1 AS " + Combined.HISTORY_ID + ", " +
+                                 "-1 AS " + Combined.VISITS + ", " +
+                                 "-1 AS " + Combined.DATE_LAST_VISITED + ", " +
+                                 qualifyColumn(TABLE_BOOKMARKS, Bookmarks.FAVICON_ID) + " AS " + Combined.FAVICON_ID +
+                    " FROM " + TABLE_BOOKMARKS +
+                    " WHERE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE)  + " = " + Bookmarks.TYPE_BOOKMARK + " AND " +
+                                qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED)  + " = 0 AND " +
+                                qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) +
+                                    " NOT IN (SELECT " + History.URL + " FROM " + TABLE_HISTORY + ")" +
+                    " UNION ALL" +
+                    // History with and without bookmark.
+                    " SELECT " + "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " WHEN 0 THEN " +
+                                 qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) +  " ELSE NULL END AS " + Combined.BOOKMARK_ID + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History.URL) + " AS " + Combined.URL + ", " +
+                                 // Prioritize bookmark titles over history titles, since the user may have
+                                 // customized the title for a bookmark.
+                                 "COALESCE(" + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + ", " +
+                                               qualifyColumn(TABLE_HISTORY, History.TITLE) +")" + " AS " + Combined.TITLE + ", " +
+                                 // Only use DISPLAY_READER if the matching bookmark entry inside reading
+                                 // list folder is not marked as deleted.
+                                 "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " WHEN 0 THEN CASE " +
+                                    qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " + Bookmarks.FIXED_READING_LIST_ID +
+                                    " THEN " + Combined.DISPLAY_READER + " ELSE " + Combined.DISPLAY_NORMAL + " END ELSE " +
+                                    Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History._ID) + " AS " + Combined.HISTORY_ID + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History.VISITS) + " AS " + Combined.VISITS + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History.DATE_LAST_VISITED) + " AS " + Combined.DATE_LAST_VISITED + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History.FAVICON_ID) + " AS " + Combined.FAVICON_ID +
+                    " FROM " + TABLE_HISTORY + " LEFT OUTER JOIN " + TABLE_BOOKMARKS +
+                        " ON " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " = " + qualifyColumn(TABLE_HISTORY, History.URL) +
+                    " WHERE " + qualifyColumn(TABLE_HISTORY, History.URL) + " IS NOT NULL AND " +
+                                qualifyColumn(TABLE_HISTORY, History.IS_DELETED)  + " = 0 AND (" +
+                                    qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " IS NULL OR " +
+                                    qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE)  + " = " + Bookmarks.TYPE_BOOKMARK + ") " +
+                ")");
+
+        debug("Creating " + VIEW_COMBINED_WITH_FAVICONS + " view");
+
+        db.execSQL("CREATE VIEW IF NOT EXISTS " + VIEW_COMBINED_WITH_FAVICONS + " AS" +
+                " SELECT " + qualifyColumn(VIEW_COMBINED, "*") + ", " +
+                    qualifyColumn(TABLE_FAVICONS, Favicons.URL) + " AS " + Combined.FAVICON_URL + ", " +
+                    qualifyColumn(TABLE_FAVICONS, Favicons.DATA) + " AS " + Combined.FAVICON +
+                " FROM " + VIEW_COMBINED + " LEFT OUTER JOIN " + TABLE_FAVICONS +
+                    " ON " + Combined.FAVICON_ID + " = " + qualifyColumn(TABLE_FAVICONS, Favicons._ID));
+    }
+
+    private void createCombinedViewOn16(SQLiteDatabase db) {
+        debug("Creating " + VIEW_COMBINED + " view");
+
+        db.execSQL("CREATE VIEW IF NOT EXISTS " + VIEW_COMBINED + " AS" +
+                " SELECT " + Combined.BOOKMARK_ID + ", " +
+                             Combined.HISTORY_ID + ", " +
+                             // We need to return an _id column because CursorAdapter requires it for its
+                             // default implementation for the getItemId() method. However, since
+                             // we're not using this feature in the parts of the UI using this view,
+                             // we can just use 0 for all rows.
+                             "0 AS " + Combined._ID + ", " +
+                             Combined.URL + ", " +
+                             Combined.TITLE + ", " +
+                             Combined.VISITS + ", " +
+                             Combined.DISPLAY + ", " +
+                             Combined.DATE_LAST_VISITED + ", " +
+                             Combined.FAVICON_ID +
+                " FROM (" +
+                    // Bookmarks without history.
+                    " SELECT " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " AS " + Combined.BOOKMARK_ID + ", " +
+                                 qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " AS " + Combined.URL + ", " +
+                                 qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + " AS " + Combined.TITLE + ", " +
+                                 "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " +
+                                    Bookmarks.FIXED_READING_LIST_ID + " THEN " + Combined.DISPLAY_READER + " ELSE " +
+                                    Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " +
+                                 "-1 AS " + Combined.HISTORY_ID + ", " +
+                                 "-1 AS " + Combined.VISITS + ", " +
+                                 "-1 AS " + Combined.DATE_LAST_VISITED + ", " +
+                                 qualifyColumn(TABLE_BOOKMARKS, Bookmarks.FAVICON_ID) + " AS " + Combined.FAVICON_ID +
+                    " FROM " + TABLE_BOOKMARKS +
+                    " WHERE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE)  + " = " + Bookmarks.TYPE_BOOKMARK + " AND " +
+                                // Ignore pinned bookmarks.
+                                qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT)  + " <> " + Bookmarks.FIXED_PINNED_LIST_ID + " AND " +
+                                qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED)  + " = 0 AND " +
+                                qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) +
+                                    " NOT IN (SELECT " + History.URL + " FROM " + TABLE_HISTORY + ")" +
+                    " UNION ALL" +
+                    // History with and without bookmark.
+                    " SELECT " + "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " WHEN 0 THEN " +
+                                    // Give pinned bookmarks a NULL ID so that they're not treated as bookmarks. We can't
+                                    // completely ignore them here because they're joined with history entries we care about.
+                                    "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " +
+                                    Bookmarks.FIXED_PINNED_LIST_ID + " THEN NULL ELSE " +
+                                    qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " END " +
+                                 "ELSE NULL END AS " + Combined.BOOKMARK_ID + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History.URL) + " AS " + Combined.URL + ", " +
+                                 // Prioritize bookmark titles over history titles, since the user may have
+                                 // customized the title for a bookmark.
+                                 "COALESCE(" + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + ", " +
+                                               qualifyColumn(TABLE_HISTORY, History.TITLE) +")" + " AS " + Combined.TITLE + ", " +
+                                 // Only use DISPLAY_READER if the matching bookmark entry inside reading
+                                 // list folder is not marked as deleted.
+                                 "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " WHEN 0 THEN CASE " +
+                                    qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " + Bookmarks.FIXED_READING_LIST_ID +
+                                    " THEN " + Combined.DISPLAY_READER + " ELSE " + Combined.DISPLAY_NORMAL + " END ELSE " +
+                                    Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History._ID) + " AS " + Combined.HISTORY_ID + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History.VISITS) + " AS " + Combined.VISITS + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History.DATE_LAST_VISITED) + " AS " + Combined.DATE_LAST_VISITED + ", " +
+                                 qualifyColumn(TABLE_HISTORY, History.FAVICON_ID) + " AS " + Combined.FAVICON_ID +
+                    " FROM " + TABLE_HISTORY + " LEFT OUTER JOIN " + TABLE_BOOKMARKS +
+                        " ON " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " = " + qualifyColumn(TABLE_HISTORY, History.URL) +
+                    " WHERE " + qualifyColumn(TABLE_HISTORY, History.URL) + " IS NOT NULL AND " +
+                                qualifyColumn(TABLE_HISTORY, History.IS_DELETED)  + " = 0 AND (" +
+                                    qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " IS NULL OR " +
+                                    qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE)  + " = " + Bookmarks.TYPE_BOOKMARK + ") " +
+                ")");
+
+        debug("Creating " + VIEW_COMBINED_WITH_FAVICONS + " view");
+
+        db.execSQL("CREATE VIEW IF NOT EXISTS " + VIEW_COMBINED_WITH_FAVICONS + " AS" +
+                " SELECT " + qualifyColumn(VIEW_COMBINED, "*") + ", " +
+                    qualifyColumn(TABLE_FAVICONS, Favicons.URL) + " AS " + Combined.FAVICON_URL + ", " +
+                    qualifyColumn(TABLE_FAVICONS, Favicons.DATA) + " AS " + Combined.FAVICON +
+                " FROM " + VIEW_COMBINED + " LEFT OUTER JOIN " + TABLE_FAVICONS +
+                    " ON " + Combined.FAVICON_ID + " = " + qualifyColumn(TABLE_FAVICONS, Favicons._ID));
+    }
+
+    @Override
+    public void onCreate(SQLiteDatabase db) {
+        debug("Creating browser.db: " + db.getPath());
+
+        createBookmarksTableOn13(db);
+        createHistoryTableOn13(db);
+        createFaviconsTable(db);
+        createThumbnailsTable(db);
+
+        createBookmarksWithFaviconsView(db);
+        createHistoryWithFaviconsView(db);
+        createCombinedViewOn16(db);
+
+        createOrUpdateSpecialFolder(db, Bookmarks.PLACES_FOLDER_GUID,
+            R.string.bookmarks_folder_places, 0);
+
+        createOrUpdateAllSpecialFolders(db);
+
+        // Create distribution bookmarks before our own default bookmarks
+        int pos = createDistributionBookmarks(db);
+        createDefaultBookmarks(db, pos);
+    }
+
+    private String getLocalizedProperty(JSONObject bookmark, String property, Locale locale) throws JSONException {
+        // Try the full locale
+        String fullLocale = property + "." + locale.toString();
+        if (bookmark.has(fullLocale)) {
+            return bookmark.getString(fullLocale);
+        }
+        // Try without a variant
+        if (!TextUtils.isEmpty(locale.getVariant())) {
+            String noVariant = fullLocale.substring(0, fullLocale.lastIndexOf("_"));
+            if (bookmark.has(noVariant)) {
+                return bookmark.getString(noVariant);
+            }
+        }
+        // Try just the language
+        String lang = property + "." + locale.getLanguage();
+        if (bookmark.has(lang)) {
+            return bookmark.getString(lang);
+        }
+        // Default to the non-localized property name
+        return bookmark.getString(property);
+    }
+
+    // Returns the number of bookmarks inserted in the db
+    private int createDistributionBookmarks(SQLiteDatabase db) {
+        JSONArray bookmarks = Distribution.getBookmarks(mContext);
+        if (bookmarks == null) {
+            return 0;
+        }
+
+        Locale locale = Locale.getDefault();
+        int pos = 0;
+        Integer mobileFolderId = getMobileFolderId(db);
+        if (mobileFolderId == null) {
+            Log.e(LOGTAG, "Error creating distribution bookmarks: mobileFolderId is null");
+            return 0;
+        }
+
+        for (int i = 0; i < bookmarks.length(); i++) {
+            try {
+                final JSONObject bookmark = bookmarks.getJSONObject(i);
+
+                String title = getLocalizedProperty(bookmark, "title", locale);
+                final String url = getLocalizedProperty(bookmark, "url", locale);
+                createBookmark(db, title, url, pos, mobileFolderId);
+
+                if (bookmark.has("pinned")) {
+                    try {
+                        // Create a fake bookmark in the hidden pinned folder to pin bookmark
+                        // to about:home top sites. Pass pos as the pinned position to pin
+                        // sites in the order that bookmarks are specified in bookmarks.json.
+                        if (bookmark.getBoolean("pinned")) {
+                            createBookmark(db, title, url, pos, Bookmarks.FIXED_PINNED_LIST_ID);
+                        }
+                    } catch (JSONException e) {
+                        Log.e(LOGTAG, "Error pinning bookmark to top sites", e);
+                    }
+                }
+
+                pos++;
+
+                // return early if there is no icon for this bookmark
+                if (!bookmark.has("icon")) {
+                    continue;
+                }
+
+                // create icons in a separate thread to avoid blocking about:home on startup
+                ThreadUtils.postToBackgroundThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        SQLiteDatabase db = getWritableDatabase();
+                        try {
+                            String iconData = bookmark.getString("icon");
+                            Bitmap icon = BitmapUtils.getBitmapFromDataURI(iconData);
+                            if (icon != null) {
+                                createFavicon(db, url, icon);
+                            }
+                        } catch (JSONException e) {
+                            Log.e(LOGTAG, "Error creating distribution bookmark icon", e);
+                        }
+                    }
+                });
+            } catch (JSONException e) {
+                Log.e(LOGTAG, "Error creating distribution bookmark", e);
+            }
+        }
+        return pos;
+    }
+
+    // Inserts default bookmarks, starting at a specified position
+    private void createDefaultBookmarks(SQLiteDatabase db, int pos) {
+        Class<?> stringsClass = R.string.class;
+        Field[] fields = stringsClass.getFields();
+        Pattern p = Pattern.compile("^bookmarkdefaults_title_");
+
+        Integer mobileFolderId = getMobileFolderId(db);
+        if (mobileFolderId == null) {
+            Log.e(LOGTAG, "Error creating default bookmarks: mobileFolderId is null");
+            return;
+        }
+
+        for (int i = 0; i < fields.length; i++) {
+            final String name = fields[i].getName();
+            Matcher m = p.matcher(name);
+            if (!m.find()) {
+                continue;
+            }
+            try {
+                int titleid = fields[i].getInt(null);
+                String title = mContext.getString(titleid);
+
+                Field urlField = stringsClass.getField(name.replace("_title_", "_url_"));
+                int urlId = urlField.getInt(null);
+                final String url = mContext.getString(urlId);
+                createBookmark(db, title, url, pos, mobileFolderId);
+
+                // create icons in a separate thread to avoid blocking about:home on startup
+                ThreadUtils.postToBackgroundThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        SQLiteDatabase db = getWritableDatabase();
+                        Bitmap icon = getDefaultFaviconFromPath(name);
+                        if (icon == null) {
+                            icon = getDefaultFaviconFromDrawable(name);
+                        }
+                        if (icon != null) {
+                            createFavicon(db, url, icon);
+                        }
+                    }
+                });
+                pos++;
+            } catch (java.lang.IllegalAccessException ex) {
+                Log.e(LOGTAG, "Can't create bookmark " + name, ex);
+            } catch (java.lang.NoSuchFieldException ex) {
+                Log.e(LOGTAG, "Can't create bookmark " + name, ex);
+            }
+        }
+    }
+
+    private void createBookmark(SQLiteDatabase db, String title, String url, int pos, int parent) {
+        ContentValues bookmarkValues = new ContentValues();
+        bookmarkValues.put(Bookmarks.PARENT, parent);
+
+        long now = System.currentTimeMillis();
+        bookmarkValues.put(Bookmarks.DATE_CREATED, now);
+        bookmarkValues.put(Bookmarks.DATE_MODIFIED, now);
+
+        bookmarkValues.put(Bookmarks.TITLE, title);
+        bookmarkValues.put(Bookmarks.URL, url);
+        bookmarkValues.put(Bookmarks.GUID, Utils.generateGuid());
+        bookmarkValues.put(Bookmarks.POSITION, pos);
+        db.insertOrThrow(TABLE_BOOKMARKS, Bookmarks.TITLE, bookmarkValues);
+    }
+
+    private void createFavicon(SQLiteDatabase db, String url, Bitmap icon) {
+        ByteArrayOutputStream stream = new ByteArrayOutputStream();
+
+        ContentValues iconValues = new ContentValues();
+        iconValues.put(Favicons.PAGE_URL, url);
+
+        byte[] data = null;
+        if (icon.compress(Bitmap.CompressFormat.PNG, 100, stream)) {
+            data = stream.toByteArray();
+        } else {
+            Log.w(LOGTAG, "Favicon compression failed.");
+        }
+        iconValues.put(Favicons.DATA, data);
+
+        insertFavicon(db, iconValues);
+    }
+
+    private Bitmap getDefaultFaviconFromPath(String name) {
+        Class<?> stringClass = R.string.class;
+        try {
+            // Look for a drawable with the id R.drawable.bookmarkdefaults_favicon_*
+            Field faviconField = stringClass.getField(name.replace("_title_", "_favicon_"));
+            if (faviconField == null) {
+                return null;
+            }
+            int faviconId = faviconField.getInt(null);
+            String path = mContext.getString(faviconId);
+
+            String apkPath = mContext.getPackageResourcePath();
+            File apkFile = new File(apkPath);
+            String bitmapPath = "jar:jar:" + apkFile.toURI() + "!/" + AppConstants.OMNIJAR_NAME + "!/" + path;
+            return GeckoJarReader.getBitmap(mContext.getResources(), bitmapPath);
+        } catch (java.lang.IllegalAccessException ex) {
+            Log.e(LOGTAG, "[Path] Can't create favicon " + name, ex);
+        } catch (java.lang.NoSuchFieldException ex) {
+            // If the field does not exist, that means we intend to load via a drawable
+        }
+        return null;
+    }
+
+    private Bitmap getDefaultFaviconFromDrawable(String name) {
+        Class<?> drawablesClass = R.drawable.class;
+        try {
+            // Look for a drawable with the id R.drawable.bookmarkdefaults_favicon_*
+            Field faviconField = drawablesClass.getField(name.replace("_title_", "_favicon_"));
+            if (faviconField == null) {
+                return null;
+            }
+            int faviconId = faviconField.getInt(null);
+            return BitmapUtils.decodeResource(mContext, faviconId);
+        } catch (java.lang.IllegalAccessException ex) {
+            Log.e(LOGTAG, "[Drawable] Can't create favicon " + name, ex);
+        } catch (java.lang.NoSuchFieldException ex) {
+            // If the field does not exist, that means we intend to load via a file path
+        }
+        return null;
+    }
+
+    private void createOrUpdateAllSpecialFolders(SQLiteDatabase db) {
+        createOrUpdateSpecialFolder(db, Bookmarks.MOBILE_FOLDER_GUID,
+            R.string.bookmarks_folder_mobile, 0);
+        createOrUpdateSpecialFolder(db, Bookmarks.TOOLBAR_FOLDER_GUID,
+            R.string.bookmarks_folder_toolbar, 1);
+        createOrUpdateSpecialFolder(db, Bookmarks.MENU_FOLDER_GUID,
+            R.string.bookmarks_folder_menu, 2);
+        createOrUpdateSpecialFolder(db, Bookmarks.TAGS_FOLDER_GUID,
+            R.string.bookmarks_folder_tags, 3);
+        createOrUpdateSpecialFolder(db, Bookmarks.UNFILED_FOLDER_GUID,
+            R.string.bookmarks_folder_unfiled, 4);
+        createOrUpdateSpecialFolder(db, Bookmarks.READING_LIST_FOLDER_GUID,
+            R.string.bookmarks_folder_reading_list, 5);
+        createOrUpdateSpecialFolder(db, Bookmarks.PINNED_FOLDER_GUID,
+            R.string.bookmarks_folder_pinned, 6);
+    }
+
+    private void createOrUpdateSpecialFolder(SQLiteDatabase db,
+            String guid, int titleId, int position) {
+        ContentValues values = new ContentValues();
+        values.put(Bookmarks.GUID, guid);
+        values.put(Bookmarks.TYPE, Bookmarks.TYPE_FOLDER);
+        values.put(Bookmarks.POSITION, position);
+
+        if (guid.equals(Bookmarks.PLACES_FOLDER_GUID))
+            values.put(Bookmarks._ID, Bookmarks.FIXED_ROOT_ID);
+        else if (guid.equals(Bookmarks.READING_LIST_FOLDER_GUID))
+            values.put(Bookmarks._ID, Bookmarks.FIXED_READING_LIST_ID);
+        else if (guid.equals(Bookmarks.PINNED_FOLDER_GUID))
+            values.put(Bookmarks._ID, Bookmarks.FIXED_PINNED_LIST_ID);
+
+        // Set the parent to 0, which sync assumes is the root
+        values.put(Bookmarks.PARENT, Bookmarks.FIXED_ROOT_ID);
+
+        String title = mContext.getResources().getString(titleId);
+        values.put(Bookmarks.TITLE, title);
+
+        long now = System.currentTimeMillis();
+        values.put(Bookmarks.DATE_CREATED, now);
+        values.put(Bookmarks.DATE_MODIFIED, now);
+
+        int updated = db.update(TABLE_BOOKMARKS, values,
+                                Bookmarks.GUID + " = ?",
+                                new String[] { guid });
+
+        if (updated == 0) {
+            db.insert(TABLE_BOOKMARKS, Bookmarks.GUID, values);
+            debug("Inserted special folder: " + guid);
+        } else {
+            debug("Updated special folder: " + guid);
+        }
+    }
+
+    private boolean isSpecialFolder(ContentValues values) {
+        String guid = values.getAsString(Bookmarks.GUID);
+        if (guid == null)
+            return false;
+
+        return guid.equals(Bookmarks.MOBILE_FOLDER_GUID) ||
+               guid.equals(Bookmarks.MENU_FOLDER_GUID) ||
+               guid.equals(Bookmarks.TOOLBAR_FOLDER_GUID) ||
+               guid.equals(Bookmarks.UNFILED_FOLDER_GUID) ||
+               guid.equals(Bookmarks.TAGS_FOLDER_GUID);
+    }
+
+    private void migrateBookmarkFolder(SQLiteDatabase db, int folderId,
+            BookmarkMigrator migrator) {
+        Cursor c = null;
+
+        debug("Migrating bookmark folder with id = " + folderId);
+
+        String selection = Bookmarks.PARENT + " = " + folderId;
+        String[] selectionArgs = null;
+
+        boolean isRootFolder = (folderId == Bookmarks.FIXED_ROOT_ID);
+
+        // If we're loading the root folder, we have to account for
+        // any previously created special folder that was created without
+        // setting a parent id (e.g. mobile folder) and making sure we're
+        // not adding any infinite recursion as root's parent is root itself.
+        if (isRootFolder) {
+            selection = Bookmarks.GUID + " != ?" + " AND (" +
+                        selection + " OR " + Bookmarks.PARENT + " = NULL)";
+            selectionArgs = new String[] { Bookmarks.PLACES_FOLDER_GUID };
+        }
+
+        List<Integer> subFolders = new ArrayList<Integer>();
+        List<ContentValues> invalidSpecialEntries = new ArrayList<ContentValues>();
+
+        try {
+            c = db.query(TABLE_BOOKMARKS_TMP,
+                         null,
+                         selection,
+                         selectionArgs,
+                         null, null, null);
+
+            // The key point here is that bookmarks should be added in
+            // parent order to avoid any problems with the foreign key
+            // in Bookmarks.PARENT.
+            while (c.moveToNext()) {
+                ContentValues values = new ContentValues();
+
+                // We're using a null projection in the query which
+                // means we're getting all columns from the table.
+                // It's safe to simply transform the row into the
+                // values to be inserted on the new table.
+                DatabaseUtils.cursorRowToContentValues(c, values);
+
+                boolean isSpecialFolder = isSpecialFolder(values);
+
+                // The mobile folder used to be created with PARENT = NULL.
+                // We want fix that here.
+                if (values.getAsLong(Bookmarks.PARENT) == null && isSpecialFolder)
+                    values.put(Bookmarks.PARENT, Bookmarks.FIXED_ROOT_ID);
+
+                if (isRootFolder && !isSpecialFolder) {
+                    invalidSpecialEntries.add(values);
+                    continue;
+                }
+
+                if (migrator != null)
+                    migrator.updateForNewTable(values);
+
+                debug("Migrating bookmark: " + values.getAsString(Bookmarks.TITLE));
+                db.insert(TABLE_BOOKMARKS, Bookmarks.URL, values);
+
+                Integer type = values.getAsInteger(Bookmarks.TYPE);
+                if (type != null && type == Bookmarks.TYPE_FOLDER)
+                    subFolders.add(values.getAsInteger(Bookmarks._ID));
+            }
+        } finally {
+            if (c != null)
+                c.close();
+        }
+
+        // At this point is safe to assume that the mobile folder is
+        // in the new table given that we've always created it on
+        // database creation time.
+        final int nInvalidSpecialEntries = invalidSpecialEntries.size();
+        if (nInvalidSpecialEntries > 0) {
+            Integer mobileFolderId = getMobileFolderId(db);
+            if (mobileFolderId == null) {
+                Log.e(LOGTAG, "Error migrating invalid special folder entries: mobile folder id is null");
+                return;
+            }
+
+            debug("Found " + nInvalidSpecialEntries + " invalid special folder entries");
+            for (int i = 0; i < nInvalidSpecialEntries; i++) {
+                ContentValues values = invalidSpecialEntries.get(i);
+                values.put(Bookmarks.PARENT, mobileFolderId);
+
+                db.insert(TABLE_BOOKMARKS, Bookmarks.URL, values);
+            }
+        }
+
+        final int nSubFolders = subFolders.size();
+        for (int i = 0; i < nSubFolders; i++) {
+            int subFolderId = subFolders.get(i);
+            migrateBookmarkFolder(db, subFolderId, migrator);
+        }
+    }
+
+    private void migrateBookmarksTable(SQLiteDatabase db) {
+        migrateBookmarksTable(db, null);
+    }
+
+    private void migrateBookmarksTable(SQLiteDatabase db, BookmarkMigrator migrator) {
+        debug("Renaming bookmarks table to " + TABLE_BOOKMARKS_TMP);
+        db.execSQL("ALTER TABLE " + TABLE_BOOKMARKS +
+                   " RENAME TO " + TABLE_BOOKMARKS_TMP);
+
+        debug("Dropping views and indexes related to " + TABLE_BOOKMARKS);
+        db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_BOOKMARKS_WITH_IMAGES);
+
+        db.execSQL("DROP INDEX IF EXISTS bookmarks_url_index");
+        db.execSQL("DROP INDEX IF EXISTS bookmarks_type_deleted_index");
+        db.execSQL("DROP INDEX IF EXISTS bookmarks_guid_index");
+        db.execSQL("DROP INDEX IF EXISTS bookmarks_modified_index");
+
+        createBookmarksTable(db);
+        createBookmarksWithImagesView(db);
+
+        createOrUpdateSpecialFolder(db, Bookmarks.PLACES_FOLDER_GUID,
+            R.string.bookmarks_folder_places, 0);
+
+        migrateBookmarkFolder(db, Bookmarks.FIXED_ROOT_ID, migrator);
+
+        // Ensure all special folders exist and have the
+        // right folder hierarchy.
+        createOrUpdateAllSpecialFolders(db);
+
+        debug("Dropping bookmarks temporary table");
+        db.execSQL("DROP TABLE IF EXISTS " + TABLE_BOOKMARKS_TMP);
+    }
+
+
+    private void migrateHistoryTable(SQLiteDatabase db) {
+        debug("Renaming history table to " + TABLE_HISTORY_TMP);
+        db.execSQL("ALTER TABLE " + TABLE_HISTORY +
+                   " RENAME TO " + TABLE_HISTORY_TMP);
+
+        debug("Dropping views and indexes related to " + TABLE_HISTORY);
+        db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_HISTORY_WITH_IMAGES);
+        db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES);
+
+        db.execSQL("DROP INDEX IF EXISTS history_url_index");
+        db.execSQL("DROP INDEX IF EXISTS history_guid_index");
+        db.execSQL("DROP INDEX IF EXISTS history_modified_index");
+        db.execSQL("DROP INDEX IF EXISTS history_visited_index");
+
+        createHistoryTable(db);
+        createHistoryWithImagesView(db);
+        createCombinedWithImagesView(db);
+
+        db.execSQL("INSERT INTO " + TABLE_HISTORY + " SELECT * FROM " + TABLE_HISTORY_TMP);
+
+        debug("Dropping history temporary table");
+        db.execSQL("DROP TABLE IF EXISTS " + TABLE_HISTORY_TMP);
+    }
+
+    private void migrateImagesTable(SQLiteDatabase db) {
+        debug("Renaming images table to " + TABLE_IMAGES_TMP);
+        db.execSQL("ALTER TABLE " + Obsolete.TABLE_IMAGES +
+                   " RENAME TO " + TABLE_IMAGES_TMP);
+
+        debug("Dropping views and indexes related to " + Obsolete.TABLE_IMAGES);
+        db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_HISTORY_WITH_IMAGES);
+        db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES);
+
+        db.execSQL("DROP INDEX IF EXISTS images_url_index");
+        db.execSQL("DROP INDEX IF EXISTS images_guid_index");
+        db.execSQL("DROP INDEX IF EXISTS images_modified_index");
+
+        createImagesTable(db);
+        createHistoryWithImagesView(db);
+        createCombinedWithImagesView(db);
+
+        db.execSQL("INSERT INTO " + Obsolete.TABLE_IMAGES + " SELECT * FROM " + TABLE_IMAGES_TMP);
+
+        debug("Dropping images temporary table");
+        db.execSQL("DROP TABLE IF EXISTS " + TABLE_IMAGES_TMP);
+    }
+
+    private void upgradeDatabaseFrom1to2(SQLiteDatabase db) {
+        migrateBookmarksTable(db);
+    }
+
+    private void upgradeDatabaseFrom2to3(SQLiteDatabase db) {
+        debug("Dropping view: " + Obsolete.VIEW_BOOKMARKS_WITH_IMAGES);
+        db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_BOOKMARKS_WITH_IMAGES);
+
+        createBookmarksWithImagesView(db);
+
+        debug("Dropping view: " + Obsolete.VIEW_HISTORY_WITH_IMAGES);
+        db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_HISTORY_WITH_IMAGES);
+
+        createHistoryWithImagesView(db);
+    }
+
+    private void upgradeDatabaseFrom3to4(SQLiteDatabase db) {
+        migrateBookmarksTable(db, new BookmarkMigrator3to4());
+    }
+
+    private void upgradeDatabaseFrom4to5(SQLiteDatabase db) {
+        createCombinedWithImagesView(db);
+    }
+
+    private void upgradeDatabaseFrom5to6(SQLiteDatabase db) {
+        debug("Dropping view: " + Obsolete.VIEW_COMBINED_WITH_IMAGES);
+        db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES);
+
+        createCombinedWithImagesView(db);
+    }
+
+    private void upgradeDatabaseFrom6to7(SQLiteDatabase db) {
+        debug("Removing history visits with NULL GUIDs");
+        db.execSQL("DELETE FROM " + TABLE_HISTORY + " WHERE " + History.GUID + " IS NULL");
+
+        debug("Update images with NULL GUIDs");
+        String[] columns = new String[] { Obsolete.Images._ID };
+        Cursor cursor = null;
+        try {
+          cursor = db.query(Obsolete.TABLE_IMAGES, columns, Obsolete.Images.GUID + " IS NULL", null, null ,null, null, null);
+          ContentValues values = new ContentValues();
+          if (cursor.moveToFirst()) {
+              do {
+                  values.put(Obsolete.Images.GUID, Utils.generateGuid());
+                  db.update(Obsolete.TABLE_IMAGES, values, Obsolete.Images._ID + " = ?", new String[] {
+                    cursor.getString(cursor.getColumnIndexOrThrow(Obsolete.Images._ID))
+                  });
+              } while (cursor.moveToNext());
+          }
+        } finally {
+          if (cursor != null)
+            cursor.close();
+        }
+
+        migrateBookmarksTable(db);
+        migrateHistoryTable(db);
+        migrateImagesTable(db);
+    }
+
+    private void upgradeDatabaseFrom7to8(SQLiteDatabase db) {
+        debug("Combining history entries with the same URL");
+
+        final String TABLE_DUPES = "duped_urls";
+        final String TOTAL = "total";
+        final String LATEST = "latest";
+        final String WINNER = "winner";
+
+        db.execSQL("CREATE TEMP TABLE " + TABLE_DUPES + " AS" +
+                  " SELECT " + History.URL + ", " +
+                              "SUM(" + History.VISITS + ") AS " + TOTAL + ", " +
+                              "MAX(" + History.DATE_MODIFIED + ") AS " + LATEST + ", " +
+                              "MAX(" + History._ID + ") AS " + WINNER +
+                  " FROM " + TABLE_HISTORY +
+                  " GROUP BY " + History.URL +
+                  " HAVING count(" + History.URL + ") > 1");
+
+        db.execSQL("CREATE UNIQUE INDEX " + TABLE_DUPES + "_url_index ON " +
+                   TABLE_DUPES + " (" + History.URL + ")");
+
+        final String fromClause = " FROM " + TABLE_DUPES + " WHERE " +
+                                  qualifyColumn(TABLE_DUPES, History.URL) + " = " +
+                                  qualifyColumn(TABLE_HISTORY, History.URL);
+
+        db.execSQL("UPDATE " + TABLE_HISTORY +
+                  " SET " + History.VISITS + " = (SELECT " + TOTAL + fromClause + "), " +
+                            History.DATE_MODIFIED + " = (SELECT " + LATEST + fromClause + "), " +
+                            History.IS_DELETED + " = " +
+                                "(" + History._ID + " <> (SELECT " + WINNER + fromClause + "))" +
+                  " WHERE " + History.URL + " IN (SELECT " + History.URL + " FROM " + TABLE_DUPES + ")");
+
+        db.execSQL("DROP TABLE " + TABLE_DUPES);
+    }
+
+    private void upgradeDatabaseFrom8to9(SQLiteDatabase db) {
+        createOrUpdateSpecialFolder(db, Bookmarks.READING_LIST_FOLDER_GUID,
+            R.string.bookmarks_folder_reading_list, 5);
+
+        debug("Dropping view: " + Obsolete.VIEW_COMBINED_WITH_IMAGES);
+        db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES);
+
+        createCombinedWithImagesViewOn9(db);
+    }
+
+    private void upgradeDatabaseFrom9to10(SQLiteDatabase db) {
+        debug("Dropping view: " + Obsolete.VIEW_COMBINED_WITH_IMAGES);
+        db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES);
+
+        createCombinedWithImagesViewOn10(db);
+    }
+
+    private void upgradeDatabaseFrom10to11(SQLiteDatabase db) {
+        debug("Dropping view: " + Obsolete.VIEW_COMBINED_WITH_IMAGES);
+        db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES);
+
+        db.execSQL("CREATE INDEX bookmarks_type_deleted_index ON " + TABLE_BOOKMARKS + "("
+                + Bookmarks.TYPE + ", " + Bookmarks.IS_DELETED + ")");
+
+        createCombinedWithImagesViewOn11(db);
+    }
+
+    private void upgradeDatabaseFrom11to12(SQLiteDatabase db) {
+        debug("Dropping view: " + Obsolete.VIEW_COMBINED_WITH_IMAGES);
+        db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES);
+
+        createCombinedViewOn12(db);
+    }
+
+    private void upgradeDatabaseFrom12to13(SQLiteDatabase db) {
+        // Update images table with favicon URLs
+        SQLiteDatabase faviconsDb = null;
+        Cursor c = null;
+        try {
+            final String FAVICON_TABLE = "favicon_urls";
+            final String FAVICON_URL = "favicon_url";
+            final String FAVICON_PAGE = "page_url";
+
+            String dbPath = mContext.getDatabasePath(Obsolete.FAVICON_DB).getPath();
+            faviconsDb = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READONLY);
+            String[] columns = new String[] { FAVICON_URL, FAVICON_PAGE };
+            c = faviconsDb.query(FAVICON_TABLE, columns, null, null, null, null, null, null);
+            int faviconIndex = c.getColumnIndexOrThrow(FAVICON_URL);
+            int pageIndex = c.getColumnIndexOrThrow(FAVICON_PAGE);
+            while (c.moveToNext()) {
+                ContentValues values = new ContentValues(1);
+                String faviconUrl = c.getString(faviconIndex);
+                String pageUrl = c.getString(pageIndex);
+                values.put(FAVICON_URL, faviconUrl);
+                db.update(Obsolete.TABLE_IMAGES, values, Obsolete.Images.URL + " = ?", new String[] { pageUrl });
+            }
+        } catch (SQLException e) {
+            // If we can't read from the database for some reason, we won't
+            // be able to import the favicon URLs. This isn't a fatal
+            // error, so continue the upgrade.
+            Log.e(LOGTAG, "Exception importing from " + Obsolete.FAVICON_DB, e);
+        } finally {
+            if (c != null)
+                c.close();
+            if (faviconsDb != null)
+                faviconsDb.close();
+        }
+
+        createFaviconsTable(db);
+
+        // Import favicons into the favicons table
+        db.execSQL("ALTER TABLE " + TABLE_HISTORY
+                + " ADD COLUMN " + History.FAVICON_ID + " INTEGER");
+        db.execSQL("ALTER TABLE " + TABLE_BOOKMARKS
+                + " ADD COLUMN " + Bookmarks.FAVICON_ID + " INTEGER");
+
+        try {
+            c = db.query(Obsolete.TABLE_IMAGES,
+                    new String[] {
+                        Obsolete.Images.URL,
+                        Obsolete.Images.FAVICON_URL,
+                        Obsolete.Images.FAVICON,
+                        Obsolete.Images.DATE_MODIFIED,
+                        Obsolete.Images.DATE_CREATED
+                    },
+                    Obsolete.Images.FAVICON + " IS NOT NULL",
+                    null, null, null, null);
+
+            while (c.moveToNext()) {
+                long faviconId = -1;
+                int faviconUrlIndex = c.getColumnIndexOrThrow(Obsolete.Images.FAVICON_URL);
+                String faviconUrl = null;
+                if (!c.isNull(faviconUrlIndex)) {
+                    faviconUrl = c.getString(faviconUrlIndex);
+                    Cursor c2 = null;
+                    try {
+                        c2 = db.query(TABLE_FAVICONS,
+                                new String[] { Favicons._ID },
+                                Favicons.URL + " = ?",
+                                new String[] { faviconUrl },
+                                null, null, null);
+                        if (c2.moveToFirst()) {
+                            faviconId = c2.getLong(c2.getColumnIndexOrThrow(Favicons._ID));
+                        }
+                    } finally {
+                        if (c2 != null)
+                            c2.close();
+                    }
+                }
+
+                if (faviconId == -1) {
+                    ContentValues values = new ContentValues(4);
+                    values.put(Favicons.URL, faviconUrl);
+                    values.put(Favicons.DATA, c.getBlob(c.getColumnIndexOrThrow(Obsolete.Images.FAVICON)));
+                    values.put(Favicons.DATE_MODIFIED, c.getLong(c.getColumnIndexOrThrow(Obsolete.Images.DATE_MODIFIED)));
+                    values.put(Favicons.DATE_CREATED, c.getLong(c.getColumnIndexOrThrow(Obsolete.Images.DATE_CREATED)));
+                    faviconId = db.insert(TABLE_FAVICONS, null, values);
+                }
+
+                ContentValues values = new ContentValues(1);
+                values.put(FaviconColumns.FAVICON_ID, faviconId);
+                db.update(TABLE_HISTORY, values, History.URL + " = ?",
+                        new String[] { c.getString(c.getColumnIndexOrThrow(Obsolete.Images.URL)) });
+                db.update(TABLE_BOOKMARKS, values, Bookmarks.URL + " = ?",
+                        new String[] { c.getString(c.getColumnIndexOrThrow(Obsolete.Images.URL)) });
+            }
+        } finally {
+            if (c != null)
+                c.close();
+        }
+
+        createThumbnailsTable(db);
+
+        // Import thumbnails into the thumbnails table
+        db.execSQL("INSERT INTO " + TABLE_THUMBNAILS + " ("
+                + Thumbnails.URL + ", "
+                + Thumbnails.DATA + ") "
+                + "SELECT " + Obsolete.Images.URL + ", " + Obsolete.Images.THUMBNAIL
+                + " FROM " + Obsolete.TABLE_IMAGES
+                + " WHERE " + Obsolete.Images.THUMBNAIL + " IS NOT NULL");
+
+        db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_BOOKMARKS_WITH_IMAGES);
+        db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_HISTORY_WITH_IMAGES);
+        db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES);
+        db.execSQL("DROP VIEW IF EXISTS " + VIEW_COMBINED);
+
+        createBookmarksWithFaviconsView(db);
+        createHistoryWithFaviconsView(db);
+        createCombinedViewOn13(db);
+
+        db.execSQL("DROP TABLE IF EXISTS " + Obsolete.TABLE_IMAGES);
+    }
+
+    private void upgradeDatabaseFrom13to14(SQLiteDatabase db) {
+        createOrUpdateSpecialFolder(db, Bookmarks.PINNED_FOLDER_GUID,
+            R.string.bookmarks_folder_pinned, 6);
+    }
+
+    private void upgradeDatabaseFrom14to15(SQLiteDatabase db) {
+        Cursor c = null;
+        try {
+            // Get all the pinned bookmarks
+            c = db.query(TABLE_BOOKMARKS,
+                         new String[] { Bookmarks._ID, Bookmarks.URL },
+                         Bookmarks.PARENT + " = ?",
+                         new String[] { Integer.toString(Bookmarks.FIXED_PINNED_LIST_ID) },
+                         null, null, null);
+
+            while (c.moveToNext()) {
+                // Check if this URL can be parsed as a URI with a valid scheme.
+                String url = c.getString(c.getColumnIndexOrThrow(Bookmarks.URL));
+                if (Uri.parse(url).getScheme() != null) {
+                    continue;
+                }
+
+                // If it can't, update the URL to be an encoded "user-entered" value.
+                ContentValues values = new ContentValues(1);
+                String newUrl = Uri.fromParts("user-entered", url, null).toString();
+                values.put(Bookmarks.URL, newUrl);
+                db.update(TABLE_BOOKMARKS, values, Bookmarks._ID + " = ?",
+                          new String[] { Integer.toString(c.getInt(c.getColumnIndexOrThrow(Bookmarks._ID))) });
+            }
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+    }
+
+    private void upgradeDatabaseFrom15to16(SQLiteDatabase db) {
+        db.execSQL("DROP VIEW IF EXISTS " + VIEW_COMBINED);
+        db.execSQL("DROP VIEW IF EXISTS " + VIEW_COMBINED_WITH_FAVICONS);
+
+        createCombinedViewOn16(db);
+    }
+
+    private void upgradeDatabaseFrom16to17(SQLiteDatabase db) {
+        // Purge any 0-byte favicons/thumbnails
+        try {
+            db.execSQL("DELETE FROM " + TABLE_FAVICONS +
+                    " WHERE length(" + Favicons.DATA + ") = 0");
+            db.execSQL("DELETE FROM " + TABLE_THUMBNAILS +
+                    " WHERE length(" + Thumbnails.DATA + ") = 0");
+        } catch (SQLException e) {
+            Log.e(LOGTAG, "Error purging invalid favicons or thumbnails", e);
+        }
+    }
+
+    @Override
+    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+        debug("Upgrading browser.db: " + db.getPath() + " from " +
+                oldVersion + " to " + newVersion);
+
+        // We have to do incremental upgrades until we reach the current
+        // database schema version.
+        for (int v = oldVersion + 1; v <= newVersion; v++) {
+            switch(v) {
+                case 2:
+                    upgradeDatabaseFrom1to2(db);
+                    break;
+
+                case 3:
+                    upgradeDatabaseFrom2to3(db);
+                    break;
+
+                case 4:
+                    upgradeDatabaseFrom3to4(db);
+                    break;
+
+                case 5:
+                    upgradeDatabaseFrom4to5(db);
+                    break;
+
+                case 6:
+                    upgradeDatabaseFrom5to6(db);
+                    break;
+
+                case 7:
+                    upgradeDatabaseFrom6to7(db);
+                    break;
+
+                case 8:
+                    upgradeDatabaseFrom7to8(db);
+                    break;
+
+                case 9:
+                    upgradeDatabaseFrom8to9(db);
+                    break;
+
+                case 10:
+                    upgradeDatabaseFrom9to10(db);
+                    break;
+
+                case 11:
+                    upgradeDatabaseFrom10to11(db);
+                    break;
+
+                case 12:
+                    upgradeDatabaseFrom11to12(db);
+                    break;
+
+                case 13:
+                    upgradeDatabaseFrom12to13(db);
+                    break;
+
+                case 14:
+                    upgradeDatabaseFrom13to14(db);
+                    break;
+
+                case 15:
+                    upgradeDatabaseFrom14to15(db);
+                    break;
+
+                case 16:
+                    upgradeDatabaseFrom15to16(db);
+                    break;
+
+                case 17:
+                    upgradeDatabaseFrom16to17(db);
+                    break;
+            }
+        }
+
+        // If an upgrade after 12->13 fails, the entire upgrade is rolled
+        // back, but we can't undo the deletion of favicon_urls.db if we
+        // delete this in step 13; therefore, we wait until all steps are
+        // complete before removing it.
+        if (oldVersion < 13 && newVersion >= 13
+                            && mContext.getDatabasePath(Obsolete.FAVICON_DB).exists()
+                            && !mContext.deleteDatabase(Obsolete.FAVICON_DB)) {
+            throw new SQLException("Could not delete " + Obsolete.FAVICON_DB);
+        }
+    }
+
+    @Override
+    public void onOpen(SQLiteDatabase db) {
+        debug("Opening browser.db: " + db.getPath());
+
+        Cursor cursor = null;
+        try {
+            cursor = db.rawQuery("PRAGMA foreign_keys=ON", null);
+        } finally {
+            if (cursor != null)
+                cursor.close();
+        }
+        cursor = null;
+        try {
+            cursor = db.rawQuery("PRAGMA synchronous=NORMAL", null);
+        } finally {
+            if (cursor != null)
+                cursor.close();
+        }
+
+        // From Honeycomb on, it's possible to run several db
+        // commands in parallel using multiple connections.
+        if (Build.VERSION.SDK_INT >= 11) {
+            db.enableWriteAheadLogging();
+            db.setLockingEnabled(false);
+        } else {
+            // Pre-Honeycomb, we can do some lesser optimizations.
+            cursor = null;
+            try {
+                cursor = db.rawQuery("PRAGMA journal_mode=PERSIST", null);
+            } finally {
+                if (cursor != null)
+                    cursor.close();
+            }
+        }
+    }
+
+    static final String qualifyColumn(String table, String column) {
+        return DBUtils.qualifyColumn(table, column);
+    }
+
+    // Calculate these once, at initialization. isLoggable is too expensive to
+    // have in-line in each log call.
+    private static boolean logDebug   = Log.isLoggable(LOGTAG, Log.DEBUG);
+    private static boolean logVerbose = Log.isLoggable(LOGTAG, Log.VERBOSE);
+    protected static void trace(String message) {
+        if (logVerbose) {
+            Log.v(LOGTAG, message);
+        }
+    }
+
+    protected static void debug(String message) {
+        if (logDebug) {
+            Log.d(LOGTAG, message);
+        }
+    }
+
+    private Integer getMobileFolderId(SQLiteDatabase db) {
+        Cursor c = null;
+
+        try {
+            c = db.query(TABLE_BOOKMARKS,
+                         mobileIdColumns,
+                         Bookmarks.GUID + " = ?",
+                         mobileIdSelectionArgs,
+                         null, null, null);
+
+            if (c == null || !c.moveToFirst())
+                return null;
+
+            return c.getInt(c.getColumnIndex(Bookmarks._ID));
+        } finally {
+            if (c != null)
+                c.close();
+        }
+    }
+
+    private long insertFavicon(SQLiteDatabase db, ContentValues values) {
+        // This method is a dupicate of BrowserProvider.insertFavicon.
+        // If changes are needed, please update both
+        String faviconUrl = values.getAsString(Favicons.URL);
+        String pageUrl = null;
+        long faviconId;
+
+        trace("Inserting favicon for URL: " + faviconUrl);
+
+        DBUtils.stripEmptyByteArray(values, Favicons.DATA);
+
+        // Extract the page URL from the ContentValues
+        if (values.containsKey(Favicons.PAGE_URL)) {
+            pageUrl = values.getAsString(Favicons.PAGE_URL);
+            values.remove(Favicons.PAGE_URL);
+        }
+
+        // If no URL is provided, insert using the default one.
+        if (TextUtils.isEmpty(faviconUrl) && !TextUtils.isEmpty(pageUrl)) {
+            values.put(Favicons.URL, org.mozilla.gecko.favicons.Favicons.guessDefaultFaviconURL(pageUrl));
+        }
+
+        long now = System.currentTimeMillis();
+        values.put(Favicons.DATE_CREATED, now);
+        values.put(Favicons.DATE_MODIFIED, now);
+        faviconId = db.insertOrThrow(TABLE_FAVICONS, null, values);
+
+        if (pageUrl != null) {
+            ContentValues updateValues = new ContentValues(1);
+            updateValues.put(FaviconColumns.FAVICON_ID, faviconId);
+            db.update(TABLE_HISTORY,
+                      updateValues,
+                      History.URL + " = ?",
+                      new String[] { pageUrl });
+            db.update(TABLE_BOOKMARKS,
+                      updateValues,
+                      Bookmarks.URL + " = ?",
+                      new String[] { pageUrl });
+        }
+
+        return faviconId;
+    }
+
+    private interface BookmarkMigrator {
+        public void updateForNewTable(ContentValues bookmark);
+    }
+
+    private class BookmarkMigrator3to4 implements BookmarkMigrator {
+        @Override
+        public void updateForNewTable(ContentValues bookmark) {
+            Integer isFolder = bookmark.getAsInteger("folder");
+            if (isFolder == null || isFolder != 1) {
+                bookmark.put(Bookmarks.TYPE, Bookmarks.TYPE_BOOKMARK);
+            } else {
+                bookmark.put(Bookmarks.TYPE, Bookmarks.TYPE_FOLDER);
+            }
+
+            bookmark.remove("folder");
+        }
+    }
+}
\ No newline at end of file
--- a/mobile/android/base/db/BrowserProvider.java
+++ b/mobile/android/base/db/BrowserProvider.java
@@ -1,82 +1,52 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.db;
 
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.Distribution;
-import org.mozilla.gecko.GeckoProfile;
-import org.mozilla.gecko.R;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
 import org.mozilla.gecko.db.BrowserContract.Bookmarks;
 import org.mozilla.gecko.db.BrowserContract.Combined;
 import org.mozilla.gecko.db.BrowserContract.CommonColumns;
 import org.mozilla.gecko.db.BrowserContract.FaviconColumns;
 import org.mozilla.gecko.db.BrowserContract.Favicons;
 import org.mozilla.gecko.db.BrowserContract.History;
 import org.mozilla.gecko.db.BrowserContract.Schema;
 import org.mozilla.gecko.db.BrowserContract.SyncColumns;
 import org.mozilla.gecko.db.BrowserContract.Thumbnails;
 import org.mozilla.gecko.db.BrowserContract.URLColumns;
-import org.mozilla.gecko.db.PerProfileDatabases.DatabaseHelperFactory;
-import org.mozilla.gecko.gfx.BitmapUtils;
 import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.util.GeckoJarReader;
-import org.mozilla.gecko.util.ThreadUtils;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
 
 import android.app.SearchManager;
-import android.content.ContentProvider;
 import android.content.ContentProviderOperation;
 import android.content.ContentProviderResult;
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.OperationApplicationException;
 import android.content.UriMatcher;
 import android.database.Cursor;
 import android.database.DatabaseUtils;
 import android.database.MatrixCursor;
 import android.database.SQLException;
 import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteQueryBuilder;
-import android.graphics.Bitmap;
 import android.net.Uri;
-import android.os.Build;
 import android.text.TextUtils;
 import android.util.Log;
 
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class BrowserProvider extends ContentProvider {
+public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper> {
     private static final String LOGTAG = "GeckoBrowserProvider";
-    private Context mContext;
-
-    private PerProfileDatabases<BrowserDatabaseHelper> mDatabases;
-
-    static final String DATABASE_NAME = "browser.db";
-
-    static final int DATABASE_VERSION = 17;
 
     // Maximum age of deleted records to be cleaned up (20 days in ms)
     static final long MAX_AGE_OF_DELETED_RECORDS = 86400000 * 20;
 
     // Number of records marked as deleted to be removed
     static final long DELETED_RECORDS_PURGE_LIMIT = 5;
 
     // How many records to reposition in a single query.
@@ -89,30 +59,25 @@ public class BrowserProvider extends Con
     static final int DEFAULT_EXPIRY_RETAIN_COUNT = 2000;
     static final int AGGRESSIVE_EXPIRY_RETAIN_COUNT = 500;
 
     // Minimum duration to keep when expiring.
     static final long DEFAULT_EXPIRY_PRESERVE_WINDOW = 1000L * 60L * 60L * 24L * 28L;     // Four weeks.
     // Minimum number of thumbnails to keep around.
     static final int DEFAULT_EXPIRY_THUMBNAIL_COUNT = 15;
 
-    static final String TABLE_BOOKMARKS = "bookmarks";
-    static final String TABLE_HISTORY = "history";
-    static final String TABLE_FAVICONS = "favicons";
-    static final String TABLE_THUMBNAILS = "thumbnails";
+    static final String TABLE_BOOKMARKS = Bookmarks.TABLE_NAME;
+    static final String TABLE_HISTORY = History.TABLE_NAME;
+    static final String TABLE_FAVICONS = Favicons.TABLE_NAME;
+    static final String TABLE_THUMBNAILS = Thumbnails.TABLE_NAME;
 
-    static final String TABLE_BOOKMARKS_TMP = TABLE_BOOKMARKS + "_tmp";
-    static final String TABLE_HISTORY_TMP = TABLE_HISTORY + "_tmp";
-    static final String TABLE_IMAGES_TMP = Obsolete.TABLE_IMAGES + "_tmp";
-
-    static final String VIEW_COMBINED = "combined";
-
-    static final String VIEW_BOOKMARKS_WITH_FAVICONS = "bookmarks_with_favicons";
-    static final String VIEW_HISTORY_WITH_FAVICONS = "history_with_favicons";
-    static final String VIEW_COMBINED_WITH_FAVICONS = "combined_with_favicons";
+    static final String VIEW_COMBINED = Combined.VIEW_NAME;
+    static final String VIEW_BOOKMARKS_WITH_FAVICONS = Bookmarks.VIEW_WITH_FAVICONS;
+    static final String VIEW_HISTORY_WITH_FAVICONS = History.VIEW_WITH_FAVICONS;
+    static final String VIEW_COMBINED_WITH_FAVICONS = Combined.VIEW_WITH_FAVICONS;
 
     static final String VIEW_FLAGS = "flags";
 
     // Bookmark matches
     static final int BOOKMARKS = 100;
     static final int BOOKMARKS_ID = 101;
     static final int BOOKMARKS_FOLDER_ID = 102;
     static final int BOOKMARKS_PARENT = 103;
@@ -146,71 +111,26 @@ public class BrowserProvider extends Con
     static final int FLAGS = 900;
 
     static final String DEFAULT_BOOKMARKS_SORT_ORDER = Bookmarks.TYPE
             + " ASC, " + Bookmarks.POSITION + " ASC, " + Bookmarks._ID
             + " ASC";
 
     static final String DEFAULT_HISTORY_SORT_ORDER = History.DATE_LAST_VISITED + " DESC";
 
-    static final String TABLE_BOOKMARKS_JOIN_FAVICONS = TABLE_BOOKMARKS + " LEFT OUTER JOIN " +
-            TABLE_FAVICONS + " ON " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.FAVICON_ID) + " = " +
-            qualifyColumn(TABLE_FAVICONS, Favicons._ID);
-
-    static final String TABLE_HISTORY_JOIN_FAVICONS = TABLE_HISTORY + " LEFT OUTER JOIN " +
-            TABLE_FAVICONS + " ON " + qualifyColumn(TABLE_HISTORY, History.FAVICON_ID) + " = " +
-            qualifyColumn(TABLE_FAVICONS, Favicons._ID);
-
     static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
 
     static final Map<String, String> BOOKMARKS_PROJECTION_MAP;
     static final Map<String, String> HISTORY_PROJECTION_MAP;
     static final Map<String, String> COMBINED_PROJECTION_MAP;
     static final Map<String, String> SCHEMA_PROJECTION_MAP;
     static final Map<String, String> SEARCH_SUGGEST_PROJECTION_MAP;
     static final Map<String, String> FAVICONS_PROJECTION_MAP;
     static final Map<String, String> THUMBNAILS_PROJECTION_MAP;
 
-    static final class Obsolete {
-        public static final String TABLE_IMAGES = "images";
-        public static final String VIEW_BOOKMARKS_WITH_IMAGES = "bookmarks_with_images";
-        public static final String VIEW_HISTORY_WITH_IMAGES = "history_with_images";
-        public static final String VIEW_COMBINED_WITH_IMAGES = "combined_with_images";
-
-        public static final class Images implements CommonColumns, SyncColumns {
-            private Images() {}
-
-            public static final String URL = "url_key";
-            public static final String FAVICON_URL = "favicon_url";
-            public static final String FAVICON = "favicon";
-            public static final String THUMBNAIL = "thumbnail";
-            public static final String _ID = "_id";
-            public static final String GUID = "guid";
-            public static final String DATE_CREATED = "created";
-            public static final String DATE_MODIFIED = "modified";
-            public static final String IS_DELETED = "deleted";
-        }
-
-        public static final class Combined {
-            private Combined() {}
-
-            public static final String THUMBNAIL = "thumbnail";
-        }
-
-        static final String TABLE_BOOKMARKS_JOIN_IMAGES = TABLE_BOOKMARKS + " LEFT OUTER JOIN " +
-                Obsolete.TABLE_IMAGES + " ON " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " = " +
-                qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.URL);
-
-        static final String TABLE_HISTORY_JOIN_IMAGES = TABLE_HISTORY + " LEFT OUTER JOIN " +
-                Obsolete.TABLE_IMAGES + " ON " + qualifyColumn(TABLE_HISTORY, History.URL) + " = " +
-                qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.URL);
-
-        static final String FAVICON_DB = "favicon_urls.db";
-    }
-
     static {
         // We will reuse this.
         HashMap<String, String> map;
 
         // Bookmarks
         URI_MATCHER.addURI(BrowserContract.AUTHORITY, "bookmarks", BOOKMARKS);
         URI_MATCHER.addURI(BrowserContract.AUTHORITY, "bookmarks/#", BOOKMARKS_ID);
         URI_MATCHER.addURI(BrowserContract.AUTHORITY, "bookmarks/parents", BOOKMARKS_PARENT);
@@ -316,34 +236,16 @@ public class BrowserProvider extends Con
                 Combined.TITLE + " AS " + SearchManager.SUGGEST_COLUMN_TEXT_1);
         map.put(SearchManager.SUGGEST_COLUMN_TEXT_2_URL,
                 Combined.URL + " AS " + SearchManager.SUGGEST_COLUMN_TEXT_2_URL);
         map.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA,
                 Combined.URL + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA);
         SEARCH_SUGGEST_PROJECTION_MAP = Collections.unmodifiableMap(map);
     }
 
-    private interface BookmarkMigrator {
-        public void updateForNewTable(ContentValues bookmark);
-    }
-
-    private class BookmarkMigrator3to4 implements BookmarkMigrator {
-        @Override
-        public void updateForNewTable(ContentValues bookmark) {
-            Integer isFolder = bookmark.getAsInteger("folder");
-            if (isFolder == null || isFolder != 1) {
-                bookmark.put(Bookmarks.TYPE, Bookmarks.TYPE_BOOKMARK);
-            } else {
-                bookmark.put(Bookmarks.TYPE, Bookmarks.TYPE_FOLDER);
-            }
-
-            bookmark.remove("folder");
-        }
-    }
-
     static final String qualifyColumn(String table, String column) {
         return table + "." + column;
     }
 
     private static boolean hasFaviconsInProjection(String[] projection) {
         if (projection == null) return true;
         for (int i = 0; i < projection.length; ++i) {
             if (projection[i].equals(FaviconColumns.FAVICON) ||
@@ -365,1628 +267,16 @@ public class BrowserProvider extends Con
     }
 
     protected static void debug(String message) {
         if (logDebug) {
             Log.d(LOGTAG, message);
         }
     }
 
-    final class BrowserDatabaseHelper extends SQLiteOpenHelper {
-        public BrowserDatabaseHelper(Context context, String databasePath) {
-            super(context, databasePath, null, DATABASE_VERSION);
-        }
-
-        private void createBookmarksTable(SQLiteDatabase db) {
-            debug("Creating " + TABLE_BOOKMARKS + " table");
-
-            // Android versions older than Froyo ship with an sqlite
-            // that doesn't support foreign keys.
-            String foreignKeyOnParent = null;
-            if (Build.VERSION.SDK_INT >= 8) {
-                foreignKeyOnParent = ", FOREIGN KEY (" + Bookmarks.PARENT +
-                    ") REFERENCES " + TABLE_BOOKMARKS + "(" + Bookmarks._ID + ")";
-            }
-
-            db.execSQL("CREATE TABLE " + TABLE_BOOKMARKS + "(" +
-                    Bookmarks._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
-                    Bookmarks.TITLE + " TEXT," +
-                    Bookmarks.URL + " TEXT," +
-                    Bookmarks.TYPE + " INTEGER NOT NULL DEFAULT " + Bookmarks.TYPE_BOOKMARK + "," +
-                    Bookmarks.PARENT + " INTEGER," +
-                    Bookmarks.POSITION + " INTEGER NOT NULL," +
-                    Bookmarks.KEYWORD + " TEXT," +
-                    Bookmarks.DESCRIPTION + " TEXT," +
-                    Bookmarks.TAGS + " TEXT," +
-                    Bookmarks.DATE_CREATED + " INTEGER," +
-                    Bookmarks.DATE_MODIFIED + " INTEGER," +
-                    Bookmarks.GUID + " TEXT NOT NULL," +
-                    Bookmarks.IS_DELETED + " INTEGER NOT NULL DEFAULT 0" +
-                    (foreignKeyOnParent != null ? foreignKeyOnParent : "") +
-                    ");");
-
-            db.execSQL("CREATE INDEX bookmarks_url_index ON " + TABLE_BOOKMARKS + "("
-                    + Bookmarks.URL + ")");
-            db.execSQL("CREATE INDEX bookmarks_type_deleted_index ON " + TABLE_BOOKMARKS + "("
-                    + Bookmarks.TYPE + ", " + Bookmarks.IS_DELETED + ")");
-            db.execSQL("CREATE UNIQUE INDEX bookmarks_guid_index ON " + TABLE_BOOKMARKS + "("
-                    + Bookmarks.GUID + ")");
-            db.execSQL("CREATE INDEX bookmarks_modified_index ON " + TABLE_BOOKMARKS + "("
-                    + Bookmarks.DATE_MODIFIED + ")");
-        }
-
-        private void createBookmarksTableOn13(SQLiteDatabase db) {
-            debug("Creating " + TABLE_BOOKMARKS + " table");
-
-            // Android versions older than Froyo ship with an sqlite
-            // that doesn't support foreign keys.
-            String foreignKeyOnParent = null;
-            if (Build.VERSION.SDK_INT >= 8) {
-                foreignKeyOnParent = ", FOREIGN KEY (" + Bookmarks.PARENT +
-                    ") REFERENCES " + TABLE_BOOKMARKS + "(" + Bookmarks._ID + ")";
-            }
-
-            db.execSQL("CREATE TABLE " + TABLE_BOOKMARKS + "(" +
-                    Bookmarks._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
-                    Bookmarks.TITLE + " TEXT," +
-                    Bookmarks.URL + " TEXT," +
-                    Bookmarks.TYPE + " INTEGER NOT NULL DEFAULT " + Bookmarks.TYPE_BOOKMARK + "," +
-                    Bookmarks.PARENT + " INTEGER," +
-                    Bookmarks.POSITION + " INTEGER NOT NULL," +
-                    Bookmarks.KEYWORD + " TEXT," +
-                    Bookmarks.DESCRIPTION + " TEXT," +
-                    Bookmarks.TAGS + " TEXT," +
-                    Bookmarks.FAVICON_ID + " INTEGER," +
-                    Bookmarks.DATE_CREATED + " INTEGER," +
-                    Bookmarks.DATE_MODIFIED + " INTEGER," +
-                    Bookmarks.GUID + " TEXT NOT NULL," +
-                    Bookmarks.IS_DELETED + " INTEGER NOT NULL DEFAULT 0" +
-                    (foreignKeyOnParent != null ? foreignKeyOnParent : "") +
-                    ");");
-
-            db.execSQL("CREATE INDEX bookmarks_url_index ON " + TABLE_BOOKMARKS + "("
-                    + Bookmarks.URL + ")");
-            db.execSQL("CREATE INDEX bookmarks_type_deleted_index ON " + TABLE_BOOKMARKS + "("
-                    + Bookmarks.TYPE + ", " + Bookmarks.IS_DELETED + ")");
-            db.execSQL("CREATE UNIQUE INDEX bookmarks_guid_index ON " + TABLE_BOOKMARKS + "("
-                    + Bookmarks.GUID + ")");
-            db.execSQL("CREATE INDEX bookmarks_modified_index ON " + TABLE_BOOKMARKS + "("
-                    + Bookmarks.DATE_MODIFIED + ")");
-        }
-
-        private void createHistoryTable(SQLiteDatabase db) {
-            debug("Creating " + TABLE_HISTORY + " table");
-            db.execSQL("CREATE TABLE " + TABLE_HISTORY + "(" +
-                    History._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
-                    History.TITLE + " TEXT," +
-                    History.URL + " TEXT NOT NULL," +
-                    History.VISITS + " INTEGER NOT NULL DEFAULT 0," +
-                    History.DATE_LAST_VISITED + " INTEGER," +
-                    History.DATE_CREATED + " INTEGER," +
-                    History.DATE_MODIFIED + " INTEGER," +
-                    History.GUID + " TEXT NOT NULL," +
-                    History.IS_DELETED + " INTEGER NOT NULL DEFAULT 0" +
-                    ");");
-
-            db.execSQL("CREATE INDEX history_url_index ON " + TABLE_HISTORY + "("
-                    + History.URL + ")");
-            db.execSQL("CREATE UNIQUE INDEX history_guid_index ON " + TABLE_HISTORY + "("
-                    + History.GUID + ")");
-            db.execSQL("CREATE INDEX history_modified_index ON " + TABLE_HISTORY + "("
-                    + History.DATE_MODIFIED + ")");
-            db.execSQL("CREATE INDEX history_visited_index ON " + TABLE_HISTORY + "("
-                    + History.DATE_LAST_VISITED + ")");
-        }
-
-        private void createHistoryTableOn13(SQLiteDatabase db) {
-            debug("Creating " + TABLE_HISTORY + " table");
-            db.execSQL("CREATE TABLE " + TABLE_HISTORY + "(" +
-                    History._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
-                    History.TITLE + " TEXT," +
-                    History.URL + " TEXT NOT NULL," +
-                    History.VISITS + " INTEGER NOT NULL DEFAULT 0," +
-                    History.FAVICON_ID + " INTEGER," +
-                    History.DATE_LAST_VISITED + " INTEGER," +
-                    History.DATE_CREATED + " INTEGER," +
-                    History.DATE_MODIFIED + " INTEGER," +
-                    History.GUID + " TEXT NOT NULL," +
-                    History.IS_DELETED + " INTEGER NOT NULL DEFAULT 0" +
-                    ");");
-
-            db.execSQL("CREATE INDEX history_url_index ON " + TABLE_HISTORY + "("
-                    + History.URL + ")");
-            db.execSQL("CREATE UNIQUE INDEX history_guid_index ON " + TABLE_HISTORY + "("
-                    + History.GUID + ")");
-            db.execSQL("CREATE INDEX history_modified_index ON " + TABLE_HISTORY + "("
-                    + History.DATE_MODIFIED + ")");
-            db.execSQL("CREATE INDEX history_visited_index ON " + TABLE_HISTORY + "("
-                    + History.DATE_LAST_VISITED + ")");
-        }
-
-        private void createImagesTable(SQLiteDatabase db) {
-            debug("Creating " + Obsolete.TABLE_IMAGES + " table");
-            db.execSQL("CREATE TABLE " + Obsolete.TABLE_IMAGES + " (" +
-                    Obsolete.Images._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
-                    Obsolete.Images.URL + " TEXT UNIQUE NOT NULL," +
-                    Obsolete.Images.FAVICON + " BLOB," +
-                    Obsolete.Images.FAVICON_URL + " TEXT," +
-                    Obsolete.Images.THUMBNAIL + " BLOB," +
-                    Obsolete.Images.DATE_CREATED + " INTEGER," +
-                    Obsolete.Images.DATE_MODIFIED + " INTEGER," +
-                    Obsolete.Images.GUID + " TEXT NOT NULL," +
-                    Obsolete.Images.IS_DELETED + " INTEGER NOT NULL DEFAULT 0" +
-                    ");");
-
-            db.execSQL("CREATE INDEX images_url_index ON " + Obsolete.TABLE_IMAGES + "("
-                    + Obsolete.Images.URL + ")");
-            db.execSQL("CREATE UNIQUE INDEX images_guid_index ON " + Obsolete.TABLE_IMAGES + "("
-                    + Obsolete.Images.GUID + ")");
-            db.execSQL("CREATE INDEX images_modified_index ON " + Obsolete.TABLE_IMAGES + "("
-                    + Obsolete.Images.DATE_MODIFIED + ")");
-        }
-
-        private void createFaviconsTable(SQLiteDatabase db) {
-            debug("Creating " + TABLE_FAVICONS + " table");
-            db.execSQL("CREATE TABLE " + TABLE_FAVICONS + " (" +
-                    Favicons._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
-                    Favicons.URL + " TEXT UNIQUE," +
-                    Favicons.DATA + " BLOB," +
-                    Favicons.DATE_CREATED + " INTEGER," +
-                    Favicons.DATE_MODIFIED + " INTEGER" +
-                    ");");
-
-            db.execSQL("CREATE INDEX favicons_url_index ON " + TABLE_FAVICONS + "("
-                    + Favicons.URL + ")");
-            db.execSQL("CREATE INDEX favicons_modified_index ON " + TABLE_FAVICONS + "("
-                    + Favicons.DATE_MODIFIED + ")");
-        }
-
-        private void createThumbnailsTable(SQLiteDatabase db) {
-            debug("Creating " + TABLE_THUMBNAILS + " table");
-            db.execSQL("CREATE TABLE " + TABLE_THUMBNAILS + " (" +
-                    Thumbnails._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
-                    Thumbnails.URL + " TEXT UNIQUE," +
-                    Thumbnails.DATA + " BLOB" +
-                    ");");
-
-            db.execSQL("CREATE INDEX thumbnails_url_index ON " + TABLE_THUMBNAILS + "("
-                    + Thumbnails.URL + ")");
-        }
-
-        private void createBookmarksWithImagesView(SQLiteDatabase db) {
-            debug("Creating " + Obsolete.VIEW_BOOKMARKS_WITH_IMAGES + " view");
-
-            db.execSQL("CREATE VIEW IF NOT EXISTS " + Obsolete.VIEW_BOOKMARKS_WITH_IMAGES + " AS " +
-                    "SELECT " + qualifyColumn(TABLE_BOOKMARKS, "*") +
-                    ", " + Obsolete.Images.FAVICON + ", " + Obsolete.Images.THUMBNAIL + " FROM " +
-                    Obsolete.TABLE_BOOKMARKS_JOIN_IMAGES);
-        }
-
-        private void createBookmarksWithFaviconsView(SQLiteDatabase db) {
-            debug("Creating " + VIEW_BOOKMARKS_WITH_FAVICONS + " view");
-
-            db.execSQL("CREATE VIEW IF NOT EXISTS " + VIEW_BOOKMARKS_WITH_FAVICONS + " AS " +
-                    "SELECT " + qualifyColumn(TABLE_BOOKMARKS, "*") +
-                    ", " + qualifyColumn(TABLE_FAVICONS, Favicons.DATA) + " AS " + Bookmarks.FAVICON +
-                    ", " + qualifyColumn(TABLE_FAVICONS, Favicons.URL) + " AS " + Bookmarks.FAVICON_URL +
-                    " FROM " + TABLE_BOOKMARKS_JOIN_FAVICONS);
-        }
-
-        private void createHistoryWithImagesView(SQLiteDatabase db) {
-            debug("Creating " + Obsolete.VIEW_HISTORY_WITH_IMAGES + " view");
-
-            db.execSQL("CREATE VIEW IF NOT EXISTS " + Obsolete.VIEW_HISTORY_WITH_IMAGES + " AS " +
-                    "SELECT " + qualifyColumn(TABLE_HISTORY, "*") +