Merge m-c to b2g-inbound on a CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Thu, 01 Aug 2013 14:51:49 -0700
changeset 153383 09d9ed3b4ffb7c7f3fcbd0398e9e939c3d8eae82
parent 153382 ff4aca0cf3ce75367060cd2a798ae53848455fd5 (current diff)
parent 153206 9d9856cf1648de77b6e5d6b2379cbe1d36bb3b30 (diff)
child 153384 584ebb3fb1134001dbf6858b5d2a698e6e132495
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone25.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to b2g-inbound on a CLOSED TREE
dom/indexedDB/nsIIDBCursor.idl
dom/indexedDB/nsIIDBCursorWithValue.idl
dom/indexedDB/nsIIDBOpenDBRequest.idl
dom/indexedDB/nsIIDBRequest.idl
--- a/CLOBBER
+++ b/CLOBBER
@@ -12,9 +12,10 @@
 #          O               O
 #          |               |
 #          O <-- Clobber   O  <-- Clobber
 #
 # Note: The description below will be part of the error message shown to users.
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
-Bug 878600 requires a clobber on Windows due to bug 890744
+
+Multiple WebIDL changes requiring a clobber on Windows due to bug 890744
--- a/accessible/src/base/ARIAStateMap.cpp
+++ b/accessible/src/base/ARIAStateMap.cpp
@@ -361,34 +361,29 @@ MapEnumType(dom::Element* aElement, uint
 
   *aState |= aData.mDefaultState;
 }
 
 static void
 MapTokenType(dom::Element* aElement, uint64_t* aState,
              const TokenTypeData& aData)
 {
-  if (aElement->HasAttr(kNameSpaceID_None, aData.mAttrName)) {
+  if (nsAccUtils::HasDefinedARIAToken(aElement, aData.mAttrName)) {
     if ((aData.mType & eMixedType) &&
         aElement->AttrValueIs(kNameSpaceID_None, aData.mAttrName,
                               nsGkAtoms::mixed, eCaseMatters)) {
       *aState |= aData.mPermanentState | states::MIXED;
       return;
     }
 
     if (aElement->AttrValueIs(kNameSpaceID_None, aData.mAttrName,
                               nsGkAtoms::_false, eCaseMatters)) {
       *aState |= aData.mPermanentState | aData.mFalseState;
       return;
     }
 
-    if (!aElement->AttrValueIs(kNameSpaceID_None, aData.mAttrName,
-                               nsGkAtoms::_undefined, eCaseMatters) &&
-        !aElement->AttrValueIs(kNameSpaceID_None, aData.mAttrName,
-                               nsGkAtoms::_empty, eCaseMatters)) {
-      *aState |= aData.mPermanentState | aData.mTrueState;
-    }
+    *aState |= aData.mPermanentState | aData.mTrueState;
     return;
   }
 
   if (aData.mType & eDefinedIfAbsent)
     *aState |= aData.mPermanentState | aData.mFalseState;
 }
--- a/accessible/tests/mochitest/test_aria_token_attrs.html
+++ b/accessible/tests/mochitest/test_aria_token_attrs.html
@@ -32,18 +32,18 @@ https://bugzilla.mozilla.org/show_bug.cg
       testStates("button_pressed_false", STATE_CHECKABLE, 0, STATE_PRESSED);
       testStates("button_pressed_empty", 0, 0, STATE_PRESSED | STATE_CHECKABLE);
       testStates("button_pressed_undefined", 0, 0, STATE_PRESSED | STATE_CHECKABLE);
       testStates("button_pressed_absent", 0, 0, STATE_PRESSED | STATE_CHECKABLE);
 
       // test (checkbox) checkable and checked states
       testStates("checkbox_checked_true", (STATE_CHECKABLE | STATE_CHECKED));
       testStates("checkbox_checked_false", STATE_CHECKABLE, 0, STATE_CHECKED);
-      testStates("checkbox_checked_empty", 0 , 0, STATE_CHECKABLE | STATE_CHECKED);
-      testStates("checkbox_checked_undefined", 0, 0, STATE_CHECKABLE | STATE_CHECKED);
+      testStates("checkbox_checked_empty", STATE_CHECKABLE , 0, STATE_CHECKED);
+      testStates("checkbox_checked_undefined", STATE_CHECKABLE, 0, STATE_CHECKED);
       testStates("checkbox_checked_absent", STATE_CHECKABLE, 0, STATE_CHECKED);
 
       // test native checkbox checked state and aria-checked state (if conflict, native wins)
       testStates("native_checkbox_nativechecked_ariatrue", (STATE_CHECKABLE | STATE_CHECKED));
       testStates("native_checkbox_nativechecked_ariafalse", (STATE_CHECKABLE | STATE_CHECKED));
       testStates("native_checkbox_nativechecked_ariaempty", (STATE_CHECKABLE | STATE_CHECKED));
       testStates("native_checkbox_nativechecked_ariaundefined", (STATE_CHECKABLE | STATE_CHECKED));
       testStates("native_checkbox_nativechecked_ariaabsent", (STATE_CHECKABLE | STATE_CHECKED));
@@ -101,39 +101,39 @@ https://bugzilla.mozilla.org/show_bug.cg
       testStates("menuitem_checked_false", STATE_CHECKABLE, 0, STATE_CHECKED);
       testStates("menuitem_checked_empty", 0, 0, (STATE_CHECKABLE | STATE_CHECKED));
       testStates("menuitem_checked_undefined", 0, 0, (STATE_CHECKABLE | STATE_CHECKED));
       testStates("menuitem_checked_absent", 0, 0, (STATE_CHECKABLE | STATE_CHECKED));
 
       // test (menuitemradio) checkable and checked states
       testStates("menuitemradio_checked_true", (STATE_CHECKABLE | STATE_CHECKED));
       testStates("menuitemradio_checked_false", STATE_CHECKABLE, 0, STATE_CHECKED);
-      testStates("menuitemradio_checked_empty", 0, 0, (STATE_CHECKABLE | STATE_CHECKED));
-      testStates("menuitemradio_checked_undefined", 0, 0, (STATE_CHECKABLE | STATE_CHECKED));
+      testStates("menuitemradio_checked_empty", STATE_CHECKABLE, 0, STATE_CHECKED);
+      testStates("menuitemradio_checked_undefined", STATE_CHECKABLE, 0, STATE_CHECKED);
       testStates("menuitemradio_checked_absent", STATE_CHECKABLE, 0, STATE_CHECKED);
 
       // test (radio) checkable and checked states
       testStates("radio_checked_true", (STATE_CHECKABLE | STATE_CHECKED));
       testStates("radio_checked_false", STATE_CHECKABLE, 0, STATE_CHECKED);
-      testStates("radio_checked_empty", 0, 0, (STATE_CHECKABLE | STATE_CHECKED));
-      testStates("radio_checked_undefined", 0, 0, (STATE_CHECKABLE | STATE_CHECKED));
+      testStates("radio_checked_empty", STATE_CHECKABLE, 0, STATE_CHECKED);
+      testStates("radio_checked_undefined", STATE_CHECKABLE, 0, STATE_CHECKED);
       testStates("radio_checked_absent", STATE_CHECKABLE, 0, STATE_CHECKED);
 
       // test (textbox) multiline states
       testStates("textbox_multiline_true", 0, EXT_STATE_MULTI_LINE);
       testStates("textbox_multiline_false", 0, EXT_STATE_SINGLE_LINE);
-      testStates("textbox_multiline_empty", 0, 0, 0, EXT_STATE_SINGLE_LINE | EXT_STATE_MULTI_LINE);
-      testStates("textbox_multiline_undefined", 0, 0, 0, EXT_STATE_SINGLE_LINE | EXT_STATE_MULTI_LINE);
+      testStates("textbox_multiline_empty", 0, EXT_STATE_SINGLE_LINE);
+      testStates("textbox_multiline_undefined", 0, EXT_STATE_SINGLE_LINE);
       testStates("textbox_multiline_absent", 0, EXT_STATE_SINGLE_LINE);
 
       // test (textbox) readonly states
       testStates("textbox_readonly_true", STATE_READONLY);
       testStates("textbox_readonly_false", 0, EXT_STATE_EDITABLE, STATE_READONLY);
-      testStates("textbox_readonly_empty", 0, 0, STATE_READONLY, EXT_STATE_EDITABLE);
-      testStates("textbox_readonly_undefined", 0, 0, STATE_READONLY, EXT_STATE_EDITABLE);
+      testStates("textbox_readonly_empty", 0, EXT_STATE_EDITABLE, STATE_READONLY);
+      testStates("textbox_readonly_undefined", 0, EXT_STATE_EDITABLE, STATE_READONLY);
       testStates("textbox_readonly_absent", 0, EXT_STATE_EDITABLE, STATE_READONLY);
 
       // test native textbox readonly state and aria-readonly state (if conflict, native wins)
       testStates("native_textbox_nativereadonly_ariatrue", STATE_READONLY);
       testStates("native_textbox_nativereadonly_ariafalse", STATE_READONLY);
       testStates("native_textbox_nativereadonly_ariaempty", STATE_READONLY);
       testStates("native_textbox_nativereadonly_ariaundefined", STATE_READONLY);
       testStates("native_textbox_nativereadonly_ariaabsent", STATE_READONLY);
@@ -142,18 +142,18 @@ https://bugzilla.mozilla.org/show_bug.cg
       testStates("native_textbox_nativeeditable_ariafalse", 0, 0, STATE_READONLY);
       testStates("native_textbox_nativeeditable_ariaempty", 0, 0, STATE_READONLY);
       testStates("native_textbox_nativeeditable_ariaundefined", 0, 0, STATE_READONLY);
       testStates("native_textbox_nativeeditable_ariaabsent", 0, 0, STATE_READONLY);
 
       // test (treeitem) selectable and selected states
       testStates("treeitem_selected_true", (STATE_SELECTABLE | STATE_SELECTED));
       testStates("treeitem_selected_false", STATE_SELECTABLE, 0, STATE_SELECTED);
-      testStates("treeitem_selected_empty", 0, 0, (STATE_SELECTABLE | STATE_SELECTED));
-      testStates("treeitem_selected_undefined", 0, 0, (STATE_SELECTABLE | STATE_SELECTED));
+      testStates("treeitem_selected_empty", STATE_SELECTABLE, 0, STATE_SELECTED);
+      testStates("treeitem_selected_undefined", STATE_SELECTABLE, 0, STATE_SELECTED);
       testStates("treeitem_selected_absent", STATE_SELECTABLE, 0, STATE_SELECTED);
 
       // test (treeitem) haspopup states
       testStates("treeitem_haspopup_true", STATE_HASPOPUP);
       testStates("treeitem_haspopup_false", 0, 0, STATE_HASPOPUP);
       testStates("treeitem_haspopup_empty", 0, 0, STATE_HASPOPUP);
       testStates("treeitem_haspopup_undefined", 0, 0, STATE_HASPOPUP);
       testStates("treeitem_haspopup_absent", 0, 0, STATE_HASPOPUP);
--- a/addon-sdk/source/lib/sdk/indexed-db.js
+++ b/addon-sdk/source/lib/sdk/indexed-db.js
@@ -48,11 +48,8 @@ let principal = Cc["@mozilla.org/scripts
 exports.indexedDB = Object.freeze({
   open: indexedDB.openForPrincipal.bind(indexedDB, principal),
   deleteDatabase: indexedDB.deleteForPrincipal.bind(indexedDB, principal),
   cmp: indexedDB.cmp
 });
 
 exports.IDBKeyRange = IDBKeyRange;
 exports.DOMException = Ci.nsIDOMDOMException;
-exports.IDBCursor = Ci.nsIIDBCursor;
-exports.IDBOpenDBRequest = Ci.nsIIDBOpenDBRequest;
-exports.IDBRequest = Ci.nsIIDBRequest;
--- a/addon-sdk/source/test/test-indexed-db.js
+++ b/addon-sdk/source/test/test-indexed-db.js
@@ -3,32 +3,30 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 let xulApp = require("sdk/system/xul-app");
 if (xulApp.versionInRange(xulApp.platformVersion, "16.0a1", "*")) {
 new function tests() {
 
-const { indexedDB, IDBKeyRange, DOMException, IDBCursor,
-        IDBOpenDBRequest, IDBRequest
+const { indexedDB, IDBKeyRange, DOMException
       } = require("sdk/indexed-db");
 
 exports["test indexedDB is frozen"] = function(assert){
   let original = indexedDB.open;
   let f = function(){};
   assert.throws(function(){indexedDB.open = f});
   assert.equal(indexedDB.open,original);
   assert.notEqual(indexedDB.open,f);
 
 };
 
 exports["test db variables"] = function(assert) {
-  [ indexedDB, IDBKeyRange, DOMException, IDBCursor,
-    IDBOpenDBRequest, IDBOpenDBRequest, IDBRequest
+  [ indexedDB, IDBKeyRange, DOMException
   ].forEach(function(value) {
     assert.notEqual(typeof(value), "undefined", "variable is defined");
   });
 }
 
 exports["test open"] = function(assert, done) {
   let request = indexedDB.open("MyTestDatabase");
   request.onerror = function(event) {
--- a/browser/components/sessionstore/src/SessionWorker.js
+++ b/browser/components/sessionstore/src/SessionWorker.js
@@ -16,42 +16,46 @@ let Decoder = new TextDecoder();
 
 /**
  * Communications with the controller.
  *
  * Accepts messages:
  * {fun:function_name, args:array_of_arguments_or_null, id: custom_id}
  *
  * Sends messages:
- * {ok: result, id: custom_id} / {fail: serialized_form_of_OS.File.Error,
- *                                id: custom_id}
+ * {ok: result, id: custom_id, telemetry: {}} /
+ * {fail: serialized_form_of_OS.File.Error, id: custom_id}
  */
 self.onmessage = function (msg) {
   let data = msg.data;
   if (!(data.fun in Agent)) {
     throw new Error("Cannot find method " + data.fun);
   }
 
   let result;
   let id = data.id;
 
   try {
-    result = Agent[data.fun].apply(Agent, data.args);
+    result = Agent[data.fun].apply(Agent, data.args) || {};
   } catch (ex if ex instanceof OS.File.Error) {
     // Instances of OS.File.Error know how to serialize themselves
     // (deserialization ensures that we end up with OS-specific
     // instances of |OS.File.Error|)
     self.postMessage({fail: OS.File.Error.toMsg(ex), id: id});
     return;
   }
 
   // Other exceptions do not, and should be propagated through DOM's
   // built-in mechanism for uncaught errors, although this mechanism
   // may lose interesting information.
-  self.postMessage({ok: result, id: id});
+  self.postMessage({
+    ok: result.result,
+    id: id,
+    telemetry: result.telemetry || {}
+  });
 };
 
 let Agent = {
   // The initial session string as read from disk.
   initialState: null,
 
   // Boolean that tells whether we already wrote
   // the loadState to disk once after startup.
@@ -95,44 +99,53 @@ let Agent = {
 
   /**
    * Read the session from disk.
    * In case sessionstore.js does not exist, attempt to read sessionstore.bak.
    */
   read: function () {
     for (let path of [this.path, this.backupPath]) {
       try {
-        return this.initialState = Decoder.decode(File.read(path));
+        let durationMs = Date.now();
+        let bytes = File.read(path);
+        durationMs = Date.now() - durationMs;
+        this.initialState = Decoder.decode(bytes);
+
+        return {
+          result: this.initialState,
+          telemetry: {FX_SESSION_RESTORE_READ_FILE_MS: durationMs}
+        };
       } catch (ex if isNoSuchFileEx(ex)) {
         // Ignore exceptions about non-existent files.
       }
     }
-
     // No sessionstore data files found. Return an empty string.
-    return "";
+    return {result: ""};
   },
 
   /**
    * Write the session to disk.
    */
   write: function (stateString, options) {
+    let telemetry = {};
     if (!this.hasWrittenState) {
       if (options && options.backupOnFirstWrite) {
         try {
+          let startMs = Date.now();
           File.move(this.path, this.backupPath);
+          telemetry.FX_SESSION_RESTORE_BACKUP_FILE_MS = Date.now() - startMs;
         } catch (ex if isNoSuchFileEx(ex)) {
           // Ignore exceptions about non-existent files.
         }
       }
 
       this.hasWrittenState = true;
     }
 
-    let bytes = Encoder.encode(stateString);
-    return File.writeAtomic(this.path, bytes, {tmpPath: this.path + ".tmp"});
+    return this._write(stateString, telemetry);
   },
 
   /**
    * Writes the session state to disk again but changes session.state to
    * 'running' before doing so. This is intended to be called only once, shortly
    * after startup so that we detect crashes on startup correctly.
    */
   writeLoadStateOnceAfterStartup: function (loadState) {
@@ -153,41 +166,51 @@ let Agent = {
     try {
       state = JSON.parse(this.initialState);
     } finally {
       this.initialState = null;
     }
 
     state.session = state.session || {};
     state.session.state = loadState;
-    let bytes = Encoder.encode(JSON.stringify(state));
-    return File.writeAtomic(this.path, bytes, {tmpPath: this.path + ".tmp"});
+    return this._write(JSON.stringify(state));
+  },
+
+  /**
+   * Write a stateString to disk
+   */
+  _write: function (stateString, telemetry = {}) {
+    let bytes = Encoder.encode(stateString);
+    let startMs = Date.now();
+    let result = File.writeAtomic(this.path, bytes, {tmpPath: this.path + ".tmp"});
+    telemetry.FX_SESSION_RESTORE_WRITE_FILE_MS = Date.now() - startMs;
+    return {result: result, telemetry: telemetry};
   },
 
   /**
    * Creates a copy of sessionstore.js.
    */
   createBackupCopy: function (ext) {
     try {
-      return File.copy(this.path, this.backupPath + ext);
+      return {result: File.copy(this.path, this.backupPath + ext)};
     } catch (ex if isNoSuchFileEx(ex)) {
       // Ignore exceptions about non-existent files.
-      return true;
+      return {result: true};
     }
   },
 
   /**
    * Removes a backup copy.
    */
   removeBackupCopy: function (ext) {
     try {
-      return File.remove(this.backupPath + ext);
+      return {result: File.remove(this.backupPath + ext)};
     } catch (ex if isNoSuchFileEx(ex)) {
       // Ignore exceptions about non-existent files.
-      return true;
+      return {result: true};
     }
   },
 
   /**
    * Wipes all files holding session data from disk.
    */
   wipe: function () {
     let exn;
@@ -214,15 +237,15 @@ let Agent = {
         }
       }
     }
 
     if (exn) {
       throw exn;
     }
 
-    return true;
+    return {result: true};
   }
 };
 
 function isNoSuchFileEx(aReason) {
   return aReason instanceof OS.File.Error && aReason.becauseNoSuchFile;
 }
--- a/browser/components/sessionstore/src/_SessionFile.jsm
+++ b/browser/components/sessionstore/src/_SessionFile.jsm
@@ -198,56 +198,66 @@ let SessionFileInternal = {
 
     // The worker needs to know the initial state read from
     // disk so that writeLoadStateOnceAfterStartup() works.
     SessionWorker.post("setInitialState", [text]);
     return text;
   },
 
   read: function () {
-    return SessionWorker.post("read").then(msg => msg.ok);
+    return SessionWorker.post("read").then(msg => {
+      this._recordTelemetry(msg.telemetry);
+      return msg.ok;
+    });
   },
 
   write: function (aData, aOptions) {
     let refObj = {};
     return TaskUtils.spawn(function task() {
-      TelemetryStopwatch.start("FX_SESSION_RESTORE_WRITE_FILE_MS", refObj);
       TelemetryStopwatch.start("FX_SESSION_RESTORE_WRITE_FILE_LONGEST_OP_MS", refObj);
 
       try {
         let promise = SessionWorker.post("write", [aData, aOptions]);
         // At this point, we measure how long we stop the main thread
         TelemetryStopwatch.finish("FX_SESSION_RESTORE_WRITE_FILE_LONGEST_OP_MS", refObj);
 
-        // Now wait for the result and measure how long we had to wait for the result
-        yield promise;
-        TelemetryStopwatch.finish("FX_SESSION_RESTORE_WRITE_FILE_MS", refObj);
+        // Now wait for the result and record how long the write took
+        let msg = yield promise;
+        this._recordTelemetry(msg.telemetry);
       } catch (ex) {
         TelemetryStopwatch.cancel("FX_SESSION_RESTORE_WRITE_FILE_LONGEST_OP_MS", refObj);
-        TelemetryStopwatch.cancel("FX_SESSION_RESTORE_WRITE_FILE_MS", refObj);
         Cu.reportError("Could not write session state file " + this.path
                        + ": " + ex);
       }
     }.bind(this));
   },
 
   writeLoadStateOnceAfterStartup: function (aLoadState) {
-    return SessionWorker.post("writeLoadStateOnceAfterStartup", [aLoadState]);
+    return SessionWorker.post("writeLoadStateOnceAfterStartup", [aLoadState]).then(msg => {
+      this._recordTelemetry(msg.telemetry);
+      return msg;
+    });
   },
 
   createBackupCopy: function (ext) {
     return SessionWorker.post("createBackupCopy", [ext]);
   },
 
   removeBackupCopy: function (ext) {
     return SessionWorker.post("removeBackupCopy", [ext]);
   },
 
   wipe: function () {
     return SessionWorker.post("wipe");
+  },
+
+  _recordTelemetry: function(telemetry) {
+    for (let histogramId in telemetry){
+      Telemetry.getHistogramById(histogramId).add(telemetry[histogramId]);
+    }
   }
 };
 
 // Interface to a dedicated thread handling I/O
 let SessionWorker = (function () {
   let worker = new PromiseWorker("resource:///modules/sessionstore/SessionWorker.js",
     OS.Shared.LOG.bind("SessionWorker"));
   return {
--- a/browser/metro/base/content/appbar.js
+++ b/browser/metro/base/content/appbar.js
@@ -95,25 +95,29 @@ var Appbar = {
     } else {
       Browser.unstarSite(function () {
         Appbar._updateStarButton();
       });
     }
   },
 
   onMenuButton: function(aEvent) {
-      var typesArray = ["find-in-page"];
+      let typesArray = [];
 
-      if (ConsolePanelView.enabled) typesArray.push("open-error-console");
-      if (!MetroUtils.immersive) typesArray.push("open-jsshell");
+      if (!StartUI.isVisible)
+        typesArray.push("find-in-page");
+      if (ConsolePanelView.enabled)
+        typesArray.push("open-error-console");
+      if (!MetroUtils.immersive)
+        typesArray.push("open-jsshell");
 
       try {
         // If we have a valid http or https URI then show the view on desktop
         // menu item.
-        var uri = Services.io.newURI(Browser.selectedBrowser.currentURI.spec,
+        let uri = Services.io.newURI(Browser.selectedBrowser.currentURI.spec,
                                      null, null);
         if (uri.schemeIs('http') || uri.schemeIs('https')) {
           typesArray.push("view-on-desktop");
         }
       } catch(ex) {
       }
 
       var x = this.menuButton.getBoundingClientRect().left;
--- a/browser/metro/base/content/apzc.js
+++ b/browser/metro/base/content/apzc.js
@@ -30,17 +30,23 @@ var APZCObserver = {
     Elements.tabList.addEventListener("TabOpen", this, true);
     Elements.tabList.addEventListener("TabClose", this, true);
   },
 
   handleEvent: function APZC_handleEvent(aEvent) {
     switch (aEvent.type) {
       case 'pageshow':
       case 'TabSelect':
-        Services.obs.notifyObservers(null, "viewport-needs-updating", null);
+        const ROOT_ID = 1;
+        let windowUtils = Browser.selectedBrowser.contentWindow.
+                          QueryInterface(Ci.nsIInterfaceRequestor).
+                          getInterface(Ci.nsIDOMWindowUtils);
+        windowUtils.setDisplayPortForElement(0, 0, ContentAreaObserver.width,
+                                             ContentAreaObserver.height,
+                                             windowUtils.findElementWithViewId(ROOT_ID));
         break;
       case 'TabOpen': {
         let browser = aEvent.originalTarget.linkedBrowser;
         browser.addEventListener("pageshow", this, true);
         break;
       }
       case 'TabClose': {
         let browser = aEvent.originalTarget.linkedBrowser;
@@ -60,16 +66,17 @@ var APZCObserver = {
     let os = Services.obs;
     os.removeObserver(this, "apzc-request-content-repaint");
     os.removeObserver(this, "apzc-handle-pan-begin");
     os.removeObserver(this, "apzc-handle-pan-end");
   },
   observe: function ao_observe(aSubject, aTopic, aData) {
     if (aTopic == "apzc-request-content-repaint") {
       let frameMetrics = JSON.parse(aData);
+      let scrollId = frameMetrics.scrollId;
       let scrollTo = frameMetrics.scrollTo;
       let displayPort = frameMetrics.displayPort;
       let resolution = frameMetrics.resolution;
       let compositedRect = frameMetrics.compositedRect;
 
       if (StartUI.isStartPageVisible) {
         let windowUtils = Browser.windowUtils;
         Browser.selectedBrowser.contentWindow.scrollTo(scrollTo.x, scrollTo.y);
@@ -88,20 +95,21 @@ var APZCObserver = {
         Browser.selectedBrowser.messageManager.sendAsyncMessage("Content:SetCacheViewport", {
           scrollX: scrollTo.x,
           scrollY: scrollTo.y,
           x: displayPort.x + scrollTo.x,
           y: displayPort.y + scrollTo.y,
           w: displayPort.width,
           h: displayPort.height,
           scale: resolution,
-          id: 1
+          id: scrollId
         });
       }
 
+      Util.dumpLn("APZC scrollId: " + scrollId);
       Util.dumpLn("APZC scrollTo.x: " + scrollTo.x + ", scrollTo.y: " + scrollTo.y);
       Util.dumpLn("APZC setResolution: " + resolution);
       Util.dumpLn("APZC setDisplayPortForElement: displayPort.x: " +
                   displayPort.x + ", displayPort.y: " + displayPort.y +
                   ", displayPort.width: " + displayPort.width +
                   ", displayort.height: " + displayPort.height);
     } else if (aTopic == "apzc-handle-pan-begin") {
       // When we're panning, hide the main scrollbars by setting imprecise
--- a/browser/metro/base/content/contenthandlers/Content.js
+++ b/browser/metro/base/content/contenthandlers/Content.js
@@ -293,16 +293,18 @@ let Content = {
     // A tap on a form input triggers touch input caret selection
     if (Util.isEditable(element) &&
         aEvent.mozInputSource == Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH) {
       let { offsetX, offsetY } = Util.translateToTopLevelWindow(element);
       sendAsyncMessage("Content:SelectionCaret", {
         xPos: aEvent.clientX + offsetX,
         yPos: aEvent.clientY + offsetY
       });
+    } else {
+      SelectionHandler.closeSelection();
     }
   },
 
   // Checks clicks we care about - events bubbling up from about pages.
   _onClickBubble: function _onClickBubble(aEvent) {
     // Don't trust synthetic events
     if (!aEvent.isTrusted)
       return;
--- a/browser/metro/base/content/contenthandlers/FormHelper.js
+++ b/browser/metro/base/content/contenthandlers/FormHelper.js
@@ -75,18 +75,19 @@ FormAssistant.prototype = {
 
     // To ensure we get the current caret positionning of the focused
     // element we need to delayed a bit the event
     this._executeDelayed(function(self) {
       // Bug 640870
       // Sometimes the element inner frame get destroyed while the element
       // receive the focus because the display is turned to 'none' for
       // example, in this "fun" case just do nothing if the element is hidden
-      if (self._isVisibleElement(gFocusManager.focusedElement))
-        sendAsyncMessage("FormAssist:Show", self._getJSON());
+      if (self._isVisibleElement(gFocusManager.focusedElement)) {
+        self._sendJsonMsgWrapper("FormAssist:Show");
+      }
     });
     return this._currentElement;
   },
 
   open: function formHelperOpen(aElement, aEvent) {
     // If the click is on an option element we want to check if the parent
     // is a valid target.
     if (aElement instanceof HTMLOptionElement &&
@@ -199,17 +200,17 @@ FormAssistant.prototype = {
       }
 
       case "FormAssist:Closed":
         currentElement.blur();
         this._open = false;
         break;
 
       case "FormAssist:Update":
-        sendAsyncMessage("FormAssist:Show", this._getJSON());
+        this._sendJsonMsgWrapper("FormAssist:Show");
         break;
     }
   },
 
   handleEvent: function formHelperHandleEvent(aEvent) {
     if (this._debugEvents) Util.dumpLn(aEvent.type, this.currentElement);
     // focus changes should be taken into account only if the user has done a
     // manual operation like manually clicking
@@ -276,28 +277,29 @@ FormAssistant.prototype = {
           // we should close the form assistant.
           let focusedElement = gFocusManager.getFocusedElementForWindow(content, true, {});
           if (!focusedElement)
             self.close();
         }, 0, this);
         break;
 
       case "text":
-        if (this._isAutocomplete(aEvent.target))
-          sendAsyncMessage("FormAssist:AutoComplete", this._getJSON());
+        if (this._isAutocomplete(aEvent.target)) {
+          this._sendJsonMsgWrapper("FormAssist:AutoComplete");
+        }
         break;
 
       case "keyup":
         // There is no need to handle keys if there is not element currently
         // used by the form assistant
         if (!currentElement)
           return;
 
         if (this._isAutocomplete(aEvent.target)) {
-          sendAsyncMessage("FormAssist:AutoComplete", this._getJSON());
+          this._sendJsonMsgWrapper("FormAssist:AutoComplete");
         }
 
         let caretRect = this._getCaretRect();
         if (!caretRect.isEmpty())
           sendAsyncMessage("FormAssist:Update", { caretRect: caretRect });
     }
   },
 
@@ -421,17 +423,20 @@ FormAssistant.prototype = {
 
     if (aElement instanceof HTMLInputElement || aElement instanceof HTMLButtonElement)
       return !(aElement.type == "hidden");
 
     return this._isEditable(aElement);
   },
 
   _isVisibleElement: function formHelperIsVisibleElement(aElement) {
-    let style = aElement ? aElement.ownerDocument.defaultView.getComputedStyle(aElement, null) : null;
+    if (!aElement || !aElement.ownerDocument) {
+      return false;
+    }
+    let style = aElement.ownerDocument.defaultView.getComputedStyle(aElement, null);
     if (!style)
       return false;
 
     let isVisible = (style.getPropertyValue("visibility") != "hidden");
     let isOpaque = (style.getPropertyValue("opacity") != 0);
 
     let rect = aElement.getBoundingClientRect();
 
@@ -499,18 +504,28 @@ FormAssistant.prototype = {
           title: label.textContent
         });
       }
     }
 
     return associatedLabels;
   },
 
+  _sendJsonMsgWrapper: function (aMsg) {
+    let json = this._getJSON();
+    if (json) {
+      sendAsyncMessage(aMsg, json);
+    }
+  },
+
   _getJSON: function() {
     let element = this.currentElement;
+    if (!element) {
+      return null;
+    }
     let choices = getListForElement(element);
     let editable = (element instanceof HTMLInputElement && element.mozIsTextField(false)) || this._isEditable(element);
 
     let labels = this._getLabels();
     return {
       current: {
         id: element.id,
         name: element.name,
--- a/browser/metro/base/content/contenthandlers/SelectionHandler.js
+++ b/browser/metro/base/content/contenthandlers/SelectionHandler.js
@@ -220,24 +220,24 @@ var SelectionHandler = {
     // Init content window information
     if (!this._initTargetInfo(aX, aY)) {
       this._onFail("failed to get target information");
       return;
     }
 
     // This should never happen, but we check to make sure
     if (!this._targetIsEditable) {
-      this._onFail("Unexpected, coordiates didn't find a text input element.");
+      this._onFail("Coordiates didn't find a text input element.");
       return;
     }
 
     // Locate and sanity check the caret position
     let selection = this._getSelection();
     if (!selection || !selection.isCollapsed) {
-      this._onFail("Unexpected, No selection or selection is not collapsed.");
+      this._onFail("No selection or selection is not collapsed.");
       return;
     }
 
     // Update the position of our selection monocles
     this._updateSelectionUI("caret", false, false, true);
   },
 
   /*
@@ -276,17 +276,17 @@ var SelectionHandler = {
    * Selection close event handler
    *
    * @param aClearSelection requests that selection be cleared.
    */
   _onSelectionClose: function _onSelectionClose(aClearSelection) {
     if (aClearSelection) {
       this._clearSelection();
     }
-    this._closeSelection();
+    this.closeSelection();
   },
 
   /*
    * Called any time SelectionHelperUI would like us to
    * recalculate the selection bounds.
    */
   _onSelectionUpdate: function _onSelectionUpdate() {
     if (!this._contentWindow) {
@@ -302,17 +302,17 @@ var SelectionHandler = {
    * Called if for any reason we fail during the selection
    * process. Cancels the selection.
    */
   _onFail: function _onFail(aDbgMessage) {
     if (aDbgMessage && aDbgMessage.length > 0)
       Util.dumpLn(aDbgMessage);
     this.sendAsync("Content:SelectionFail");
     this._clearSelection();
-    this._closeSelection();
+    this.closeSelection();
   },
 
   /*
    * _repositionInfoRequest - fired at us by ContentAreaObserver when the
    * soft keyboard is being displayed. CAO wants to make a decision about
    * whether the browser deck needs repositioning.
    */
   _repositionInfoRequest: function _repositionInfoRequest(aJsonMsg) {
@@ -363,21 +363,21 @@ var SelectionHandler = {
     } else {
       let selection = content.getSelection();
       if (selection)
         selection.removeAllRanges();
     }
   },
 
   /*
-   * _closeSelection
+   * closeSelection
    *
    * Shuts SelectionHandler down.
    */
-  _closeSelection: function _closeSelection() {
+  closeSelection: function closeSelection() {
     this._clearTimers();
     this._cache = null;
     this._contentWindow = null;
     this._targetElement = null;
     this._selectionMoveActive = false;
     this._contentOffset = null;
     this._domWinUtils = null;
     this._targetIsEditable = false;
--- a/browser/metro/base/content/helperui/SelectionHelperUI.js
+++ b/browser/metro/base/content/helperui/SelectionHelperUI.js
@@ -635,48 +635,16 @@ var SelectionHelperUI = {
       newMode: "selection",
       change: targetMark.tag,
       xPos: xpos,
       yPos: ypos,
     });
   },
 
   /*
-   * _transitionFromSelectionToCaret
-   *
-   * Transitions from text selection mode to caret mode.
-   *
-   * @param aClientX, aClientY - client coordinates of the
-   * tap that initiates the change.
-   */
-  _transitionFromSelectionToCaret: function _transitionFromSelectionToCaret(aClientX, aClientY) {
-    // Reset some of our state
-    this._activeSelectionRect = null;
-
-    // Reset the monocles
-    this._shutdownAllMarkers();
-    this._setupMonocleIdArray();
-
-    // Translate to browser relative client coordinates
-    let coords =
-      this._msgTarget.ptClientToBrowser(aClientX, aClientY, true);
-
-    // Init SelectionHandler and turn on caret selection. Note the focus caret
-    // will have been removed from the target element due to the shutdown call.
-    // This won't set the caret position on its own.
-    this._sendAsyncMessage("Browser:CaretAttach", {
-      xPos: coords.x,
-      yPos: coords.y
-    });
-
-    // Set the caret position
-    this._setCaretPositionAtPoint(coords.x, coords.y);
-  },
-
-  /*
    * _setupDebugOptions
    *
    * Sends a message over to content instructing it to
    * turn on various debug features.
    */
   _setupDebugOptions: function _setupDebugOptions() {
     // Debug options for selection
     let debugOpts = { dumpRanges: false, displayRanges: false, dumpEvents: false };
@@ -798,78 +766,24 @@ var SelectionHelperUI = {
     }
   },
 
   /*
    * Event handlers for document events
    */
 
   /*
-   * _onTap
-   *
    * Handles taps that move the current caret around in text edits,
    * clear active selection and focus when neccessary, or change
    * modes.
-   * Future: changing selection modes by tapping on a monocle.
    */
-  _onTap: function _onTap(aEvent) {
-    let clientCoords =
-      this._msgTarget.ptBrowserToClient(aEvent.clientX, aEvent.clientY, true);
-
-    // Check for a tap on a monocle
-    if (this.startMark.hitTest(clientCoords.x, clientCoords.y) ||
-        this.endMark.hitTest(clientCoords.x, clientCoords.y)) {
-      aEvent.stopPropagation();
-      aEvent.preventDefault();
-      return;
-    }
-
-    // Is the tap point within the bound of the target element? This
-    // is useful if we are dealing with some sort of input control.
-    // Not so much if the target is a page or div.
-    let pointInTargetElement =
-      Util.pointWithinRect(clientCoords.x, clientCoords.y,
-                           this._targetElementRect);
-
-    // If the tap is within an editable element and the caret monocle is
-    // active, update the caret.
-    if (this.caretMark.visible && pointInTargetElement) {
-      // setCaretPositionAtPoint takes browser relative coords.
-      this._setCaretPositionAtPoint(aEvent.clientX, aEvent.clientY);
-      return;
+  _onClick: function(aEvent) {
+    if (this.layerMode == kChromeLayer && this._targetIsEditable) {
+      this.attachToCaret(this._msgTarget, aEvent.clientX, aEvent.clientY);
     }
-
-    // if the target is editable, we have selection or a caret, and the
-    // user clicks off the target clear selection and remove focus from
-    // the input.
-    if (this._targetIsEditable && !pointInTargetElement) {
-      // shutdown but leave focus alone. the event will fall through
-      // and the dom will update focus for us. If the user tapped on
-      // another input, we'll get a attachToCaret call soonish on the
-      // new input.
-      this.closeEditSession(false);
-      return;
-    }
-
-    if (this._hitTestSelection(aEvent) && this._targetIsEditable) {
-      // Attach to the newly placed caret position
-      this.attachToCaret(this._msgTarget, aEvent.clientX, aEvent.clientY);
-      return;
-    }
-
-    // A tap within an editable but outside active selection, clear the
-    // selection and flip back to caret mode.
-    if (this.startMark.visible && pointInTargetElement &&
-        this._targetIsEditable) {
-      this._transitionFromSelectionToCaret(clientCoords.x, clientCoords.y);
-      return;
-    }
-
-    // Close when we get a single tap in content.
-    this.closeEditSession(false);
   },
 
   _onKeypress: function _onKeypress() {
     this.closeEditSession();
   },
 
   _onResize: function _onResize() {
     this._sendAsyncMessage("Browser:SelectionUpdate", {});
@@ -1014,17 +928,17 @@ var SelectionHelperUI = {
    */
 
   handleEvent: function handleEvent(aEvent) {
     if (this._debugEvents && aEvent.type != "touchmove") {
       Util.dumpLn("SelectionHelperUI:", aEvent.type);
     }
     switch (aEvent.type) {
       case "click":
-        this._onTap(aEvent);
+        this._onClick(aEvent);
         break;
 
       case "touchstart": {
         if (aEvent.touches.length != 1)
           break;
         // Only prevent default if we're dragging so that
         // APZC doesn't scroll.
         if (this._checkForActiveDrag()) {
--- a/browser/metro/base/tests/mochitest/Makefile.in
+++ b/browser/metro/base/tests/mochitest/Makefile.in
@@ -51,12 +51,14 @@ MOCHITEST_METRO_FILES += \
   browser_selection_inputs.html \
   browser_selection_frame_textarea.js \
   browser_selection_frame_textarea.html \
   browser_selection_frame_inputs.js \
   browser_selection_frame_inputs.html \
   browser_selection_urlbar.js \
   browser_selection_contenteditable.js \
   browser_selection_contenteditable.html \
+  browser_selection_caretfocus.js \
+  browser_selection_caretfocus.html \
   $(NULL)
 endif
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/browser/metro/base/tests/mochitest/browser_selection_caretfocus.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+  <head>
+  </head>
+<body>
+<input id="Text1" style="width:300px;" value="text input text input text input" type="text">
+<input id="Text2" style="width:300px;" value="text input text input text input" type="text">
+<input id="Text3" style="width:300px;" value="text input text input text input" type="text">
+<iframe id="Text4" frameborder="0" style="overflow: hidden; border: 1px solid lightgray;" height="50" src="./res/textarea01.html" width="300"></iframe>
+<textarea id="Text5" style="overflow: hidden;" name="textarea" rows="2" cols="36">text area text area text area text area text area</textarea>
+<div id="Text6" style="width:300px; border: 1px solid lightgray;">text div text div text div text div</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/metro/base/tests/mochitest/browser_selection_caretfocus.js
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+let gWindow = null;
+
+///////////////////////////////////////////////////
+// form input tests
+///////////////////////////////////////////////////
+
+function setUpAndTearDown() {
+  emptyClipboard();
+  if (gWindow)
+    clearSelection(gWindow);
+  yield waitForCondition(function () {
+    return !SelectionHelperUI.isSelectionUIVisible;
+  });
+  InputSourceHelper.isPrecise = false;
+  InputSourceHelper.fireUpdate();
+}
+
+gTests.push({
+  desc: "normalize browser",
+  setUp: setUpAndTearDown,
+  tearDown: setUpAndTearDown,
+  run: function test() {
+    info(chromeRoot + "browser_selection_caretfocus.html");
+    yield addTab(chromeRoot + "browser_selection_caretfocus.html");
+
+    yield waitForCondition(function () {
+      return !StartUI.isStartPageVisible;
+    });
+
+    yield hideContextUI();
+
+    gWindow = Browser.selectedTab.browser.contentWindow;
+  },
+});
+
+function tapText(aIndex) {
+  gWindow = Browser.selectedTab.browser.contentWindow;
+  let id = "Text" + aIndex;
+  info("tapping " + id);
+  let element = gWindow.document.getElementById(id);
+  if (element.contentDocument) {
+    element = element.contentDocument.getElementById("textarea");
+    gWindow = element.ownerDocument.defaultView;
+  }
+  sendElementTap(gWindow, element, 100, 10);
+  return element;
+}
+
+gTests.push({
+  desc: "focus navigation",
+  setUp: setUpAndTearDown,
+  tearDown: setUpAndTearDown,
+  run: function test() {
+    for (let iteration = 0; iteration < 3; iteration++) {
+      for (let input = 1; input <= 6; input++) {
+        let element = tapText(input);
+        if (input == 6) {
+          // div
+          yield waitForCondition(function () {
+            return !SelectionHelperUI.isActive;
+          });
+        } else {
+          // input
+          yield SelectionHelperUI.pingSelectionHandler();
+          yield waitForCondition(function () {
+            return SelectionHelperUI.isCaretUIVisible;
+          });
+          ok(element == gWindow.document.activeElement, "element has focus");
+        }
+      }
+    }
+  },
+});
+
+function test() {
+  if (!isLandscapeMode()) {
+    todo(false, "browser_selection_tests need landscape mode to run.");
+    return;
+  }
+  // XXX need this until bugs 886624 and 859742 are fully resolved
+  setDevPixelEqualToPx();
+  runTests();
+}
--- a/browser/metro/theme/flyoutpanel.css
+++ b/browser/metro/theme/flyoutpanel.css
@@ -63,17 +63,18 @@ flyoutpanel[visible] {
   border-width: 1px;
   -moz-border-start-style: solid;
   border-color: #c2c2c2;
   padding: 40px;
   width: 100%;
 }
 
 .flyoutpanel-contents[input="precise"] {
-  overflow: scroll;
+  overflow-y: scroll;
+  overflow-x: hidden;
 }
 
 .flyout-close-button {
   border: 0 none;
   -moz-appearance: none;
   list-style-image: url(chrome://browser/skin/images/flyout-back-button.png);
   -moz-image-region: rect(0 32px 32px 0);
 }
--- a/config/makefiles/nonrecursive.mk
+++ b/config/makefiles/nonrecursive.mk
@@ -14,49 +14,55 @@
 # NONRECURSIVE_TARGETS variable lists the make targets that modified. For
 # each target in this list, the NONRECURSIVE_TARGET_<target> variable will
 # contain a list of partial variable names. We will then look in variables
 # named NONRECURSIVE_TARGETS_<target>_<fragment>_* for information describing
 # how to evaluate non-recursive make targets.
 #
 # Targets are defined by the following variables:
 #
-#   FILE - The make file to evaluate.
+#   FILE - The make file to evaluate. This is equivalent to
+#      |make -f <FILE>|
+#   DIRECTORY - The directory whose Makefile to evaluate. This is
+#      equivalent to |make -C <DIRECTORY>|.
 #   TARGETS - Targets to evaluate in that make file.
 #
+# Only 1 of FILE or DIRECTORY may be defined.
+#
 # For example:
 #
 # NONRECURSIVE_TARGETS = export libs
 # NONRECURSIVE_TARGETS_export = headers
 # NONRECURSIVE_TARGETS_export_headers_FILE = /path/to/exports.mk
 # NONRECURSIVE_TARGETS_export_headers_TARGETS = $(DIST)/include/foo.h $(DIST)/include/bar.h
 # NONRECURSIVE_TARGETS_libs = cppsrcs
-# NONRECURSIVE_TARGETS_libs_cppsrcs_FILE = /path/to/compilation.mk
+# NONRECURSIVE_TARGETS_libs_cppsrcs_DIRECTORY = $(DEPTH)/foo
 # NONRECURSIVE_TARGETS_libs_cppsrcs_TARGETS = /path/to/foo.o /path/to/bar.o
 #
 # Will get turned into the following:
 #
 # exports::
-#     $(MAKE) -f /path/to/exports.mk $(DIST)/include/foo.h $(DIST)/include/bar.h
+#     $(MAKE) -C $(DEPTH) -f /path/to/exports.mk $(DIST)/include/foo.h $(DIST)/include/bar.h
 #
 # libs::
-#     $(MAKE) -f /path/to/compilation.mk /path/to/foo.o /path/to/bar.o
+#     $(MAKE) -C $(DEPTH)/foo /path/to/foo.o /path/to/bar.o
 
 ifndef INCLUDED_NONRECURSIVE_MK
 
 define define_nonrecursive_target
 $(1)::
-	cd $$(DEPTH) && $$(MAKE) -f $(2) $(3)
+	$$(MAKE) -C $(or $(4),$$(DEPTH)) $(addprefix -f ,$(3)) $(2)
 endef
 
 $(foreach target,$(NONRECURSIVE_TARGETS), \
     $(foreach entry,$(NONRECURSIVE_TARGETS_$(target)), \
         $(eval $(call define_nonrecursive_target, \
             $(target), \
+            $(NONRECURSIVE_TARGETS_$(target)_$(entry)_TARGETS), \
             $(NONRECURSIVE_TARGETS_$(target)_$(entry)_FILE), \
-            $(NONRECURSIVE_TARGETS_$(target)_$(entry)_TARGETS) \
+            $(NONRECURSIVE_TARGETS_$(target)_$(entry)_DIRECTORY), \
         )) \
     ) \
 )
 
 INCLUDED_NONRECURSIVE_MK := 1
 endif
 
new file mode 100644
--- /dev/null
+++ b/config/makefiles/precompile/Makefile.in
@@ -0,0 +1,34 @@
+# 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/.
+
+# This make file defines the precompile tier. This tier effectively fans out
+# to other make files and specialized targets.
+
+DEPTH := @DEPTH@
+topsrcdir := @top_srcdir@
+srcdir := @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+SUPPRESS_DEFAULT_RULES := 1
+
+include $(topsrcdir)/config/rules.mk
+
+define make_subtier_dir
+@echo "BUILDSTATUS SUBTIER_START precompile $(1)"
+$(MAKE) -C $(2) $(3)
+@echo "BUILDSTATUS SUBTIER_FINISH precompile $(1)"
+
+endef
+
+export::
+	@echo "BUILDSTATUS SUBTIERS IPDL WebIDL"
+
+export:: ipdl webidl
+
+ipdl:
+	$(call make_subtier_dir,IPDL,$(DEPTH)/ipc/ipdl,ipdl)
+
+webidl:
+	$(call make_subtier_dir,WebIDL,$(DEPTH)/dom/bindings,webidl)
new file mode 100644
--- /dev/null
+++ b/config/makefiles/precompile/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -2111,16 +2111,21 @@ public:
    * @param aFeature the feature ("Views", "Core", "HTML", "Range" ...)
    * @param aVersion the version ("1.0", "2.0", ...)
    * @return whether the feature is supported or not
    */
   static bool InternalIsSupported(nsISupports* aObject,
                                   const nsAString& aFeature,
                                   const nsAString& aVersion);
 
+  /**
+   * Return true if the browser.dom.window.dump.enabled pref is set.
+   */
+  static bool DOMWindowDumpEnabled();
+
 private:
   static bool InitializeEventTable();
 
   static nsresult EnsureStringBundle(PropertiesFile aFile);
 
   static bool CanCallerAccess(nsIPrincipal* aSubjectPrincipal,
                                 nsIPrincipal* aPrincipal);
 
@@ -2220,16 +2225,20 @@ private:
   static bool sFragmentParsingActive;
 
   static nsString* sShiftText;
   static nsString* sControlText;
   static nsString* sMetaText;
   static nsString* sOSText;
   static nsString* sAltText;
   static nsString* sModifierSeparator;
+
+#if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
+  static bool sDOMWindowDumpEnabled;
+#endif
 };
 
 typedef nsCharSeparatedTokenizerTemplate<nsContentUtils::IsHTMLWhitespace>
                                                     HTMLSplitOnSpacesTokenizer;
 
 #define NS_HOLD_JS_OBJECTS(obj, clazz)                                         \
   nsContentUtils::HoldJSObjects(NS_CYCLE_COLLECTION_UPCAST(obj, clazz),        \
                                 NS_CYCLE_COLLECTION_PARTICIPANT(clazz))
--- a/content/base/src/DirectionalityUtils.cpp
+++ b/content/base/src/DirectionalityUtils.cpp
@@ -203,16 +203,17 @@
   When the contents of a text node change, nsGenericDOMDataNode::SetTextInternal
   gets called.
   */
 
 #include "mozilla/dom/DirectionalityUtils.h"
 #include "nsINode.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
+#include "mozilla/DebugOnly.h"
 #include "mozilla/dom/Element.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsUnicodeProperties.h"
 #include "nsTextFragment.h"
 #include "nsAttrValue.h"
 #include "nsContentUtils.h"
 #include "nsTextNode.h"
 #include "nsCheapSets.h"
@@ -530,17 +531,17 @@ public:
 
   void ResetAutoDirection(nsINode* aTextNode)
   {
     mElements.EnumerateEntries(ResetNodeDirection, aTextNode);
   }
 
   void EnsureMapIsClear(nsINode* aTextNode)
   {
-    uint32_t clearedEntries =
+    DebugOnly<uint32_t> clearedEntries =
       mElements.EnumerateEntries(ClearEntry, aTextNode);
     MOZ_ASSERT(clearedEntries == 0, "Map should be empty already");
   }
 
   static void RemoveElementFromMap(nsINode* aTextNode, Element* aElement)
   {
     if (aTextNode->HasTextNodeDirectionalityMap()) {
       GetDirectionalityMap(aTextNode)->RemoveEntry(aTextNode, aElement);
--- a/content/base/src/Element.cpp
+++ b/content/base/src/Element.cpp
@@ -1961,17 +1961,18 @@ Element::List(FILE* out, int32_t aIndent
   fputs(aPrefix.get(), out);
 
   fputs(NS_LossyConvertUTF16toASCII(mNodeInfo->QualifiedName()).get(), out);
 
   fprintf(out, "@%p", (void *)this);
 
   ListAttributes(out);
 
-  fprintf(out, " state=[%llx]", State().GetInternalValue());
+  fprintf(out, " state=[%llx]",
+          static_cast<unsigned long long>(State().GetInternalValue()));
   fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
   if (IsCommonAncestorForRangeInSelection()) {
     nsRange::RangeHashTable* ranges =
       static_cast<nsRange::RangeHashTable*>(GetProperty(nsGkAtoms::range));
     fprintf(out, " ranges:%d", ranges ? ranges->Count() : 0);
   }
   fprintf(out, " primaryframe=%p", static_cast<void*>(GetPrimaryFrame()));
   fprintf(out, " refcount=%d<", mRefCnt.get());
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -237,16 +237,20 @@ bool nsContentUtils::sIsPerformanceTimin
 
 uint32_t nsContentUtils::sHandlingInputTimeout = 1000;
 
 nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nullptr;
 nsIParser* nsContentUtils::sXMLFragmentParser = nullptr;
 nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nullptr;
 bool nsContentUtils::sFragmentParsingActive = false;
 
+#if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
+bool nsContentUtils::sDOMWindowDumpEnabled;
+#endif
+
 namespace {
 
 static const char kJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
 static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID);
 static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
 
 static PLDHashTable sEventListenerManagersHash;
 
@@ -429,16 +433,21 @@ nsContentUtils::Init()
 
   Preferences::AddBoolVarCache(&sIsPerformanceTimingEnabled,
                                "dom.enable_performance", true);
 
   Preferences::AddUintVarCache(&sHandlingInputTimeout,
                                "dom.event.handling-user-input-time-limit",
                                1000);
 
+#if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
+  Preferences::AddBoolVarCache(&sDOMWindowDumpEnabled,
+                               "browser.dom.window.dump.enabled");
+#endif
+
   Element::InitCCCallbacks();
 
   sInitialized = true;
 
   return NS_OK;
 }
 
 void
@@ -6418,8 +6427,21 @@ nsContentUtils::InternalIsSupported(nsIS
     return (aVersion.IsEmpty() || aVersion.EqualsLiteral("1.0") ||
             aVersion.EqualsLiteral("1.1")) &&
            nsSVGFeatures::HasFeature(aObject, aFeature);
   }
 
   // Otherwise, we claim to support everything
   return true;
 }
+
+bool
+nsContentUtils::DOMWindowDumpEnabled()
+{
+#if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
+  // In optimized builds we check a pref that controls if we should
+  // enable output from dump() or not, in debug builds it's always
+  // enabled.
+  return nsContentUtils::sDOMWindowDumpEnabled;
+#else
+  return true;
+#endif
+}
--- a/content/canvas/src/CanvasRenderingContext2D.h
+++ b/content/canvas/src/CanvasRenderingContext2D.h
@@ -540,17 +540,17 @@ protected:
   /*
    * Disposes an old target and prepares to lazily create a new target.
    */
   void ClearTarget();
 
   /**
    * Check if the target is valid after calling EnsureTarget.
    */
-  bool IsTargetValid() { return mTarget != sErrorTarget; }
+  bool IsTargetValid() { return mTarget != sErrorTarget && mTarget != nullptr; }
 
   /**
     * Returns the surface format this canvas should be allocated using. Takes
     * into account mOpaque, platform requirements, etc.
     */
   mozilla::gfx::SurfaceFormat GetSurfaceFormat() const;
 
   void DrawImage(const HTMLImageOrCanvasOrVideoElement &imgElt,
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -140,16 +140,25 @@ static bool ConvertToMidasInternalComman
                                             bool& boolValue);
 
 static bool ConvertToMidasInternalCommand(const nsAString & inCommandID,
                                             nsACString& outCommandID);
 
 // ==================================================================
 // =
 // ==================================================================
+static void
+ReportUseOfDeprecatedMethod(nsHTMLDocument* aDoc, const char* aWarning)
+{
+  nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
+                                  "DOM Events", aDoc,
+                                  nsContentUtils::eDOM_PROPERTIES,
+                                  aWarning);
+}
+
 static nsresult
 RemoveFromAgentSheets(nsCOMArray<nsIStyleSheet> &aAgentSheets, const nsAString& url)
 {
   nsCOMPtr<nsIURI> uri;
   nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
   NS_ENSURE_SUCCESS(rv, rv);
 
   for (int32_t i = aAgentSheets.Count() - 1; i >= 0; --i) {
@@ -2233,16 +2242,30 @@ nsHTMLDocument::GetSelection(ErrorResult
     return nullptr;
   }
 
   nsCOMPtr<nsISelection> sel;
   rv = window->GetSelection(getter_AddRefs(sel));
   return sel.forget();
 }
 
+NS_IMETHODIMP
+nsHTMLDocument::CaptureEvents(int32_t aEventFlags)
+{
+  ReportUseOfDeprecatedMethod(this, "UseOfCaptureEventsWarning");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsHTMLDocument::ReleaseEvents(int32_t aEventFlags)
+{
+  ReportUseOfDeprecatedMethod(this, "UseOfReleaseEventsWarning");
+  return NS_OK;
+}
+
 // Mapped to document.embeds for NS4 compatibility
 NS_IMETHODIMP
 nsHTMLDocument::GetPlugins(nsIDOMHTMLCollection** aPlugins)
 {
   *aPlugins = nullptr;
 
   return GetEmbeds(aPlugins);
 }
--- a/content/html/document/src/nsHTMLDocument.h
+++ b/content/html/document/src/nsHTMLDocument.h
@@ -237,16 +237,18 @@ public:
   // The XPCOM Get/SetBgColor work OK for us, since they never throw.
   nsIHTMLCollection* Anchors();
   nsIHTMLCollection* Applets();
   void Clear() const
   {
     // Deprecated
   }
   already_AddRefed<nsISelection> GetSelection(mozilla::ErrorResult& rv);
+  // The XPCOM CaptureEvents works fine for us.
+  // The XPCOM ReleaseEvents works fine for us.
   // We're picking up GetLocation from Document
   already_AddRefed<nsIDOMLocation> GetLocation() const {
     return nsIDocument::GetLocation();
   }
 
   virtual nsHTMLDocument* AsHTMLDocument() MOZ_OVERRIDE { return this; }
 
 protected:
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -197,18 +197,16 @@
 
 #include "nsDOMFile.h"
 
 #include "nsIEventListenerService.h"
 #include "nsIMessageManager.h"
 #include "mozilla/dom/Element.h"
 
 #include "mozilla/dom/indexedDB/IDBWrapperCache.h"
-#include "mozilla/dom/indexedDB/IDBRequest.h"
-#include "mozilla/dom/indexedDB/IDBCursor.h"
 #include "mozilla/dom/indexedDB/IDBKeyRange.h"
 
 using mozilla::dom::indexedDB::IDBWrapperCache;
 using mozilla::dom::workers::ResolveWorkerClasses;
 
 #include "nsIDOMMediaQueryList.h"
 
 #include "mozilla/dom/Activity.h"
@@ -248,16 +246,17 @@ using mozilla::dom::workers::ResolveWork
 #include "BluetoothDevice.h"
 #endif
 
 #include "DOMCameraManager.h"
 #include "DOMCameraControl.h"
 #include "DOMCameraCapabilities.h"
 #include "nsIOpenWindowEventDetail.h"
 #include "nsIAsyncScrollEventDetail.h"
+#include "nsIDOMGlobalObjectConstructor.h"
 #include "nsIDOMCanvasRenderingContext2D.h"
 #include "LockedFile.h"
 #include "nsDebug.h"
 
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/Likely.h"
 
 #ifdef MOZ_TIME_MANAGER
@@ -626,26 +625,18 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ContentFrameMessageManager, nsEventTargetSH,
                                        DOM_DEFAULT_SCRIPTABLE_FLAGS |
                                        nsIXPCScriptable::IS_GLOBAL_OBJECT)
   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ChromeMessageBroadcaster, nsDOMGenericSH,
                                        DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ChromeMessageSender, nsDOMGenericSH,
                                        DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
-  NS_DEFINE_CLASSINFO_DATA(IDBRequest, IDBEventTargetSH,
-                           IDBEVENTTARGET_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(IDBCursor, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(IDBCursorWithValue, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(IDBKeyRange, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(IDBOpenDBRequest, IDBEventTargetSH,
-                           IDBEVENTTARGET_SCRIPTABLE_FLAGS)
 
 
   NS_DEFINE_CLASSINFO_DATA(MozCSSKeyframeRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(MozCSSKeyframesRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(CSSPageRule, nsDOMGenericSH,
@@ -1522,40 +1513,20 @@ nsDOMClassInfo::Init()
 
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ChromeMessageSender, nsISupports)
     DOM_CLASSINFO_MAP_ENTRY(nsIProcessChecker)
     DOM_CLASSINFO_MAP_ENTRY(nsIFrameScriptLoader)
     DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager)
     DOM_CLASSINFO_MAP_ENTRY(nsIMessageSender)
   DOM_CLASSINFO_MAP_END
 
-  DOM_CLASSINFO_MAP_BEGIN(IDBRequest, nsIIDBRequest)
-    DOM_CLASSINFO_MAP_ENTRY(nsIIDBRequest)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
-  DOM_CLASSINFO_MAP_END
-
-  DOM_CLASSINFO_MAP_BEGIN(IDBCursor, nsIIDBCursor)
-    DOM_CLASSINFO_MAP_ENTRY(nsIIDBCursor)
-  DOM_CLASSINFO_MAP_END
-
-  DOM_CLASSINFO_MAP_BEGIN(IDBCursorWithValue, nsIIDBCursorWithValue)
-    DOM_CLASSINFO_MAP_ENTRY(nsIIDBCursor)
-    DOM_CLASSINFO_MAP_ENTRY(nsIIDBCursorWithValue)
-  DOM_CLASSINFO_MAP_END
-
   DOM_CLASSINFO_MAP_BEGIN(IDBKeyRange, nsIIDBKeyRange)
     DOM_CLASSINFO_MAP_ENTRY(nsIIDBKeyRange)
   DOM_CLASSINFO_MAP_END
 
-  DOM_CLASSINFO_MAP_BEGIN(IDBOpenDBRequest, nsIIDBOpenDBRequest)
-    DOM_CLASSINFO_MAP_ENTRY(nsIIDBOpenDBRequest)
-    DOM_CLASSINFO_MAP_ENTRY(nsIIDBRequest)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
-  DOM_CLASSINFO_MAP_END
-
   DOM_CLASSINFO_MAP_BEGIN(MozCSSKeyframeRule, nsIDOMMozCSSKeyframeRule)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozCSSKeyframeRule)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(MozCSSKeyframesRule, nsIDOMMozCSSKeyframesRule)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozCSSKeyframesRule)
   DOM_CLASSINFO_MAP_END
 
@@ -2701,32 +2672,86 @@ BaseStubConstructor(nsIWeakReference* aW
     native = do_CreateInstance(*name_struct->mData->mConstructorCID, &rv);
   }
   if (NS_FAILED(rv)) {
     NS_ERROR("Failed to create the object");
     return rv;
   }
 
   nsCOMPtr<nsIJSNativeInitializer> initializer(do_QueryInterface(native));
-  if (initializer) {
+  nsCOMPtr<nsIDOMGlobalObjectConstructor> constructor(do_QueryInterface(native));
+  if (initializer || constructor) {
     // Initialize object using the current inner window, but only if
     // the caller can access it.
     nsCOMPtr<nsPIDOMWindow> owner = do_QueryReferent(aWeakOwner);
     nsPIDOMWindow* outerWindow = owner ? owner->GetOuterWindow() : nullptr;
     nsPIDOMWindow* currentInner =
       outerWindow ? outerWindow->GetCurrentInnerWindow() : nullptr;
     if (!currentInner ||
         (owner != currentInner &&
          !nsContentUtils::CanCallerAccess(currentInner))) {
       return NS_ERROR_DOM_SECURITY_ERR;
     }
 
-    rv = initializer->Initialize(currentInner, cx, obj, args);
-    if (NS_FAILED(rv)) {
-      return rv;
+    if (initializer) {
+      rv = initializer->Initialize(currentInner, cx, obj, args);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+    } else {
+      nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS = do_QueryInterface(native);
+
+      JS::Rooted<JSObject*> thisObject(cx, wrappedJS->GetJSObject());
+      if (!thisObject) {
+        return NS_ERROR_UNEXPECTED;
+      }
+
+      nsCxPusher pusher;
+      pusher.Push(cx);
+
+      JSAutoCompartment ac(cx, thisObject);
+
+      JS::Rooted<JS::Value> funval(cx);
+      if (!JS_GetProperty(cx, thisObject, "constructor", &funval) ||
+          !funval.isObject()) {
+        return NS_ERROR_UNEXPECTED;
+      }
+
+      // Check if the object is even callable.
+      NS_ENSURE_STATE(JS_ObjectIsCallable(cx, &funval.toObject()));
+      {
+        // wrap parameters in the target compartment
+        // we also pass in the calling window as the first argument
+        unsigned argc = args.length() + 1;
+        nsAutoArrayPtr<JS::Value> argv(new JS::Value[argc]);
+        JS::AutoArrayRooter rooter(cx, 0, argv);
+
+        nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
+        nsCOMPtr<nsIDOMWindow> currentWin(do_GetInterface(currentInner));
+        rv = WrapNative(cx, obj, currentWin, &NS_GET_IID(nsIDOMWindow),
+                        true, &argv[0], getter_AddRefs(holder));
+        if (!JS_WrapValue(cx, &argv[0]))
+          return NS_ERROR_FAILURE;
+        rooter.changeLength(1);
+
+        for (size_t i = 1; i < argc; ++i) {
+          argv[i] = args[i - 1];
+          if (!JS_WrapValue(cx, &argv[i]))
+            return NS_ERROR_FAILURE;
+          rooter.changeLength(i + 1);
+        }
+
+        JS::Rooted<JS::Value> frval(cx);
+        bool ret = JS_CallFunctionValue(cx, thisObject, funval, argc, argv,
+                                        frval.address());
+
+        if (!ret) {
+          return NS_ERROR_FAILURE;
+        }
+      }
     }
   }
 
   return WrapNative(cx, obj, native, true, args.rval().address());
 }
 
 static nsresult
 DefineInterfaceConstants(JSContext *cx, JS::Handle<JSObject*> obj, const nsIID *aIID)
@@ -2803,152 +2828,16 @@ DefineInterfaceConstants(JSContext *cx, 
                              JSPROP_PERMANENT)) {
       return NS_ERROR_UNEXPECTED;
     }
   }
 
   return NS_OK;
 }
 
-// This code is temporary until we remove support for the constants defined
-// on IDBCursor/IDBRequest
-
-struct IDBConstant
-{
-  const char* interface;
-  const char* name;
-  const char* value;
-
-  static const char* IDBCursor;
-  static const char* IDBRequest;
-};
-
-const char* IDBConstant::IDBCursor = "IDBCursor";
-const char* IDBConstant::IDBRequest = "IDBRequest";
-
-static const IDBConstant sIDBConstants[] = {
-  { IDBConstant::IDBCursor,  "NEXT",              "next" },
-  { IDBConstant::IDBCursor,  "NEXT_NO_DUPLICATE", "nextunique" },
-  { IDBConstant::IDBCursor,  "PREV",              "prev" },
-  { IDBConstant::IDBCursor,  "PREV_NO_DUPLICATE", "prevunique" },
-  { IDBConstant::IDBRequest, "LOADING",           "pending" },
-  { IDBConstant::IDBRequest, "DONE",              "done" },
-};
-
-static JSBool
-IDBConstantGetter(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
-                  JS::MutableHandle<JS::Value> vp)
-{
-  JSString *idstr = JSID_TO_STRING(id);
-  unsigned index;
-  for (index = 0; index < mozilla::ArrayLength(sIDBConstants); index++) {
-    JSBool match;
-    if (!JS_StringEqualsAscii(cx, idstr, sIDBConstants[index].name, &match)) {
-      return JS_FALSE;
-    }
-    if (match) {
-      break;
-    }
-  }
-  MOZ_ASSERT(index < mozilla::ArrayLength(sIDBConstants));
-
-  const IDBConstant& c = sIDBConstants[index];
-
-  // Put a warning on the console
-  nsString warnText =
-    NS_LITERAL_STRING("The constant ") +
-    NS_ConvertASCIItoUTF16(c.interface) +
-    NS_LITERAL_STRING(".") +
-    NS_ConvertASCIItoUTF16(c.name) +
-    NS_LITERAL_STRING(" has been deprecated. Use the string value \"") +
-    NS_ConvertASCIItoUTF16(c.value) +
-    NS_LITERAL_STRING("\" instead.");
-
-  uint64_t windowID = 0;
-  nsIScriptContext* context = GetScriptContextFromJSContext(cx);
-  if (context) {
-    nsCOMPtr<nsPIDOMWindow> window =
-      do_QueryInterface(context->GetGlobalObject());
-    if (window) {
-      window = window->GetCurrentInnerWindow();
-    }
-    NS_WARN_IF_FALSE(window, "Missing a window, got a door?");
-    if (window) {
-      windowID = window->WindowID();
-    }
-  }
-
-  nsCOMPtr<nsIScriptError> errorObject =
-    do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
-  NS_WARN_IF_FALSE(errorObject, "Failed to create error object");
-  if (errorObject) {
-    nsresult rv = errorObject->InitWithWindowID(warnText,
-                                                EmptyString(), // file name
-                                                EmptyString(), // source line
-                                                0, 0, // Line/col number
-                                                nsIScriptError::warningFlag,
-                                                "DOM Core", windowID);
-    NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to init error object");
-
-    if (NS_SUCCEEDED(rv)) {
-      nsCOMPtr<nsIConsoleService> consoleServ =
-        do_GetService(NS_CONSOLESERVICE_CONTRACTID);
-      if (consoleServ) {
-        consoleServ->LogMessage(errorObject);
-      }
-    }
-  }
-
-  // Redefine property to remove getter
-  NS_ConvertASCIItoUTF16 valStr(c.value);
-  JS::Rooted<JS::Value> value(cx);
-  if (!xpc::StringToJsval(cx, valStr, value.address())) {
-    return JS_FALSE;
-  }
-  if (!::JS_DefineProperty(cx, obj, c.name, value,
-                           JS_PropertyStub, JS_StrictPropertyStub,
-                           JSPROP_ENUMERATE)) {
-    return JS_FALSE;
-  }
-
-  // Return value
-  vp.set(value);
-  return JS_TRUE;
-}
-
-static nsresult
-DefineIDBInterfaceConstants(JSContext *cx, JS::Handle<JSObject*> obj, const nsIID *aIID)
-{
-  const char* interface;
-  if (aIID->Equals(NS_GET_IID(nsIIDBCursor))) {
-    interface = IDBConstant::IDBCursor;
-  }
-  else if (aIID->Equals(NS_GET_IID(nsIIDBRequest))) {
-    interface = IDBConstant::IDBRequest;
-  }
-  else {
-    MOZ_CRASH("unexpected IID");
-  }
-
-  for (int8_t i = 0; i < (int8_t)mozilla::ArrayLength(sIDBConstants); ++i) {
-    const IDBConstant& c = sIDBConstants[i];
-    if (c.interface != interface) {
-      continue;
-    }
-
-    if (!JS_DefineProperty(cx, obj, c.name, JSVAL_VOID,
-                           IDBConstantGetter, JS_StrictPropertyStub,
-                           JSPROP_ENUMERATE)) {
-      return NS_ERROR_UNEXPECTED;
-    }
-  }
-
-  return NS_OK;
-}
-
 class nsDOMConstructor MOZ_FINAL : public nsIDOMDOMConstructor
 {
 protected:
   nsDOMConstructor(const PRUnichar* aName,
                    bool aIsConstructable,
                    nsPIDOMWindow* aOwner)
     : mClassName(aName),
       mConstructable(aIsConstructable),
@@ -3338,24 +3227,16 @@ nsDOMConstructor::ResolveInterfaceConsta
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Special case for |IDBKeyRange| which gets funny "static" functions.
   if (class_iid->Equals(NS_GET_IID(nsIIDBKeyRange)) &&
       !indexedDB::IDBKeyRange::DefineConstructors(cx, obj)) {
     return NS_ERROR_FAILURE;
   }
 
-  // Special case a few IDB interfaces which for now are getting transitional
-  // constants.
-  if (class_iid->Equals(NS_GET_IID(nsIIDBCursor)) ||
-      class_iid->Equals(NS_GET_IID(nsIIDBRequest))) {
-    rv = DefineIDBInterfaceConstants(cx, obj, class_iid);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMConstructor::ToString(nsAString &aResult)
 {
   aResult.AssignLiteral("[object ");
   aResult.Append(mClassName);
@@ -3476,24 +3357,16 @@ ResolvePrototype(nsIXPConnect *aXPConnec
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Special case for |IDBKeyRange| which gets funny "static" functions.
     if (primary_iid->Equals(NS_GET_IID(nsIIDBKeyRange)) &&
         !indexedDB::IDBKeyRange::DefineConstructors(cx, class_obj)) {
       return NS_ERROR_FAILURE;
     }
 
-    // Special case a few IDB interfaces which for now are getting transitional
-    // constants.
-    if (primary_iid->Equals(NS_GET_IID(nsIIDBCursor)) ||
-        primary_iid->Equals(NS_GET_IID(nsIIDBRequest))) {
-      rv = DefineIDBInterfaceConstants(cx, class_obj, primary_iid);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-
     nsCOMPtr<nsIInterfaceInfoManager>
       iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
     NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE);
 
     iim->GetInfoForIID(primary_iid, getter_AddRefs(if_info));
     NS_ENSURE_TRUE(if_info, NS_ERROR_UNEXPECTED);
 
     const nsIID *iid = nullptr;
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -114,22 +114,17 @@ DOMCI_CLASS(CSSFontFaceRule)
 DOMCI_CLASS(DataTransfer)
 
 DOMCI_CLASS(EventListenerInfo)
 
 DOMCI_CLASS(ContentFrameMessageManager)
 DOMCI_CLASS(ChromeMessageBroadcaster)
 DOMCI_CLASS(ChromeMessageSender)
 
-DOMCI_CLASS(IDBRequest)
-DOMCI_CLASS(IDBCursor)
-DOMCI_CLASS(IDBCursorWithValue)
 DOMCI_CLASS(IDBKeyRange)
-DOMCI_CLASS(IDBOpenDBRequest)
-
 
 DOMCI_CLASS(MozCSSKeyframeRule)
 DOMCI_CLASS(MozCSSKeyframesRule)
 
 DOMCI_CLASS(CSSPageRule)
 
 DOMCI_CLASS(MediaQueryList)
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -278,20 +278,16 @@ static uint32_t             gSerialCount
 static uint32_t             gTimeoutsRecentlySet       = 0;
 static TimeStamp            gLastRecordedRecentTimeouts;
 #define STATISTICS_INTERVAL (30 * PR_MSEC_PER_SEC)
 
 #ifdef DEBUG_jst
 int32_t gTimeoutCnt                                    = 0;
 #endif
 
-#if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
-static bool                 gDOMWindowDumpEnabled      = false;
-#endif
-
 #if defined(DEBUG_bryner) || defined(DEBUG_chb)
 #define DEBUG_PAGE_CACHE
 #endif
 
 #define DOM_TOUCH_LISTENER_ADDED "dom-touch-listener-added"
 
 // The default shortest interval/timeout we permit
 #define DEFAULT_MIN_TIMEOUT_VALUE 4 // 4ms
@@ -1080,20 +1076,16 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
 
   // We could have failed the first time through trying
   // to create the entropy collector, so we should
   // try to get one until we succeed.
 
   gRefCnt++;
 
   if (gRefCnt == 1) {
-#if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
-    Preferences::AddBoolVarCache(&gDOMWindowDumpEnabled,
-                                 "browser.dom.window.dump.enabled");
-#endif
     Preferences::AddIntVarCache(&gMinTimeoutValue,
                                 "dom.min_timeout_value",
                                 DEFAULT_MIN_TIMEOUT_VALUE);
     Preferences::AddIntVarCache(&gMinBackgroundTimeoutValue,
                                 "dom.min_background_timeout_value",
                                 DEFAULT_MIN_BACKGROUND_TIMEOUT_VALUE);
     Preferences::AddBoolVarCache(&sIdleObserversAPIFuzzTimeDisabled, 
                                  "dom.idle-observers-api.fuzz_time.disabled",
@@ -5155,33 +5147,20 @@ nsGlobalWindow::GetFullScreen(bool* aFul
     }
   }
 
   // We are the root window, or something went wrong. Return our internal value.
   *aFullScreen = mFullScreen;
   return NS_OK;
 }
 
-bool
-nsGlobalWindow::DOMWindowDumpEnabled()
-{
-#if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
-  // In optimized builds we check a pref that controls if we should
-  // enable output from dump() or not, in debug builds it's always
-  // enabled.
-  return gDOMWindowDumpEnabled;
-#else
-  return true;
-#endif
-}
-
 NS_IMETHODIMP
 nsGlobalWindow::Dump(const nsAString& aStr)
 {
-  if (!DOMWindowDumpEnabled()) {
+  if (!nsContentUtils::DOMWindowDumpEnabled()) {
     return NS_OK;
   }
 
   char *cstr = ToNewUTF8String(aStr);
 
 #if defined(XP_MACOSX)
   // have to convert \r to \n so that printing to the console works
   char *c = cstr, *cEnd = cstr + strlen(cstr);
@@ -6227,16 +6206,40 @@ nsGlobalWindow::SetInterval(int32_t *_re
 NS_IMETHODIMP
 nsGlobalWindow::SetResizable(bool aResizable)
 {
   // nop
 
   return NS_OK;
 }
 
+static void
+ReportUseOfDeprecatedMethod(nsGlobalWindow* aWindow, const char* aWarning)
+{
+  nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
+  nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
+                                  "DOM Events", doc,
+                                  nsContentUtils::eDOM_PROPERTIES,
+                                  aWarning);
+}
+
+NS_IMETHODIMP
+nsGlobalWindow::CaptureEvents(int32_t aEventFlags)
+{
+  ReportUseOfDeprecatedMethod(this, "UseOfCaptureEventsWarning");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGlobalWindow::ReleaseEvents(int32_t aEventFlags)
+{
+  ReportUseOfDeprecatedMethod(this, "UseOfReleaseEventsWarning");
+  return NS_OK;
+}
+
 static
 bool IsPopupBlocked(nsIDocument* aDoc)
 {
   nsCOMPtr<nsIPopupWindowManager> pm =
     do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
 
   if (!pm) {
     return false;
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -626,18 +626,16 @@ public:
 
 #ifdef MOZ_B2G
   virtual void EnableNetworkEvent(uint32_t aType);
   virtual void DisableNetworkEvent(uint32_t aType);
 #endif // MOZ_B2G
 
   virtual nsresult SetArguments(nsIArray *aArguments);
 
-  static bool DOMWindowDumpEnabled();
-
   void MaybeForgiveSpamCount();
   bool IsClosedOrClosing() {
     return (mIsClosed ||
             mInClose ||
             mHavePendingClose ||
             mCleanedUp);
   }
 
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -550,42 +550,42 @@ NS_ScriptErrorReporter(JSContext *cx,
                              report->lineno,
                              report->uctokenptr - report->uclinebuf,
                              report->flags, msg, fileName, sourceLine,
                              report->errorNumber != JSMSG_OUT_OF_MEMORY,
                              innerWindowID));
     }
   }
 
-#ifdef DEBUG
-  // Print it to stderr as well, for the benefit of those invoking
-  // mozilla with -console.
-  nsAutoCString error;
-  error.Assign("JavaScript ");
-  if (JSREPORT_IS_STRICT(report->flags))
-    error.Append("strict ");
-  if (JSREPORT_IS_WARNING(report->flags))
-    error.Append("warning: ");
-  else
-    error.Append("error: ");
-  error.Append(report->filename);
-  error.Append(", line ");
-  error.AppendInt(report->lineno, 10);
-  error.Append(": ");
-  if (report->ucmessage) {
-    AppendUTF16toUTF8(reinterpret_cast<const PRUnichar*>(report->ucmessage),
-                      error);
-  } else {
-    error.Append(message);
+  if (nsContentUtils::DOMWindowDumpEnabled()) {
+    // Print it to stderr as well, for the benefit of those invoking
+    // mozilla with -console.
+    nsAutoCString error;
+    error.Assign("JavaScript ");
+    if (JSREPORT_IS_STRICT(report->flags))
+      error.Append("strict ");
+    if (JSREPORT_IS_WARNING(report->flags))
+      error.Append("warning: ");
+    else
+      error.Append("error: ");
+    error.Append(report->filename);
+    error.Append(", line ");
+    error.AppendInt(report->lineno, 10);
+    error.Append(": ");
+    if (report->ucmessage) {
+      AppendUTF16toUTF8(reinterpret_cast<const PRUnichar*>(report->ucmessage),
+                        error);
+    } else {
+      error.Append(message);
+    }
+
+    fprintf(stderr, "%s\n", error.get());
+    fflush(stderr);
   }
 
-  fprintf(stderr, "%s\n", error.get());
-  fflush(stderr);
-#endif
-
 #ifdef PR_LOGGING
   if (!gJSDiagnostics)
     gJSDiagnostics = PR_NewLogModule("JSDiagnostics");
 
   if (gJSDiagnostics) {
     PR_LOG(gJSDiagnostics,
            JSREPORT_IS_WARNING(report->flags) ? PR_LOG_WARNING : PR_LOG_ERROR,
            ("file %s, line %u: %s\n%s%s",
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -533,16 +533,28 @@ DOMInterfaces = {
         'sheet'
     ]
 },
 
 'HTMLUListElement': {
     'nativeType' : 'mozilla::dom::HTMLSharedListElement'
 },
 
+'IDBCursor': {
+    'nativeType': 'mozilla::dom::indexedDB::IDBCursor',
+    'implicitJSContext': [ 'delete' ],
+    'binaryNames': {
+        'direction': 'getDirection'
+    }
+},
+
+'IDBCursorWithValue': {
+    'nativeType': 'mozilla::dom::indexedDB::IDBCursor',
+},
+
 'IDBDatabase': {
     'nativeType': 'mozilla::dom::indexedDB::IDBDatabase',
 },
 
 'IDBFactory': {
     'nativeType': 'mozilla::dom::indexedDB::IDBFactory',
 },
 
@@ -561,16 +573,25 @@ DOMInterfaces = {
 'IDBObjectStore': {
     'nativeType': 'mozilla::dom::indexedDB::IDBObjectStore',
     'implicitJSContext': [ 'createIndex' ],
     'binaryNames': {
         'mozGetAll': 'getAll'
     }
 },
 
+'IDBOpenDBRequest': {
+    'nativeType': 'mozilla::dom::indexedDB::IDBOpenDBRequest',
+    'headerFile': 'IDBRequest.h'
+},
+
+'IDBRequest': {
+    'nativeType': 'mozilla::dom::indexedDB::IDBRequest',
+},
+
 'IDBTransaction': {
     'nativeType': 'mozilla::dom::indexedDB::IDBTransaction',
 },
 
 'IDBVersionChangeEvent': {
     'nativeType': 'mozilla::dom::indexedDB::IDBVersionChangeEvent',
     'headerFile': 'IDBEvents.h',
 },
@@ -1674,18 +1695,16 @@ addExternalIface('DeviceRotationRate', h
 addExternalIface('mozIDOMApplication', nativeType='mozIDOMApplication', headerFile='nsIDOMApplicationRegistry.h')
 addExternalIface('CSSRuleList')
 addExternalIface('DOMStringList')
 addExternalIface('RTCDataChannel', nativeType='nsIDOMDataChannel')
 addExternalIface('File')
 addExternalIface('FileCallback', nativeType='nsIFileCallback',
                  headerFile='nsIDOMHTMLCanvasElement.h')
 addExternalIface('HitRegionOptions', nativeType='nsISupports')
-addExternalIface('IDBOpenDBRequest', nativeType='nsIIDBOpenDBRequest')
-addExternalIface('IDBRequest', nativeType='nsIIDBRequest')
 addExternalIface('imgINotificationObserver', nativeType='imgINotificationObserver')
 addExternalIface('imgIRequest', nativeType='imgIRequest', notflattened=True)
 addExternalIface('LockedFile')
 addExternalIface('MediaList')
 addExternalIface('MenuBuilder', nativeType='nsIMenuBuilder', notflattened=True)
 addExternalIface('MozBluetoothManager', nativeType='nsIDOMBluetoothManager')
 addExternalIface('MozBoxObject', nativeType='nsIBoxObject')
 addExternalIface('MozCellBroadcast')
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -39,8 +39,9 @@ MSG_DEF(MSG_OVERLOAD_RESOLUTION_FAILED, 
 MSG_DEF(MSG_GLOBAL_NOT_NATIVE, 0, "Global is not a native object.")
 MSG_DEF(MSG_ENCODING_NOT_SUPPORTED, 1, "The given encoding '{0}' is not supported.")
 MSG_DEF(MSG_DOM_ENCODING_NOT_UTF, 0, "The encoding must be utf-8, utf-16, or utf-16be.")
 MSG_DEF(MSG_NOT_FINITE, 1, "{0} is not a finite floating-point value.")
 MSG_DEF(MSG_INVALID_VERSION, 0, "0 (Zero) is not a valid database version.")
 MSG_DEF(MSG_INVALID_BYTESTRING, 2, "Cannot convert string to ByteString because the character"
         " at index {0} has value {1} which is greater than 255.")
 MSG_DEF(MSG_NOT_DATE, 1, "{0} is not a date.")
+MSG_DEF(MSG_INVALID_ADVANCE_COUNT, 0, "0 (Zero) is not a valid advance count.")
--- a/dom/bindings/Makefile.in
+++ b/dom/bindings/Makefile.in
@@ -237,18 +237,26 @@ GARBAGE += \
   $(binding_dependency_trackers) \
   $(NULL)
 
 # Make sure all binding header files are created during the export stage, so we
 # don't have issues with .cpp files being compiled before we've generated the
 # headers they depend on.  This is really only needed for the test files, since
 # the non-test headers are all exported above anyway.  Note that this means that
 # we do all of our codegen during export.
-export:: $(binding_header_files)
+webidl: $(binding_header_files)
+
+.PHONY: webidl
 
 distclean::
 	-$(RM) \
         $(binding_header_files) \
         $(binding_cpp_files) \
         $(all_webidl_files) \
         $(globalgen_targets) \
         ParserResults.pkl \
         $(NULL)
+
+# This is only needed to support |make| from this leaf directory/Makefile.
+NONRECURSIVE_TARGETS := export
+NONRECURSIVE_TARGETS_export := webidl
+NONRECURSIVE_TARGETS_export_webidl_DIRECTORY := .
+NONRECURSIVE_TARGETS_export_webidl_TARGETS := webidl
--- a/dom/indexedDB/AsyncConnectionHelper.cpp
+++ b/dom/indexedDB/AsyncConnectionHelper.cpp
@@ -114,17 +114,18 @@ HelperBase::WrapNative(JSContext* aCx,
                        nsISupports* aNative,
                        JS::MutableHandle<JS::Value> aResult)
 {
   NS_ASSERTION(aCx, "Null context!");
   NS_ASSERTION(aNative, "Null pointer!");
   NS_ASSERTION(aResult.address(), "Null pointer!");
   NS_ASSERTION(mRequest, "Null request!");
 
-  JS::Rooted<JSObject*> global(aCx, mRequest->GetParentObject());
+  nsRefPtr<IDBWrapperCache> wrapper = static_cast<IDBWrapperCache*>(mRequest);
+  JS::Rooted<JSObject*> global(aCx, wrapper->GetParentObject());
   NS_ASSERTION(global, "This should never be null!");
 
   nsresult rv =
     nsContentUtils::WrapNative(aCx, global, aNative, aResult.address());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
--- a/dom/indexedDB/IDBCursor.cpp
+++ b/dom/indexedDB/IDBCursor.cpp
@@ -23,19 +23,22 @@
 #include "IDBTransaction.h"
 #include "ProfilerHelpers.h"
 #include "TransactionThreadPool.h"
 
 #include "ipc/IndexedDBChild.h"
 #include "ipc/IndexedDBParent.h"
 
 #include "IndexedDatabaseInlines.h"
+#include "mozilla/dom/BindingDeclarations.h"
 
 USING_INDEXEDDB_NAMESPACE
 using namespace mozilla::dom::indexedDB::ipc;
+using mozilla::dom::Optional;
+using mozilla::ErrorResult;
 
 static_assert(sizeof(size_t) >= sizeof(IDBCursor::Direction),
               "Relying on conversion between size_t and "
               "IDBCursor::Direction");
 
 namespace {
 
 class CursorHelper : public AsyncConnectionHelper
@@ -348,16 +351,18 @@ IDBCursor::IDBCursor()
   mHaveCachedKey(false),
   mHaveCachedPrimaryKey(false),
   mHaveCachedValue(false),
   mRooted(false),
   mContinueCalled(false),
   mHaveValue(true)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  SetIsDOMBinding();
 }
 
 IDBCursor::~IDBCursor()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!");
   if (mActorChild) {
@@ -383,41 +388,37 @@ IDBCursor::DropJSObjects()
   mHaveCachedKey = false;
   mHaveCachedPrimaryKey = false;
   mHaveCachedValue = false;
   mRooted = false;
   mHaveValue = false;
   NS_DROP_JS_OBJECTS(this, IDBCursor);
 }
 
-nsresult
-IDBCursor::ContinueInternal(const Key& aKey,
-                            int32_t aCount)
+void
+IDBCursor::ContinueInternal(const Key& aKey, int32_t aCount, ErrorResult& aRv)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aCount > 0, "Must have a count!");
 
   if (!mTransaction->IsOpen()) {
-    return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
+    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
+    return;
   }
 
   if (!mHaveValue || mContinueCalled) {
-    return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
+    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
+    return;
   }
 
   mContinueToKey = aKey;
 
 #ifdef DEBUG
-  {
-    nsAutoString readyState;
-    if (NS_FAILED(mRequest->GetReadyState(readyState))) {
-      NS_ERROR("This should never fail!");
-    }
-    NS_ASSERTION(readyState.EqualsLiteral("done"), "Should be DONE!");
-  }
+  NS_ASSERTION(mRequest->ReadyState() == IDBRequestReadyState::Done,
+               "Should be DONE!");
 #endif
 
   mRequest->Reset();
 
   nsRefPtr<ContinueHelper> helper;
   switch (mType) {
     case OBJECTSTORE:
       helper = new ContinueObjectStoreHelper(this, aCount);
@@ -431,234 +432,240 @@ IDBCursor::ContinueInternal(const Key& a
       helper = new ContinueIndexObjectHelper(this, aCount);
       break;
 
     default:
       NS_NOTREACHED("Unknown cursor type!");
   }
 
   nsresult rv = helper->DispatchToTransactionPool();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Failed to dispatch!");
+    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    return;
+  }
 
   mContinueCalled = true;
-  return NS_OK;
 }
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBCursor)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRequest)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObjectStore)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndex)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBCursor)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
   NS_ASSERTION(tmp->mHaveCachedKey || JSVAL_IS_VOID(tmp->mCachedKey),
                "Should have a cached key");
   NS_ASSERTION(tmp->mHaveCachedPrimaryKey ||
                JSVAL_IS_VOID(tmp->mCachedPrimaryKey),
                "Should have a cached primary key");
   NS_ASSERTION(tmp->mHaveCachedValue || JSVAL_IS_VOID(tmp->mCachedValue),
                "Should have a cached value");
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mScriptOwner)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedKey)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedPrimaryKey)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedValue)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBCursor)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
   // Don't unlink mObjectStore, mIndex, or mTransaction!
   tmp->DropJSObjects();
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mRequest)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBCursor)
-  NS_INTERFACE_MAP_ENTRY(nsIIDBCursor)
-  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIDBCursorWithValue, mType != INDEXKEY)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(IDBCursorWithValue,
-                                                   mType != INDEXKEY)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(IDBCursor,
-                                                   mType == INDEXKEY)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBCursor)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBCursor)
 
-DOMCI_DATA(IDBCursor, IDBCursor)
-DOMCI_DATA(IDBCursorWithValue, IDBCursor)
+JSObject*
+IDBCursor::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
+{
+  return mType != INDEXKEY
+          ? IDBCursorWithValueBinding::Wrap(aCx, aScope, this)
+          : IDBCursorBinding::Wrap(aCx, aScope, this);
+}
 
-NS_IMETHODIMP
-IDBCursor::GetDirection(nsAString& aDirection)
+mozilla::dom::IDBCursorDirection
+IDBCursor::GetDirection() const
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   switch (mDirection) {
     case NEXT:
-      aDirection.AssignLiteral("next");
-      break;
+      return mozilla::dom::IDBCursorDirection::Next;
+
     case NEXT_UNIQUE:
-      aDirection.AssignLiteral("nextunique");
-      break;
+      return mozilla::dom::IDBCursorDirection::Nextunique;
+
     case PREV:
-      aDirection.AssignLiteral("prev");
-      break;
+      return mozilla::dom::IDBCursorDirection::Prev;
+
     case PREV_UNIQUE:
-      aDirection.AssignLiteral("prevunique");
-      break;
+      return mozilla::dom::IDBCursorDirection::Prevunique;
 
     case DIRECTION_INVALID:
     default:
-      NS_NOTREACHED("Bad direction value!");
-      return NS_ERROR_UNEXPECTED;
+      MOZ_CRASH("Unknown direction!");
+      return mozilla::dom::IDBCursorDirection::Next;
   }
-
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-IDBCursor::GetSource(nsISupports** aSource)
+
+already_AddRefed<nsISupports>
+IDBCursor::Source() const
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  return mType == OBJECTSTORE ?
-         CallQueryInterface(mObjectStore, aSource) :
-         CallQueryInterface(mIndex, aSource);
+  nsCOMPtr<nsISupports> source;
+  if (mType == OBJECTSTORE) {
+    source = do_QueryInterface(mObjectStore);
+  }
+  else {
+    source = do_QueryInterface(mIndex);
+  }
+
+  return source.forget();
 }
 
-NS_IMETHODIMP
-IDBCursor::GetKey(JSContext* aCx,
-                  jsval* aKey)
+JS::Value
+IDBCursor::GetKey(JSContext* aCx, ErrorResult& aRv)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   NS_ASSERTION(!mKey.IsUnset() || !mHaveValue, "Bad key!");
 
   if (!mHaveValue) {
-    *aKey = JSVAL_VOID;
-    return NS_OK;
+    return JSVAL_VOID;
   }
 
   if (!mHaveCachedKey) {
     if (!mRooted) {
       NS_HOLD_JS_OBJECTS(this, IDBCursor);
       mRooted = true;
     }
 
-    nsresult rv = mKey.ToJSVal(aCx, mCachedKey);
-    NS_ENSURE_SUCCESS(rv, rv);
+    aRv = mKey.ToJSVal(aCx, mCachedKey);
+    ENSURE_SUCCESS(aRv, JSVAL_VOID);
 
     mHaveCachedKey = true;
   }
 
-  *aKey = mCachedKey;
-  return NS_OK;
+  return mCachedKey;
 }
 
-NS_IMETHODIMP
-IDBCursor::GetPrimaryKey(JSContext* aCx,
-                         jsval* aValue)
+JS::Value
+IDBCursor::GetPrimaryKey(JSContext* aCx, ErrorResult& aRv)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (!mHaveValue) {
-    *aValue = JSVAL_VOID;
-    return NS_OK;
+    return JSVAL_VOID;
   }
 
   if (!mHaveCachedPrimaryKey) {
     if (!mRooted) {
       NS_HOLD_JS_OBJECTS(this, IDBCursor);
       mRooted = true;
     }
 
     JSAutoRequest ar(aCx);
 
     NS_ASSERTION(mType == OBJECTSTORE ? !mKey.IsUnset() :
                                         !mObjectKey.IsUnset(), "Bad key!");
 
     const Key& key = mType == OBJECTSTORE ? mKey : mObjectKey;
 
-    nsresult rv = key.ToJSVal(aCx, mCachedPrimaryKey);
-    NS_ENSURE_SUCCESS(rv, rv);
+    aRv = key.ToJSVal(aCx, mCachedPrimaryKey);
+    ENSURE_SUCCESS(aRv, JSVAL_VOID);
 
     mHaveCachedPrimaryKey = true;
   }
 
-  *aValue = mCachedPrimaryKey;
-  return NS_OK;
+  return mCachedPrimaryKey;
 }
 
-NS_IMETHODIMP
-IDBCursor::GetValue(JSContext* aCx,
-                    jsval* aValue)
+JS::Value
+IDBCursor::GetValue(JSContext* aCx, ErrorResult& aRv)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(mType != INDEXKEY, "GetValue shouldn't exist on index keys");
 
   if (!mHaveValue) {
-    *aValue = JSVAL_VOID;
-    return NS_OK;
+    return JSVAL_VOID;
   }
 
   if (!mHaveCachedValue) {
     if (!mRooted) {
       NS_HOLD_JS_OBJECTS(this, IDBCursor);
       mRooted = true;
     }
 
     JS::Rooted<JS::Value> val(aCx);
     if (!IDBObjectStore::DeserializeValue(aCx, mCloneReadInfo, &val)) {
-      return NS_ERROR_DOM_DATA_CLONE_ERR;
+      aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
+      return JSVAL_VOID;
     }
 
     mCloneReadInfo.mCloneBuffer.clear();
 
     mCachedValue = val;
     mHaveCachedValue = true;
   }
 
-  *aValue = mCachedValue;
-  return NS_OK;
+  return mCachedValue;
 }
 
-NS_IMETHODIMP
-IDBCursor::Continue(const jsval& aKey,
-                    JSContext* aCx)
+void
+IDBCursor::Continue(JSContext* aCx,
+                    const Optional<JS::Handle<JS::Value> >& aKey,
+                    ErrorResult &aRv)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   Key key;
-  nsresult rv = key.SetFromJSVal(aCx, aKey);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (aKey.WasPassed()) {
+    aRv = key.SetFromJSVal(aCx, aKey.Value());
+    ENSURE_SUCCESS_VOID(aRv);
+  }
 
   if (!key.IsUnset()) {
     switch (mDirection) {
       case IDBCursor::NEXT:
       case IDBCursor::NEXT_UNIQUE:
         if (key <= mKey) {
-          return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
+          aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
+          return;
         }
         break;
 
       case IDBCursor::PREV:
       case IDBCursor::PREV_UNIQUE:
         if (key >= mKey) {
-          return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
+          aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
+          return;
         }
         break;
 
       default:
         NS_NOTREACHED("Unknown direction type!");
     }
   }
 
-  rv = ContinueInternal(key, 1);
-  if (NS_FAILED(rv)) {
-    return rv;
+  ContinueInternal(key, 1, aRv);
+  if (aRv.Failed()) {
+    return;
   }
 
 #ifdef IDB_PROFILER_USE_MARKS
   if (mType == OBJECTSTORE) {
     IDB_PROFILER_MARK("IndexedDB Request %llu: "
                       "database(%s).transaction(%s).objectStore(%s).cursor(%s)."
                       "continue(%s)",
                       "IDBRequest[%llu] MT IDBCursor.continue()",
@@ -678,83 +685,80 @@ IDBCursor::Continue(const jsval& aKey,
                       IDB_PROFILER_STRING(Transaction()->Database()),
                       IDB_PROFILER_STRING(Transaction()),
                       IDB_PROFILER_STRING(mObjectStore),
                       IDB_PROFILER_STRING(mIndex),
                       IDB_PROFILER_STRING(mDirection),
                       key.IsUnset() ? "" : IDB_PROFILER_STRING(key));
   }
 #endif
-
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-IDBCursor::Update(const jsval& aValue,
-                  JSContext* aCx,
-                  nsIIDBRequest** _retval)
+already_AddRefed<IDBRequest>
+IDBCursor::Update(JSContext* aCx, JS::Handle<JS::Value> aValue,
+                  ErrorResult& aRv)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (!mTransaction->IsOpen()) {
-    return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
+    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
+    return nullptr;
   }
 
   if (!mTransaction->IsWriteAllowed()) {
-    return NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR;
+    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
+    return nullptr;
   }
 
   if (!mHaveValue || mType == INDEXKEY) {
-    return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
+    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
+    return nullptr;
   }
 
   NS_ASSERTION(mObjectStore, "This cannot be null!");
   NS_ASSERTION(!mKey.IsUnset() , "Bad key!");
   NS_ASSERTION(mType != INDEXOBJECT || !mObjectKey.IsUnset(), "Bad key!");
 
-  nsresult rv;
-
   JSAutoRequest ar(aCx);
 
   Key& objectKey = (mType == OBJECTSTORE) ? mKey : mObjectKey;
 
-  nsCOMPtr<nsIIDBRequest> request;
+  nsRefPtr<IDBRequest> request;
   if (mObjectStore->HasValidKeyPath()) {
     // Make sure the object given has the correct keyPath value set on it.
     const KeyPath& keyPath = mObjectStore->GetKeyPath();
     Key key;
 
-    rv = keyPath.ExtractKey(aCx, aValue, key);
-    if (NS_FAILED(rv)) {
-      return rv;
+    aRv = keyPath.ExtractKey(aCx, aValue, key);
+    if (aRv.Failed()) {
+      return nullptr;
     }
 
     if (key != objectKey) {
-      return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
+      aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
+      return nullptr;
     }
 
-    ErrorResult error;
     JS::Rooted<JS::Value> value(aCx, aValue);
     Optional<JS::Handle<JS::Value> > keyValue(aCx);
-    request = mObjectStore->Put(aCx, value, keyValue, error);
-    if (error.Failed()) {
-      return error.ErrorCode();
+    request = mObjectStore->Put(aCx, value, keyValue, aRv);
+    if (aRv.Failed()) {
+      return nullptr;
     }
   }
   else {
     JS::Rooted<JS::Value> keyVal(aCx);
-    rv = objectKey.ToJSVal(aCx, &keyVal);
-    NS_ENSURE_SUCCESS(rv, rv);
+    aRv = objectKey.ToJSVal(aCx, &keyVal);
+    ENSURE_SUCCESS(aRv, nullptr);
 
-    ErrorResult error;
     JS::Rooted<JS::Value> value(aCx, aValue);
     Optional<JS::Handle<JS::Value> > keyValue(aCx, keyVal);
-    request = mObjectStore->Put(aCx, value, keyValue, error);
-    if (error.Failed()) {
-      return error.ErrorCode();
+    request = mObjectStore->Put(aCx, value, keyValue, aRv);
+    if (aRv.Failed()) {
+      return nullptr;
     }
   }
 
 #ifdef IDB_PROFILER_USE_MARKS
   {
     uint64_t requestSerial =
       static_cast<IDBRequest*>(request.get())->GetSerialNumber();
     if (mType == OBJECTSTORE) {
@@ -782,57 +786,56 @@ IDBCursor::Update(const jsval& aValue,
                         IDB_PROFILER_STRING(mIndex),
                         IDB_PROFILER_STRING(mDirection),
                         mObjectStore->HasValidKeyPath() ? "" :
                           IDB_PROFILER_STRING(objectKey));
     }
   }
 #endif
 
-  request.forget(_retval);
-  return NS_OK;
+  return request.forget();
 }
 
-NS_IMETHODIMP
-IDBCursor::Delete(JSContext* aCx,
-                  nsIIDBRequest** _retval)
+already_AddRefed<IDBRequest>
+IDBCursor::Delete(JSContext* aCx, ErrorResult& aRv)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (!mTransaction->IsOpen()) {
-    return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
+    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
+    return nullptr;
   }
 
   if (!mTransaction->IsWriteAllowed()) {
-    return NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR;
+    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
+    return nullptr;
   }
 
   if (!mHaveValue || mType == INDEXKEY) {
-    return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
+    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
+    return nullptr;
   }
 
   NS_ASSERTION(mObjectStore, "This cannot be null!");
   NS_ASSERTION(!mKey.IsUnset() , "Bad key!");
 
   Key& objectKey = (mType == OBJECTSTORE) ? mKey : mObjectKey;
 
   JS::Rooted<JS::Value> key(aCx);
-  nsresult rv = objectKey.ToJSVal(aCx, &key);
-  NS_ENSURE_SUCCESS(rv, rv);
+  aRv = objectKey.ToJSVal(aCx, &key);
+  ENSURE_SUCCESS(aRv, nullptr);
 
-  ErrorResult error;
-  nsCOMPtr<nsIIDBRequest> request = mObjectStore->Delete(aCx, key, error);
-  if (error.Failed()) {
-    return error.ErrorCode();
+  nsRefPtr<IDBRequest> request = mObjectStore->Delete(aCx, key, aRv);
+  if (aRv.Failed()) {
+    return nullptr;
   }
 
 #ifdef IDB_PROFILER_USE_MARKS
   {
-    uint64_t requestSerial =
-      static_cast<IDBRequest*>(request.get())->GetSerialNumber();
+    uint64_t requestSerial = request->GetSerialNumber();
     if (mType == OBJECTSTORE) {
       IDB_PROFILER_MARK("IndexedDB Request %llu: "
                         "database(%s).transaction(%s).objectStore(%s)."
                         "cursor(%s).delete(%s)",
                         "IDBRequest[%llu] MT IDBCursor.delete()",
                         requestSerial,
                         IDB_PROFILER_STRING(mTransaction->Database()),
                         IDB_PROFILER_STRING(mTransaction),
@@ -853,34 +856,32 @@ IDBCursor::Delete(JSContext* aCx,
                         IDB_PROFILER_STRING(mIndex),
                         IDB_PROFILER_STRING(mDirection),
                         mObjectStore->HasValidKeyPath() ? "" :
                           IDB_PROFILER_STRING(objectKey));
     }
   }
 #endif
 
-  request.forget(_retval);
-  return NS_OK;
+  return request.forget();
 }
 
-NS_IMETHODIMP
-IDBCursor::Advance(int64_t aCount)
+void
+IDBCursor::Advance(uint32_t aCount, ErrorResult &aRv)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  if (aCount < 1 || aCount > UINT32_MAX) {
-    return NS_ERROR_TYPE_ERR;
+  if (aCount < 1) {
+    aRv.ThrowTypeError(MSG_INVALID_ADVANCE_COUNT);
+    return;
   }
 
   Key key;
-  nsresult rv = ContinueInternal(key, int32_t(aCount));
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
+  ContinueInternal(key, int32_t(aCount), aRv);
+  ENSURE_SUCCESS_VOID(aRv);
 
 #ifdef IDB_PROFILER_USE_MARKS
   {
     if (mType == OBJECTSTORE) {
       IDB_PROFILER_MARK("IndexedDB Request %llu: "
                         "database(%s).transaction(%s).objectStore(%s)."
                         "cursor(%s).advance(%ld)",
                         "IDBRequest[%llu] MT IDBCursor.advance()",
@@ -899,18 +900,16 @@ IDBCursor::Advance(int64_t aCount)
                         IDB_PROFILER_STRING(Transaction()->Database()),
                         IDB_PROFILER_STRING(Transaction()),
                         IDB_PROFILER_STRING(mObjectStore),
                         IDB_PROFILER_STRING(mIndex),
                         IDB_PROFILER_STRING(mDirection), aCount);
     }
   }
 #endif
-
-  return NS_OK;
 }
 
 void
 CursorHelper::ReleaseMainThreadObjects()
 {
   mCursor = nullptr;
   AsyncConnectionHelper::ReleaseMainThreadObjects();
 }
--- a/dom/indexedDB/IDBCursor.h
+++ b/dom/indexedDB/IDBCursor.h
@@ -4,53 +4,51 @@
  * 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/. */
 
 #ifndef mozilla_dom_indexeddb_idbcursor_h__
 #define mozilla_dom_indexeddb_idbcursor_h__
 
 #include "mozilla/dom/indexedDB/IndexedDatabase.h"
 
-#include "nsIIDBCursorWithValue.h"
-
+#include "mozilla/Attributes.h"
 #include "mozilla/dom/IDBCursorBinding.h"
+#include "mozilla/ErrorResult.h"
 #include "nsCycleCollectionParticipant.h"
+#include "nsWrapperCache.h"
 
 #include "mozilla/dom/indexedDB/IDBObjectStore.h"
 #include "mozilla/dom/indexedDB/Key.h"
 
-
 class nsIRunnable;
 class nsIScriptContext;
 class nsPIDOMWindow;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class ContinueHelper;
 class ContinueObjectStoreHelper;
 class ContinueIndexHelper;
 class ContinueIndexObjectHelper;
 class IDBIndex;
 class IDBRequest;
 class IDBTransaction;
 class IndexedDBCursorChild;
 class IndexedDBCursorParent;
 
-class IDBCursor MOZ_FINAL : public nsIIDBCursorWithValue
+class IDBCursor MOZ_FINAL : public nsISupports,
+                            public nsWrapperCache
 {
   friend class ContinueHelper;
   friend class ContinueObjectStoreHelper;
   friend class ContinueIndexHelper;
   friend class ContinueIndexObjectHelper;
 
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_NSIIDBCURSOR
-  NS_DECL_NSIIDBCURSORWITHVALUE
-
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(IDBCursor)
 
   enum Type
   {
     OBJECTSTORE = 0,
     INDEXKEY,
     INDEXOBJECT
   };
@@ -141,19 +139,58 @@ public:
   }
 
   IndexedDBCursorParent*
   GetActorParent() const
   {
     return mActorParent;
   }
 
-  nsresult
-  ContinueInternal(const Key& aKey,
-                   int32_t aCount);
+  void
+  ContinueInternal(const Key& aKey, int32_t aCount,
+                   ErrorResult& aRv);
+
+  // nsWrapperCache
+  virtual JSObject*
+  WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
+  // WebIDL
+  IDBTransaction*
+  GetParentObject() const
+  {
+    return mTransaction;
+  }
+
+  already_AddRefed<nsISupports>
+  Source() const;
+
+  IDBCursorDirection
+  GetDirection() const;
+
+  JS::Value
+  GetKey(JSContext* aCx, ErrorResult& aRv);
+
+  JS::Value
+  GetPrimaryKey(JSContext* aCx, ErrorResult& aRv);
+
+  already_AddRefed<IDBRequest>
+  Update(JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv);
+
+  void
+  Advance(uint32_t aCount, ErrorResult& aRv);
+
+  void
+  Continue(JSContext* aCx, const Optional<JS::Handle<JS::Value> >& aKey,
+           ErrorResult& aRv);
+
+  already_AddRefed<IDBRequest>
+  Delete(JSContext* aCx, ErrorResult& aRv);
+
+  JS::Value
+  GetValue(JSContext* aCx, ErrorResult& aRv);
 
 protected:
   IDBCursor();
   ~IDBCursor();
 
   void DropJSObjects();
 
   static
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -640,44 +640,44 @@ IDBFactory::Cmp(JSContext* aCx, JS::Hand
   if (first.IsUnset() || second.IsUnset()) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
     return 0;
   }
 
   return Key::CompareKeys(first, second);
 }
 
-already_AddRefed<nsIIDBOpenDBRequest>
+already_AddRefed<IDBOpenDBRequest>
 IDBFactory::OpenForPrincipal(nsIPrincipal* aPrincipal,
                              const nsAString& aName,
                              const Optional<uint64_t>& aVersion,
                              ErrorResult& aRv)
 {
   // Just to be on the extra-safe side
   if (!nsContentUtils::IsCallerChrome()) {
     MOZ_CRASH();
   }
 
   return Open(aPrincipal, aName, aVersion, false, aRv);
 }
 
-already_AddRefed<nsIIDBOpenDBRequest>
+already_AddRefed<IDBOpenDBRequest>
 IDBFactory::DeleteForPrincipal(nsIPrincipal* aPrincipal,
                                const nsAString& aName,
                                ErrorResult& aRv)
 {
   // Just to be on the extra-safe side
   if (!nsContentUtils::IsCallerChrome()) {
     MOZ_CRASH();
   }
 
   return Open(aPrincipal, aName, Optional<uint64_t>(), true, aRv);
 }
 
-already_AddRefed<nsIIDBOpenDBRequest>
+already_AddRefed<IDBOpenDBRequest>
 IDBFactory::Open(nsIPrincipal* aPrincipal,
                  const nsAString& aName, const Optional<uint64_t>& aVersion,
                  bool aDelete, ErrorResult& aRv)
 {
   nsresult rv;
 
   nsCString origin;
   if (aPrincipal) {
--- a/dom/indexedDB/IDBFactory.h
+++ b/dom/indexedDB/IDBFactory.h
@@ -13,17 +13,16 @@
 
 #include "mozilla/dom/BindingUtils.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsWrapperCache.h"
 
 class nsIAtom;
 class nsIFile;
 class nsIFileURL;
-class nsIIDBOpenDBRequest;
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 class ContentParent;
 }
 }
 
@@ -135,46 +134,46 @@ public:
   {
     return mWindow;
   }
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
   // WebIDL
-  already_AddRefed<nsIIDBOpenDBRequest>
+  already_AddRefed<IDBOpenDBRequest>
   Open(const nsAString& aName, const Optional<uint64_t>& aVersion,
        ErrorResult& aRv)
   {
     return Open(nullptr, aName, aVersion, false, aRv);
   }
 
-  already_AddRefed<nsIIDBOpenDBRequest>
+  already_AddRefed<IDBOpenDBRequest>
   DeleteDatabase(const nsAString& aName, ErrorResult& aRv)
   {
     return Open(nullptr, aName, Optional<uint64_t>(), true, aRv);
   }
 
   int16_t
   Cmp(JSContext* aCx, JS::Handle<JS::Value> aFirst,
       JS::Handle<JS::Value> aSecond, ErrorResult& aRv);
 
-  already_AddRefed<nsIIDBOpenDBRequest>
+  already_AddRefed<IDBOpenDBRequest>
   OpenForPrincipal(nsIPrincipal* aPrincipal, const nsAString& aName,
                    const Optional<uint64_t>& aVersion, ErrorResult& aRv);
 
-  already_AddRefed<nsIIDBOpenDBRequest>
+  already_AddRefed<IDBOpenDBRequest>
   DeleteForPrincipal(nsIPrincipal* aPrincipal, const nsAString& aName,
                      ErrorResult& aRv);
 
 private:
   IDBFactory();
   ~IDBFactory();
 
-  already_AddRefed<nsIIDBOpenDBRequest>
+  already_AddRefed<IDBOpenDBRequest>
   Open(nsIPrincipal* aPrincipal, const nsAString& aName,
        const Optional<uint64_t>& aVersion, bool aDelete, ErrorResult& aRv);
 
   nsCString mASCIIOrigin;
 
   // If this factory lives on a window then mWindow must be non-null. Otherwise
   // mOwningObject must be non-null.
   nsCOMPtr<nsPIDOMWindow> mWindow;
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -3,16 +3,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/. */
 
 #include "IDBRequest.h"
 
 #include "nsIScriptContext.h"
 
+#include "mozilla/dom/IDBOpenDBRequestBinding.h"
 #include "nsComponentManagerUtils.h"
 #include "nsDOMClassInfoID.h"
 #include "nsDOMJSUtils.h"
 #include "nsContentUtils.h"
 #include "nsCxPusher.h"
 #include "nsEventDispatcher.h"
 #include "nsJSUtils.h"
 #include "nsPIDOMWindow.h"
@@ -41,16 +42,18 @@ IDBRequest::IDBRequest()
 #ifdef MOZ_ENABLE_PROFILER_SPS
   mSerialNumber(gNextSerialNumber++),
 #endif
   mErrorCode(NS_OK),
   mLineNo(0),
   mHaveResultOrErrorCode(false)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  SetIsDOMBinding();
 }
 
 IDBRequest::~IDBRequest()
 {
   mResultVal = JSVAL_VOID;
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
@@ -108,17 +111,17 @@ IDBRequest::NotifyHelperCompleted(Helper
   AutoPushJSContext cx(GetJSContext());
   if (!cx) {
     NS_WARNING("Failed to get safe JSContext!");
     rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     SetError(rv);
     return rv;
   }
 
-  JS::Rooted<JSObject*> global(cx, GetParentObject());
+  JS::Rooted<JSObject*> global(cx, IDBWrapperCache::GetParentObject());
   NS_ASSERTION(global, "This should never be null!");
 
   JSAutoCompartment ac(cx, global);
   AssertIsRooted();
 
   JS::Rooted<JS::Value> value(cx);
   rv = aHelper->GetSuccessResult(cx, &value);
   if (NS_FAILED(rv)) {
@@ -224,87 +227,60 @@ IDBRequest::CaptureCaller()
 
 void
 IDBRequest::FillScriptErrorEvent(nsScriptErrorEvent* aEvent) const
 {
   aEvent->lineNr = mLineNo;
   aEvent->fileName = mFilename.get();
 }
 
-NS_IMETHODIMP
-IDBRequest::GetReadyState(nsAString& aReadyState)
+mozilla::dom::IDBRequestReadyState
+IDBRequest::ReadyState() const
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (IsPending()) {
-    aReadyState.AssignLiteral("pending");
-  }
-  else {
-    aReadyState.AssignLiteral("done");
+    return IDBRequestReadyState::Pending;
   }
 
-  return NS_OK;
+  return IDBRequestReadyState::Done;
 }
 
-NS_IMETHODIMP
-IDBRequest::GetSource(nsISupports** aSource)
+JSObject*
+IDBRequest::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  nsCOMPtr<nsISupports> source(mSource);
-  source.forget(aSource);
-  return NS_OK;
+  return IDBRequestBinding::Wrap(aCx, aScope, this);
 }
 
-NS_IMETHODIMP
-IDBRequest::GetTransaction(nsISupports** aTransaction)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  nsRefPtr<IDBWrapperCache> transaction(mTransaction);
-  transaction.forget(aTransaction);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-IDBRequest::GetResult(jsval* aResult)
+JS::Value
+IDBRequest::GetResult(JSContext* aCx, mozilla::ErrorResult& aRv) const
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (!mHaveResultOrErrorCode) {
     // XXX Need a real error code here.
-    return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
+    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
   }
 
-  *aResult = mResultVal;
-  return NS_OK;
+  return mResultVal;
 }
 
 mozilla::dom::DOMError*
 IDBRequest::GetError(mozilla::ErrorResult& aRv)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (!mHaveResultOrErrorCode) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
   return mError;
 }
 
-NS_IMETHODIMP
-IDBRequest::GetError(nsISupports** aError)
-{
-  ErrorResult rv;
-  *aError = GetError(rv);
-  NS_IF_ADDREF(*aError);
-  return rv.ErrorCode();
-}
-
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBRequest, IDBWrapperCache)
   // Don't need NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS because
   // nsDOMEventTargetHelper does it for us.
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSource)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mError)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
@@ -317,38 +293,38 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(IDBRequest, IDBWrapperCache)
   // Don't need NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER because
   // nsDOMEventTargetHelper does it for us.
   NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mResultVal)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBRequest)
-  NS_INTERFACE_MAP_ENTRY(nsIIDBRequest)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBRequest)
 NS_INTERFACE_MAP_END_INHERITING(IDBWrapperCache)
 
 NS_IMPL_ADDREF_INHERITED(IDBRequest, IDBWrapperCache)
 NS_IMPL_RELEASE_INHERITED(IDBRequest, IDBWrapperCache)
 
-DOMCI_DATA(IDBRequest, IDBRequest)
-
-NS_IMPL_EVENT_HANDLER(IDBRequest, success)
-NS_IMPL_EVENT_HANDLER(IDBRequest, error)
-
 nsresult
 IDBRequest::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   aVisitor.mCanHandle = true;
   aVisitor.mParentTarget = mTransaction;
   return NS_OK;
 }
 
+IDBOpenDBRequest::IDBOpenDBRequest()
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  SetIsDOMBinding();
+}
+
 IDBOpenDBRequest::~IDBOpenDBRequest()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
 // static
 already_AddRefed<IDBOpenDBRequest>
 IDBOpenDBRequest::Create(IDBFactory* aFactory,
@@ -385,25 +361,24 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBOpenDBRequest,
                                                 IDBRequest)
   // Don't unlink mFactory!
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBOpenDBRequest)
-  NS_INTERFACE_MAP_ENTRY(nsIIDBOpenDBRequest)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBOpenDBRequest)
 NS_INTERFACE_MAP_END_INHERITING(IDBRequest)
 
 NS_IMPL_ADDREF_INHERITED(IDBOpenDBRequest, IDBRequest)
 NS_IMPL_RELEASE_INHERITED(IDBOpenDBRequest, IDBRequest)
 
-DOMCI_DATA(IDBOpenDBRequest, IDBOpenDBRequest)
-
-NS_IMPL_EVENT_HANDLER(IDBOpenDBRequest, blocked)
-NS_IMPL_EVENT_HANDLER(IDBOpenDBRequest, upgradeneeded)
-
 nsresult
 IDBOpenDBRequest::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
 {
   return IndexedDatabaseManager::FireWindowOnError(GetOwner(), aVisitor);
 }
+
+JSObject*
+IDBOpenDBRequest::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
+{
+  return IDBOpenDBRequestBinding::Wrap(aCx, aScope, this);
+}
--- a/dom/indexedDB/IDBRequest.h
+++ b/dom/indexedDB/IDBRequest.h
@@ -2,41 +2,41 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #ifndef mozilla_dom_indexeddb_idbrequest_h__
 #define mozilla_dom_indexeddb_idbrequest_h__
 
-#include "mozilla/Attributes.h"
 #include "mozilla/dom/indexedDB/IndexedDatabase.h"
 
-#include "nsIIDBRequest.h"
-#include "nsIIDBOpenDBRequest.h"
-#include "nsDOMEventTargetHelper.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/dom/DOMError.h"
+#include "mozilla/dom/IDBRequestBinding.h"
+#include "mozilla/ErrorResult.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsWrapperCache.h"
+
 #include "mozilla/dom/indexedDB/IDBWrapperCache.h"
-#include "mozilla/dom/DOMError.h"
 
 class nsIScriptContext;
 class nsPIDOMWindow;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class HelperBase;
 class IDBFactory;
 class IDBTransaction;
 class IndexedDBRequestParentBase;
 
-class IDBRequest : public IDBWrapperCache,
-                   public nsIIDBRequest
+class IDBRequest : public IDBWrapperCache
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIIDBREQUEST
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(IDBRequest,
                                                          IDBWrapperCache)
 
   static
   already_AddRefed<IDBRequest> Create(nsISupports* aSource,
                                       IDBWrapperCache* aOwnerCache,
                                       IDBTransaction* aTransaction);
 
@@ -96,16 +96,50 @@ public:
 #ifdef MOZ_ENABLE_PROFILER_SPS
   uint64_t
   GetSerialNumber() const
   {
     return mSerialNumber;
   }
 #endif
 
+  // nsWrapperCache
+  virtual JSObject*
+  WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
+  // WebIDL
+  nsPIDOMWindow*
+  GetParentObject() const
+  {
+    return GetOwner();
+  }
+
+  JS::Value
+  GetResult(JSContext* aCx, ErrorResult& aRv) const;
+
+  nsISupports*
+  GetSource() const
+  {
+    NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+    return mSource;
+  }
+
+  IDBTransaction*
+  GetTransaction() const
+  {
+    NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+    return mTransaction;
+  }
+
+  IDBRequestReadyState
+  ReadyState() const;
+
+  IMPL_EVENT_HANDLER(success);
+  IMPL_EVENT_HANDLER(error);
+
 protected:
   IDBRequest();
   ~IDBRequest();
 
   nsCOMPtr<nsISupports> mSource;
   nsRefPtr<IDBTransaction> mTransaction;
 
   JS::Heap<JS::Value> mResultVal;
@@ -115,23 +149,20 @@ protected:
 #ifdef MOZ_ENABLE_PROFILER_SPS
   uint64_t mSerialNumber;
 #endif
   nsresult mErrorCode;
   uint32_t mLineNo;
   bool mHaveResultOrErrorCode;
 };
 
-class IDBOpenDBRequest : public IDBRequest,
-                         public nsIIDBOpenDBRequest
+class IDBOpenDBRequest : public IDBRequest
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
-  NS_FORWARD_NSIIDBREQUEST(IDBRequest::)
-  NS_DECL_NSIIDBOPENDBREQUEST
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBOpenDBRequest, IDBRequest)
 
   static
   already_AddRefed<IDBOpenDBRequest>
   Create(IDBFactory* aFactory,
          nsPIDOMWindow* aOwner,
          JS::Handle<JSObject*> aScriptOwner);
 
@@ -146,17 +177,26 @@ public:
   }
 
   IDBFactory*
   Factory() const
   {
     return mFactory;
   }
 
+  // nsWrapperCache
+  virtual JSObject*
+  WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
+  // WebIDL
+  IMPL_EVENT_HANDLER(blocked);
+  IMPL_EVENT_HANDLER(upgradeneeded);
+
 protected:
+  IDBOpenDBRequest();
   ~IDBOpenDBRequest();
 
   // Only touched on the main thread.
   nsRefPtr<IDBFactory> mFactory;
 };
 
 END_INDEXEDDB_NAMESPACE
 
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -271,18 +271,17 @@ IndexedDatabaseManager::FireWindowOnErro
 
   if (!type.EqualsLiteral(ERROR_EVT_STR)) {
     return NS_OK;
   }
 
   nsCOMPtr<EventTarget> eventTarget =
     aVisitor.mDOMEvent->InternalDOMEvent()->GetTarget();
 
-  nsCOMPtr<nsIIDBRequest> strongRequest = do_QueryInterface(eventTarget);
-  IDBRequest* request = static_cast<IDBRequest*>(strongRequest.get());
+  IDBRequest* request = static_cast<IDBRequest*>(eventTarget.get());
   NS_ENSURE_TRUE(request, NS_ERROR_UNEXPECTED);
 
   ErrorResult ret;
   nsRefPtr<DOMError> error = request->GetError(ret);
   if (ret.Failed()) {
     return ret.ErrorCode();
   }
 
--- a/dom/indexedDB/ipc/IndexedDBParent.cpp
+++ b/dom/indexedDB/ipc/IndexedDBParent.cpp
@@ -378,19 +378,19 @@ IndexedDBDatabaseParent::HandleRequestEv
       return NS_ERROR_FAILURE;
     }
 
     return NS_OK;
   }
 
   AutoSafeJSContext cx;
 
-  JS::Rooted<JS::Value> result(cx);
-  rv = mOpenRequest->GetResult(result.address());
-  NS_ENSURE_SUCCESS(rv, rv);
+  ErrorResult error;
+  JS::Rooted<JS::Value> result(cx, mOpenRequest->GetResult(cx, error));
+  ENSURE_SUCCESS(error, error.ErrorCode());
 
   MOZ_ASSERT(!JSVAL_IS_PRIMITIVE(result));
 
   IDBDatabase *database;
   rv = UnwrapObject<IDBDatabase>(cx, &result.toObject(), database);
   if (NS_FAILED(rv)) {
     NS_WARNING("Didn't get the object we expected!");
     return rv;
@@ -2039,18 +2039,19 @@ bool
 IndexedDBCursorRequestParent::Continue(const ContinueParams& aParams)
 {
   MOZ_ASSERT(mCursor);
   MOZ_ASSERT(mRequestType == ParamsUnionType::TContinueParams);
 
   {
     AutoSetCurrentTransaction asct(mCursor->Transaction());
 
-    nsresult rv = mCursor->ContinueInternal(aParams.key(), aParams.count());
-    NS_ENSURE_SUCCESS(rv, false);
+    ErrorResult rv;
+    mCursor->ContinueInternal(aParams.key(), aParams.count(), rv);
+    ENSURE_SUCCESS(rv, false);
   }
 
   mRequest = mCursor->Request();
   MOZ_ASSERT(mRequest);
 
   mRequest->SetActor(this);
   return true;
 }
--- a/dom/indexedDB/moz.build
+++ b/dom/indexedDB/moz.build
@@ -3,21 +3,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/.
 
 DIRS += ['ipc']
 TEST_DIRS += ['test']
 
 XPIDL_SOURCES += [
-    'nsIIDBCursor.idl',
-    'nsIIDBCursorWithValue.idl',
     'nsIIDBKeyRange.idl',
-    'nsIIDBOpenDBRequest.idl',
-    'nsIIDBRequest.idl',
     'nsIIndexedDatabaseManager.idl',
 ]
 
 XPIDL_MODULE = 'dom_indexeddb'
 
 XPIDL_FLAGS += [
     '-I$(topsrcdir)/dom/interfaces/base',
     '-I$(topsrcdir)/dom/interfaces/events',
deleted file mode 100644
--- a/dom/indexedDB/nsIIDBCursor.idl
+++ /dev/null
@@ -1,45 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* 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/. */
-
-#include "nsISupports.idl"
-
-interface nsIIDBRequest;
-
-/**
- * IDBCursor interface.  See
- * http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-IDBCursor for more
- * information.
- */
-[scriptable, builtinclass, uuid(148579a3-6b28-4b2a-92c3-ff5719e8e03e)]
-interface nsIIDBCursor : nsISupports
-{
-  // "next", "nextunique", "prev" or "prevunique"
-  readonly attribute DOMString direction;
-
-  readonly attribute nsISupports source;
-
-  [implicit_jscontext]
-  readonly attribute jsval key;
-
-  [implicit_jscontext]
-  readonly attribute jsval primaryKey;
-
-  // Calling continue means that the same onsuccess function will be called
-  // again with the new key/value (or null if no more matches).
-  [implicit_jscontext]
-  void continue([optional /* undefined */] in jsval key);
-
-  // Success fires IDBTransactionEvent, result == key
-  [implicit_jscontext]
-  nsIIDBRequest update(in jsval value);
-
-  // Success fires IDBTransactionEvent, result == null
-  [implicit_jscontext]
-  nsIIDBRequest delete();
-
-  void
-  advance(in long long count);
-};
deleted file mode 100644
--- a/dom/indexedDB/nsIIDBCursorWithValue.idl
+++ /dev/null
@@ -1,19 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* 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/. */
-
-#include "nsIIDBCursor.idl"
-
-/**
- * IDBCursor interface.  See
- * http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-IDBCursor for more
- * information.
- */
-[scriptable, builtinclass, uuid(b6b7e08a-4379-4441-a176-447c5c96df69)]
-interface nsIIDBCursorWithValue : nsIIDBCursor
-{
-  [implicit_jscontext]
-  readonly attribute jsval value;
-};
deleted file mode 100644
--- a/dom/indexedDB/nsIIDBOpenDBRequest.idl
+++ /dev/null
@@ -1,21 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* 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/. */
-
-#include "nsISupports.idl"
-
-interface nsIDOMEventListener;
-
-/**
- * IDBOpenDBRequest interface.  See
- * http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBOpenDBRequest
- * for more information.
- */
-[scriptable, builtinclass, uuid(2d6c5ef4-b84a-45ae-9030-eb6cfc65bb26)]
-interface nsIIDBOpenDBRequest : nsISupports
-{
-  [implicit_jscontext] attribute jsval onblocked;
-  [implicit_jscontext] attribute jsval onupgradeneeded;
-};
deleted file mode 100644
--- a/dom/indexedDB/nsIIDBRequest.idl
+++ /dev/null
@@ -1,34 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* 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/. */
-
-#include "nsISupports.idl"
-
-interface nsIDOMEventListener;
-
-/**
- * IDBRequest interface.  See
- * http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-IDBRequest for more
- * information.
- */
-[scriptable, builtinclass, uuid(4d1e9ee3-4bd0-4c99-9e6a-19cb536ab6d4)]
-interface nsIIDBRequest : nsISupports
-{
-  readonly attribute jsval result;
-
-  // This is a DOMError
-  readonly attribute nsISupports error;
-
-  readonly attribute nsISupports source;
-
-  // This is a nsIIDBTransaction
-  readonly attribute nsISupports transaction;
-
-  // "pending" or "done"
-  readonly attribute DOMString readyState;
-
-  [implicit_jscontext] attribute jsval onsuccess;
-  [implicit_jscontext] attribute jsval onerror;
-};
--- a/dom/indexedDB/test/unit/head.js
+++ b/dom/indexedDB/test/unit/head.js
@@ -1,19 +1,16 @@
 /**
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 const { 'classes': Cc, 'interfaces': Ci } = Components;
 
 const DOMException = Ci.nsIDOMDOMException;
-const IDBCursor = Ci.nsIIDBCursor;
-const IDBOpenDBRequest = Ci.nsIIDBOpenDBRequest;
-const IDBRequest = Ci.nsIIDBRequest
 
 function is(a, b, msg) {
   dump("is(" + a + ", " + b + ", \"" + msg + "\")");
   do_check_eq(a, b, Components.stack.caller);
 }
 
 function ok(cond, msg) {
   dump("ok(" + cond + ", \"" + msg + "\")");
--- a/dom/interfaces/base/moz.build
+++ b/dom/interfaces/base/moz.build
@@ -11,16 +11,17 @@ XPIDL_SOURCES += [
     'nsIContentPrefService.idl',
     'nsIContentPrefService2.idl',
     'nsIContentURIGrouper.idl',
     'nsIDOMCRMFObject.idl',
     'nsIDOMChromeWindow.idl',
     'nsIDOMClientRect.idl',
     'nsIDOMClientRectList.idl',
     'nsIDOMConstructor.idl',
+    'nsIDOMGlobalObjectConstructor.idl',
     'nsIDOMGlobalPropertyInitializer.idl',
     'nsIDOMHistory.idl',
     'nsIDOMJSWindow.idl',
     'nsIDOMLocation.idl',
     'nsIDOMMediaQueryList.idl',
     'nsIDOMModalContentWindow.idl',
     'nsIDOMNavigator.idl',
     'nsIDOMPkcs11.idl',
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/base/nsIDOMGlobalObjectConstructor.idl
@@ -0,0 +1,19 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "domstubs.idl"
+
+[scriptable, uuid(cb439c73-0129-4289-a349-c5216e6b912a)]
+interface nsIDOMGlobalObjectConstructor : nsISupports
+{
+  /*
+   * JS use only
+   *
+   * The constructor() method will be called with any parameters passed
+   * to the object constructor.
+   * If the JS implementation returns a value, it will be ignored.
+   */
+  void constructor();
+};
--- a/dom/interfaces/base/nsIDOMJSWindow.idl
+++ b/dom/interfaces/base/nsIDOMJSWindow.idl
@@ -1,16 +1,16 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 #include "domstubs.idl"
 
-[scriptable, uuid(f28c92a2-302a-4448-b589-46af599de352)]
+[scriptable, uuid(5a9689e8-5822-4dd5-b231-609b8d0260ab)]
 interface nsIDOMJSWindow : nsISupports
 {
   void                      dump(in DOMString str);
 
   /**
    * These methods take typeless arguments and optional arguments, the
    * first argument is either a function or a string, the second
    * argument must be a number (ms) and the rest of the arguments (2
@@ -29,16 +29,23 @@ interface nsIDOMJSWindow : nsISupports
 
   /**
    * This method is here for backwards compatibility with 4.x only,
    * its implementation is a no-op
    */
   void                      setResizable(in boolean resizable);
 
   /**
+   * @deprecated These are old Netscape 4 methods. Do not use,
+   *             the implementation is no-op.
+   */
+  void                      captureEvents(in long eventFlags);
+  void                      releaseEvents(in long eventFlags);
+
+  /**
    * This is the scriptable version of nsIDOMWindow::open()
    * that takes 3 optional arguments. Its binary name is OpenJS to
    * avoid colliding with nsIDOMWindow::open(), which has the
    * same signature. The reason we can't have that collision is that
    * the implementation needs to know whether it was called from JS or
    * not.
    *
    * IOW, DO NOT CALL THIS FROM C++
--- a/dom/interfaces/html/nsIDOMHTMLDocument.idl
+++ b/dom/interfaces/html/nsIDOMHTMLDocument.idl
@@ -8,17 +8,17 @@
 /**
  * The nsIDOMHTMLDocument interface is the interface to a [X]HTML
  * document object.
  *
  * @see <http://www.whatwg.org/html/>
  */
 interface nsISelection;
 
-[scriptable, uuid(cb0cc619-5862-4e00-86d3-dca3c6ecc34b)]
+[scriptable, uuid(a3efb7eb-ae02-447b-99a5-bebca100afbd)]
 interface nsIDOMHTMLDocument : nsIDOMDocument
 {
            attribute DOMString            domain;
            attribute DOMString            cookie;
 
   readonly attribute nsIDOMHTMLHeadElement head;
            attribute nsIDOMHTMLElement    body;
 
@@ -83,9 +83,18 @@ interface nsIDOMHTMLDocument : nsIDOMDoc
   readonly attribute nsIDOMHTMLCollection anchors;
   readonly attribute nsIDOMHTMLCollection applets;
 
   void                      clear();
 
 
   // DOM Range
   nsISelection                getSelection();
+
+
+  // Mozilla extensions
+  /**
+   * @deprecated These are old Netscape 4 methods. Do not use,
+   *             the implementation is no-op.
+   */
+  void                      captureEvents(in long eventFlags);
+  void                      releaseEvents(in long eventFlags);
 };
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -11,16 +11,18 @@ DebugScriptButton=Debug script
 WaitForScriptButton=Continue
 DontAskAgain=&Don't ask me again
 JSURLLoadBlockedWarning=Attempt to load a javascript: URL from one host\nin a window displaying content from another host\nwas blocked by the security manager.
 WindowCloseBlockedWarning=Scripts may not close windows that were not opened by script.
 OnBeforeUnloadTitle=Are you sure?
 OnBeforeUnloadMessage=This page is asking you to confirm that you want to leave - data you have entered may not be saved.
 OnBeforeUnloadStayButton=Stay on Page
 OnBeforeUnloadLeaveButton=Leave Page
+UseOfCaptureEventsWarning=Use of captureEvents() is deprecated. To upgrade your code, use the DOM 2 addEventListener() method. For more help http://developer.mozilla.org/en/docs/DOM:element.addEventListener
+UseOfReleaseEventsWarning=Use of releaseEvents() is deprecated. To upgrade your code, use the DOM 2 removeEventListener() method. For more help http://developer.mozilla.org/en/docs/DOM:element.removeEventListener
 UseOfDOM3LoadMethodWarning=Use of Document.load() is deprecated. To upgrade your code, use the DOM XMLHttpRequest object. For more help https://developer.mozilla.org/en/XMLHttpRequest
 UnexpectedCanvasVariantStyle=canvas: an attempt to set strokeStyle or fillStyle to a value that is neither a string, a CanvasGradient, or a CanvasPattern was ignored.
 EmptyGetElementByIdParam=Empty string passed to getElementById().
 LowMemoryTitle=Warning: Low memory
 LowMemoryMessage=A script on this page has been stopped due to a low memory condition.
 SpeculationFailed=An unbalanced tree was written using document.write() causing data from the network to be reparsed. For more information https://developer.mozilla.org/en/Optimizing_Your_Pages_for_Speculative_Parsing
 DocumentWriteIgnored=A call to document.write() from an asynchronously-loaded external script was ignored.
 FormValidationTextTooLong=Please shorten this text to %S characters or less (you are currently using %S characters).
--- a/dom/webidl/HTMLDocument.webidl
+++ b/dom/webidl/HTMLDocument.webidl
@@ -66,9 +66,15 @@ interface HTMLDocument : Document {
   void clear();
 
   [Throws]
   readonly attribute object all;
 
   // https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html#selections
   [Throws]
   Selection getSelection();
+
+  // @deprecated These are old Netscape 4 methods. Do not use,
+  //             the implementation is no-op.
+  // XXXbz do we actually need these anymore?
+  void                      captureEvents(long eventFlags);
+  void                      releaseEvents(long eventFlags);
 };
--- a/dom/webidl/IDBCursor.webidl
+++ b/dom/webidl/IDBCursor.webidl
@@ -8,8 +8,38 @@
  */
 
 enum IDBCursorDirection {
     "next",
     "nextunique",
     "prev",
     "prevunique"
 };
+
+interface IDBCursor {
+    // This should be: readonly    attribute (IDBObjectStore or IDBIndex) source;
+    readonly    attribute nsISupports source;
+
+    readonly    attribute IDBCursorDirection           direction;
+
+    [Throws]
+    readonly    attribute any                          key;
+
+    [Throws]
+    readonly    attribute any                          primaryKey;
+
+    [Throws]
+    IDBRequest update (any value);
+
+    [Throws]
+    void       advance ([EnforceRange] unsigned long count);
+
+    [Throws]
+    void       continue (optional any key);
+
+    [Throws]
+    IDBRequest delete ();
+};
+
+interface IDBCursorWithValue : IDBCursor {
+    [Throws]
+    readonly    attribute any value;
+};
--- a/dom/webidl/IDBFactory.webidl
+++ b/dom/webidl/IDBFactory.webidl
@@ -5,17 +5,16 @@
  *
  * The origin of this IDL file is
  * https://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBFactory
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
-interface IDBOpenDBRequest;
 interface Principal;
 
 /**
  * Interface that defines the indexedDB property on a window.  See
  * http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBFactory
  * for more information.
  */
 interface IDBFactory {
--- a/dom/webidl/IDBObjectStore.webidl
+++ b/dom/webidl/IDBObjectStore.webidl
@@ -2,18 +2,16 @@
 /* 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/.
  *
  * The origin of this IDL file is
  * https://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBObjectStore
  */
 
-interface IDBRequest;
-
 dictionary IDBObjectStoreParameters {
     // TODO (DOMString or sequence<DOMString>)? keyPath = null;
     any                                         keyPath = null;
     boolean                             autoIncrement = false;
 };
 
 interface IDBObjectStore {
     readonly    attribute DOMString      name;
new file mode 100644
--- /dev/null
+++ b/dom/webidl/IDBOpenDBRequest.webidl
@@ -0,0 +1,16 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/.
+ *
+ * The origin of this IDL file is
+ * https://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBOpenDBRequest
+ */
+
+interface IDBOpenDBRequest : IDBRequest {
+    [SetterThrows]
+                attribute EventHandler onblocked;
+
+    [SetterThrows]
+                attribute EventHandler onupgradeneeded;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/IDBRequest.webidl
@@ -0,0 +1,32 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/.
+ *
+ * The origin of this IDL file is
+ * https://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBRequest
+ * https://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBRequestReadyState
+ */
+
+enum IDBRequestReadyState {
+    "pending",
+    "done"
+};
+
+interface IDBRequest : EventTarget {
+    [Throws]
+    readonly    attribute any                  result;
+
+    [Throws]
+    readonly    attribute DOMError?            error;
+
+    readonly    attribute nsISupports?         source;
+    readonly    attribute IDBTransaction?      transaction;
+    readonly    attribute IDBRequestReadyState readyState;
+
+    [SetterThrows]
+                attribute EventHandler         onsuccess;
+
+    [SetterThrows]
+                attribute EventHandler         onerror;
+};
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -165,16 +165,18 @@ webidl_files = \
   HTMLUListElement.webidl \
   HTMLVideoElement.webidl \
   IDBCursor.webidl \
   IDBDatabase.webidl \
   IDBFactory.webidl \
   IDBFileHandle.webidl \
   IDBIndex.webidl \
   IDBObjectStore.webidl \
+  IDBOpenDBRequest.webidl \
+  IDBRequest.webidl \
   IDBTransaction.webidl \
   IDBVersionChangeEvent.webidl \
   ImageData.webidl \
   ImageDocument.webidl \
   InspectorUtils.webidl \
   KeyboardEvent.webidl \
   KeyEvent.webidl \
   LinkStyle.webidl \
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -1121,17 +1121,17 @@ public:
       else if (NS_SUCCEEDED(consoleService->LogStringMessage(aMessage.get()))) {
         logged = true;
       }
       else {
         NS_WARNING("Failed to log script error!");
       }
     }
 
-    if (!logged) {
+    if (!logged || nsContentUtils::DOMWindowDumpEnabled()) {
       NS_ConvertUTF16toUTF8 msg(aMessage);
 #ifdef ANDROID
       __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", msg.get());
 #endif
       fputs(msg.get(), stderr);
       fflush(stderr);
     }
 
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -83,221 +83,19 @@ namespace mozilla {
 namespace mozilla {
 namespace gl {
 typedef uintptr_t SharedTextureHandle;
 
 class GLContext
     : public GLLibraryLoader
     , public GenericAtomicRefCounted
 {
-protected:
-    typedef class gfx::SharedSurface SharedSurface;
-    typedef gfx::SharedSurfaceType SharedSurfaceType;
-    typedef gfxASurface::gfxImageFormat ImageFormat;
-    typedef gfx::SurfaceFormat SurfaceFormat;
-
+// -----------------------------------------------------------------------------
+// basic enums
 public:
-    typedef struct gfx::SurfaceCaps SurfaceCaps;
-
-    GLContext(const SurfaceCaps& caps,
-              GLContext* sharedContext = nullptr,
-              bool isOffscreen = false)
-      : mTexBlit_Buffer(0),
-        mTexBlit_VertShader(0),
-        mTex2DBlit_FragShader(0),
-        mTex2DRectBlit_FragShader(0),
-        mTex2DBlit_Program(0),
-        mTex2DRectBlit_Program(0),
-        mTexBlit_UseDrawNotCopy(false),
-        mInitialized(false),
-        mIsOffscreen(isOffscreen),
-        mIsGLES2(false),
-        mIsGlobalSharedContext(false),
-        mHasRobustness(false),
-        mContextLost(false),
-        mVendor(-1),
-        mRenderer(-1),
-        mSharedContext(sharedContext),
-        mFlipped(false),
-        mBlitProgram(0),
-        mBlitFramebuffer(0),
-        mCaps(caps),
-        mScreen(nullptr),
-        mLockedSurface(nullptr),
-        mMaxTextureSize(0),
-        mMaxCubeMapTextureSize(0),
-        mMaxTextureImageSize(0),
-        mMaxRenderbufferSize(0),
-        mNeedsTextureSizeChecks(false),
-        mWorkAroundDriverBugs(true)
-#ifdef DEBUG
-        , mGLError(LOCAL_GL_NO_ERROR)
-#endif
-    {
-        mUserData.Init();
-        mOwningThread = NS_GetCurrentThread();
-
-        mTexBlit_UseDrawNotCopy = Preferences::GetBool("gl.blit-draw-not-copy", false);
-    }
-
-    virtual ~GLContext() {
-        NS_ASSERTION(IsDestroyed(), "GLContext implementation must call MarkDestroyed in destructor!");
-#ifdef DEBUG
-        if (mSharedContext) {
-            GLContext *tip = mSharedContext;
-            while (tip->mSharedContext)
-                tip = tip->mSharedContext;
-            tip->SharedContextDestroyed(this);
-            tip->ReportOutstandingNames();
-        } else {
-            ReportOutstandingNames();
-        }
-#endif
-    }
-
-    enum ContextFlags {
-        ContextFlagsNone = 0x0,
-        ContextFlagsGlobal = 0x1,
-        ContextFlagsMesaLLVMPipe = 0x2
-    };
-
-    enum GLContextType {
-        ContextTypeUnknown,
-        ContextTypeWGL,
-        ContextTypeCGL,
-        ContextTypeGLX,
-        ContextTypeEGL
-    };
-
-    virtual GLContextType GetContextType() { return ContextTypeUnknown; }
-
-    virtual bool MakeCurrentImpl(bool aForce = false) = 0;
-
-#ifdef DEBUG
-    static void StaticInit() {
-        PR_NewThreadPrivateIndex(&sCurrentGLContextTLS, nullptr);
-    }
-#endif
-
-    bool MakeCurrent(bool aForce = false) {
-#ifdef DEBUG
-    PR_SetThreadPrivate(sCurrentGLContextTLS, this);
-
-    // XXX this assertion is disabled because it's triggering on Mac;
-    // we need to figure out why and reenable it.
-#if 0
-        // IsOwningThreadCurrent is a bit of a misnomer;
-        // the "owning thread" is the creation thread,
-        // and the only thread that can own this.  We don't
-        // support contexts used on multiple threads.
-        NS_ASSERTION(IsOwningThreadCurrent(),
-                     "MakeCurrent() called on different thread than this context was created on!");
-#endif
-#endif
-        return MakeCurrentImpl(aForce);
-    }
-
-    virtual bool IsCurrent() = 0;
-
-    bool IsContextLost() { return mContextLost; }
-
-    virtual bool SetupLookupFunction() = 0;
-
-    virtual void ReleaseSurface() {}
-
-    void *GetUserData(void *aKey) {
-        void *result = nullptr;
-        mUserData.Get(aKey, &result);
-        return result;
-    }
-
-    void SetUserData(void *aKey, void *aValue) {
-        mUserData.Put(aKey, aValue);
-    }
-
-    // Mark this context as destroyed.  This will nullptr out all
-    // the GL function pointers!
-    void MarkDestroyed();
-
-    bool IsDestroyed() {
-        // MarkDestroyed will mark all these as null.
-        return mSymbols.fUseProgram == nullptr;
-    }
-
-    enum NativeDataType {
-      NativeGLContext,
-      NativeImageSurface,
-      NativeThebesSurface,
-      NativeDataTypeMax
-    };
-
-    virtual void *GetNativeData(NativeDataType aType) { return nullptr; }
-    GLContext *GetSharedContext() { return mSharedContext; }
-
-    bool IsGlobalSharedContext() { return mIsGlobalSharedContext; }
-    void SetIsGlobalSharedContext(bool aIsOne) { mIsGlobalSharedContext = aIsOne; }
-
-    /**
-     * Returns true if the thread on which this context was created is the currently
-     * executing thread.
-     */
-    bool IsOwningThreadCurrent() { return NS_GetCurrentThread() == mOwningThread; }
-
-    void DispatchToOwningThread(nsIRunnable *event) {
-        // Before dispatching, we need to ensure we're not in the middle of
-        // shutting down. Dispatching runnables in the middle of shutdown
-        // (that is, when the main thread is no longer get-able) can cause them
-        // to leak. See Bug 741319, and Bug 744115.
-        nsCOMPtr<nsIThread> mainThread;
-        if (NS_SUCCEEDED(NS_GetMainThread(getter_AddRefs(mainThread)))) {
-            mOwningThread->Dispatch(event, NS_DISPATCH_NORMAL);
-        }
-    }
-
-    virtual EGLContext GetEGLContext() { return nullptr; }
-    virtual GLLibraryEGL* GetLibraryEGL() { return nullptr; }
-
-    virtual void MakeCurrent_EGLSurface(void* surf) {
-        MOZ_CRASH("Must be called against a GLContextEGL.");
-    }
-
-    /**
-     * If this context is double-buffered, returns TRUE.
-     */
-    virtual bool IsDoubleBuffered() { return false; }
-
-    /**
-     * If this context is the GLES2 API, returns TRUE.
-     * This means that various GLES2 restrictions might be in effect (modulo
-     * extensions).
-     */
-    bool IsGLES2() const {
-        return mIsGLES2;
-    }
-
-    /**
-     * Returns true if either this is the GLES2 API, or had the GL_ARB_ES2_compatibility extension
-     */
-    bool HasES2Compatibility() {
-        return mIsGLES2 || IsExtensionSupported(ARB_ES2_compatibility);
-    }
-
-    /**
-     * Returns true if the context is using ANGLE. This should only be overridden for an ANGLE
-     * implementation.
-     */
-    virtual bool IsANGLE() {
-        return false;
-    }
-
-    /**
-     * The derived class is expected to provide information on whether or not it
-     * supports robustness.
-     */
-    virtual bool SupportsRobustness() = 0;
 
     enum {
         VendorIntel,
         VendorNVIDIA,
         VendorATI,
         VendorQualcomm,
         VendorImagination,
         VendorNouveau,
@@ -310,724 +108,112 @@ public:
         RendererAdrenoTM205,
         RendererAdrenoTM320,
         RendererSGX530,
         RendererSGX540,
         RendererTegra,
         RendererOther
     };
 
+    enum ContextFlags {
+        ContextFlagsNone = 0x0,
+        ContextFlagsGlobal = 0x1,
+        ContextFlagsMesaLLVMPipe = 0x2
+    };
+
+    enum GLContextType {
+        ContextTypeUnknown,
+        ContextTypeWGL,
+        ContextTypeCGL,
+        ContextTypeGLX,
+        ContextTypeEGL
+    };
+
+
+// -----------------------------------------------------------------------------
+// basic getters
+public:
+
+    /**
+     * Returns true if the context is using ANGLE. This should only be overridden
+     * for an ANGLE implementation.
+     */
+    virtual bool IsANGLE() {
+        return false;
+    }
+
     int Vendor() const {
         return mVendor;
     }
 
     int Renderer() const {
         return mRenderer;
     }
 
-    bool CanUploadSubTextures();
-
-    static void PlatformStartup();
-
-protected:
-    static bool sPowerOfTwoForced;
-    static bool sPowerOfTwoPrefCached;
-    static void CacheCanUploadNPOT();
-
-public:
-    bool CanUploadNonPowerOfTwo();
-
-    bool WantsSmallTiles();
-
-    /**
-     * If this context wraps a double-buffered target, swap the back
-     * and front buffers.  It should be assumed that after a swap, the
-     * contents of the new back buffer are undefined.
-     */
-    virtual bool SwapBuffers() { return false; }
-
-    /**
-     * Defines a two-dimensional texture image for context target surface
-     */
-    virtual bool BindTexImage() { return false; }
-    /*
-     * Releases a color buffer that is being used as a texture
-     */
-    virtual bool ReleaseTexImage() { return false; }
-
-    /**
-     * Applies aFilter to the texture currently bound to GL_TEXTURE_2D.
-     */
-    void ApplyFilterToBoundTexture(gfxPattern::GraphicsFilter aFilter);
-
-    /**
-     * Applies aFilter to the texture currently bound to aTarget.
-     */
-    void ApplyFilterToBoundTexture(GLuint aTarget,
-                                   gfxPattern::GraphicsFilter aFilter);
-
-    virtual bool BindExternalBuffer(GLuint texture, void* buffer) { return false; }
-    virtual bool UnbindExternalBuffer(GLuint texture) { return false; }
-
-#ifdef MOZ_WIDGET_GONK
-    virtual EGLImage CreateEGLImageForNativeBuffer(void* buffer) = 0;
-    virtual void DestroyEGLImage(EGLImage image) = 0;
-    virtual EGLImage GetNullEGLImage() = 0;
-#endif
-
-    virtual already_AddRefed<TextureImage>
-    CreateDirectTextureImage(android::GraphicBuffer* aBuffer, GLenum aWrapMode)
-    { return nullptr; }
-
-    // Before reads from offscreen texture
-    void GuaranteeResolve();
-
-protected:
-    GLuint mTexBlit_Buffer;
-    GLuint mTexBlit_VertShader;
-    GLuint mTex2DBlit_FragShader;
-    GLuint mTex2DRectBlit_FragShader;
-    GLuint mTex2DBlit_Program;
-    GLuint mTex2DRectBlit_Program;
-
-    bool mTexBlit_UseDrawNotCopy;
-
-    bool UseTexQuadProgram(GLenum target = LOCAL_GL_TEXTURE_2D,
-                           const gfxIntSize& srcSize = gfxIntSize());
-    bool InitTexQuadProgram(GLenum target = LOCAL_GL_TEXTURE_2D);
-    void DeleteTexBlitProgram();
-
-public:
-    // If you don't have |srcFormats| for the 2nd definition,
-    // then you'll need the framebuffer_blit extensions to use
-    // the first BlitFramebufferToFramebuffer.
-    void BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
-                                      const gfxIntSize& srcSize,
-                                      const gfxIntSize& destSize);
-    void BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
-                                      const gfxIntSize& srcSize,
-                                      const gfxIntSize& destSize,
-                                      const GLFormats& srcFormats);
-    void BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
-                                  const gfxIntSize& srcSize,
-                                  const gfxIntSize& destSize,
-                                  GLenum srcTarget = LOCAL_GL_TEXTURE_2D);
-    void BlitFramebufferToTexture(GLuint srcFB, GLuint destTex,
-                                  const gfxIntSize& srcSize,
-                                  const gfxIntSize& destSize,
-                                  GLenum destTarget = LOCAL_GL_TEXTURE_2D);
-    void BlitTextureToTexture(GLuint srcTex, GLuint destTex,
-                              const gfxIntSize& srcSize,
-                              const gfxIntSize& destSize,
-                              GLenum srcTarget = LOCAL_GL_TEXTURE_2D,
-                              GLenum destTarget = LOCAL_GL_TEXTURE_2D);
-
-    /*
-     * Resize the current offscreen buffer.  Returns true on success.
-     * If it returns false, the context should be treated as unusable
-     * and should be recreated.  After the resize, the viewport is not
-     * changed; glViewport should be called as appropriate.
-     *
-     * Only valid if IsOffscreen() returns true.
-     */
-    virtual bool ResizeOffscreen(const gfxIntSize& size) {
-        return ResizeScreenBuffer(size);
-    }
-
-    /*
-     * Return size of this offscreen context.
-     *
-     * Only valid if IsOffscreen() returns true.
-     */
-    const gfxIntSize& OffscreenSize() const;
-
-    virtual bool SupportsFramebufferMultisample() const {
-        return IsExtensionSupported(EXT_framebuffer_multisample) ||
-               IsExtensionSupported(ANGLE_framebuffer_multisample);
-    }
-
-    virtual bool SupportsSplitFramebuffer() {
-        return IsExtensionSupported(EXT_framebuffer_blit) ||
-               IsExtensionSupported(ANGLE_framebuffer_blit);
-    }
-
-
-    enum SharedTextureShareType {
-        SameProcess = 0,
-        CrossProcess
-    };
-
-    enum SharedTextureBufferType {
-        TextureID
-#ifdef MOZ_WIDGET_ANDROID
-        , SurfaceTexture
-#endif
-#ifdef XP_MACOSX
-        , IOSurface
-#endif
-    };
-
-    /*
-     * Create a new shared GLContext content handle, using the passed buffer as a source.
-     * Must be released by ReleaseSharedHandle. UpdateSharedHandle will have no effect
-     * on handles created with this method, as the caller owns the source (the passed buffer)
-     * and is responsible for updating it accordingly.
-     */
-    virtual SharedTextureHandle CreateSharedHandle(SharedTextureShareType shareType,
-                                                   void* buffer,
-                                                   SharedTextureBufferType bufferType)
-    { return 0; }
-    /**
-     * Publish GLContext content to intermediate buffer attached to shared handle.
-     * Shared handle content is ready to be used after call returns, and no need extra Flush/Finish are required.
-     * GLContext must be current before this call
-     */
-    virtual void UpdateSharedHandle(SharedTextureShareType shareType,
-                                    SharedTextureHandle sharedHandle)
-    { }
-    /**
-     * - It is better to call ReleaseSharedHandle before original GLContext destroyed,
-     *     otherwise warning will be thrown on attempt to destroy Texture associated with SharedHandle, depends on backend implementation.
-     * - It does not require to be called on context where it was created,
-     *     because SharedHandle suppose to keep Context reference internally,
-     *     or don't require specific context at all, for example IPC SharedHandle.
-     * - Not recommended to call this between AttachSharedHandle and Draw Target call.
-     *      if it is really required for some special backend, then DetachSharedHandle API must be added with related implementation.
-     * - It is recommended to stop any possible access to SharedHandle (Attachments, pending GL calls) before calling Release,
-     *      otherwise some artifacts might appear or even crash if API backend implementation does not expect that.
-     * SharedHandle (currently EGLImage) does not require GLContext because it is EGL call, and can be destroyed
-     *   at any time, unless EGLImage have siblings (which are not expected with current API).
-     */
-    virtual void ReleaseSharedHandle(SharedTextureShareType shareType,
-                                     SharedTextureHandle sharedHandle)
-    { }
-
-
-    typedef struct {
-        GLenum mTarget;
-        SurfaceFormat mTextureFormat;
-        gfx3DMatrix mTextureTransform;
-    } SharedHandleDetails;
-
-    /**
-     * Returns information necessary for rendering a shared handle.
-     * These values change depending on what sharing mechanism is in use
-     */
-    virtual bool GetSharedHandleDetails(SharedTextureShareType shareType,
-                                        SharedTextureHandle sharedHandle,
-                                        SharedHandleDetails& details)
-    { return false; }
-    /**
-     * Attach Shared GL Handle to GL_TEXTURE_2D target
-     * GLContext must be current before this call
-     */
-    virtual bool AttachSharedHandle(SharedTextureShareType shareType,
-                                    SharedTextureHandle sharedHandle)
-    { return false; }
+    bool IsContextLost() const {
+        return mContextLost;
+    }
 
     /**
-     * Detach Shared GL Handle from GL_TEXTURE_2D target
+     * If this context is double-buffered, returns TRUE.
      */
-    virtual void DetachSharedHandle(SharedTextureShareType shareType,
-                                    SharedTextureHandle sharedHandle)
-    { }
-
-    void fBindFramebuffer(GLenum target, GLuint framebuffer) {
-        if (!mScreen) {
-            raw_fBindFramebuffer(target, framebuffer);
-            return;
-        }
-
-        switch (target) {
-            case LOCAL_GL_DRAW_FRAMEBUFFER_EXT:
-                mScreen->BindDrawFB(framebuffer);
-                return;
-
-            case LOCAL_GL_READ_FRAMEBUFFER_EXT:
-                mScreen->BindReadFB(framebuffer);
-                return;
-
-            case LOCAL_GL_FRAMEBUFFER:
-                 mScreen->BindFB(framebuffer);
-                 return;
-
-            default:
-                // Nothing we care about, likely an error.
-                break;
-       }
-
-        raw_fBindFramebuffer(target, framebuffer);
-    }
-
-    void BindFB(GLuint fb) {
-        fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb);
-        MOZ_ASSERT(!fb || fIsFramebuffer(fb));
-    }
-
-    void BindDrawFB(GLuint fb) {
-        fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, fb);
-    }
-
-    void BindReadFB(GLuint fb) {
-        fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, fb);
-    }
-
-    void fGetIntegerv(GLenum pname, GLint *params) {
-        switch (pname)
-        {
-            // LOCAL_GL_FRAMEBUFFER_BINDING is equal to
-            // LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT,
-            // so we don't need two cases.
-            case LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT:
-                if (mScreen) {
-                    *params = mScreen->GetDrawFB();
-                } else {
-                    raw_fGetIntegerv(pname, params);
-                }
-                break;
-
-            case LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT:
-                if (mScreen) {
-                    *params = mScreen->GetReadFB();
-                } else {
-                    raw_fGetIntegerv(pname, params);
-                }
-                break;
-
-            case LOCAL_GL_MAX_TEXTURE_SIZE:
-                MOZ_ASSERT(mMaxTextureSize>0);
-                *params = mMaxTextureSize;
-                break;
-
-            case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE:
-                MOZ_ASSERT(mMaxCubeMapTextureSize>0);
-                *params = mMaxCubeMapTextureSize;
-                break;
-
-            case LOCAL_GL_MAX_RENDERBUFFER_SIZE:
-                MOZ_ASSERT(mMaxRenderbufferSize>0);
-                *params = mMaxRenderbufferSize;
-                break;
-
-            default:
-                raw_fGetIntegerv(pname, params);
-                break;
-        }
-    }
-
-    GLuint GetDrawFB() {
-        if (mScreen)
-            return mScreen->GetDrawFB();
-
-        GLuint ret = 0;
-        GetUIntegerv(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, &ret);
-        return ret;
-    }
-
-    GLuint GetReadFB() {
-        if (mScreen)
-            return mScreen->GetReadFB();
-
-        GLenum bindEnum = SupportsSplitFramebuffer() ? LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT
-                                                     : LOCAL_GL_FRAMEBUFFER_BINDING;
-
-        GLuint ret = 0;
-        GetUIntegerv(bindEnum, &ret);
-        return ret;
-    }
-
-    GLuint GetFB() {
-        if (mScreen) {
-            // This has a very important extra assert that checks that we're
-            // not accidentally ignoring a situation where the draw and read
-            // FBs differ.
-            return mScreen->GetFB();
-        }
-
-        GLuint ret = 0;
-        GetUIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &ret);
-        return ret;
-    }
-
-private:
-    void GetShaderPrecisionFormatNonES2(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
-        switch (precisiontype) {
-            case LOCAL_GL_LOW_FLOAT:
-            case LOCAL_GL_MEDIUM_FLOAT:
-            case LOCAL_GL_HIGH_FLOAT:
-                // Assume IEEE 754 precision
-                range[0] = 127;
-                range[1] = 127;
-                *precision = 23;
-                break;
-            case LOCAL_GL_LOW_INT:
-            case LOCAL_GL_MEDIUM_INT:
-            case LOCAL_GL_HIGH_INT:
-                // Some (most) hardware only supports single-precision floating-point numbers,
-                // which can accurately represent integers up to +/-16777216
-                range[0] = 24;
-                range[1] = 24;
-                *precision = 0;
-                break;
-        }
-    }
-
-    // Do whatever setup is necessary to draw to our offscreen FBO, if it's
-    // bound.
-    void BeforeGLDrawCall() {
-    }
-
-    // Do whatever tear-down is necessary after drawing to our offscreen FBO,
-    // if it's bound.
-    void AfterGLDrawCall() {
-        if (mScreen)
-            mScreen->AfterDrawCall();
-    }
-
-    // Do whatever setup is necessary to read from our offscreen FBO, if it's
-    // bound.
-    void BeforeGLReadCall() {
-        if (mScreen)
-            mScreen->BeforeReadCall();
-    }
-
-    // Do whatever tear-down is necessary after reading from our offscreen FBO,
-    // if it's bound.
-    void AfterGLReadCall() {
-    }
-
-public:
-    // Draw call hooks:
-    void fClear(GLbitfield mask) {
-        BeforeGLDrawCall();
-        raw_fClear(mask);
-        AfterGLDrawCall();
-    }
-
-    void fDrawArrays(GLenum mode, GLint first, GLsizei count) {
-        BeforeGLDrawCall();
-        raw_fDrawArrays(mode, first, count);
-        AfterGLDrawCall();
-    }
-
-    void fDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) {
-        BeforeGLDrawCall();
-        raw_fDrawElements(mode, count, type, indices);
-        AfterGLDrawCall();
-    }
-
-    // Read call hooks:
-    void fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) {
-        y = FixYValue(y, height);
-
-        BeforeGLReadCall();
-
-        bool didReadPixels = false;
-        if (mScreen) {
-            didReadPixels = mScreen->ReadPixels(x, y, width, height, format, type, pixels);
-        }
-
-        if (!didReadPixels) {
-            raw_fReadPixels(x, y, width, height, format, type, pixels);
-        }
-
-        AfterGLReadCall();
-    }
-
-    void fCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {
-        y = FixYValue(y, height);
-
-        if (!IsTextureSizeSafeToPassToDriver(target, width, height)) {
-            // pass wrong values to cause the GL to generate GL_INVALID_VALUE.
-            // See bug 737182 and the comment in IsTextureSizeSafeToPassToDriver.
-            level = -1;
-            width = -1;
-            height = -1;
-            border = -1;
-        }
-
-        BeforeGLReadCall();
-        raw_fCopyTexImage2D(target, level, internalformat,
-                            x, y, width, height, border);
-        AfterGLReadCall();
-    }
-
-    void fCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {
-        y = FixYValue(y, height);
-
-        BeforeGLReadCall();
-        raw_fCopyTexSubImage2D(target, level, xoffset, yoffset,
-                               x, y, width, height);
-        AfterGLReadCall();
-    }
-
-    void ForceDirtyScreen();
-    void CleanDirtyScreen();
-
-    // Draw/Read
-    void fBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
-        BeforeGLDrawCall();
-        BeforeGLReadCall();
-        raw_fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
-        AfterGLReadCall();
-        AfterGLDrawCall();
-    }
-
-    virtual bool TextureImageSupportsGetBackingSurface() {
+    virtual bool IsDoubleBuffered() {
         return false;
     }
 
-    virtual GLenum GetPreferredARGB32Format() { return LOCAL_GL_RGBA; }
-
-    virtual bool RenewSurface() { return false; }
+    virtual GLContextType GetContextType() {
+        return ContextTypeUnknown;
+    }
+
+    virtual bool IsCurrent() = 0;
 
     /**
-     * Return a valid, allocated TextureImage of |aSize| with
-     * |aContentType|.  The TextureImage's texture is configured to
-     * use |aWrapMode| (usually GL_CLAMP_TO_EDGE or GL_REPEAT) and by
-     * default, GL_LINEAR filtering.  Specify
-     * |aFlags=UseNearestFilter| for GL_NEAREST filtering. Specify
-     * |aFlags=NeedsYFlip| if the image is flipped. Return
-     * nullptr if creating the TextureImage fails.
-     *
-     * The returned TextureImage may only be used with this GLContext.
-     * Attempting to use the returned TextureImage after this
-     * GLContext is destroyed will result in undefined (and likely
-     * crashy) behavior.
+     * If this context is the GLES2 API, returns TRUE.
+     * This means that various GLES2 restrictions might be in effect (modulo
+     * extensions).
      */
-    virtual already_AddRefed<TextureImage>
-    CreateTextureImage(const nsIntSize& aSize,
-                       TextureImage::ContentType aContentType,
-                       GLenum aWrapMode,
-                       TextureImage::Flags aFlags = TextureImage::NoFlags);
-
-    /**
-     * In EGL we want to use Tiled Texture Images, which we return
-     * from CreateTextureImage above.
-     * Inside TiledTextureImage we need to create actual images and to
-     * prevent infinite recursion we need to differentiate the two
-     * functions.
-     **/
-    virtual already_AddRefed<TextureImage>
-    TileGenFunc(const nsIntSize& aSize,
-                TextureImage::ContentType aContentType,
-                TextureImage::Flags aFlags = TextureImage::NoFlags)
-    {
-        return nullptr;
+    inline bool IsGLES2() const {
+        return mIsGLES2;
     }
 
     /**
-     * Read the image data contained in aTexture, and return it as an ImageSurface.
-     * If GL_RGBA is given as the format, a ImageFormatARGB32 surface is returned.
-     * Not implemented yet:
-     * If GL_RGB is given as the format, a ImageFormatRGB24 surface is returned.
-     * If GL_LUMINANCE is given as the format, a ImageFormatA8 surface is returned.
-     *
-     * THIS IS EXPENSIVE.  It is ridiculously expensive.  Only do this
-     * if you absolutely positively must, and never in any performance
-     * critical path.
-     */
-    already_AddRefed<gfxImageSurface> ReadTextureImage(GLuint aTexture,
-                                                       const gfxIntSize& aSize,
-                                                       GLenum aTextureFormat,
-                                                       bool aYInvert = false);
-
-    already_AddRefed<gfxImageSurface> GetTexImage(GLuint aTexture, bool aYInvert, SurfaceFormat aFormat);
-
-    /**
-     * Call ReadPixels into an existing gfxImageSurface.
-     * The image surface must be using image format RGBA32 or RGB24,
-     * and must have stride == width*4.
-     * Note that neither ReadPixelsIntoImageSurface nor
-     * ReadScreenIntoImageSurface call dest->Flush/MarkDirty.
-     */
-    void ReadPixelsIntoImageSurface(gfxImageSurface* dest);
-
-    // Similar to ReadPixelsIntoImageSurface, but pulls from the screen
-    // instead of the currently bound framebuffer.
-    void ReadScreenIntoImageSurface(gfxImageSurface* dest);
-
-    /**
-     * Copy a rectangle from one TextureImage into another.  The
-     * source and destination are given in integer coordinates, and
-     * will be converted to texture coordinates.
-     *
-     * For the source texture, the wrap modes DO apply -- it's valid
-     * to use REPEAT or PAD and expect appropriate behaviour if the source
-     * rectangle extends beyond its bounds.
-     *
-     * For the destination texture, the wrap modes DO NOT apply -- the
-     * destination will be clipped by the bounds of the texture.
-     *
-     * Note: calling this function will cause the following OpenGL state
-     * to be changed:
-     *
-     *   - current program
-     *   - framebuffer binding
-     *   - viewport
-     *   - blend state (will be enabled at end)
-     *   - scissor state (will be enabled at end)
-     *   - vertex attrib 0 and 1 (pointer and enable state [enable state will be disabled at exit])
-     *   - array buffer binding (will be 0)
-     *   - active texture (will be 0)
-     *   - texture 0 binding
-     */
-    void BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect,
-                          TextureImage *aDst, const nsIntRect& aDstRect);
-
-    /**
-     * Creates a RGB/RGBA texture (or uses one provided) and uploads the surface
-     * contents to it within aSrcRect.
-     *
-     * aSrcRect.x/y will be uploaded to 0/0 in the texture, and the size
-     * of the texture with be aSrcRect.width/height.
-     *
-     * If an existing texture is passed through aTexture, it is assumed it
-     * has already been initialised with glTexImage2D (or this function),
-     * and that its size is equal to or greater than aSrcRect + aDstPoint.
-     * You can alternatively set the overwrite flag to true and have a new
-     * texture memory block allocated.
-     *
-     * The aDstPoint parameter is ignored if no texture was provided
-     * or aOverwrite is true.
-     *
-     * \param aData Image data to upload.
-     * \param aDstRegion Region of texture to upload to.
-     * \param aTexture Texture to use, or 0 to have one created for you.
-     * \param aOverwrite Over an existing texture with a new one.
-     * \param aSrcPoint Offset into aSrc where the region's bound's
-     *  TopLeft() sits.
-     * \param aPixelBuffer Pass true to upload texture data with an
-     *  offset from the base data (generally for pixel buffer objects),
-     *  otherwise textures are upload with an absolute pointer to the data.
-     * \param aTextureUnit, the texture unit used temporarily to upload the
-     *  surface. This testure may be overridden, clients should not rely on
-     *  the contents of this texture after this call or even on this
-     *  texture unit being active.
-     * \return Surface format of this texture.
-     */
-    SurfaceFormat UploadImageDataToTexture(unsigned char* aData,
-                                           int32_t aStride,
-                                           gfxASurface::gfxImageFormat aFormat,
-                                           const nsIntRegion& aDstRegion,
-                                           GLuint& aTexture,
-                                           bool aOverwrite = false,
-                                           bool aPixelBuffer = false,
-                                           GLenum aTextureUnit = LOCAL_GL_TEXTURE0,
-                                           GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D);
-
-    /**
-     * Convenience wrapper around UploadImageDataToTexture for gfxASurfaces. 
+     * Returns true if either this is the GLES2 API, or had the GL_ARB_ES2_compatibility extension
+     * We would like to introduce a XXX_ES2_compatibility
      */
-    SurfaceFormat UploadSurfaceToTexture(gfxASurface *aSurface,
-                                         const nsIntRegion& aDstRegion,
-                                         GLuint& aTexture,
-                                         bool aOverwrite = false,
-                                         const nsIntPoint& aSrcPoint = nsIntPoint(0, 0),
-                                         bool aPixelBuffer = false,
-                                         GLenum aTextureUnit = LOCAL_GL_TEXTURE0,
-                                         GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D);
-
-    /**
-     * Same as above, for DataSourceSurfaces.
-     */
-    SurfaceFormat UploadSurfaceToTexture(gfx::DataSourceSurface *aSurface,
-                                         const nsIntRegion& aDstRegion,
-                                         GLuint& aTexture,
-                                         bool aOverwrite = false,
-                                         const nsIntPoint& aSrcPoint = nsIntPoint(0, 0),
-                                         bool aPixelBuffer = false,
-                                         GLenum aTextureUnit = LOCAL_GL_TEXTURE0,
-                                         GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D);
-
-    void TexImage2D(GLenum target, GLint level, GLint internalformat,
-                    GLsizei width, GLsizei height, GLsizei stride,
-                    GLint pixelsize, GLint border, GLenum format,
-                    GLenum type, const GLvoid *pixels);
-
-    void TexSubImage2D(GLenum target, GLint level,
-                       GLint xoffset, GLint yoffset,
-                       GLsizei width, GLsizei height, GLsizei stride,
-                       GLint pixelsize, GLenum format,
-                       GLenum type, const GLvoid* pixels);
-
-    /**
-     * Uses the Khronos GL_EXT_unpack_subimage extension, working around
-     * quirks in the Tegra implementation of this extension.
-     */
-    void TexSubImage2DWithUnpackSubimageGLES(GLenum target, GLint level,
-                                             GLint xoffset, GLint yoffset,
-                                             GLsizei width, GLsizei height,
-                                             GLsizei stride, GLint pixelsize,
-                                             GLenum format, GLenum type,
-                                             const GLvoid* pixels);
-
-    void TexSubImage2DWithoutUnpackSubimage(GLenum target, GLint level,
-                                            GLint xoffset, GLint yoffset,
-                                            GLsizei width, GLsizei height,
-                                            GLsizei stride, GLint pixelsize,
-                                            GLenum format, GLenum type,
-                                            const GLvoid* pixels);
-
-    /** Helper for DecomposeIntoNoRepeatTriangles
-     */
-    struct RectTriangles {
-        RectTriangles() { }
-
-        // Always pass texture coordinates upright. If you want to flip the
-        // texture coordinates emitted to the tex_coords array, set flip_y to
-        // true.
-        void addRect(GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1,
-                     GLfloat tx0, GLfloat ty0, GLfloat tx1, GLfloat ty1,
-                     bool flip_y = false);
-
-        /**
-         * these return a float pointer to the start of each array respectively.
-         * Use it for glVertexAttribPointer calls.
-         * We can return nullptr if we choose to use Vertex Buffer Objects here.
-         */
-        float* vertexPointer() {
-            return &vertexCoords[0].x;
-        }
-
-        float* texCoordPointer() {
-            return &texCoords[0].u;
-        }
-
-        unsigned int elements() {
-            return vertexCoords.Length();
-        }
-
-        typedef struct { GLfloat x,y; } vert_coord;
-        typedef struct { GLfloat u,v; } tex_coord;
-    private:
-        // default is 4 rectangles, each made up of 2 triangles (3 coord vertices each)
-        nsAutoTArray<vert_coord, 6> vertexCoords;
-        nsAutoTArray<tex_coord, 6>  texCoords;
-    };
-
-    /**
-     * Decompose drawing the possibly-wrapped aTexCoordRect rectangle
-     * of a texture of aTexSize into one or more rectangles (represented
-     * as 2 triangles) and associated tex coordinates, such that
-     * we don't have to use the REPEAT wrap mode. If aFlipY is true, the
-     * texture coordinates will be specified vertically flipped.
-     *
-     * The resulting triangle vertex coordinates will be in the space of
-     * (0.0, 0.0) to (1.0, 1.0) -- transform the coordinates appropriately
-     * if you need a different space.
-     *
-     * The resulting vertex coordinates should be drawn using GL_TRIANGLES,
-     * and rects.numRects * 3 * 6
-     */
-    static void DecomposeIntoNoRepeatTriangles(const nsIntRect& aTexCoordRect,
-                                               const nsIntSize& aTexSize,
-                                               RectTriangles& aRects,
-                                               bool aFlipY = false);
-
+    bool HasES2Compatibility() const {
+        return IsGLES2() || IsExtensionSupported(ARB_ES2_compatibility);
+    }
+
+
+protected:
+
+    bool mInitialized;
+    bool mIsOffscreen;
+    bool mIsGlobalSharedContext;
+    bool mContextLost;
+    bool mIsGLES2;
+
+    int32_t mVendor;
+    int32_t mRenderer;
+
+    inline void SetIsGLES2(bool isGLES2) {
+        MOZ_ASSERT(!mInitialized, "SetIsGLES2 can only be called before initialization!");
+        mIsGLES2 = isGLES2;
+    }
+
+
+// -----------------------------------------------------------------------------
+// Extensions management
+/**
+ * This mechanism is designed to know if an extension is supported. In the long
+ * term, we would like to only use the extension group queries XXX_* to have
+ * full compatibility with context version and profiles (especialy the core that
+ * officialy don't bring any extensions).
+ */
+public:
 
     /**
      * Known GL extensions that can be queried by
      * IsExtensionSupported.  The results of this are cached, and as
      * such it's safe to use this even in performance critical code.
      * If you add to this array, remember to add to the string names
      * in GLContext.cpp.
      */
@@ -1083,117 +269,46 @@ public:
         EXT_blend_minmax,
         ARB_draw_instanced,
         EXT_draw_instanced,
         NV_draw_instanced,
         ANGLE_instanced_array,
         Extensions_Max
     };
 
-    /**
-     * This enum introduce the possibility to check if a extension is
-     * supported, regardless it is a ARB, EXT, OES, NV, AMD, APPLE, ANGLE ...
-     * Be sure that extensions specifications are exactly same !
-     * This enum should be sorted by name.
-     */
-    enum GLExtensionPackages {
-        XXX_draw_buffers,
-        XXX_draw_instanced,
-        XXX_framebuffer_blit,
-        XXX_framebuffer_multisample,
-        XXX_framebuffer_object,
-        XXX_texture_float,
-        XXX_texture_non_power_of_two,
-        XXX_robustness,
-        XXX_vertex_array_object,
-        ExtensionPackages_Max
-    };
-
     bool IsExtensionSupported(GLExtensions aKnownExtension) const {
         return mAvailableExtensions[aKnownExtension];
     }
 
-    bool IsExtensionSupported(GLExtensionPackages aKnownExtensionPackage) const
-    {
-        switch (aKnownExtensionPackage)
-        {
-        case XXX_draw_buffers:
-            return IsExtensionSupported(ARB_draw_buffers) ||
-                   IsExtensionSupported(EXT_draw_buffers);
-
-        case XXX_draw_instanced:
-            return IsExtensionSupported(ARB_draw_instanced) ||
-                   IsExtensionSupported(EXT_draw_instanced) ||
-                   IsExtensionSupported(NV_draw_instanced) ||
-                   IsExtensionSupported(ANGLE_instanced_array);
-
-        case XXX_framebuffer_blit:
-            return IsExtensionSupported(EXT_framebuffer_blit) ||
-                   IsExtensionSupported(ANGLE_framebuffer_blit);
-
-        case XXX_framebuffer_multisample:
-            return IsExtensionSupported(EXT_framebuffer_multisample) ||
-                   IsExtensionSupported(ANGLE_framebuffer_multisample);
-
-        case XXX_framebuffer_object:
-            return IsExtensionSupported(ARB_framebuffer_object) ||
-                   IsExtensionSupported(EXT_framebuffer_object);
-
-        case XXX_texture_float:
-            return IsExtensionSupported(ARB_texture_float) ||
-                   IsExtensionSupported(OES_texture_float);
-
-        case XXX_robustness:
-            return IsExtensionSupported(ARB_robustness) ||
-                   IsExtensionSupported(EXT_robustness);
-
-        case XXX_texture_non_power_of_two:
-            return IsExtensionSupported(ARB_texture_non_power_of_two) ||
-                   IsExtensionSupported(OES_texture_npot);
-
-        case XXX_vertex_array_object:
-            return IsExtensionSupported(ARB_vertex_array_object) ||
-                   IsExtensionSupported(OES_vertex_array_object) ||
-                   IsExtensionSupported(APPLE_vertex_array_object);
-
-        default:
-            break;
-        }
-
-        MOZ_ASSERT(false, "GLContext::IsExtensionSupported : unknown <aKnownExtensionPackage>");
-        return false;
-    }
-
     void MarkExtensionUnsupported(GLExtensions aKnownExtension) {
         mAvailableExtensions[aKnownExtension] = 0;
     }
 
     void MarkExtensionSupported(GLExtensions aKnownExtension) {
         mAvailableExtensions[aKnownExtension] = 1;
     }
 
-    // Shared code for GL extensions and GLX extensions.
-    static bool ListHasExtension(const GLubyte *extensions,
-                                 const char *extension);
-
-    GLint GetMaxTextureImageSize() { return mMaxTextureImageSize; }
-    void SetFlipped(bool aFlipped) { mFlipped = aFlipped; }
+
+public:
 
     // this should just be a std::bitset, but that ended up breaking
     // MacOS X builds; see bug 584919.  We can replace this with one
     // later on.  This is handy to use in WebGL contexts as well,
     // so making it public.
     template<size_t Size>
-    struct ExtensionBitset {
-        ExtensionBitset() {
+    struct ExtensionBitset
+    {
+        ExtensionBitset()
+        {
             for (size_t i = 0; i < Size; ++i)
                 extensions[i] = false;
         }
 
-        void Load(const char* extStr, const char** extList, bool verbose = false) {
+        void Load(const char* extStr, const char** extList, bool verbose = false)
+        {
             char* exts = strdup(extStr);
 
             if (verbose)
                 printf_stderr("Extensions: %s\n", exts);
 
             char* cur = exts;
             bool done = false;
             while (!done) {
@@ -1226,395 +341,139 @@ public:
         const bool& operator[](size_t index) const {
             MOZ_ASSERT(index < Size, "out of range");
             return extensions[index];
         }
 
         bool extensions[Size];
     };
 
+
 protected:
     ExtensionBitset<Extensions_Max> mAvailableExtensions;
 
+
+// -----------------------------------------------------------------------------
+// XXX_* Extension group queries
+/*
+ * This mecahnism introduces a new way to check if an extension is supported,
+ * regardless if it is an ARB, EXT, OES, etc.
+ */
 public:
+
     /**
-     * Context reset constants.
-     * These are used to determine who is guilty when a context reset
-     * happens.
+     * This enum should be sorted by name.
      */
-    enum ContextResetARB {
-        CONTEXT_NO_ERROR = 0,
-        CONTEXT_GUILTY_CONTEXT_RESET_ARB = 0x8253,
-        CONTEXT_INNOCENT_CONTEXT_RESET_ARB = 0x8254,
-        CONTEXT_UNKNOWN_CONTEXT_RESET_ARB = 0x8255
+    enum GLExtensionPackages {
+        XXX_draw_buffers,
+        XXX_draw_instanced,
+        XXX_framebuffer_blit,
+        XXX_framebuffer_multisample,
+        XXX_framebuffer_object,
+        XXX_texture_float,
+        XXX_texture_non_power_of_two,
+        XXX_robustness,
+        XXX_vertex_array_object,
+        ExtensionPackages_Max
     };
 
+    bool IsExtensionSupported(GLExtensionPackages aKnownExtensionPackage) const
+    {
+        switch (aKnownExtensionPackage)
+        {
+            case XXX_draw_buffers:
+                return IsExtensionSupported(ARB_draw_buffers) ||
+                       IsExtensionSupported(EXT_draw_buffers);
+
+            case XXX_draw_instanced:
+                return IsExtensionSupported(ARB_draw_instanced) ||
+                       IsExtensionSupported(EXT_draw_instanced) ||
+                       IsExtensionSupported(NV_draw_instanced) ||
+                       IsExtensionSupported(ANGLE_instanced_array);
+
+            case XXX_framebuffer_blit:
+                return IsExtensionSupported(EXT_framebuffer_blit) ||
+                       IsExtensionSupported(ANGLE_framebuffer_blit);
+
+            case XXX_framebuffer_multisample:
+                return IsExtensionSupported(EXT_framebuffer_multisample) ||
+                       IsExtensionSupported(ANGLE_framebuffer_multisample);
+
+            case XXX_framebuffer_object:
+                return IsExtensionSupported(ARB_framebuffer_object) ||
+                       IsExtensionSupported(EXT_framebuffer_object);
+
+            case XXX_texture_float:
+                return IsExtensionSupported(ARB_texture_float) ||
+                       IsExtensionSupported(OES_texture_float);
+
+            case XXX_robustness:
+                return IsExtensionSupported(ARB_robustness) ||
+                       IsExtensionSupported(EXT_robustness);
+
+            case XXX_texture_non_power_of_two:
+                return IsExtensionSupported(ARB_texture_non_power_of_two) ||
+                       IsExtensionSupported(OES_texture_npot);
+
+            case XXX_vertex_array_object:
+                return IsExtensionSupported(ARB_vertex_array_object) ||
+                       IsExtensionSupported(OES_vertex_array_object) ||
+                       IsExtensionSupported(APPLE_vertex_array_object);
+
+            default:
+                break;
+        }
+
+        MOZ_ASSERT(false, "GLContext::IsExtensionSupported : unknown <aKnownExtensionPackage>");
+        return false;
+    }
+
+
+// -----------------------------------------------------------------------------
+// Deprecated extension group queries (use XXX_* instead)
+public:
+
+    bool SupportsFramebufferMultisample() const {
+        return IsExtensionSupported(XXX_framebuffer_multisample);
+    }
+
+    bool HasExt_FramebufferBlit() const {
+        return IsExtensionSupported(XXX_framebuffer_blit);
+    }
+
+    bool SupportsSplitFramebuffer() const {
+        return IsExtensionSupported(XXX_framebuffer_blit);
+    }
+
+
+// -----------------------------------------------------------------------------
+// Robustness handling
+public:
+
     bool HasRobustness() {
         return mHasRobustness;
     }
 
-    bool HasExt_FramebufferBlit() {
-        return IsExtensionSupported(EXT_framebuffer_blit) ||
-               IsExtensionSupported(ANGLE_framebuffer_blit);
-    }
-
-protected:
-    bool mInitialized;
-    bool mIsOffscreen;
-    bool mIsGLES2;
-    bool mIsGlobalSharedContext;
+    /**
+     * The derived class is expected to provide information on whether or not it
+     * supports robustness.
+     */
+    virtual bool SupportsRobustness() = 0;
+
+
+private:
     bool mHasRobustness;
-    bool mContextLost;
-
-    int32_t mVendor;
-    int32_t mRenderer;
-
-public:
-    std::map<GLuint, SharedSurface_GL*> mFBOMapping;
-
-    enum {
-        DebugEnabled = 1 << 0,
-        DebugTrace = 1 << 1,
-        DebugAbortOnError = 1 << 2
-    };
-
-    static uint32_t sDebugMode;
-
-    static uint32_t DebugMode() {
-#ifdef DEBUG
-        return sDebugMode;
-#else
-        return 0;
-#endif
-    }
-
-protected:
-    nsRefPtr<GLContext> mSharedContext;
-
-    // The thread on which this context was created.
-    nsCOMPtr<nsIThread> mOwningThread;
-
-    GLContextSymbols mSymbols;
-
-#ifdef DEBUG
-    // GLDebugMode will check that we don't send call
-    // to a GLContext that isn't current on the current
-    // thread.
-    // Store the current context when binding to thread local
-    // storage to support DebugMode on an arbitrary thread.
-    static unsigned sCurrentGLContextTLS;
-#endif
-    bool mFlipped;
-
-    // lazy-initialized things
-    GLuint mBlitProgram, mBlitFramebuffer;
-    void UseBlitProgram();
-    void SetBlitFramebufferForDestTexture(GLuint aTexture);
-
-public:
-    // Assumes shares are created by all sharing with the same global context.
-    bool SharesWith(const GLContext* other) const {
-        MOZ_ASSERT(!this->mSharedContext || !this->mSharedContext->mSharedContext);
-        MOZ_ASSERT(!other->mSharedContext || !other->mSharedContext->mSharedContext);
-        MOZ_ASSERT(!this->mSharedContext ||
-                   !other->mSharedContext ||
-                   this->mSharedContext == other->mSharedContext);
-
-        const GLContext* thisShared = this->mSharedContext ? this->mSharedContext
-                                                           : this;
-        const GLContext* otherShared = other->mSharedContext ? other->mSharedContext
-                                                             : other;
-
-        return thisShared == otherShared;
-    }
-
-    bool InitOffscreen(const gfxIntSize& size, const SurfaceCaps& caps) {
-        if (!CreateScreenBuffer(size, caps))
-            return false;
-
-        MakeCurrent();
-        fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
-        fScissor(0, 0, size.width, size.height);
-        fViewport(0, 0, size.width, size.height);
-
-        mCaps = mScreen->Caps();
-        if (mCaps.any)
-            DetermineCaps();
-
-        UpdateGLFormats(mCaps);
-        UpdatePixelFormat();
-
-        return true;
-    }
-
-protected:
-    // Note that it does -not- clear the resized buffers.
-    bool CreateScreenBuffer(const gfxIntSize& size, const SurfaceCaps& caps) {
-        if (!IsOffscreenSizeAllowed(size))
-            return false;
-
-        SurfaceCaps tryCaps = caps;
-        if (tryCaps.antialias) {
-            // AA path
-            if (CreateScreenBufferImpl(size, tryCaps))
-                return true;
-
-            NS_WARNING("CreateScreenBuffer failed to initialize an AA context! Falling back to no AA...");
-            tryCaps.antialias = false;
-        }
-        MOZ_ASSERT(!tryCaps.antialias);
-
-        if (CreateScreenBufferImpl(size, tryCaps))
-            return true;
-
-        NS_WARNING("CreateScreenBuffer failed to initialize non-AA context!");
-        return false;
-    }
-
-    bool CreateScreenBufferImpl(const gfxIntSize& size,
-                                const SurfaceCaps& caps);
-
-public:
-    bool ResizeScreenBuffer(const gfxIntSize& size);
-
-protected:
-    SurfaceCaps mCaps;
-    nsAutoPtr<GLFormats> mGLFormats;
-    nsAutoPtr<PixelBufferFormat> mPixelFormat;
-
+
+
+// -----------------------------------------------------------------------------
+// Error handling
 public:
-    void DetermineCaps();
-    const SurfaceCaps& Caps() const {
-        return mCaps;
-    }
-
-    // Only varies based on bpp16 and alpha.
-    GLFormats ChooseGLFormats(const SurfaceCaps& caps) const;
-    void UpdateGLFormats(const SurfaceCaps& caps) {
-        mGLFormats = new GLFormats(ChooseGLFormats(caps));
-    }
-
-    const GLFormats& GetGLFormats() const {
-        MOZ_ASSERT(mGLFormats);
-        return *mGLFormats;
-    }
-
-    PixelBufferFormat QueryPixelFormat();
-    void UpdatePixelFormat();
-
-    const PixelBufferFormat& GetPixelFormat() const {
-        MOZ_ASSERT(mPixelFormat);
-        return *mPixelFormat;
-    }
-
-
-    GLuint CreateTextureForOffscreen(const GLFormats& formats,
-                                     const gfxIntSize& size);
-    GLuint CreateTexture(GLenum internalFormat,
-                         GLenum format, GLenum type,
-                         const gfxIntSize& size);
-    GLuint CreateRenderbuffer(GLenum format,
-                              GLsizei samples,
-                              const gfxIntSize& size);
-    bool IsFramebufferComplete(GLuint fb, GLenum* status = nullptr);
-
-    // Pass null to an RB arg to disable its creation.
-    void CreateRenderbuffersForOffscreen(const GLFormats& formats,
-                                         const gfxIntSize& size,
-                                         bool multisample,
-                                         GLuint* colorMSRB,
-                                         GLuint* depthRB,
-                                         GLuint* stencilRB);
-
-    // Does not check completeness.
-    void AttachBuffersToFB(GLuint colorTex, GLuint colorRB,
-                           GLuint depthRB, GLuint stencilRB,
-                           GLuint fb, GLenum target = LOCAL_GL_TEXTURE_2D);
-
-    // Passing null is fine if the value you'd get is 0.
-    bool AssembleOffscreenFBs(const GLuint colorMSRB,
-                              const GLuint depthRB,
-                              const GLuint stencilRB,
-                              const GLuint texture,
-                              GLuint* drawFB,
-                              GLuint* readFB);
-
-protected:
-    friend class GLScreenBuffer;
-    GLScreenBuffer* mScreen;
-
-    void DestroyScreenBuffer();
-
-    SharedSurface* mLockedSurface;
-
-public:
-    void LockSurface(SharedSurface* surf) {
-        MOZ_ASSERT(!mLockedSurface);
-        mLockedSurface = surf;
-    }
-
-    void UnlockSurface(SharedSurface* surf) {
-        MOZ_ASSERT(mLockedSurface == surf);
-        mLockedSurface = nullptr;
-    }
-
-    SharedSurface* GetLockedSurface() const {
-        return mLockedSurface;
-    }
-
-    bool IsOffscreen() const {
-        return mScreen;
-    }
-
-    GLScreenBuffer* Screen() const {
-        return mScreen;
-    }
-
-    bool PublishFrame();
-    SharedSurface* RequestFrame();
-
-    /* Clear to transparent black, with 0 depth and stencil,
-     * while preserving current ClearColor etc. values.
-     * Useful for resizing offscreen buffers.
-     */
-    void ClearSafely();
-
-    bool WorkAroundDriverBugs() const { return mWorkAroundDriverBugs; }
-
-protected:
-    nsRefPtr<TextureGarbageBin> mTexGarbageBin;
-
-public:
-    TextureGarbageBin* TexGarbageBin() {
-        MOZ_ASSERT(mTexGarbageBin);
-        return mTexGarbageBin;
-    }
-
-    void EmptyTexGarbageBin();
-
-protected:
-    nsDataHashtable<nsPtrHashKey<void>, void*> mUserData;
-
-    void SetIsGLES2(bool aIsGLES2) {
-        NS_ASSERTION(!mInitialized, "SetIsGLES2 can only be called before initialization!");
-        mIsGLES2 = aIsGLES2;
-    }
-
-    bool InitWithPrefix(const char *prefix, bool trygl);
-
-    void InitExtensions();
-
-    bool IsOffscreenSizeAllowed(const gfxIntSize& aSize) const {
-        int32_t biggerDimension = std::max(aSize.width, aSize.height);
-        int32_t maxAllowed = std::min(mMaxRenderbufferSize, mMaxTextureSize);
-        return biggerDimension <= maxAllowed;
-    }
-
-    nsTArray<nsIntRect> mViewportStack;
-    nsTArray<nsIntRect> mScissorStack;
-
-    GLint mMaxTextureSize;
-    GLint mMaxCubeMapTextureSize;
-    GLint mMaxTextureImageSize;
-    GLint mMaxRenderbufferSize;
-    GLsizei mMaxSamples;
-    bool mNeedsTextureSizeChecks;
-    bool mWorkAroundDriverBugs;
-
-    bool IsTextureSizeSafeToPassToDriver(GLenum target, GLsizei width, GLsizei height) const {
-        if (mNeedsTextureSizeChecks) {
-            // some drivers incorrectly handle some large texture sizes that are below the
-            // max texture size that they report. So we check ourselves against our own values
-            // (mMax[CubeMap]TextureSize).
-            // see bug 737182 for Mac Intel 2D textures
-            // see bug 684882 for Mac Intel cube map textures
-            // see bug 814716 for Mesa Nouveau
-            GLsizei maxSize = target == LOCAL_GL_TEXTURE_CUBE_MAP ||
-                                (target >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
-                                target <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
-                              ? mMaxCubeMapTextureSize
-                              : mMaxTextureSize;
-            return width <= maxSize && height <= maxSize;
-        }
-        return true;
-    }
-
-public:
-
-    /** \returns the first GL error, and guarantees that all GL error flags are cleared,
-      * i.e. that a subsequent GetError call will return NO_ERROR
-      */
-    GLenum GetAndClearError() {
-        // the first error is what we want to return
-        GLenum error = fGetError();
-
-        if (error) {
-            // clear all pending errors
-            while(fGetError()) {}
-        }
-
-        return error;
-    }
-
-#ifdef DEBUG
-
-#ifndef MOZ_FUNCTION_NAME
-# ifdef __GNUC__
-#  define MOZ_FUNCTION_NAME __PRETTY_FUNCTION__
-# elif defined(_MSC_VER)
-#  define MOZ_FUNCTION_NAME __FUNCTION__
-# else
-#  define MOZ_FUNCTION_NAME __func__  // defined in C99, supported in various C++ compilers. Just raw function name.
-# endif
-#endif
-
-protected:
-    GLenum mGLError;
-
-public:
-
-    void BeforeGLCall(const char* glFunction) {
-        MOZ_ASSERT(IsCurrent());
-        if (DebugMode()) {
-            GLContext *currentGLContext = nullptr;
-
-            currentGLContext = (GLContext*)PR_GetThreadPrivate(sCurrentGLContextTLS);
-
-            if (DebugMode() & DebugTrace)
-                printf_stderr("[gl:%p] > %s\n", this, glFunction);
-            if (this != currentGLContext) {
-                printf_stderr("Fatal: %s called on non-current context %p. "
-                              "The current context for this thread is %p.\n",
-                               glFunction, this, currentGLContext);
-                NS_ABORT();
-            }
-        }
-    }
-
-    void AfterGLCall(const char* glFunction) {
-        if (DebugMode()) {
-            // calling fFinish() immediately after every GL call makes sure that if this GL command crashes,
-            // the stack trace will actually point to it. Otherwise, OpenGL being an asynchronous API, stack traces
-            // tend to be meaningless
-            mSymbols.fFinish();
-            mGLError = mSymbols.fGetError();
-            if (DebugMode() & DebugTrace)
-                printf_stderr("[gl:%p] < %s [0x%04x]\n", this, glFunction, mGLError);
-            if (mGLError != LOCAL_GL_NO_ERROR) {
-                printf_stderr("GL ERROR: %s generated GL error %s(0x%04x)\n",
-                              glFunction,
-                              GLErrorToString(mGLError),
-                              mGLError);
-                if (DebugMode() & DebugAbortOnError)
-                    NS_ABORT();
-            }
-        }
-    }
-
-    const char* GLErrorToString(GLenum aError)
+
+    // TODO: this function should be a static
+    const char* GLErrorToString(GLenum aError) const
     {
         switch (aError) {
             case LOCAL_GL_INVALID_ENUM:
                 return "GL_INVALID_ENUM";
             case LOCAL_GL_INVALID_VALUE:
                 return "GL_INVALID_VALUE";
             case LOCAL_GL_INVALID_OPERATION:
                 return "GL_INVALID_OPERATION";
@@ -1626,155 +485,186 @@ public:
                 return "GL_OUT_OF_MEMORY";
             case LOCAL_GL_TABLE_TOO_LARGE:
                 return "GL_TABLE_TOO_LARGE";
             case LOCAL_GL_INVALID_FRAMEBUFFER_OPERATION:
                 return "GL_INVALID_FRAMEBUFFER_OPERATION";
             default:
                 return "";
         }
-     }
-
-#define BEFORE_GL_CALL do {                     \
-    BeforeGLCall(MOZ_FUNCTION_NAME);            \
-} while (0)
-
-#define AFTER_GL_CALL do {                      \
-    AfterGLCall(MOZ_FUNCTION_NAME);             \
-} while (0)
-
-#else
-
-#define BEFORE_GL_CALL do { } while (0)
-#define AFTER_GL_CALL do { } while (0)
-
-#endif
-
-#define ASSERT_SYMBOL_PRESENT(func) \
-    do {\
-        MOZ_ASSERT(strstr(MOZ_FUNCTION_NAME, #func) != nullptr, "Mismatched symbol check.");\
-        if (MOZ_UNLIKELY(!mSymbols.func)) {\
-            printf_stderr("RUNTIME ASSERT: Uninitialized GL function: %s\n", #func);\
-            MOZ_CRASH();\
-        }\
-    } while (0)
+    }
+
+
+    /** \returns the first GL error, and guarantees that all GL error flags are cleared,
+     * i.e. that a subsequent GetError call will return NO_ERROR
+     */
+    GLenum GetAndClearError()
+    {
+        // the first error is what we want to return
+        GLenum error = fGetError();
+
+        if (error) {
+            // clear all pending errors
+            while(fGetError()) {}
+        }
+
+        return error;
+    }
+
 
     /*** In GL debug mode, we completely override glGetError ***/
 
-    GLenum fGetError() {
+    GLenum fGetError()
+    {
 #ifdef DEBUG
         // debug mode ends up eating the error in AFTER_GL_CALL
         if (DebugMode()) {
             GLenum err = mGLError;
             mGLError = LOCAL_GL_NO_ERROR;
             return err;
         }
-#endif
+#endif // DEBUG
 
         return mSymbols.fGetError();
     }
 
 
-    /*** Scissor functions ***/
-
-protected:
-    GLint FixYValue(GLint y, GLint height)
+#ifdef DEBUG
+private:
+
+    GLenum mGLError;
+#endif // DEBUG
+
+
+// -----------------------------------------------------------------------------
+// MOZ_GL_DEBUG implementation
+private:
+
+#ifdef DEBUG
+
+#ifndef MOZ_FUNCTION_NAME
+# ifdef __GNUC__
+#  define MOZ_FUNCTION_NAME __PRETTY_FUNCTION__
+# elif defined(_MSC_VER)
+#  define MOZ_FUNCTION_NAME __FUNCTION__
+# else
+#  define MOZ_FUNCTION_NAME __func__  // defined in C99, supported in various C++ compilers. Just raw function name.
+# endif
+#endif
+
+    void BeforeGLCall(const char* glFunction)
     {
-        MOZ_ASSERT( !(mIsOffscreen && mFlipped) );
-        return mFlipped ? ViewportRect().height - (height + y) : y;
-    }
-
-public:
-    void fScissor(GLint x, GLint y, GLsizei width, GLsizei height) {
-        ScissorRect().SetRect(x, y, width, height);
-
-        // GL's coordinate system is flipped compared to the one we use in
-        // OGL Layers (in the Y axis), so we may need to flip our rectangle.
-        y = FixYValue(y, height);
-        raw_fScissor(x, y, width, height);
-    }
-
-    nsIntRect& ScissorRect() {
-        return mScissorStack[mScissorStack.Length()-1];
-    }
-
-    void PushScissorRect() {
-        nsIntRect copy(ScissorRect());
-        mScissorStack.AppendElement(copy);
-    }
-
-    void PushScissorRect(const nsIntRect& aRect) {
-        mScissorStack.AppendElement(aRect);
-        fScissor(aRect.x, aRect.y, aRect.width, aRect.height);
-    }
-
-    void PopScissorRect() {
-        if (mScissorStack.Length() < 2) {
-            NS_WARNING("PopScissorRect with Length < 2!");
-            return;
+        MOZ_ASSERT(IsCurrent());
+        if (DebugMode()) {
+            GLContext *currentGLContext = nullptr;
+
+            currentGLContext = (GLContext*)PR_GetThreadPrivate(sCurrentGLContextTLS);
+
+            if (DebugMode() & DebugTrace)
+                printf_stderr("[gl:%p] > %s\n", this, glFunction);
+            if (this != currentGLContext) {
+                printf_stderr("Fatal: %s called on non-current context %p. "
+                              "The current context for this thread is %p.\n",
+                              glFunction, this, currentGLContext);
+                NS_ABORT();
+            }
         }
-
-        nsIntRect thisRect = ScissorRect();
-        mScissorStack.TruncateLength(mScissorStack.Length() - 1);
-        if (!thisRect.IsEqualInterior(ScissorRect())) {
-            fScissor(ScissorRect().x, ScissorRect().y,
-                     ScissorRect().width, ScissorRect().height);
+    }
+
+    void AfterGLCall(const char* glFunction)
+    {
+        if (DebugMode()) {
+            // calling fFinish() immediately after every GL call makes sure that if this GL command crashes,
+            // the stack trace will actually point to it. Otherwise, OpenGL being an asynchronous API, stack traces
+            // tend to be meaningless
+            mSymbols.fFinish();
+            mGLError = mSymbols.fGetError();
+            if (DebugMode() & DebugTrace)
+                printf_stderr("[gl:%p] < %s [0x%04x]\n", this, glFunction, mGLError);
+            if (mGLError != LOCAL_GL_NO_ERROR) {
+                printf_stderr("GL ERROR: %s generated GL error %s(0x%04x)\n",
+                              glFunction,
+                              GLErrorToString(mGLError),
+                              mGLError);
+                if (DebugMode() & DebugAbortOnError)
+                    NS_ABORT();
+            }
         }
     }
 
-    /*** Viewport functions ***/
-
-private:
-    // only does the glViewport call, no ViewportRect business
-    void raw_fViewport(GLint x, GLint y, GLsizei width, GLsizei height) {
-        BEFORE_GL_CALL;
-        // XXX: Flipping should really happen using the destination height, but
-        // we use viewport instead and assume viewport size matches the
-        // destination. If we ever try use partial viewports for layers we need
-        // to fix this, and remove the assertion.
-        NS_ASSERTION(!mFlipped || (x == 0 && y == 0), "TODO: Need to flip the viewport rect");
-        mSymbols.fViewport(x, y, width, height);
-        AFTER_GL_CALL;
-    }
-
+    GLContext *TrackingContext()
+    {
+        GLContext *tip = this;
+        while (tip->mSharedContext)
+            tip = tip->mSharedContext;
+        return tip;
+    }
+
+#define BEFORE_GL_CALL                              \
+            do {                                    \
+                BeforeGLCall(MOZ_FUNCTION_NAME);    \
+            } while (0)
+
+#define AFTER_GL_CALL                               \
+            do {                                    \
+                AfterGLCall(MOZ_FUNCTION_NAME);     \
+            } while (0)
+
+#define TRACKING_CONTEXT(a)                         \
+            do {                                    \
+                TrackingContext()->a;               \
+            } while (0)
+
+#else // ifdef DEBUG
+
+#define BEFORE_GL_CALL do { } while (0)
+#define AFTER_GL_CALL do { } while (0)
+#define TRACKING_CONTEXT(a) do {} while (0)
+
+#endif // ifdef DEBUG
+
+#define ASSERT_SYMBOL_PRESENT(func) \
+            do {\
+                MOZ_ASSERT(strstr(MOZ_FUNCTION_NAME, #func) != nullptr, "Mismatched symbol check.");\
+                if (MOZ_UNLIKELY(!mSymbols.func)) {\
+                    printf_stderr("RUNTIME ASSERT: Uninitialized GL function: %s\n", #func);\
+                    MOZ_CRASH();\
+                }\
+            } while (0)
+
+    // Do whatever setup is necessary to draw to our offscreen FBO, if it's
+    // bound.
+    void BeforeGLDrawCall() {
+    }
+
+    // Do whatever tear-down is necessary after drawing to our offscreen FBO,
+    // if it's bound.
+    void AfterGLDrawCall()
+    {
+        if (mScreen)
+            mScreen->AfterDrawCall();
+    }
+
+    // Do whatever setup is necessary to read from our offscreen FBO, if it's
+    // bound.
+    void BeforeGLReadCall()
+    {
+        if (mScreen)
+            mScreen->BeforeReadCall();
+    }
+
+    // Do whatever tear-down is necessary after reading from our offscreen FBO,
+    // if it's bound.
+    void AfterGLReadCall() {
+    }
+
+
+// -----------------------------------------------------------------------------
+// GL official entry points
 public:
-    void fViewport(GLint x, GLint y, GLsizei width, GLsizei height) {
-        ViewportRect().SetRect(x, y, width, height);
-        raw_fViewport(x, y, width, height);
-    }
-
-    nsIntRect& ViewportRect() {
-        return mViewportStack[mViewportStack.Length()-1];
-    }
-
-    void PushViewportRect() {
-        nsIntRect copy(ViewportRect());
-        mViewportStack.AppendElement(copy);
-    }
-
-    void PushViewportRect(const nsIntRect& aRect) {
-        mViewportStack.AppendElement(aRect);
-        raw_fViewport(aRect.x, aRect.y, aRect.width, aRect.height);
-    }
-
-    void PopViewportRect() {
-        if (mViewportStack.Length() < 2) {
-            NS_WARNING("PopViewportRect with Length < 2!");
-            return;
-        }
-
-        nsIntRect thisRect = ViewportRect();
-        mViewportStack.TruncateLength(mViewportStack.Length() - 1);
-        if (!thisRect.IsEqualInterior(ViewportRect())) {
-            raw_fViewport(ViewportRect().x, ViewportRect().y,
-                          ViewportRect().width, ViewportRect().height);
-        }
-    }
-
-    /*** other GL functions ***/
 
     void fActiveTexture(GLenum texture) {
         BEFORE_GL_CALL;
         mSymbols.fActiveTexture(texture);
         AFTER_GL_CALL;
     }
 
     void fAttachShader(GLuint program, GLuint shader) {
@@ -1796,16 +686,43 @@ public:
     }
 
     void fBindBuffer(GLenum target, GLuint buffer) {
         BEFORE_GL_CALL;
         mSymbols.fBindBuffer(target, buffer);
         AFTER_GL_CALL;
     }
 
+    void fBindFramebuffer(GLenum target, GLuint framebuffer) {
+        if (!mScreen) {
+            raw_fBindFramebuffer(target, framebuffer);
+            return;
+        }
+
+        switch (target) {
+            case LOCAL_GL_DRAW_FRAMEBUFFER_EXT:
+                mScreen->BindDrawFB(framebuffer);
+                return;
+
+            case LOCAL_GL_READ_FRAMEBUFFER_EXT:
+                mScreen->BindReadFB(framebuffer);
+                return;
+
+            case LOCAL_GL_FRAMEBUFFER:
+                mScreen->BindFB(framebuffer);
+                return;
+
+            default:
+                // Nothing we care about, likely an error.
+                break;
+        }
+
+        raw_fBindFramebuffer(target, framebuffer);
+    }
+
     void fBindTexture(GLenum target, GLuint texture) {
         BEFORE_GL_CALL;
         mSymbols.fBindTexture(target, texture);
         AFTER_GL_CALL;
     }
 
     void fBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
         BEFORE_GL_CALL;
@@ -1867,16 +784,22 @@ public:
 private:
     void raw_fClear(GLbitfield mask) {
         BEFORE_GL_CALL;
         mSymbols.fClear(mask);
         AFTER_GL_CALL;
     }
 
 public:
+    void fClear(GLbitfield mask) {
+        BeforeGLDrawCall();
+        raw_fClear(mask);
+        AfterGLDrawCall();
+    }
+
     void fClearColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a) {
         BEFORE_GL_CALL;
         mSymbols.fClearColor(r, g, b, a);
         AFTER_GL_CALL;
     }
 
     void fClearStencil(GLint s) {
         BEFORE_GL_CALL;
@@ -1897,16 +820,43 @@ public:
     }
 
     void fCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *pixels) {
         BEFORE_GL_CALL;
         mSymbols.fCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, pixels);
         AFTER_GL_CALL;
     }
 
+    void fCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {
+        y = FixYValue(y, height);
+
+        if (!IsTextureSizeSafeToPassToDriver(target, width, height)) {
+            // pass wrong values to cause the GL to generate GL_INVALID_VALUE.
+            // See bug 737182 and the comment in IsTextureSizeSafeToPassToDriver.
+            level = -1;
+            width = -1;
+            height = -1;
+            border = -1;
+        }
+
+        BeforeGLReadCall();
+        raw_fCopyTexImage2D(target, level, internalformat,
+                            x, y, width, height, border);
+        AfterGLReadCall();
+    }
+
+    void fCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {
+        y = FixYValue(y, height);
+
+        BeforeGLReadCall();
+        raw_fCopyTexSubImage2D(target, level, xoffset, yoffset,
+                               x, y, width, height);
+        AfterGLReadCall();
+    }
+
     void fCullFace(GLenum mode) {
         BEFORE_GL_CALL;
         mSymbols.fCullFace(mode);
         AFTER_GL_CALL;
     }
 
     void fDetachShader(GLuint program, GLuint shader) {
         BEFORE_GL_CALL;
@@ -1939,36 +889,42 @@ public:
     }
 
     void fDrawBuffer(GLenum mode) {
         BEFORE_GL_CALL;
         mSymbols.fDrawBuffer(mode);
         AFTER_GL_CALL;
     }
 
-    void fDrawBuffers(GLsizei n, const GLenum* bufs) {
-        BEFORE_GL_CALL;
-        mSymbols.fDrawBuffers(n, bufs);
-        AFTER_GL_CALL;
-    }
-
 private:
     void raw_fDrawArrays(GLenum mode, GLint first, GLsizei count) {
         BEFORE_GL_CALL;
         mSymbols.fDrawArrays(mode, first, count);
         AFTER_GL_CALL;
     }
 
     void raw_fDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) {
         BEFORE_GL_CALL;
         mSymbols.fDrawElements(mode, count, type, indices);
         AFTER_GL_CALL;
     }
 
 public:
+    void fDrawArrays(GLenum mode, GLint first, GLsizei count) {
+        BeforeGLDrawCall();
+        raw_fDrawArrays(mode, first, count);
+        AfterGLDrawCall();
+    }
+
+    void fDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) {
+        BeforeGLDrawCall();
+        raw_fDrawElements(mode, count, type, indices);
+        AfterGLDrawCall();
+    }
+
     void fEnable(GLenum capability) {
         BEFORE_GL_CALL;
         mSymbols.fEnable(capability);
         AFTER_GL_CALL;
     }
 
     void fEnableVertexAttribArray(GLuint index) {
         BEFORE_GL_CALL;
@@ -2046,16 +1002,60 @@ public:
 private:
     void raw_fGetIntegerv(GLenum pname, GLint *params) {
         BEFORE_GL_CALL;
         mSymbols.fGetIntegerv(pname, params);
         AFTER_GL_CALL;
     }
 
 public:
+
+    void fGetIntegerv(GLenum pname, GLint *params) {
+        switch (pname)
+        {
+            // LOCAL_GL_FRAMEBUFFER_BINDING is equal to
+            // LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT,
+            // so we don't need two cases.
+            case LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT:
+                if (mScreen) {
+                    *params = mScreen->GetDrawFB();
+                } else {
+                    raw_fGetIntegerv(pname, params);
+                }
+                break;
+
+            case LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT:
+                if (mScreen) {
+                    *params = mScreen->GetReadFB();
+                } else {
+                    raw_fGetIntegerv(pname, params);
+                }
+                break;
+
+            case LOCAL_GL_MAX_TEXTURE_SIZE:
+                MOZ_ASSERT(mMaxTextureSize>0);
+                *params = mMaxTextureSize;
+                break;
+
+            case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE:
+                MOZ_ASSERT(mMaxCubeMapTextureSize>0);
+                *params = mMaxCubeMapTextureSize;
+                break;
+
+            case LOCAL_GL_MAX_RENDERBUFFER_SIZE:
+                MOZ_ASSERT(mMaxRenderbufferSize>0);
+                *params = mMaxRenderbufferSize;
+                break;
+
+            default:
+                raw_fGetIntegerv(pname, params);
+                break;
+        }
+    }
+
     void GetUIntegerv(GLenum pname, GLuint *params) {
         fGetIntegerv(pname, reinterpret_cast<GLint*>(params));
     }
 
     void fGetFloatv(GLenum pname, GLfloat *params) {
         BEFORE_GL_CALL;
         mSymbols.fGetFloatv(pname, params);
         AFTER_GL_CALL;
@@ -2260,16 +1260,34 @@ public:
 private:
     void raw_fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) {
         BEFORE_GL_CALL;
         mSymbols.fReadPixels(x, FixYValue(y, height), width, height, format, type, pixels);
         AFTER_GL_CALL;
     }
 
 public:
+    void fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) {
+        y = FixYValue(y, height);
+
+        BeforeGLReadCall();
+
+        bool didReadPixels = false;
+        if (mScreen) {
+            didReadPixels = mScreen->ReadPixels(x, y, width, height, format, type, pixels);
+        }
+
+        if (!didReadPixels) {
+            raw_fReadPixels(x, y, width, height, format, type, pixels);
+        }
+
+        AfterGLReadCall();
+    }
+
+public:
     void fSampleCoverage(GLclampf value, realGLboolean invert) {
         BEFORE_GL_CALL;
         mSymbols.fSampleCoverage(value, invert);
         AFTER_GL_CALL;
     }
 
 private:
     void raw_fScissor(GLint x, GLint y, GLsizei width, GLsizei height) {
@@ -2550,27 +1568,27 @@ public:
     void fGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog) {
         BEFORE_GL_CALL;
         mSymbols.fGetShaderInfoLog(shader, bufSize, length, infoLog);
         AFTER_GL_CALL;
     }
 
 private:
     void raw_fGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
-        MOZ_ASSERT(mIsGLES2);
+        MOZ_ASSERT(IsGLES2());
 
         BEFORE_GL_CALL;
         ASSERT_SYMBOL_PRESENT(fGetShaderPrecisionFormat);
         mSymbols.fGetShaderPrecisionFormat(shadertype, precisiontype, range, precision);
         AFTER_GL_CALL;
     }
 
 public:
     void fGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
-       if (mIsGLES2) {
+        if (IsGLES2()) {
             raw_fGetShaderPrecisionFormat(shadertype, precisiontype, range, precision);
         } else {
             // Fall back to automatic values because almost all desktop hardware supports the OpenGL standard precisions.
             GetShaderPrecisionFormatNonES2(shadertype, precisiontype, range, precision);
         }
     }
 
     void fGetShaderSource(GLint obj, GLsizei maxLength, GLsizei* length, GLchar* source) {
@@ -2632,93 +1650,78 @@ public:
 
     realGLboolean fIsFramebuffer (GLuint framebuffer) {
         BEFORE_GL_CALL;
         realGLboolean retval = mSymbols.fIsFramebuffer(framebuffer);
         AFTER_GL_CALL;
         return retval;
     }
 
-private:
-    void raw_fBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
-        BEFORE_GL_CALL;
-        ASSERT_SYMBOL_PRESENT(fBlitFramebuffer);
-        mSymbols.fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
-        AFTER_GL_CALL;
-    }
-
 public:
     realGLboolean fIsRenderbuffer (GLuint renderbuffer) {
         BEFORE_GL_CALL;
         realGLboolean retval = mSymbols.fIsRenderbuffer(renderbuffer);
         AFTER_GL_CALL;
         return retval;
     }
 
     void fRenderbufferStorage(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height) {
         BEFORE_GL_CALL;
         mSymbols.fRenderbufferStorage(target, internalFormat, width, height);
         AFTER_GL_CALL;
     }
 
-    void fRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height) {
-        BEFORE_GL_CALL;
-        ASSERT_SYMBOL_PRESENT(fRenderbufferStorageMultisample);
-        mSymbols.fRenderbufferStorageMultisample(target, samples, internalFormat, width, height);
-        AFTER_GL_CALL;
-    }
-
 private:
     void raw_fDepthRange(GLclampf a, GLclampf b) {
-        MOZ_ASSERT(!mIsGLES2);
+        MOZ_ASSERT(!IsGLES2());
 
         BEFORE_GL_CALL;
         ASSERT_SYMBOL_PRESENT(fDepthRange);
         mSymbols.fDepthRange(a, b);
         AFTER_GL_CALL;
     }
 
     void raw_fDepthRangef(GLclampf a, GLclampf b) {
-        MOZ_ASSERT(mIsGLES2);
+        MOZ_ASSERT(IsGLES2());
 
         BEFORE_GL_CALL;
         ASSERT_SYMBOL_PRESENT(fDepthRangef);
         mSymbols.fDepthRangef(a, b);
         AFTER_GL_CALL;
     }
 
     void raw_fClearDepth(GLclampf v) {
-        MOZ_ASSERT(!mIsGLES2);
+        MOZ_ASSERT(!IsGLES2());
 
         BEFORE_GL_CALL;
         ASSERT_SYMBOL_PRESENT(fClearDepth);
         mSymbols.fClearDepth(v);
         AFTER_GL_CALL;
     }
 
     void raw_fClearDepthf(GLclampf v) {
-        MOZ_ASSERT(mIsGLES2);
+        MOZ_ASSERT(IsGLES2());
 
         BEFORE_GL_CALL;
         ASSERT_SYMBOL_PRESENT(fClearDepthf);
         mSymbols.fClearDepthf(v);
         AFTER_GL_CALL;
     }
 
 public:
     void fDepthRange(GLclampf a, GLclampf b) {
-        if (mIsGLES2) {
+        if (IsGLES2()) {
             raw_fDepthRangef(a, b);
         } else {
             raw_fDepthRange(a, b);
         }
     }
 
     void fClearDepth(GLclampf v) {
-        if (mIsGLES2) {
+        if (IsGLES2()) {
             raw_fClearDepthf(v);
         } else {
             raw_fClearDepth(v);
         }
     }
 
     void* fMapBuffer(GLenum target, GLenum access) {
         BEFORE_GL_CALL;
@@ -2733,29 +1736,16 @@ public:
         ASSERT_SYMBOL_PRESENT(fUnmapBuffer);
         realGLboolean ret = mSymbols.fUnmapBuffer(target);
         AFTER_GL_CALL;
         return ret;
     }
 
 
 private:
-#ifdef DEBUG
-    GLContext *TrackingContext() {
-        GLContext *tip = this;
-        while (tip->mSharedContext)
-            tip = tip->mSharedContext;
-        return tip;
-    }
-
-#define TRACKING_CONTEXT(a) do { TrackingContext()->a; } while (0)
-#else
-#define TRACKING_CONTEXT(a) do {} while (0)
-#endif
-
     GLuint GLAPIENTRY raw_fCreateProgram() {
         BEFORE_GL_CALL;
         GLuint ret = mSymbols.fCreateProgram();
         AFTER_GL_CALL;
         return ret;
     }
 
     GLuint GLAPIENTRY raw_fCreateShader(GLenum t) {
@@ -2919,27 +1909,30 @@ public:
         TRACKING_CONTEXT(DeletedRenderbuffers(this, n, names));
     }
 
     void fDeleteTextures(GLsizei n, GLuint *names) {
         raw_fDeleteTextures(n, names);
         TRACKING_CONTEXT(DeletedTextures(this, n, names));
     }
 
-
     GLenum GLAPIENTRY fGetGraphicsResetStatus() {
         MOZ_ASSERT(mHasRobustness);
 
         BEFORE_GL_CALL;
         ASSERT_SYMBOL_PRESENT(fGetGraphicsResetStatus);
         GLenum ret = mSymbols.fGetGraphicsResetStatus();
         AFTER_GL_CALL;
         return ret;
     }
 
+
+// -----------------------------------------------------------------------------
+// Extension ARB_sync (GL)
+public:
     GLsync GLAPIENTRY fFenceSync(GLenum condition, GLbitfield flags) {
         BEFORE_GL_CALL;
         ASSERT_SYMBOL_PRESENT(fFenceSync);
         GLsync ret = mSymbols.fFenceSync(condition, flags);
         AFTER_GL_CALL;
         return ret;
     }
 
@@ -2982,32 +1975,102 @@ public:
 
     void GLAPIENTRY fGetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values) {
         BEFORE_GL_CALL;
         ASSERT_SYMBOL_PRESENT(fGetSynciv);
         mSymbols.fGetSynciv(sync, pname, bufSize, length, values);
         AFTER_GL_CALL;
     }
 
-    // OES_EGL_image (GLES)
+
+// -----------------------------------------------------------------------------
+// Extension OES_EGL_image (GLES)
+public:
     void fEGLImageTargetTexture2D(GLenum target, GLeglImage image) {
         BEFORE_GL_CALL;
         ASSERT_SYMBOL_PRESENT(fEGLImageTargetTexture2D);
         mSymbols.fEGLImageTargetTexture2D(target, image);
         AFTER_GL_CALL;
     }
 
     void fEGLImageTargetRenderbufferStorage(GLenum target, GLeglImage image)
     {
         BEFORE_GL_CALL;
         ASSERT_SYMBOL_PRESENT(fEGLImageTargetRenderbufferStorage);
         mSymbols.fEGLImageTargetRenderbufferStorage(target, image);
         AFTER_GL_CALL;
     }
 
+
+// -----------------------------------------------------------------------------
+// Package XXX_draw_buffers
+public:
+    void fDrawBuffers(GLsizei n, const GLenum* bufs) {
+        BEFORE_GL_CALL;
+        mSymbols.fDrawBuffers(n, bufs);
+        AFTER_GL_CALL;
+    }
+
+
+// -----------------------------------------------------------------------------
+// Package XXX_draw_instanced
+public:
+    void fDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
+    {
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fDrawArraysInstanced);
+        mSymbols.fDrawArraysInstanced(mode, first, count, primcount);
+        AFTER_GL_CALL;
+    }
+
+    void fDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei primcount)
+    {
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fDrawElementsInstanced);
+        mSymbols.fDrawElementsInstanced(mode, count, type, indices, primcount);
+        AFTER_GL_CALL;
+    }
+
+
+// -----------------------------------------------------------------------------
+// Package XXX_framebuffer_blit
+public:
+    // Draw/Read
+    void fBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
+        BeforeGLDrawCall();
+        BeforeGLReadCall();
+        raw_fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+        AfterGLReadCall();
+        AfterGLDrawCall();
+    }
+
+
+private:
+    void raw_fBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fBlitFramebuffer);
+        mSymbols.fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+        AFTER_GL_CALL;
+    }
+
+
+// -----------------------------------------------------------------------------
+// Package XXX_framebuffer_multisample
+public:
+    void fRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height) {
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fRenderbufferStorageMultisample);
+        mSymbols.fRenderbufferStorageMultisample(target, samples, internalFormat, width, height);
+        AFTER_GL_CALL;
+    }
+
+
+// -----------------------------------------------------------------------------
+// Package XXX_vertex_array_object
+public:
     void GLAPIENTRY fBindVertexArray(GLuint array)
     {
         BEFORE_GL_CALL;
         ASSERT_SYMBOL_PRESENT(fBindVertexArray);
         mSymbols.fBindVertexArray(array);
         AFTER_GL_CALL;
     }
 
@@ -3031,32 +2094,1091 @@ public:
     {
         BEFORE_GL_CALL;
         ASSERT_SYMBOL_PRESENT(fIsVertexArray);
         realGLboolean ret = mSymbols.fIsVertexArray(array);
         AFTER_GL_CALL;
         return ret;
     }
 
-    // ARB_draw_instanced
-    void fDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
+
+// -----------------------------------------------------------------------------
+// Constructor
+public:
+
+    typedef struct gfx::SurfaceCaps SurfaceCaps;
+
+
+protected:
+    GLContext(const SurfaceCaps& caps,
+              GLContext* sharedContext = nullptr,
+              bool isOffscreen = false)
+      : mInitialized(false),
+        mIsOffscreen(isOffscreen),
+        mIsGlobalSharedContext(false),
+        mContextLost(false),
+        mIsGLES2(false),
+        mVendor(-1),
+        mRenderer(-1),
+        mHasRobustness(false),
+#ifdef DEBUG
+        mGLError(LOCAL_GL_NO_ERROR),
+#endif
+        mTexBlit_Buffer(0),
+        mTexBlit_VertShader(0),
+        mTex2DBlit_FragShader(0),
+        mTex2DRectBlit_FragShader(0),
+        mTex2DBlit_Program(0),
+        mTex2DRectBlit_Program(0),
+        mTexBlit_UseDrawNotCopy(false),
+        mSharedContext(sharedContext),
+        mFlipped(false),
+        mBlitProgram(0),
+        mBlitFramebuffer(0),
+        mCaps(caps),
+        mScreen(nullptr),
+        mLockedSurface(nullptr),
+        mMaxTextureSize(0),
+        mMaxCubeMapTextureSize(0),
+        mMaxTextureImageSize(0),
+        mMaxRenderbufferSize(0),
+        mNeedsTextureSizeChecks(false),
+        mWorkAroundDriverBugs(true)
+    {
+        mUserData.Init();
+        mOwningThread = NS_GetCurrentThread();
+
+        mTexBlit_UseDrawNotCopy = Preferences::GetBool("gl.blit-draw-not-copy", false);
+    }
+
+
+// -----------------------------------------------------------------------------
+// Destructor
+public:
+    virtual ~GLContext() {
+        NS_ASSERTION(IsDestroyed(), "GLContext implementation must call MarkDestroyed in destructor!");
+#ifdef DEBUG
+        if (mSharedContext) {
+            GLContext *tip = mSharedContext;
+            while (tip->mSharedContext)
+                tip = tip->mSharedContext;
+            tip->SharedContextDestroyed(this);
+            tip->ReportOutstandingNames();
+        } else {
+            ReportOutstandingNames();
+        }
+#endif
+    }
+
+
+// -----------------------------------------------------------------------------
+// Everything that isn't standard GL APIs
+protected:
+
+    typedef class gfx::SharedSurface SharedSurface;
+    typedef gfx::SharedSurfaceType SharedSurfaceType;
+    typedef gfxASurface::gfxImageFormat ImageFormat;
+    typedef gfx::SurfaceFormat SurfaceFormat;
+
+public:
+
+    virtual bool MakeCurrentImpl(bool aForce = false) = 0;
+
+#ifdef DEBUG
+    static void StaticInit() {
+        PR_NewThreadPrivateIndex(&sCurrentGLContextTLS, nullptr);
+    }
+#endif
+
+    bool MakeCurrent(bool aForce = false) {
+#ifdef DEBUG
+    PR_SetThreadPrivate(sCurrentGLContextTLS, this);
+
+    // XXX this assertion is disabled because it's triggering on Mac;
+    // we need to figure out why and reenable it.
+#if 0
+        // IsOwningThreadCurrent is a bit of a misnomer;
+        // the "owning thread" is the creation thread,
+        // and the only thread that can own this.  We don't
+        // support contexts used on multiple threads.
+        NS_ASSERTION(IsOwningThreadCurrent(),
+                     "MakeCurrent() called on different thread than this context was created on!");
+#endif
+#endif
+        return MakeCurrentImpl(aForce);
+    }
+
+    virtual bool SetupLookupFunction() = 0;
+
+    virtual void ReleaseSurface() {}
+
+    void *GetUserData(void *aKey) {
+        void *result = nullptr;
+        mUserData.Get(aKey, &result);
+        return result;
+    }
+
+    void SetUserData(void *aKey, void *aValue) {
+        mUserData.Put(aKey, aValue);
+    }
+
+    // Mark this context as destroyed.  This will nullptr out all
+    // the GL function pointers!
+    void MarkDestroyed();
+
+    bool IsDestroyed() {
+        // MarkDestroyed will mark all these as null.
+        return mSymbols.fUseProgram == nullptr;
+    }
+
+    enum NativeDataType {
+      NativeGLContext,
+      NativeImageSurface,
+      NativeThebesSurface,
+      NativeDataTypeMax
+    };
+
+    virtual void *GetNativeData(NativeDataType aType) { return nullptr; }
+    GLContext *GetSharedContext() { return mSharedContext; }
+
+    bool IsGlobalSharedContext() { return mIsGlobalSharedContext; }
+    void SetIsGlobalSharedContext(bool aIsOne) { mIsGlobalSharedContext = aIsOne; }
+
+    /**
+     * Returns true if the thread on which this context was created is the currently
+     * executing thread.
+     */
+    bool IsOwningThreadCurrent() { return NS_GetCurrentThread() == mOwningThread; }
+
+    void DispatchToOwningThread(nsIRunnable *event) {
+        // Before dispatching, we need to ensure we're not in the middle of
+        // shutting down. Dispatching runnables in the middle of shutdown
+        // (that is, when the main thread is no longer get-able) can cause them
+        // to leak. See Bug 741319, and Bug 744115.
+        nsCOMPtr<nsIThread> mainThread;
+        if (NS_SUCCEEDED(NS_GetMainThread(getter_AddRefs(mainThread)))) {
+            mOwningThread->Dispatch(event, NS_DISPATCH_NORMAL);
+        }
+    }
+
+    virtual EGLContext GetEGLContext() { return nullptr; }
+    virtual GLLibraryEGL* GetLibraryEGL() { return nullptr; }
+
+    virtual void MakeCurrent_EGLSurface(void* surf) {
+        MOZ_CRASH("Must be called against a GLContextEGL.");
+    }
+
+    bool CanUploadSubTextures();
+
+    static void PlatformStartup();
+
+protected:
+    static bool sPowerOfTwoForced;
+    static bool sPowerOfTwoPrefCached;
+    static void CacheCanUploadNPOT();
+
+public:
+    bool CanUploadNonPowerOfTwo();
+
+    bool WantsSmallTiles();
+
+    /**
+     * If this context wraps a double-buffered target, swap the back
+     * and front buffers.  It should be assumed that after a swap, the
+     * contents of the new back buffer are undefined.
+     */
+    virtual bool SwapBuffers() { return false; }
+
+    /**
+     * Defines a two-dimensional texture image for context target surface
+     */
+    virtual bool BindTexImage() { return false; }
+    /*
+     * Releases a color buffer that is being used as a texture
+     */
+    virtual bool ReleaseTexImage() { return false; }
+
+    /**
+     * Applies aFilter to the texture currently bound to GL_TEXTURE_2D.
+     */
+    void ApplyFilterToBoundTexture(gfxPattern::GraphicsFilter aFilter);
+
+    /**
+     * Applies aFilter to the texture currently bound to aTarget.
+     */
+    void ApplyFilterToBoundTexture(GLuint aTarget,
+                                   gfxPattern::GraphicsFilter aFilter);
+
+    virtual bool BindExternalBuffer(GLuint texture, void* buffer) { return false; }
+    virtual bool UnbindExternalBuffer(GLuint texture) { return false; }
+
+#ifdef MOZ_WIDGET_GONK
+    virtual EGLImage CreateEGLImageForNativeBuffer(void* buffer) = 0;
+    virtual void DestroyEGLImage(EGLImage image) = 0;
+    virtual EGLImage GetNullEGLImage() = 0;
+#endif
+
+    virtual already_AddRefed<TextureImage>
+    CreateDirectTextureImage(android::GraphicBuffer* aBuffer, GLenum aWrapMode)
+    { return nullptr; }
+
+    // Before reads from offscreen texture
+    void GuaranteeResolve();
+
+protected:
+    GLuint mTexBlit_Buffer;
+    GLuint mTexBlit_VertShader;
+    GLuint mTex2DBlit_FragShader;
+    GLuint mTex2DRectBlit_FragShader;
+    GLuint mTex2DBlit_Program;
+    GLuint mTex2DRectBlit_Program;
+
+    bool mTexBlit_UseDrawNotCopy;
+
+    bool UseTexQuadProgram(GLenum target = LOCAL_GL_TEXTURE_2D,
+                           const gfxIntSize& srcSize = gfxIntSize());
+    bool InitTexQuadProgram(GLenum target = LOCAL_GL_TEXTURE_2D);
+    void DeleteTexBlitProgram();
+
+public:
+    // If you don't have |srcFormats| for the 2nd definition,
+    // then you'll need the framebuffer_blit extensions to use
+    // the first BlitFramebufferToFramebuffer.
+    void BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
+                                      const gfxIntSize& srcSize,
+                                      const gfxIntSize& destSize);
+    void BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
+                                      const gfxIntSize& srcSize,
+                                      const gfxIntSize& destSize,
+                                      const GLFormats& srcFormats);
+    void BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
+                                  const gfxIntSize& srcSize,
+                                  const gfxIntSize& destSize,
+                                  GLenum srcTarget = LOCAL_GL_TEXTURE_2D);
+    void BlitFramebufferToTexture(GLuint srcFB, GLuint destTex,
+                                  const gfxIntSize& srcSize,
+                                  const gfxIntSize& destSize,
+                                  GLenum destTarget = LOCAL_GL_TEXTURE_2D);
+    void BlitTextureToTexture(GLuint srcTex, GLuint destTex,
+                              const gfxIntSize& srcSize,
+                              const gfxIntSize& destSize,
+                              GLenum srcTarget = LOCAL_GL_TEXTURE_2D,
+                              GLenum destTarget = LOCAL_GL_TEXTURE_2D);
+
+    /*
+     * Resize the current offscreen buffer.  Returns true on success.
+     * If it returns false, the context should be treated as unusable
+     * and should be recreated.  After the resize, the viewport is not
+     * changed; glViewport should be called as appropriate.
+     *
+     * Only valid if IsOffscreen() returns true.
+     */
+    virtual bool ResizeOffscreen(const gfxIntSize& size) {
+        return ResizeScreenBuffer(size);
+    }
+
+    /*
+     * Return size of this offscreen context.
+     *
+     * Only valid if IsOffscreen() returns true.
+     */
+    const gfxIntSize& OffscreenSize() const;
+
+
+    enum SharedTextureShareType {
+        SameProcess = 0,
+        CrossProcess
+    };
+
+    enum SharedTextureBufferType {
+        TextureID
+#ifdef MOZ_WIDGET_ANDROID
+        , SurfaceTexture
+#endif
+#ifdef XP_MACOSX
+        , IOSurface
+#endif
+    };
+
+    /*
+     * Create a new shared GLContext content handle, using the passed buffer as a source.
+     * Must be released by ReleaseSharedHandle. UpdateSharedHandle will have no effect
+     * on handles created with this method, as the caller owns the source (the passed buffer)
+     * and is responsible for updating it accordingly.
+     */
+    virtual SharedTextureHandle CreateSharedHandle(SharedTextureShareType shareType,
+                                                   void* buffer,
+                                                   SharedTextureBufferType bufferType)
+    { return 0; }
+    /**
+     * Publish GLContext content to intermediate buffer attached to shared handle.
+     * Shared handle content is ready to be used after call returns, and no need extra Flush/Finish are required.
+     * GLContext must be current before this call
+     */
+    virtual void UpdateSharedHandle(SharedTextureShareType shareType,
+                                    SharedTextureHandle sharedHandle)
+    { }
+    /**
+     * - It is better to call ReleaseSharedHandle before original GLContext destroyed,
+     *     otherwise warning will be thrown on attempt to destroy Texture associated with SharedHandle, depends on backend implementation.
+     * - It does not require to be called on context where it was created,
+     *     because SharedHandle suppose to keep Context reference internally,
+     *     or don't require specific context at all, for example IPC SharedHandle.
+     * - Not recommended to call this between AttachSharedHandle and Draw Target call.
+     *      if it is really required for some special backend, then DetachSharedHandle API must be added with related implementation.
+     * - It is recommended to stop any possible access to SharedHandle (Attachments, pending GL calls) before calling Release,
+     *      otherwise some artifacts might appear or even crash if API backend implementation does not expect that.
+     * SharedHandle (currently EGLImage) does not require GLContext because it is EGL call, and can be destroyed
+     *   at any time, unless EGLImage have siblings (which are not expected with current API).
+     */
+    virtual void ReleaseSharedHandle(SharedTextureShareType shareType,
+                                     SharedTextureHandle sharedHandle)
+    { }
+
+
+    typedef struct {
+        GLenum mTarget;
+        SurfaceFormat mTextureFormat;
+        gfx3DMatrix mTextureTransform;
+    } SharedHandleDetails;
+
+    /**
+     * Returns information necessary for rendering a shared handle.
+     * These values change depending on what sharing mechanism is in use
+     */
+    virtual bool GetSharedHandleDetails(SharedTextureShareType shareType,
+                                        SharedTextureHandle sharedHandle,
+                                        SharedHandleDetails& details)
+    { return false; }
+    /**
+     * Attach Shared GL Handle to GL_TEXTURE_2D target
+     * GLContext must be current before this call
+     */
+    virtual bool AttachSharedHandle(SharedTextureShareType shareType,
+                                    SharedTextureHandle sharedHandle)
+    { return false; }
+
+    /**
+     * Detach Shared GL Handle from GL_TEXTURE_2D target
+     */
+    virtual void DetachSharedHandle(SharedTextureShareType shareType,
+                                    SharedTextureHandle sharedHandle)
+    { }
+
+    void BindFB(GLuint fb) {
+        fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb);
+        MOZ_ASSERT(!fb || fIsFramebuffer(fb));
+    }
+
+    void BindDrawFB(GLuint fb) {
+        fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, fb);
+    }
+
+    void BindReadFB(GLuint fb) {
+        fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, fb);
+    }
+
+    GLuint GetDrawFB() {
+        if (mScreen)
+            return mScreen->GetDrawFB();
+
+        GLuint ret = 0;
+        GetUIntegerv(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, &ret);
+        return ret;
+    }
+
+    GLuint GetReadFB() {
+        if (mScreen)
+            return mScreen->GetReadFB();
+
+        GLenum bindEnum = SupportsSplitFramebuffer() ? LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT
+                                                     : LOCAL_GL_FRAMEBUFFER_BINDING;
+
+        GLuint ret = 0;
+        GetUIntegerv(bindEnum, &ret);
+        return ret;
+    }
+
+    GLuint GetFB() {
+        if (mScreen) {
+            // This has a very important extra assert that checks that we're
+            // not accidentally ignoring a situation where the draw and read
+            // FBs differ.
+            return mScreen->GetFB();
+        }
+
+        GLuint ret = 0;
+        GetUIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &ret);
+        return ret;
+    }
+
+private:
+    void GetShaderPrecisionFormatNonES2(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
+        switch (precisiontype) {
+            case LOCAL_GL_LOW_FLOAT:
+            case LOCAL_GL_MEDIUM_FLOAT:
+            case LOCAL_GL_HIGH_FLOAT:
+                // Assume IEEE 754 precision
+                range[0] = 127;
+                range[1] = 127;
+                *precision = 23;
+                break;
+            case LOCAL_GL_LOW_INT:
+            case LOCAL_GL_MEDIUM_INT:
+            case LOCAL_GL_HIGH_INT:
+                // Some (most) hardware only supports single-precision floating-point numbers,
+                // which can accurately represent integers up to +/-16777216
+                range[0] = 24;
+                range[1] = 24;
+                *precision = 0;
+                break;
+        }
+    }
+
+public:
+
+    void ForceDirtyScreen();
+    void CleanDirtyScreen();
+
+    virtual bool TextureImageSupportsGetBackingSurface() {
+        return false;
+    }
+
+    virtual GLenum GetPreferredARGB32Format() { return LOCAL_GL_RGBA; }
+
+    virtual bool RenewSurface() { return false; }
+
+    /**
+     * Return a valid, allocated TextureImage of |aSize| with
+     * |aContentType|.  The TextureImage's texture is configured to
+     * use |aWrapMode| (usually GL_CLAMP_TO_EDGE or GL_REPEAT) and by
+     * default, GL_LINEAR filtering.  Specify
+     * |aFlags=UseNearestFilter| for GL_NEAREST filtering. Specify
+     * |aFlags=NeedsYFlip| if the image is flipped. Return
+     * nullptr if creating the TextureImage fails.
+     *
+     * The returned TextureImage may only be used with this GLContext.
+     * Attempting to use the returned TextureImage after this
+     * GLContext is destroyed will result in undefined (and likely
+     * crashy) behavior.
+     */
+    virtual already_AddRefed<TextureImage>
+    CreateTextureImage(const nsIntSize& aSize,
+                       TextureImage::ContentType aContentType,
+                       GLenum aWrapMode,
+                       TextureImage::Flags aFlags = TextureImage::NoFlags);
+
+    /**
+     * In EGL we want to use Tiled Texture Images, which we return
+     * from CreateTextureImage above.
+     * Inside TiledTextureImage we need to create actual images and to
+     * prevent infinite recursion we need to differentiate the two
+     * functions.
+     **/
+    virtual already_AddRefed<TextureImage>
+    TileGenFunc(const nsIntSize& aSize,
+                TextureImage::ContentType aContentType,
+                TextureImage::Flags aFlags = TextureImage::NoFlags)
     {
+        return nullptr;
+    }
+
+    /**
+     * Read the image data contained in aTexture, and return it as an ImageSurface.
+     * If GL_RGBA is given as the format, a ImageFormatARGB32 surface is returned.
+     * Not implemented yet:
+     * If GL_RGB is given as the format, a ImageFormatRGB24 surface is returned.
+     * If GL_LUMINANCE is given as the format, a ImageFormatA8 surface is returned.
+     *
+     * THIS IS EXPENSIVE.  It is ridiculously expensive.  Only do this
+     * if you absolutely positively must, and never in any performance
+     * critical path.
+     */
+    already_AddRefed<gfxImageSurface> ReadTextureImage(GLuint aTexture,
+                                                       const gfxIntSize& aSize,
+                                                       GLenum aTextureFormat,
+                                                       bool aYInvert = false);
+
+    already_AddRefed<gfxImageSurface> GetTexImage(GLuint aTexture, bool aYInvert, SurfaceFormat aFormat);
+
+    /**
+     * Call ReadPixels into an existing gfxImageSurface.
+     * The image surface must be using image format RGBA32 or RGB24,
+     * and must have stride == width*4.
+     * Note that neither ReadPixelsIntoImageSurface nor
+     * ReadScreenIntoImageSurface call dest->Flush/MarkDirty.
+     */
+    void ReadPixelsIntoImageSurface(gfxImageSurface* dest);
+
+    // Similar to ReadPixelsIntoImageSurface, but pulls from the screen
+    // instead of the currently bound framebuffer.
+    void ReadScreenIntoImageSurface(gfxImageSurface* dest);
+
+    /**
+     * Copy a rectangle from one TextureImage into another.  The
+     * source and destination are given in integer coordinates, and
+     * will be converted to texture coordinates.
+     *
+     * For the source texture, the wrap modes DO apply -- it's valid
+     * to use REPEAT or PAD and expect appropriate behaviour if the source
+     * rectangle extends beyond its bounds.
+     *
+     * For the destination texture, the wrap modes DO NOT apply -- the
+     * destination will be clipped by the bounds of the texture.
+     *
+     * Note: calling this function will cause the following OpenGL state
+     * to be changed:
+     *
+     *   - current program
+     *   - framebuffer binding
+     *   - viewport
+     *   - blend state (will be enabled at end)
+     *   - scissor state (will be enabled at end)
+     *   - vertex attrib 0 and 1 (pointer and enable state [enable state will be disabled at exit])
+     *   - array buffer binding (will be 0)
+     *   - active texture (will be 0)
+     *   - texture 0 binding
+     */
+    void BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect,
+                          TextureImage *aDst, const nsIntRect& aDstRect);
+
+    /**
+     * Creates a RGB/RGBA texture (or uses one provided) and uploads the surface
+     * contents to it within aSrcRect.
+     *
+     * aSrcRect.x/y will be uploaded to 0/0 in the texture, and the size
+     * of the texture with be aSrcRect.width/height.
+     *
+     * If an existing texture is passed through aTexture, it is assumed it
+     * has already been initialised with glTexImage2D (or this function),
+     * and that its size is equal to or greater than aSrcRect + aDstPoint.
+     * You can alternatively set the overwrite flag to true and have a new
+     * texture memory block allocated.
+     *
+     * The aDstPoint parameter is ignored if no texture was provided
+     * or aOverwrite is true.
+     *
+     * \param aData Image data to upload.
+     * \param aDstRegion Region of texture to upload to.
+     * \param aTexture Texture to use, or 0 to have one created for you.
+     * \param aOverwrite Over an existing texture with a new one.
+     * \param aSrcPoint Offset into aSrc where the region's bound's
+     *  TopLeft() sits.
+     * \param aPixelBuffer Pass true to upload texture data with an
+     *  offset from the base data (generally for pixel buffer objects),
+     *  otherwise textures are upload with an absolute pointer to the data.
+     * \param aTextureUnit, the texture unit used temporarily to upload the
+     *  surface. This testure may be overridden, clients should not rely on
+     *  the contents of this texture after this call or even on this
+     *  texture unit being active.
+     * \return Surface format of this texture.
+     */
+    SurfaceFormat UploadImageDataToTexture(unsigned char* aData,
+                                           int32_t aStride,
+                                           gfxASurface::gfxImageFormat aFormat,
+                                           const nsIntRegion& aDstRegion,
+                                           GLuint& aTexture,
+                                           bool aOverwrite = false,
+                                           bool aPixelBuffer = false,
+                                           GLenum aTextureUnit = LOCAL_GL_TEXTURE0,
+                                           GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D);
+
+    /**
+     * Convenience wrapper around UploadImageDataToTexture for gfxASurfaces. 
+     */
+    SurfaceFormat UploadSurfaceToTexture(gfxASurface *aSurface,
+                                         const nsIntRegion& aDstRegion,
+                                         GLuint& aTexture,
+                                         bool aOverwrite = false,
+                                         const nsIntPoint& aSrcPoint = nsIntPoint(0, 0),
+                                         bool aPixelBuffer = false,
+                                         GLenum aTextureUnit = LOCAL_GL_TEXTURE0,
+                                         GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D);
+
+    /**
+     * Same as above, for DataSourceSurfaces.
+     */
+    SurfaceFormat UploadSurfaceToTexture(gfx::DataSourceSurface *aSurface,
+                                         const nsIntRegion& aDstRegion,
+                                         GLuint& aTexture,
+                                         bool aOverwrite = false,
+                                         const nsIntPoint& aSrcPoint = nsIntPoint(0, 0),
+                                         bool aPixelBuffer = false,
+                                         GLenum aTextureUnit = LOCAL_GL_TEXTURE0,
+                                         GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D);
+
+    void TexImage2D(GLenum target, GLint level, GLint internalformat,
+                    GLsizei width, GLsizei height, GLsizei stride,
+                    GLint pixelsize, GLint border, GLenum format,
+                    GLenum type, const GLvoid *pixels);
+
+    void TexSubImage2D(GLenum target, GLint level,
+                       GLint xoffset, GLint yoffset,
+                       GLsizei width, GLsizei height, GLsizei stride,
+                       GLint pixelsize, GLenum format,
+                       GLenum type, const GLvoid* pixels);
+
+    /**
+     * Uses the Khronos GL_EXT_unpack_subimage extension, working around
+     * quirks in the Tegra implementation of this extension.
+     */
+    void TexSubImage2DWithUnpackSubimageGLES(GLenum target, GLint level,
+                                             GLint xoffset, GLint yoffset,
+                                             GLsizei width, GLsizei height,
+                                             GLsizei stride, GLint pixelsize,
+                                             GLenum format, GLenum type,
+                                             const GLvoid* pixels);
+
+    void TexSubImage2DWithoutUnpackSubimage(GLenum target, GLint level,
+                                            GLint xoffset, GLint yoffset,
+                                            GLsizei width, GLsizei height,
+                                            GLsizei stride, GLint pixelsize,
+                                            GLenum format, GLenum type,
+                                            const GLvoid* pixels);
+
+    /** Helper for DecomposeIntoNoRepeatTriangles
+     */
+    struct RectTriangles {
+        RectTriangles() { }
+
+        // Always pass texture coordinates upright. If you want to flip the
+        // texture coordinates emitted to the tex_coords array, set flip_y to
+        // true.
+        void addRect(GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1,
+                     GLfloat tx0, GLfloat ty0, GLfloat tx1, GLfloat ty1,
+                     bool flip_y = false);
+
+        /**
+         * these return a float pointer to the start of each array respectively.
+         * Use it for glVertexAttribPointer calls.
+         * We can return nullptr if we choose to use Vertex Buffer Objects here.
+         */
+        float* vertexPointer() {
+            return &vertexCoords[0].x;
+        }
+
+        float* texCoordPointer() {
+            return &texCoords[0].u;
+        }
+
+        unsigned int elements() {
+            return vertexCoords.Length();
+        }
+
+        typedef struct { GLfloat x,y; } vert_coord;
+        typedef struct { GLfloat u,v; } tex_coord;
+    private:
+        // default is 4 rectangles, each made up of 2 triangles (3 coord vertices each)
+        nsAutoTArray<vert_coord, 6> vertexCoords;
+        nsAutoTArray<tex_coord, 6>  texCoords;
+    };
+
+    /**
+     * Decompose drawing the possibly-wrapped aTexCoordRect rectangle
+     * of a texture of aTexSize into one or more rectangles (represented
+     * as 2 triangles) and associated tex coordinates, such that
+     * we don't have to use the REPEAT wrap mode. If aFlipY is true, the
+     * texture coordinates will be specified vertically flipped.
+     *
+     * The resulting triangle vertex coordinates will be in the space of
+     * (0.0, 0.0) to (1.0, 1.0) -- transform the coordinates appropriately
+     * if you need a different space.
+     *
+     * The resulting vertex coordinates should be drawn using GL_TRIANGLES,
+     * and rects.numRects * 3 * 6
+     */
+    static void DecomposeIntoNoRepeatTriangles(const nsIntRect& aTexCoordRect,
+                                               const nsIntSize& aTexSize,
+                                               RectTriangles& aRects,
+                                               bool aFlipY = false);
+
+
+    // Shared code for GL extensions and GLX extensions.
+    static bool ListHasExtension(const GLubyte *extensions,
+                                 const char *extension);
+
+    GLint GetMaxTextureImageSize() { return mMaxTextureImageSize; }
+    void SetFlipped(bool aFlipped) { mFlipped = aFlipped; }
+
+
+public:
+    /**
+     * Context reset constants.
+     * These are used to determine who is guilty when a context reset
+     * happens.
+     */
+    enum ContextResetARB {
+        CONTEXT_NO_ERROR = 0,
+        CONTEXT_GUILTY_CONTEXT_RESET_ARB = 0x8253,
+        CONTEXT_INNOCENT_CONTEXT_RESET_ARB = 0x8254,
+        CONTEXT_UNKNOWN_CONTEXT_RESET_ARB = 0x8255
+    };
+
+public:
+    std::map<GLuint, SharedSurface_GL*> mFBOMapping;
+
+    enum {
+        DebugEnabled = 1 << 0,
+        DebugTrace = 1 << 1,
+        DebugAbortOnError = 1 << 2
+    };
+
+    static uint32_t sDebugMode;
+
+    static uint32_t DebugMode() {
+#ifdef DEBUG
+        return sDebugMode;
+#else
+        return 0;
+#endif
+    }
+
+protected:
+    nsRefPtr<GLContext> mSharedContext;
+
+    // The thread on which this context was created.
+    nsCOMPtr<nsIThread> mOwningThread;
+
+    GLContextSymbols mSymbols;
+
+#ifdef DEBUG
+    // GLDebugMode will check that we don't send call
+    // to a GLContext that isn't current on the current
+    // thread.
+    // Store the current context when binding to thread local
+    // storage to support DebugMode on an arbitrary thread.
+    static unsigned sCurrentGLContextTLS;
+#endif
+    bool mFlipped;
+
+    // lazy-initialized things
+    GLuint mBlitProgram, mBlitFramebuffer;
+    void UseBlitProgram();
+    void SetBlitFramebufferForDestTexture(GLuint aTexture);
+
+public:
+    // Assumes shares are created by all sharing with the same global context.
+    bool SharesWith(const GLContext* other) const {
+        MOZ_ASSERT(!this->mSharedContext || !this->mSharedContext->mSharedContext);
+        MOZ_ASSERT(!other->mSharedContext || !other->mSharedContext->mSharedContext);
+        MOZ_ASSERT(!this->mSharedContext ||
+                   !other->mSharedContext ||
+                   this->mSharedContext == other->mSharedContext);
+
+        const GLContext* thisShared = this->mSharedContext ? this->mSharedContext
+                                                           : this;
+        const GLContext* otherShared = other->mSharedContext ? other->mSharedContext
+                                                             : other;
+
+        return thisShared == otherShared;
+    }
+
+    bool InitOffscreen(const gfxIntSize& size, const SurfaceCaps& caps) {
+        if (!CreateScreenBuffer(size, caps))
+            return false;
+
+        MakeCurrent();
+        fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
+        fScissor(0, 0, size.width, size.height);
+        fViewport(0, 0, size.width, size.height);
+
+        mCaps = mScreen->Caps();
+        if (mCaps.any)
+            DetermineCaps();
+
+        UpdateGLFormats(mCaps);
+        UpdatePixelFormat();
+
+        return true;
+    }
+
+protected:
+    // Note that it does -not- clear the resized buffers.
+    bool CreateScreenBuffer(const gfxIntSize& size, const SurfaceCaps& caps) {
+        if (!IsOffscreenSizeAllowed(size))
+            return false;
+
+        SurfaceCaps tryCaps = caps;
+        if (tryCaps.antialias) {
+            // AA path
+            if (CreateScreenBufferImpl(size, tryCaps))
+                return true;
+
+            NS_WARNING("CreateScreenBuffer failed to initialize an AA context! Falling back to no AA...");
+            tryCaps.antialias = false;
+        }
+        MOZ_ASSERT(!tryCaps.antialias);
+
+        if (CreateScreenBufferImpl(size, tryCaps))
+            return true;
+
+        NS_WARNING("CreateScreenBuffer failed to initialize non-AA context!");
+        return false;
+    }
+
+    bool CreateScreenBufferImpl(const gfxIntSize& size,
+                                const SurfaceCaps& caps);
+
+public:
+    bool ResizeScreenBuffer(const gfxIntSize& size);
+
+protected:
+    SurfaceCaps mCaps;
+    nsAutoPtr<GLFormats> mGLFormats;
+    nsAutoPtr<PixelBufferFormat> mPixelFormat;
+
+public:
+    void DetermineCaps();
+    const SurfaceCaps& Caps() const {
+        return mCaps;
+    }
+
+    // Only varies based on bpp16 and alpha.
+    GLFormats ChooseGLFormats(const SurfaceCaps& caps) const;
+    void UpdateGLFormats(const SurfaceCaps& caps) {
+        mGLFormats = new GLFormats(ChooseGLFormats(caps));
+    }
+
+    const GLFormats& GetGLFormats() const {
+        MOZ_ASSERT(mGLFormats);
+        return *mGLFormats;
+    }
+
+    PixelBufferFormat QueryPixelFormat();
+    void UpdatePixelFormat();
+
+    const PixelBufferFormat& GetPixelFormat() const {
+        MOZ_ASSERT(mPixelFormat);
+        return *mPixelFormat;
+    }
+
+
+    GLuint CreateTextureForOffscreen(const GLFormats& formats,
+                                     const gfxIntSize& size);
+    GLuint CreateTexture(GLenum internalFormat,
+                         GLenum format, GLenum type,
+                         const gfxIntSize& size);
+    GLuint CreateRenderbuffer(GLenum format,
+                              GLsizei samples,
+                              const gfxIntSize& size);
+    bool IsFramebufferComplete(GLuint fb, GLenum* status = nullptr);
+
+    // Pass null to an RB arg to disable its creation.
+    void CreateRenderbuffersForOffscreen(const GLFormats& formats,
+                                         const gfxIntSize& size,
+                                         bool multisample,
+                                         GLuint* colorMSRB,
+                                         GLuint* depthRB,
+                                         GLuint* stencilRB);
+
+    // Does not check completeness.
+    void AttachBuffersToFB(GLuint colorTex, GLuint colorRB,
+                           GLuint depthRB, GLuint stencilRB,
+                           GLuint fb, GLenum target = LOCAL_GL_TEXTURE_2D);
+
+    // Passing null is fine if the value you'd get is 0.
+    bool AssembleOffscreenFBs(const GLuint colorMSRB,
+                              const GLuint depthRB,
+                              const GLuint stencilRB,
+                              const GLuint texture,
+                              GLuint* drawFB,
+                              GLuint* readFB);
+
+protected:
+    friend class GLScreenBuffer;
+    GLScreenBuffer* mScreen;
+
+    void DestroyScreenBuffer();
+
+    SharedSurface* mLockedSurface;
+
+public:
+    void LockSurface(SharedSurface* surf) {
+        MOZ_ASSERT(!mLockedSurface);
+        mLockedSurface = surf;
+    }
+
+    void UnlockSurface(SharedSurface* surf) {
+        MOZ_ASSERT(mLockedSurface == surf);
+        mLockedSurface = nullptr;
+    }
+
+    SharedSurface* GetLockedSurface() const {
+        return mLockedSurface;
+    }
+
+    bool IsOffscreen() const {
+        return mScreen;
+    }
+
+    GLScreenBuffer* Screen() const {
+        return mScreen;
+    }
+
+    bool PublishFrame();
+    SharedSurface* RequestFrame();
+
+    /* Clear to transparent black, with 0 depth and stencil,
+     * while preserving current ClearColor etc. values.
+     * Useful for resizing offscreen buffers.
+     */
+    void ClearSafely();
+
+    bool WorkAroundDriverBugs() const { return mWorkAroundDriverBugs; }
+
+protected:
+    nsRefPtr<TextureGarbageBin> mTexGarbageBin;
+
+public:
+    TextureGarbageBin* TexGarbageBin() {
+        MOZ_ASSERT(mTexGarbageBin);
+        return mTexGarbageBin;
+    }
+
+    void EmptyTexGarbageBin();
+
+protected:
+    nsDataHashtable<nsPtrHashKey<void>, void*> mUserData;
+
+    bool InitWithPrefix(const char *prefix, bool trygl);
+
+    void InitExtensions();
+
+    bool IsOffscreenSizeAllowed(const gfxIntSize& aSize) const {
+        int32_t biggerDimension = std::max(aSize.width, aSize.height);
+        int32_t maxAllowed = std::min(mMaxRenderbufferSize, mMaxTextureSize);
+        return biggerDimension <= maxAllowed;
+    }
+
+    nsTArray<nsIntRect> mViewportStack;
+    nsTArray<nsIntRect> mScissorStack;
+
+    GLint mMaxTextureSize;
+    GLint mMaxCubeMapTextureSize;
+    GLint mMaxTextureImageSize;
+    GLint mMaxRenderbufferSize;
+    GLsizei mMaxSamples;
+    bool mNeedsTextureSizeChecks;
+    bool mWorkAroundDriverBugs;
+
+    bool IsTextureSizeSafeToPassToDriver(GLenum target, GLsizei width, GLsizei height) const {
+        if (mNeedsTextureSizeChecks) {
+            // some drivers incorrectly handle some large texture sizes that are below the
+            // max texture size that they report. So we check ourselves against our own values
+            // (mMax[CubeMap]TextureSize).
+            // see bug 737182 for Mac Intel 2D textures
+            // see bug 684882 for Mac Intel cube map textures
+            // see bug 814716 for Mesa Nouveau
+            GLsizei maxSize = target == LOCAL_GL_TEXTURE_CUBE_MAP ||
+                                (target >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
+                                target <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
+                              ? mMaxCubeMapTextureSize
+                              : mMaxTextureSize;
+            return width <= maxSize && height <= maxSize;
+        }
+        return true;
+    }
+
+
+    /*** Scissor functions ***/
+
+protected:
+    GLint FixYValue(GLint y, GLint height)
+    {
+        MOZ_ASSERT( !(mIsOffscreen && mFlipped) );
+        return mFlipped ? ViewportRect().height - (height + y) : y;
+    }
+
+public:
+    void fScissor(GLint x, GLint y, GLsizei width, GLsizei height) {
+        ScissorRect().SetRect(x, y, width, height);
+
+        // GL's coordinate system is flipped compared to the one we use in
+        // OGL Layers (in the Y axis), so we may need to flip our rectangle.
+        y = FixYValue(y, height);
+        raw_fScissor(x, y, width, height);
+    }
+
+    nsIntRect& ScissorRect() {
+        return mScissorStack[mScissorStack.Length()-1];
+    }
+
+    void PushScissorRect() {
+        nsIntRect copy(ScissorRect());
+        mScissorStack.AppendElement(copy);
+    }
+
+    void PushScissorRect(const nsIntRect& aRect) {
+        mScissorStack.AppendElement(aRect);
+        fScissor(aRect.x, aRect.y, aRect.width, aRect.height);
+    }
+
+    void PopScissorRect() {
+        if (mScissorStack.Length() < 2) {
+            NS_WARNING("PopScissorRect with Length < 2!");
+            return;
+        }
+
+        nsIntRect thisRect = ScissorRect();
+        mScissorStack.TruncateLength(mScissorStack.Length() - 1);
+        if (!thisRect.IsEqualInterior(ScissorRect())) {
+            fScissor(ScissorRect().x, ScissorRect().y,
+                     ScissorRect().width, ScissorRect().height);
+        }
+    }
+
+    /*** Viewport functions ***/
+
+private:
+    // only does the glViewport call, no ViewportRect business
+    void raw_fViewport(GLint x, GLint y, GLsizei width, GLsizei height) {
         BEFORE_GL_CALL;
-        ASSERT_SYMBOL_PRESENT(fDrawArraysInstanced);
-        mSymbols.fDrawArraysInstanced(mode, first, count, primcount);
+        // XXX: Flipping should really happen using the destination height, but
+        // we use viewport instead and assume viewport size matches the
+        // destination. If we ever try use partial viewports for layers we need
+        // to fix this, and remove the assertion.
+        NS_ASSERTION(!mFlipped || (x == 0 && y == 0), "TODO: Need to flip the viewport rect");
+        mSymbols.fViewport(x, y, width, height);
         AFTER_GL_CALL;
     }
 
-    void fDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei primcount)
-    {
-        BEFORE_GL_CALL;
-        ASSERT_SYMBOL_PRESENT(fDrawElementsInstanced);
-        mSymbols.fDrawElementsInstanced(mode, count, type, indices, primcount);
-        AFTER_GL_CALL;
-    }
+public:
+    void fViewport(GLint x, GLint y, GLsizei width, GLsizei height) {
+        ViewportRect().SetRect(x, y, width, height);
+        raw_fViewport(x, y, width, height);
+    }
+
+    nsIntRect& ViewportRect() {
+        return mViewportStack[mViewportStack.Length()-1];
+    }
+
+    void PushViewportRect() {
+        nsIntRect copy(ViewportRect());
+        mViewportStack.AppendElement(copy);
+    }
+
+    void PushViewportRect(const nsIntRect& aRect) {
+        mViewportStack.AppendElement(aRect);
+        raw_fViewport(aRect.x, aRect.y, aRect.width, aRect.height);
+    }
+
+    void PopViewportRect() {
+        if (mViewportStack.Length() < 2) {
+            NS_WARNING("PopViewportRect with Length < 2!");
+            return;
+        }
+
+        nsIntRect thisRect = ViewportRect();
+        mViewportStack.TruncateLength(mViewportStack.Length() - 1);
+        if (!thisRect.IsEqualInterior(ViewportRect())) {
+            raw_fViewport(ViewportRect().x, ViewportRect().y,
+                          ViewportRect().width, ViewportRect().height);
+        }
+    }
+
 
 #undef ASSERT_SYMBOL_PRESENT
 
 #ifdef DEBUG
     void CreatedProgram(GLContext *aOrigin, GLuint aName);
     void CreatedShader(GLContext *aOrigin, GLuint aName);
     void CreatedBuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
     void CreatedQueries(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
--- a/gfx/layers/CopyableCanvasLayer.cpp
+++ b/gfx/layers/CopyableCanvasLayer.cpp
@@ -69,98 +69,77 @@ CopyableCanvasLayer::UpdateSurface(gfxAS
   if (!mGLContext && aDestSurface) {
     nsRefPtr<gfxContext> tmpCtx = new gfxContext(aDestSurface);
     tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
     CopyableCanvasLayer::PaintWithOpacity(tmpCtx, 1.0f, aMaskLayer);
     return;
   }
 
   if (mGLContext) {
-    if (aDestSurface && aDestSurface->GetType() != gfxASurface::SurfaceTypeImage) {
-      MOZ_ASSERT(false, "Destination surface must be ImageSurface type.");
-      return;
-    }
-
     nsRefPtr<gfxImageSurface> readSurf;
-    nsRefPtr<gfxImageSurface> resultSurf;
+    nsRefPtr<gfxASurface> resultSurf;
 
     SharedSurface* sharedSurf = mGLContext->RequestFrame();
     if (!sharedSurf) {
       NS_WARNING("Null frame received.");
       return;
     }
 
     gfxIntSize readSize(sharedSurf->Size());
     gfxImageFormat format = (GetContentFlags() & CONTENT_OPAQUE)
                             ? gfxASurface::ImageFormatRGB24
                             : gfxASurface::ImageFormatARGB32;
 
     if (aDestSurface) {
-      resultSurf = static_cast<gfxImageSurface*>(aDestSurface);
+      resultSurf = aDestSurface;
     } else {
       resultSurf = GetTempSurface(readSize, format);
     }
     MOZ_ASSERT(resultSurf);
     if (resultSurf->CairoStatus() != 0) {
       MOZ_ASSERT(false, "Bad resultSurf->CairoStatus().");
       return;
     }
 
     MOZ_ASSERT(sharedSurf->APIType() == APITypeT::OpenGL);
     SharedSurface_GL* surfGL = SharedSurface_GL::Cast(sharedSurf);
 
     if (surfGL->Type() == SharedSurfaceType::Basic) {
       SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(surfGL);
       readSurf = sharedSurf_Basic->GetData();
     } else {
-      if (resultSurf->Format() == format &&
-          resultSurf->GetSize() == readSize)
+      if (resultSurf->GetSize() != readSize ||
+          !(readSurf = resultSurf->GetAsImageSurface()) ||
+          readSurf->Format() != format)
       {
-        readSurf = resultSurf;
-      } else {
         readSurf = GetTempSurface(readSize, format);
       }
 
       // Readback handles Flush/MarkDirty.
       mGLContext->Screen()->Readback(surfGL, readSurf);
     }
     MOZ_ASSERT(readSurf);
 
     bool needsPremult = surfGL->HasAlpha() && !mIsGLAlphaPremult;
     if (needsPremult) {
-      gfxImageSurface* sizedReadSurf = nullptr;
-      if (readSurf->Format()  == resultSurf->Format() &&
-          readSurf->GetSize() == resultSurf->GetSize())
-      {
-        sizedReadSurf = readSurf;
-      } else {
-        readSurf->Flush();
-        nsRefPtr<gfxContext> ctx = new gfxContext(resultSurf);
-        ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
-        ctx->SetSource(readSurf);
-        ctx->Paint();
-
-        sizedReadSurf = resultSurf;
-      }
-      MOZ_ASSERT(sizedReadSurf);
-
       readSurf->Flush();
-      resultSurf->Flush();
-      gfxUtils::PremultiplyImageSurface(readSurf, resultSurf);
-      resultSurf->MarkDirty();
-    } else if (resultSurf != readSurf) {
-      // Didn't need premult, but we do need to blit to resultSurf
+      gfxUtils::PremultiplyImageSurface(readSurf);
+      readSurf->MarkDirty();
+    }
+    
+    if (readSurf != resultSurf) {
       readSurf->Flush();
       nsRefPtr<gfxContext> ctx = new gfxContext(resultSurf);
       ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
       ctx->SetSource(readSurf);
       ctx->Paint();
     }
 
-    // stick our surface into mSurface, so that the Paint() path is the same
+    // If !aDestSurface then we will end up painting using mSurface, so
+    // stick our surface into mSurface, so that the Paint() path is the same.
     if (!aDestSurface) {
       mSurface = resultSurf;
     }
   }
 }
 
 void
 CopyableCanvasLayer::PaintWithOpacity(gfxContext* aContext,
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -61,17 +61,17 @@ CanvasClient2D::Update(gfx::IntSize aSiz
   }
 
   bool isOpaque = (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE);
   gfxASurface::gfxContentType contentType = isOpaque
                                               ? gfxASurface::CONTENT_COLOR
                                               : gfxASurface::CONTENT_COLOR_ALPHA;
   mDeprecatedTextureClient->EnsureAllocated(aSize, contentType);
 
-  gfxASurface* surface = mDeprecatedTextureClient->LockImageSurface();
+  gfxASurface* surface = mDeprecatedTextureClient->LockSurface();
   aLayer->UpdateSurface(surface);
   mDeprecatedTextureClient->Unlock();
 }
 
 void
 CanvasClientWebGL::Updated()
 {
   mForwarder->UpdateTextureNoSwap(this, 1, mDeprecatedTextureClient->GetDescriptor());
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -27,16 +27,21 @@
 using namespace base;
 using namespace mozilla;
 using namespace mozilla::ipc;
 using namespace std;
 
 namespace mozilla {
 namespace layers {
 
+CompositorParent::LayerTreeState::LayerTreeState()
+  : mParent(nullptr)
+{
+}
+
 typedef map<uint64_t, CompositorParent::LayerTreeState> LayerTreeMap;
 static LayerTreeMap sIndirectLayerTrees;
 
 // FIXME/bug 774386: we're assuming that there's only one
 // CompositorParent, but that's not always true.  This assumption only
 // affects CrossProcessCompositorParent below.
 static Thread* sCompositorThread = nullptr;
 // manual reference count of the compositor thread.
@@ -907,19 +912,19 @@ CrossProcessCompositorParent::ActorDestr
 PLayerTransactionParent*
 CrossProcessCompositorParent::AllocPLayerTransactionParent(const LayersBackend& aBackendType,
                                                            const uint64_t& aId,
                                                            TextureFactoryIdentifier* aTextureFactoryIdentifier)
 {
   MOZ_ASSERT(aId != 0);
 
   if (sIndirectLayerTrees[aId].mParent) {
-    nsRefPtr<LayerManager> lm = sIndirectLayerTrees[aId].mParent->GetLayerManager();
+    LayerManagerComposite* lm = sIndirectLayerTrees[aId].mParent->GetLayerManager();
     *aTextureFactoryIdentifier = lm->GetTextureFactoryIdentifier();
-    return new LayerTransactionParent(lm->AsLayerManagerComposite(), this, aId);
+    return new LayerTransactionParent(lm, this, aId);
   }
 
   NS_WARNING("Created child without a matching parent?");
   return new LayerTransactionParent(nullptr, this, aId);
 }
 
 bool
 CrossProcessCompositorParent::DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers)
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -172,19 +172,20 @@ public:
    * Should be used when CompositorParent should work in existing thread/MessageLoop,
    * for example moving Compositor into native toolkit main thread will allow to avoid
    * extra synchronization and call ::Composite() right from toolkit::Paint event
    */
   static void StartUpWithExistingThread(MessageLoop* aMsgLoop,
                                         PlatformThreadId aThreadID);
 
   struct LayerTreeState {
+    LayerTreeState();
     nsRefPtr<Layer> mRoot;
     nsRefPtr<GeckoContentController> mController;
-    CompositorParent *mParent;
+    CompositorParent* mParent;
     TargetConfig mTargetConfig;
   };
 
   /**
    * Lookup the indirect shadow tree for |aId| and return it if it
    * exists.  Otherwise null is returned.  This must only be called on
    * the compositor thread.
    */
--- a/ipc/ipdl/Makefile.in
+++ b/ipc/ipdl/Makefile.in
@@ -26,20 +26,28 @@ LOCAL_INCLUDES += -I$(DEPTH)/ipc/ipdl/_i
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/config/rules.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 
 
 # NB: the IPDL compiler manages .ipdl-->.h/.cpp dependencies itself,
 # which is why we don't have explicit .h/.cpp targets here
-export:: $(ALL_IPDLSRCS)
+ipdl: $(ALL_IPDLSRCS)
 	$(PYTHON) $(topsrcdir)/config/pythonpath.py \
 	  $(PLY_INCLUDE) \
 	  $(srcdir)/ipdl.py \
 	  --outheaders-dir=_ipdlheaders \
 	  --outcpp-dir=. \
 	  $(IPDLDIRS:%=-I%) \
 	  $^
 
+.PHONY: ipdl
+
 # We #include some things in the dom/plugins/ directory that rely on
 # toolkit libraries.
 CXXFLAGS    += $(TK_CFLAGS)
+
+# This is only needed to support |make| from this leaf directory/Makefile.
+NONRECURSIVE_TARGETS := export
+NONRECURSIVE_TARGETS_export := ipdl
+NONRECURSIVE_TARGETS_export_ipdl_DIRECTORY := .
+NONRECURSIVE_TARGETS_export_ipdl_TARGETS := ipdl
--- a/js/ipc/JavaScriptChild.cpp
+++ b/js/ipc/JavaScriptChild.cpp
@@ -86,17 +86,17 @@ JavaScriptChild::makeId(JSContext *cx, J
     }
 
     id <<= OBJECT_EXTRA_BITS;
     if (JS_ObjectIsCallable(cx, obj))
         id |= OBJECT_IS_CALLABLE;
 
     if (!objects_.add(id, obj))
         return false;
-    if (!ids_.add(obj, id))
+    if (!ids_.add(cx, obj, id))
         return false;
 
     *idp = id;
     return true;
 }
 
 JSObject *
 JavaScriptChild::unwrap(JSContext *cx, ObjectId id)
--- a/js/ipc/JavaScriptShared.cpp
+++ b/js/ipc/JavaScriptShared.cpp
@@ -24,19 +24,19 @@ ObjectStore::init()
 {
     return table_.init(32);
 }
 
 void
 ObjectStore::trace(JSTracer *trc)
 {
     for (ObjectTable::Range r(table_.all()); !r.empty(); r.popFront()) {
-        JSObject *obj = r.front().value;
-        JS_CallObjectTracer(trc, &obj, "ipc-object");
-        MOZ_ASSERT(obj == r.front().value);
+        DebugOnly<JSObject *> prior = r.front().value.get();
+        JS_CallHeapObjectTracer(trc, &r.front().value, "ipc-object");
+        MOZ_ASSERT(r.front().value == prior);
     }
 }
 
 JSObject *
 ObjectStore::find(ObjectId id)
 {
     ObjectTable::Ptr p = table_.lookup(id);
     if (!p)
@@ -82,19 +82,35 @@ ObjectIdCache::find(JSObject *obj)
 {
     ObjectIdTable::Ptr p = table_.lookup(obj);
     if (!p)
         return 0;
     return p->value;
 }
 
 bool
-ObjectIdCache::add(JSObject *obj, ObjectId id)
+ObjectIdCache::add(JSContext *cx, JSObject *obj, ObjectId id)
 {
-    return table_.put(obj, id);
+    if (!table_.put(obj, id))
+        return false;
+    JS_StoreObjectPostBarrierCallback(cx, keyMarkCallback, obj, this);
+    return true;
+}
+
+/*
+ * This function is called during minor GCs for each key in the HashMap that has
+ * been moved.
+ */
+/* static */ void
+ObjectIdCache::keyMarkCallback(JSTracer *trc, void *k, void *d) {
+    JSObject *key = static_cast<JSObject*>(k);
+    ObjectIdCache* self = static_cast<ObjectIdCache*>(d);
+    JSObject *prior = key;
+    JS_CallObjectTracer(trc, &key, "ObjectIdCache::table_ key");
+    self->table_.rekey(prior, key);
 }
 
 void
 ObjectIdCache::remove(JSObject *obj)
 {
     table_.remove(obj);
 }
 
--- a/js/ipc/JavaScriptShared.h
+++ b/js/ipc/JavaScriptShared.h
@@ -39,17 +39,17 @@ class CpowIdHolder : public CpowHolder
     const InfallibleTArray<CpowEntry> &cpows_;
 };
 
 // Map ids -> JSObjects
 class ObjectStore
 {
     typedef js::DefaultHasher<ObjectId> TableKeyHasher;
 
-    typedef js::HashMap<ObjectId, JSObject *, TableKeyHasher, js::SystemAllocPolicy> ObjectTable;
+    typedef js::HashMap<ObjectId, JS::Heap<JSObject *>, TableKeyHasher, js::SystemAllocPolicy> ObjectTable;
 
   public:
     ObjectStore();
 
     bool init();
     void trace(JSTracer *trc);
 
     bool add(ObjectId id, JSObject *obj);
@@ -67,21 +67,23 @@ class ObjectIdCache
     typedef js::HashMap<JSObject *, ObjectId, Hasher, js::SystemAllocPolicy> ObjectIdTable;
 
   public:
     ObjectIdCache();
 
     bool init();
     void trace(JSTracer *trc);
 
-    bool add(JSObject *, ObjectId id);
+    bool add(JSContext *cx, JSObject *obj, ObjectId id);
     ObjectId find(JSObject *obj);
     void remove(JSObject *obj);
 
   private:
+    static void keyMarkCallback(JSTracer *trc, void *key, void *data);
+
     ObjectIdTable table_;
 };
 
 class JavaScriptShared
 {
   public:
     bool init();
 
--- a/js/src/config/makefiles/nonrecursive.mk
+++ b/js/src/config/makefiles/nonrecursive.mk
@@ -14,49 +14,55 @@
 # NONRECURSIVE_TARGETS variable lists the make targets that modified. For
 # each target in this list, the NONRECURSIVE_TARGET_<target> variable will
 # contain a list of partial variable names. We will then look in variables
 # named NONRECURSIVE_TARGETS_<target>_<fragment>_* for information describing
 # how to evaluate non-recursive make targets.
 #
 # Targets are defined by the following variables:
 #
-#   FILE - The make file to evaluate.
+#   FILE - The make file to evaluate. This is equivalent to
+#      |make -f <FILE>|
+#   DIRECTORY - The directory whose Makefile to evaluate. This is
+#      equivalent to |make -C <DIRECTORY>|.
 #   TARGETS - Targets to evaluate in that make file.
 #
+# Only 1 of FILE or DIRECTORY may be defined.
+#
 # For example:
 #
 # NONRECURSIVE_TARGETS = export libs
 # NONRECURSIVE_TARGETS_export = headers
 # NONRECURSIVE_TARGETS_export_headers_FILE = /path/to/exports.mk
 # NONRECURSIVE_TARGETS_export_headers_TARGETS = $(DIST)/include/foo.h $(DIST)/include/bar.h
 # NONRECURSIVE_TARGETS_libs = cppsrcs
-# NONRECURSIVE_TARGETS_libs_cppsrcs_FILE = /path/to/compilation.mk
+# NONRECURSIVE_TARGETS_libs_cppsrcs_DIRECTORY = $(DEPTH)/foo
 # NONRECURSIVE_TARGETS_libs_cppsrcs_TARGETS = /path/to/foo.o /path/to/bar.o
 #
 # Will get turned into the following:
 #
 # exports::
-#     $(MAKE) -f /path/to/exports.mk $(DIST)/include/foo.h $(DIST)/include/bar.h
+#     $(MAKE) -C $(DEPTH) -f /path/to/exports.mk $(DIST)/include/foo.h $(DIST)/include/bar.h
 #
 # libs::
-#     $(MAKE) -f /path/to/compilation.mk /path/to/foo.o /path/to/bar.o
+#     $(MAKE) -C $(DEPTH)/foo /path/to/foo.o /path/to/bar.o
 
 ifndef INCLUDED_NONRECURSIVE_MK
 
 define define_nonrecursive_target
 $(1)::
-	cd $$(DEPTH) && $$(MAKE) -f $(2) $(3)
+	$$(MAKE) -C $(or $(4),$$(DEPTH)) $(addprefix -f ,$(3)) $(2)
 endef
 
 $(foreach target,$(NONRECURSIVE_TARGETS), \
     $(foreach entry,$(NONRECURSIVE_TARGETS_$(target)), \
         $(eval $(call define_nonrecursive_target, \
             $(target), \
+            $(NONRECURSIVE_TARGETS_$(target)_$(entry)_TARGETS), \
             $(NONRECURSIVE_TARGETS_$(target)_$(entry)_FILE), \
-            $(NONRECURSIVE_TARGETS_$(target)_$(entry)_TARGETS) \
+            $(NONRECURSIVE_TARGETS_$(target)_$(entry)_DIRECTORY), \
         )) \
     ) \
 )
 
 INCLUDED_NONRECURSIVE_MK := 1
 endif
 
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -61,18 +61,18 @@ CheckArgumentsWithinEval(JSContext *cx, 
     // Force construction of arguments objects for functions that use
     // |arguments| within an eval.
     RootedScript script(cx, fun->nonLazyScript());
     if (script->argumentsHasVarBinding()) {
         if (!JSScript::argumentsOptimizationFailed(cx, script))
             return false;
     }
 
-    // It's an error to use |arguments| in a generator expression.
-    if (script->isGeneratorExp) {
+    // It's an error to use |arguments| in a legacy generator expression.
+    if (script->isGeneratorExp && script->isLegacyGenerator) {
         parser.report(ParseError, false, NULL, JSMSG_BAD_GENEXP_BODY, js_arguments_str);
         return false;
     }
 
     return true;
 }
 
 static bool
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -386,17 +386,17 @@ template <typename ParseHandler>
 Parser<ParseHandler>::Parser(ExclusiveContext *cx, LifoAlloc *alloc,
                              const CompileOptions &options,
                              const jschar *chars, size_t length, bool foldConstants,
                              Parser<SyntaxParseHandler> *syntaxParser,
                              LazyScript *lazyOuterFunction)
   : AutoGCRooter(cx, PARSER),
     context(cx),
     alloc(*alloc),
-    tokenStream(cx, options, chars, length, thisForCtor(), keepAtoms),
+    tokenStream(cx, options, chars, length, thisForCtor()),
     traceListHead(NULL),
     pc(NULL),
     sct(NULL),
     ss(NULL),
     keepAtoms(cx->perThreadData),
     foldConstants(foldConstants),
     abortedSyntaxParse(false),
     handler(cx, *alloc, tokenStream, foldConstants, syntaxParser, lazyOuterFunction)
@@ -1063,17 +1063,17 @@ Parser<ParseHandler>::functionBody(Funct
         Node kid = assignExpr();
         if (!kid)
             return null();
 
         pn = handler.newReturnStatement(kid, handler.getPosition(kid));
         if (!pn)
             return null();
 
-        if (pc->sc->asFunctionBox()->isGenerator()) {
+        if (pc->sc->asFunctionBox()->isLegacyGenerator()) {
             reportBadReturn(pn, ParseError,
                             JSMSG_BAD_GENERATOR_RETURN,
                             JSMSG_BAD_ANON_GENERATOR_RETURN);
             return null();
         }
     }
 
     /* Check for falling off the end of a function that returns a value. */
@@ -4402,25 +4402,27 @@ Parser<ParseHandler>::returnStatementOrY
     uint32_t begin = pos().begin;
 
     if (!pc->sc->isFunctionBox()) {
         report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD,
                isYield ? js_yield_str : js_return_str);
         return null();
     }
 
+    // Legacy generators are identified by the presence of "yield" in their
+    // bodies.  We only see "yield" as TOK_YIELD in JS 1.7+.
     if (isYield) {
         if (!abortIfSyntaxParser())
             return null();
 
         // If we're within parens, we won't know if this is a generator
         // expression until we see a |for| token, so we have to delay flagging
         // the current function.
         if (pc->parenDepth == 0) {
-            pc->sc->asFunctionBox()->setIsGenerator();
+            pc->sc->asFunctionBox()->setIsLegacyGenerator();
         } else {
             pc->yieldCount++;
             pc->yieldOffset = begin;
         }
     }
 
     // Parse an optional operand.
     //
@@ -4459,17 +4461,17 @@ Parser<ParseHandler>::returnStatementOrY
     }
 
     Node pn = isYield
               ? handler.newUnary(PNK_YIELD, JSOP_YIELD, begin, exprNode)
               : handler.newReturnStatement(exprNode, TokenPos(begin, pos().end));
     if (!pn)
         return null();
 
-    if (pc->funHasReturnExpr && pc->sc->asFunctionBox()->isGenerator()) {
+    if (pc->funHasReturnExpr && pc->sc->asFunctionBox()->isLegacyGenerator()) {
         /* As in Python (see PEP-255), disallow return v; in generators. */
         reportBadReturn(pn, ParseError, JSMSG_BAD_GENERATOR_RETURN,
                         JSMSG_BAD_ANON_GENERATOR_RETURN);
         return null();
     }
 
     if (options().extraWarningsOption && pc->funHasReturnExpr && pc->funHasReturnVoid &&
         !reportBadReturn(pn, ParseExtraWarning,
@@ -5409,31 +5411,34 @@ class CompExprTransplanter
     bool init() {
         return visitedImplicitArguments.init();
     }
 
     bool transplant(ParseNode *pn);
 };
 
 /*
- * A helper for lazily checking for the presence of illegal |yield| or |arguments|
- * tokens inside of generator expressions. This must be done lazily since we don't
- * know whether we're in a generator expression until we see the "for" token after
- * we've already parsed the body expression.
+ * A helper for lazily checking for the presence of illegal |yield| or
+ * |arguments| tokens inside of legacy generator expressions. This must be done
+ * lazily since we don't know whether we're in a legacy generator expression
+ * until we see the "for" token after we've already parsed the body expression.
+ * (For ES6 generator comprehensions, we won't need this lazy check because the
+ * |for| is at the beginning.)
  *
- * Use in any context which may turn out to be inside a generator expression. This
- * includes parenthesized expressions and argument lists, and it includes the tail
- * of generator expressions.
+ * Use in any context which may turn out to be inside a legacy generator
+ * expression. This includes parenthesized expressions and argument lists, and
+ * it includes the tail of legacy generator expressions.
  *
  * The guard will keep track of any |yield| or |arguments| tokens that occur while
  * parsing the body. As soon as the parser reaches the end of the body expression,
  * call endBody() to reset the context's state, and then immediately call:
  *
- * - checkValidBody() if this *did* turn out to be a generator expression
- * - maybeNoteGenerator() if this *did not* turn out to be a generator expression
+ * - checkValidBody() if this *did* turn out to be a legacy generator expression
+ * - maybeNoteLegacyGenerator() if this *did not* turn out to be a legacy
+ *   generator expression
  */
 template <typename ParseHandler>
 class GenexpGuard
 {
     Parser<ParseHandler> *parser;
     uint32_t startYieldCount;
 
     typedef typename ParseHandler::Node Node;
@@ -5448,17 +5453,17 @@ class GenexpGuard
             pc->yieldOffset = 0;
         }
         startYieldCount = pc->yieldCount;
         pc->parenDepth++;
     }
 
     void endBody();
     bool checkValidBody(Node pn, unsigned err = JSMSG_BAD_GENEXP_BODY);
-    bool maybeNoteGenerator(Node pn);
+    bool maybeNoteLegacyGenerator(Node pn);
 };
 
 template <typename ParseHandler>
 void
 GenexpGuard<ParseHandler>::endBody()
 {
     parser->pc->parenDepth--;
 }
@@ -5492,28 +5497,32 @@ GenexpGuard<ParseHandler>::checkValidBod
  * Check whether a |yield| token has been encountered in the body expression,
  * and if so, note that the current function is a generator function.
  *
  * Call this after endBody() when determining that the body *was not* in a
  * generator expression.
  */
 template <typename ParseHandler>
 bool
-GenexpGuard<ParseHandler>::maybeNoteGenerator(Node pn)
+GenexpGuard<ParseHandler>::maybeNoteLegacyGenerator(Node pn)
 {
     ParseContext<ParseHandler> *pc = parser->pc;
+    // yieldCount is only incremented when we see yield in JS 1.7+ code.
     if (pc->yieldCount > 0) {
         if (!pc->sc->isFunctionBox()) {
+            // FIXME: This error should be detected eagerly, when the yield is
+            // seen.
             parser->report(ParseError, false, ParseHandler::null(),
                            JSMSG_BAD_RETURN_OR_YIELD, js_yield_str);
             return false;
         }
-        pc->sc->asFunctionBox()->setIsGenerator();
+        pc->sc->asFunctionBox()->setIsLegacyGenerator();
         if (pc->funHasReturnExpr) {
-            /* At the time we saw the yield, we might not have set isGenerator yet. */
+            // At the time we saw the yield, we might not have set
+            // isLegacyGenerator yet.
             parser->reportBadReturn(pn, ParseError,
                                     JSMSG_BAD_GENERATOR_RETURN, JSMSG_BAD_ANON_GENERATOR_RETURN);
             return false;
         }
     }
     return true;
 }
 
@@ -5866,17 +5875,17 @@ Parser<FullParseHandler>::comprehensionT
         MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL);
 
         guard.endBody();
 
         if (isGenexp) {
             if (!guard.checkValidBody(pn2))
                 return null();
         } else {
-            if (!guard.maybeNoteGenerator(pn2))
+            if (!guard.maybeNoteLegacyGenerator(pn2))
                 return null();
         }
 
         switch (tt) {
 #if JS_HAS_DESTRUCTURING
           case TOK_LB:
           case TOK_LC:
             if (!checkDestructuring(&data, pn3))
@@ -6052,17 +6061,17 @@ Parser<FullParseHandler>::generatorExpr(
          * come from the kid. So we propagate these flags into genfn. For code
          * simplicity we also do not detect if the flags were only set in the
          * kid and could be removed from pc->sc.
          */
         genFunbox->anyCxFlags = outerpc->sc->anyCxFlags;
         if (outerpc->sc->isFunctionBox())
             genFunbox->funCxFlags = outerpc->sc->asFunctionBox()->funCxFlags;
 
-        genFunbox->setIsGenerator();
+        genFunbox->setIsLegacyGenerator();
         genFunbox->inGenexpLambda = true;
         genfn->pn_blockid = genpc.bodyid;
 
         ParseNode *body = comprehensionTail(pn, outerpc->blockid(), true, outerpc);
         if (!body)
             return null();
         JS_ASSERT(!genfn->pn_body);
         genfn->pn_body = body;
@@ -6142,17 +6151,17 @@ Parser<ParseHandler>::argumentList(Node 
             if (!argNode)
                 return false;
             if (!arg0 || tokenStream.peekToken() == TOK_COMMA) {
                 report(ParseError, false, argNode, JSMSG_BAD_GENERATOR_SYNTAX, js_generator_str);
                 return false;
             }
         } else
 #endif
-        if (arg0 && !guard.maybeNoteGenerator(argNode))
+        if (arg0 && !guard.maybeNoteLegacyGenerator(argNode))
             return false;
 
         arg0 = false;
 
         handler.addList(listNode, argNode);
     } while (tokenStream.matchToken(TOK_COMMA));
 
     if (tokenStream.getToken() != TOK_RP) {
@@ -6811,17 +6820,17 @@ Parser<ParseHandler>::parenExpr(bool *ge
                 return null();
             }
             handler.setEndPosition(pn, pos().end);
             *genexp = true;
         }
     } else
 #endif /* JS_HAS_GENERATOR_EXPRS */
 
-    if (!guard.maybeNoteGenerator(pn))
+    if (!guard.maybeNoteLegacyGenerator(pn))
         return null();
 
     return pn;
 }
 
 template class Parser<FullParseHandler>;
 template class Parser<SyntaxParseHandler>;
 
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -68,18 +68,19 @@ class AnyContextFlags
     { }
 };
 
 class FunctionContextFlags
 {
     // This class's data is all private and so only visible to these friends.
     friend class FunctionBox;
 
-    // We parsed a yield statement in the function.
-    bool isGenerator:1;
+    // We parsed a yield statement in the function, which can happen in JS1.7+
+    // mode.
+    bool isLegacyGenerator:1;
 
     // The function or a function that encloses it may define new local names
     // at runtime through means other than calling eval.
     bool mightAliasLocals:1;
 
     // This function does something that can extend the set of bindings in its
     // call objects --- it does a direct eval in non-strict code, or includes a
     // function statement (as opposed to a function definition).
@@ -124,17 +125,17 @@ class FunctionContextFlags
     // dataflow analysis only looks at how JSOP_ARGUMENTS is used, so it will
     // be unsound in several cases. The frontend filters out such cases by
     // setting this flag which eagerly sets script->needsArgsObj to true.
     //
     bool definitelyNeedsArgsObj:1;
 
   public:
     FunctionContextFlags()
-     :  isGenerator(false),
+     :  isLegacyGenerator(false),
         mightAliasLocals(false),
         hasExtensibleScope(false),
         needsDeclEnvObject(false),
         argumentsHasLocalBinding(false),
         definitelyNeedsArgsObj(false)
     { }
 };
 
@@ -279,24 +280,26 @@ class FunctionBox : public ObjectBox, pu
     template <typename ParseHandler>
     FunctionBox(ExclusiveContext *cx, ObjectBox* traceListHead, JSFunction *fun,
                 ParseContext<ParseHandler> *pc, Directives directives,
                 bool extraWarnings);
 
     ObjectBox *toObjectBox() { return this; }
     JSFunction *function() const { return &object->as<JSFunction>(); }
 
-    bool isGenerator()              const { return funCxFlags.isGenerator; }
+    // In the future, isGenerator will also return true for ES6 generators.
+    bool isGenerator()              const { return isLegacyGenerator(); }
+    bool isLegacyGenerator()        const { return funCxFlags.isLegacyGenerator; }
     bool mightAliasLocals()         const { return funCxFlags.mightAliasLocals; }
     bool hasExtensibleScope()       const { return funCxFlags.hasExtensibleScope; }
     bool needsDeclEnvObject()       const { return funCxFlags.needsDeclEnvObject; }
     bool argumentsHasLocalBinding() const { return funCxFlags.argumentsHasLocalBinding; }
     bool definitelyNeedsArgsObj()   const { return funCxFlags.definitelyNeedsArgsObj; }
 
-    void setIsGenerator()                  { funCxFlags.isGenerator              = true; }
+    void setIsLegacyGenerator()            { funCxFlags.isLegacyGenerator        = true; }
     void setMightAliasLocals()             { funCxFlags.mightAliasLocals         = true; }
     void setHasExtensibleScope()           { funCxFlags.hasExtensibleScope       = true; }
     void setNeedsDeclEnvObject()           { funCxFlags.needsDeclEnvObject       = true; }
     void setArgumentsHasLocalBinding()     { funCxFlags.argumentsHasLocalBinding = true; }
     void setDefinitelyNeedsArgsObj()       { JS_ASSERT(funCxFlags.argumentsHasLocalBinding);
                                              funCxFlags.definitelyNeedsArgsObj   = true; }
 
     // Return whether this function has either specified "use asm" or is
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -260,18 +260,17 @@ TokenStream::SourceCoords::lineNumAndCol
 
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable:4351)
 #endif
 
 /* Initialize members that aren't initialized in |init|. */
 TokenStream::TokenStream(ExclusiveContext *cx, const CompileOptions &options,
-                         const jschar *base, size_t length, StrictModeGetter *smg,
-                         AutoKeepAtoms& keepAtoms)
+                         const jschar *base, size_t length, StrictModeGetter *smg)
   : srcCoords(cx, options.lineno),
     options_(options),
     tokens(),
     cursor(),
     lookahead(),
     lineno(options.lineno),
     flags(),
     linebase(base - options.column),
@@ -293,40 +292,19 @@ TokenStream::TokenStream(ExclusiveContex
     JS_ASSERT_IF(originPrincipals, originPrincipals->refcount);
 
     // Column numbers are computed as offsets from the current line's base, so the
     // initial line's base must be included in the buffer. linebase and userbuf
     // were adjusted above, and if we are starting tokenization part way through
     // this line then adjust the next character.
     userbuf.setAddressOfNextRawChar(base);
 
-    /*
-     * This table holds all the token kinds that satisfy these properties:
-     * - A single char long.
-     * - Cannot be a prefix of any longer token (e.g. '+' is excluded because
-     *   '+=' is a valid token).
-     *
-     * The few token kinds satisfying these properties cover roughly 35--45%
-     * of the tokens seen in practice.
-     *
-     * Nb: oneCharTokens, maybeEOL and maybeStrSpecial could be static, but
-     * initializing them this way is a bit easier.  Don't worry, the time to
-     * initialize them for each TokenStream is trivial.  See bug 639420.
-     */
-    memset(oneCharTokens, 0, sizeof(oneCharTokens));
-    oneCharTokens[unsigned(';')] = TOK_SEMI;
-    oneCharTokens[unsigned(',')] = TOK_COMMA;
-    oneCharTokens[unsigned('?')] = TOK_HOOK;
-    oneCharTokens[unsigned('[')] = TOK_LB;
-    oneCharTokens[unsigned(']')] = TOK_RB;
-    oneCharTokens[unsigned('{')] = TOK_LC;
-    oneCharTokens[unsigned('}')] = TOK_RC;
-    oneCharTokens[unsigned('(')] = TOK_LP;
-    oneCharTokens[unsigned(')')] = TOK_RP;
-    oneCharTokens[unsigned('~')] = TOK_BITNOT;
+    // Nb: the following tables could be static, but initializing them here is
+    // much easier.  Don't worry, the time to initialize them for each
+    // TokenStream is trivial.  See bug 639420.
 
     /* See getChar() for an explanation of maybeEOL[]. */
     memset(maybeEOL, 0, sizeof(maybeEOL));
     maybeEOL[unsigned('\n')] = true;
     maybeEOL[unsigned('\r')] = true;
     maybeEOL[unsigned(LINE_SEPARATOR & 0xff)] = true;
     maybeEOL[unsigned(PARA_SEPARATOR & 0xff)] = true;
 
@@ -501,17 +479,17 @@ TokenStream::peekChars(int n, jschar *cp
     for (i = 0; i < n; i++) {
         c = getCharIgnoreEOL();
         if (c == EOF)
             break;
         if (c == '\n') {
             ungetCharIgnoreEOL(c);
             break;
         }
-        cp[i] = (jschar)c;
+        cp[i] = jschar(c);
     }
     for (j = i - 1; j >= 0; j--)
         ungetCharIgnoreEOL(cp[j]);
     return i == n;
 }
 
 const jschar *
 TokenStream::TokenBuf::findEOLMax(const jschar *p, size_t max)
@@ -894,17 +872,17 @@ TokenStream::getSourceMappingURL(bool is
             return false;
 
         PodCopy(sourceMap, tokenbuf.begin(), sourceMapLength);
         sourceMap[sourceMapLength] = '\0';
     }
     return true;
 }
 
-Token *
+JS_ALWAYS_INLINE Token *
 TokenStream::newToken(ptrdiff_t adjust)
 {
     cursor = (cursor + 1) & ntokensMask;
     Token *tp = &tokens[cursor];
     tp->pos.begin = userbuf.addressOfNextRawChar() + adjust - userbuf.base();
 
     // NOTE: tp->pos.end is not set until the very end of getTokenInternal().
     MOZ_MAKE_MEM_UNDEFINED(&tp->pos.end, sizeof(tp->pos.end));
@@ -989,66 +967,83 @@ TokenStream::checkForKeyword(const jscha
             return true;
     }
 
     /* Strict reserved word. */
     return reportStrictModeError(JSMSG_RESERVED_ID, kw->chars);
 }
 
 enum FirstCharKind {
-    Other,
-    OneChar,
+    // A jschar has the 'OneChar' kind if it, by itself, constitutes a valid
+    // token that cannot also be a prefix of a longer token.  E.g. ';' has the
+    // OneChar kind, but '+' does not, because '++' and '+=' are valid longer tokens
+    // that begin with '+'.
+    //
+    // The few token kinds satisfying these properties cover roughly 35--45%
+    // of the tokens seen in practice.
+    //
+    // We represent the 'OneChar' kind with any positive value less than
+    // TOK_LIMIT.  This representation lets us associate each one-char token
+    // jschar with a TokenKind and thus avoid a subsequent jschar-to-TokenKind
+    // conversion.
+    OneChar_Min = 0,
+    OneChar_Max = TOK_LIMIT - 1,
+
+    Space = TOK_LIMIT,
     Ident,
-    Dot,
-    Equals,
-    String,
     Dec,
-    Colon,
-    Plus,
+    String,
+    EOL,
     BasePrefix,
+    Other,
 
-    /* These two must be last, so that |c >= Space| matches both. */
-    Space,
-    EOL
+    LastCharKind = Other
 };
 
-#define _______ Other
-
 /*
- * OneChar:  40,  41,  44,  59,  63,  91,  93, 123, 125, 126:
- *          '(', ')', ',', ';', '?', '[', ']', '{', '}', '~'
+ * OneChar: 40,  41,  44,  58,  59,  63,  91,  93,  123, 125, 126:
+ *          '(', ')', ',', ':', ';', '?', '[', ']', '{', '}', '~'
  * Ident:   36, 65..90, 95, 97..122: '$', 'A'..'Z', '_', 'a'..'z'
  * Dot:     46: '.'
  * Equals:  61: '='
  * String:  34, 39: '"', '\''
  * Dec:     49..57: '1'..'9'
- * Colon:   58: ':'
  * Plus:    43: '+'
  * BasePrefix:  48: '0'
- * Space:   9, 11, 12: '\t', '\v', '\f'
+ * Space:   9, 11, 12, 32: '\t', '\v', '\f', ' '
  * EOL:     10, 13: '\n', '\r'
  */
+
+#define T_COMMA     TOK_COMMA
+#define T_COLON     TOK_COLON
+#define T_BITNOT    TOK_BITNOT
+#define _______ Other
 static const uint8_t firstCharKinds[] = {
 /*         0        1        2        3        4        5        6        7        8        9    */
 /*   0+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______,   Space,
 /*  10+ */     EOL,   Space,   Space,     EOL, _______, _______, _______, _______, _______, _______,
 /*  20+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
 /*  30+ */ _______, _______,   Space, _______,  String, _______,   Ident, _______, _______,  String,
-/*  40+ */ OneChar, OneChar, _______,    Plus, OneChar, _______,     Dot, _______, BasePrefix,  Dec,
-/*  50+ */     Dec,     Dec,     Dec,     Dec,     Dec,     Dec,     Dec,     Dec,   Colon, OneChar,
-/*  60+ */ _______,  Equals, _______, OneChar, _______,   Ident,   Ident,   Ident,   Ident,   Ident,
+/*  40+ */  TOK_LP,  TOK_RP, _______, _______, T_COMMA,_______,  _______, _______,BasePrefix,  Dec,
+/*  50+ */     Dec,     Dec,     Dec,     Dec,     Dec,     Dec,     Dec,    Dec,  T_COLON,TOK_SEMI,
+/*  60+ */ _______, _______, _______,TOK_HOOK, _______,   Ident,   Ident,   Ident,   Ident,   Ident,
 /*  70+ */   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,
 /*  80+ */   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,
-/*  90+ */   Ident, OneChar, _______, OneChar, _______,   Ident, _______,   Ident,   Ident,   Ident,
+/*  90+ */   Ident,  TOK_LB, _______,  TOK_RB, _______,   Ident, _______,   Ident,   Ident,   Ident,
 /* 100+ */   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,
 /* 110+ */   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,
-/* 120+ */   Ident,   Ident,   Ident, OneChar, _______, OneChar, OneChar, _______
+/* 120+ */   Ident,   Ident,   Ident,  TOK_LC, _______,  TOK_RC,T_BITNOT, _______
 };
+#undef T_COMMA
+#undef T_COLON
+#undef T_BITNOT
+#undef _______
 
-#undef _______
+static_assert(LastCharKind < (1 << (sizeof(firstCharKinds[0]) * 8)),
+              "Elements of firstCharKinds[] are too small");
 
 TokenKind
 TokenStream::getTokenInternal()
 {
     TokenKind tt;
     int c, qc;
     Token *tp;
     FirstCharKind c1kind;
@@ -1093,144 +1088,172 @@ TokenStream::getTokenInternal()
             goto identifier;
         }
 
         goto badchar;
     }
 
     /*
      * Get the token kind, based on the first char.  The ordering of c1kind
-     * comparison is based on the frequency of tokens in real code.  Minified
-     * and non-minified code have different characteristics, mostly in that
-     * whitespace occurs much less in minified code.  Token kinds that fall in
-     * the 'Other' category typically account for less than 2% of all tokens,
-     * so their order doesn't matter much.
+     * comparison is based on the frequency of tokens in real code -- Parsemark
+     * (which represents typical JS code on the web) and the Unreal demo (which
+     * represents asm.js code).
+     *
+     *                  Parsemark   Unreal
+     *  OneChar         32.9%       39.7%
+     *  Space           25.0%        0.6%
+     *  Ident           19.2%       36.4%
+     *  Dec              7.2%        5.1%
+     *  String           7.9%        0.0%
+     *  EOL              1.7%        0.0%
+     *  BasePrefix       0.4%        4.9%
+     *  Other            5.7%       13.3%
+     *
+     * The ordering is based mostly only Parsemark frequencies, with Unreal
+     * frequencies used to break close categories (e.g. |Dec| and |String|).
+     * |Other| is biggish, but no other token kind is common enough for it to
+     * be worth adding extra values to FirstCharKind.
      */
     c1kind = FirstCharKind(firstCharKinds[c]);
 
     /*
-     * Skip over whitespace chars;  update line state on EOLs.  Even though
-     * whitespace isn't very common in minified code we have to handle it first
-     * (and jump back to 'retry') before calling newToken().
+     * Look for an unambiguous single-char token.
      */
-    if (c1kind >= Space) {
-        if (c1kind == EOL) {
-            /* If it's a \r\n sequence: treat as a single EOL, skip over the \n. */
-            if (c == '\r' && userbuf.hasRawChars())
-                userbuf.matchRawChar('\n');
-            updateLineInfoForEOL();
-            updateFlagsForEOL();
-        }
-        goto retry;
+    if (c1kind < OneChar_Max) {
+        tp = newToken(-1);
+        tt = TokenKind(c1kind);
+        goto out;
     }
 
-    tp = newToken(-1);
-
     /*
-     * Look for an unambiguous single-char token.
+     * Skip over non-EOL whitespace chars.
      */
-    if (c1kind == OneChar) {
-        tt = (TokenKind)oneCharTokens[c];
-        goto out;
-    }
+    if (c1kind == Space)
+        goto retry;
 
     /*
      * Look for an identifier.
      */
     if (c1kind == Ident) {
+        tp = newToken(-1);
         identStart = userbuf.addressOfNextRawChar() - 1;
         hadUnicodeEscape = false;
 
       identifier:
         for (;;) {
             c = getCharIgnoreEOL();
             if (c == EOF)
                 break;
             if (!IsIdentifierPart(c)) {
                 if (c != '\\' || !matchUnicodeEscapeIdent(&qc))
                     break;
                 hadUnicodeEscape = true;
             }
         }
         ungetCharIgnoreEOL(c);
 
-        /* Convert the escapes by putting into tokenbuf. */
-        if (hadUnicodeEscape && !putIdentInTokenbuf(identStart))
-            goto error;
+        /*
+         * Identifiers containing no Unicode escapes can be processed directly
+         * from userbuf.  The rest must use the escapes converted via tokenbuf
+         * before atomizing.
+         */
+        const jschar *chars;
+        size_t length;
+        if (hadUnicodeEscape) {
+            if (!putIdentInTokenbuf(identStart))
+                goto error;
+
+            chars = tokenbuf.begin();
+            length = tokenbuf.length();
+        } else {
+            chars = identStart;
+            length = userbuf.addressOfNextRawChar() - identStart;
+        }
 
         /* Check for keywords unless parser asks us to ignore keywords. */
         if (!(flags & TSF_KEYWORD_IS_NAME)) {
-            const jschar *chars;
-            size_t length;
-            if (hadUnicodeEscape) {
-                chars = tokenbuf.begin();
-                length = tokenbuf.length();
-            } else {
-                chars = identStart;
-                length = userbuf.addressOfNextRawChar() - identStart;
-            }
             tt = TOK_NAME;
             if (!checkForKeyword(chars, length, &tt))
                 goto error;
-            if (tt != TOK_NAME)
-                goto out;
+            if (tt != TOK_NAME)                goto out;
         }
 
-        /*
-         * Identifiers containing no Unicode escapes can be atomized directly
-         * from userbuf.  The rest must use the escapes converted via
-         * tokenbuf before atomizing.
-         */
-        JSAtom *atom;
-        if (!hadUnicodeEscape)
-            atom = AtomizeChars<CanGC>(cx, identStart, userbuf.addressOfNextRawChar() - identStart);
-        else
-            atom = atomize(cx, tokenbuf);
+        JSAtom *atom = AtomizeChars<CanGC>(cx, chars, length);
         if (!atom)
             goto error;
         tp->setName(atom->asPropertyName());
         tt = TOK_NAME;
         goto out;
     }
 
-    if (c1kind == Dot) {
-        c = getCharIgnoreEOL();
-        if (JS7_ISDEC(c)) {
-            numStart = userbuf.addressOfNextRawChar() - 2;
+    /*
+     * Look for a decimal number.
+     */
+    if (c1kind == Dec) {
+        tp = newToken(-1);
+        numStart = userbuf.addressOfNextRawChar() - 1;
+
+      decimal:
+        decimalPoint = NoDecimal;
+        hasExp = false;
+        while (JS7_ISDEC(c))
+            c = getCharIgnoreEOL();
+
+        if (c == '.') {
             decimalPoint = HasDecimal;
-            hasExp = false;
-            goto decimal_dot;
+          decimal_dot:
+            do {
+                c = getCharIgnoreEOL();
+            } while (JS7_ISDEC(c));
         }
-        if (c == '.') {
-            qc = getCharIgnoreEOL();
-            if (qc == '.') {
-                tt = TOK_TRIPLEDOT;
-                goto out;
+        if (c == 'e' || c == 'E') {
+            hasExp = true;
+            c = getCharIgnoreEOL();
+            if (c == '+' || c == '-')
+                c = getCharIgnoreEOL();
+            if (!JS7_ISDEC(c)) {
+                ungetCharIgnoreEOL(c);
+                reportError(JSMSG_MISSING_EXPONENT);
+                goto error;
             }
-            ungetCharIgnoreEOL(qc);
+            do {
+                c = getCharIgnoreEOL();
+            } while (JS7_ISDEC(c));
         }
         ungetCharIgnoreEOL(c);
-        tt = TOK_DOT;
-        goto out;
-    }
+
+        if (c != EOF && IsIdentifierStart(c)) {
+            reportError(JSMSG_IDSTART_AFTER_NUMBER);
+            goto error;
+        }
 
-    if (c1kind == Equals) {
-        if (matchChar('='))
-            tt = matchChar('=') ? TOK_STRICTEQ : TOK_EQ;
-        else if (matchChar('>'))
-            tt = TOK_ARROW;
-        else
-            tt = TOK_ASSIGN;
+        /*
+         * Unlike identifiers and strings, numbers cannot contain escaped
+         * chars, so we don't need to use tokenbuf.  Instead we can just
+         * convert the jschars in userbuf directly to the numeric value.
+         */
+        double dval;
+        if (!((decimalPoint == HasDecimal) || hasExp)) {
+            if (!GetDecimalInteger(cx, numStart, userbuf.addressOfNextRawChar(), &dval))
+                goto error;
+        } else {
+            const jschar *dummy;
+            if (!js_strtod(cx, numStart, userbuf.addressOfNextRawChar(), &dummy, &dval))
+                goto error;
+        }
+        tp->setNumber(dval, decimalPoint);
+        tt = TOK_NUMBER;
         goto out;
     }
 
     /*
      * Look for a string.
      */
     if (c1kind == String) {
+        tp = newToken(-1);
         qc = c;
         tokenbuf.clear();
         while (true) {
             /*
              * We need to detect any of these chars:  " or ', \n (or its
              * equivalents), \\, EOF.  We use maybeStrSpecial[] in a manner
              * similar to maybeEOL[], see above.  Because we detect EOL
              * sequences here and put them back immediately, we can use
@@ -1269,17 +1292,17 @@ TokenStream::getTokenInternal()
                                     val = 8 * val + JS7_UNDEC(c);
                                     if (val <= 0377)
                                         getChar();
                                     else
                                         val = save;
                                 }
                             }
 
-                            c = (jschar)val;
+                            c = jschar(val);
                         } else if (c == 'u') {
                             jschar cp[4];
                             if (peekChars(4, cp) &&
                                 JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1]) &&
                                 JS7_ISHEX(cp[2]) && JS7_ISHEX(cp[3])) {
                                 c = (((((JS7_UNHEX(cp[0]) << 4)
                                         + JS7_UNHEX(cp[1])) << 4)
                                       + JS7_UNHEX(cp[2])) << 4)
@@ -1321,89 +1344,30 @@ TokenStream::getTokenInternal()
         if (!atom)
             goto error;
         tp->setAtom(atom);
         tt = TOK_STRING;
         goto out;
     }
 
     /*
-     * Look for a decimal number.
+     * Skip over EOL chars, updating line state along the way.
      */
-    if (c1kind == Dec) {
-        numStart = userbuf.addressOfNextRawChar() - 1;
-
-      decimal:
-        decimalPoint = NoDecimal;
-        hasExp = false;
-        while (JS7_ISDEC(c))
-            c = getCharIgnoreEOL();
-
-        if (c == '.') {
-            decimalPoint = HasDecimal;
-          decimal_dot:
-            do {
-                c = getCharIgnoreEOL();
-            } while (JS7_ISDEC(c));
-        }
-        if (c == 'e' || c == 'E') {
-            hasExp = true;
-            c = getCharIgnoreEOL();
-            if (c == '+' || c == '-')
-                c = getCharIgnoreEOL();
-            if (!JS7_ISDEC(c)) {
-                ungetCharIgnoreEOL(c);
-                reportError(JSMSG_MISSING_EXPONENT);
-                goto error;
-            }
-            do {
-                c = getCharIgnoreEOL();
-            } while (JS7_ISDEC(c));
-        }
-        ungetCharIgnoreEOL(c);
-
-        if (c != EOF && IsIdentifierStart(c)) {
-            reportError(JSMSG_IDSTART_AFTER_NUMBER);
-            goto error;
-        }
-
-        /*
-         * Unlike identifiers and strings, numbers cannot contain escaped
-         * chars, so we don't need to use tokenbuf.  Instead we can just
-         * convert the jschars in userbuf directly to the numeric value.
-         */
-        double dval;
-        const jschar *dummy;
-        if (!((decimalPoint == HasDecimal) || hasExp)) {
-            if (!GetPrefixInteger(cx, numStart, userbuf.addressOfNextRawChar(), 10, &dummy, &dval))
-                goto error;
-        } else {
-            if (!js_strtod(cx, numStart, userbuf.addressOfNextRawChar(), &dummy, &dval))
-                goto error;
-        }
-        tp->setNumber(dval, decimalPoint);
-        tt = TOK_NUMBER;
-        goto out;
-    }
-
-    if (c1kind == Colon) {
-        tt = TOK_COLON;
-        goto out;
-    }
-
-    if (c1kind == Plus) {
-        if (matchChar('+'))
-            tt = TOK_INC;
-        else
-            tt = matchChar('=') ? TOK_ADDASSIGN : TOK_PLUS;
-        goto out;
+    if (c1kind == EOL) {
+        /* If it's a \r\n sequence: treat as a single EOL, skip over the \n. */
+        if (c == '\r' && userbuf.hasRawChars())
+            userbuf.matchRawChar('\n');
+        updateLineInfoForEOL();
+        updateFlagsForEOL();
+        goto retry;
     }
 
     // Look for a hexadecimal, octal, or binary number.
     if (c1kind == BasePrefix) {
+        tp = newToken(-1);
         int radix;
         c = getCharIgnoreEOL();
         if (c == 'x' || c == 'X') {
             radix = 16;
             c = getCharIgnoreEOL();
             if (!JS7_ISHEX(c)) {
                 ungetCharIgnoreEOL(c);
                 reportError(JSMSG_MISSING_HEXDIGITS);
@@ -1476,17 +1440,52 @@ TokenStream::getTokenInternal()
         tt = TOK_NUMBER;
         goto out;
     }
 
     /*
      * This handles everything else.
      */
     JS_ASSERT(c1kind == Other);
+    tp = newToken(-1);
     switch (c) {
+      case '.':
+        c = getCharIgnoreEOL();
+        if (JS7_ISDEC(c)) {
+            numStart = userbuf.addressOfNextRawChar() - 2;
+            decimalPoint = HasDecimal;
+            hasExp = false;
+            goto decimal_dot;
+        }
+        if (c == '.') {
+            if (matchChar('.')) {
+                tt = TOK_TRIPLEDOT;
+                goto out;
+            }
+        }
+        ungetCharIgnoreEOL(c);
+        tt = TOK_DOT;
+        break;
+
+      case '=':
+        if (matchChar('='))
+            tt = matchChar('=') ? TOK_STRICTEQ : TOK_EQ;
+        else if (matchChar('>'))
+            tt = TOK_ARROW;
+        else
+            tt = TOK_ASSIGN;
+        break;
+
+      case '+':
+        if (matchChar('+'))
+            tt = TOK_INC;
+        else
+            tt = matchChar('=') ? TOK_ADDASSIGN : TOK_PLUS;
+        break;
+
       case '\\':
         hadUnicodeEscape = matchUnicodeEscapeIdStart(&qc);
         if (hadUnicodeEscape) {
             identStart = userbuf.addressOfNextRawChar() - 6;
             goto identifier;
         }
         goto badchar;
 
@@ -1514,20 +1513,18 @@ TokenStream::getTokenInternal()
         else
             tt = TOK_NOT;
         break;
 
       case '<':
         /* NB: treat HTML begin-comment as comment-till-end-of-line */
         if (matchChar('!')) {
             if (matchChar('-')) {
-                if (matchChar('-')) {
-                    flags |= TSF_IN_HTML_COMMENT;
+                if (matchChar('-'))
                     goto skipline;
-                }
                 ungetChar('-');
             }
             ungetChar('!');
         }
         if (matchChar('<')) {
             tt = matchChar('=') ? TOK_LSHASSIGN : TOK_LSH;
         } else {
             tt = matchChar('=') ? TOK_LE : TOK_LT;
@@ -1555,27 +1552,19 @@ TokenStream::getTokenInternal()
          */
         if (matchChar('/')) {
             c = peekChar();
             if (c == '@' || c == '#') {
                 if (!getSourceMappingURL(false, getChar() == '@'))
                     goto error;
             }
 
-  skipline:
-            /* Optimize line skipping if we are not in an HTML comment. */
-            if (flags & TSF_IN_HTML_COMMENT) {
-                while ((c = getChar()) != EOF && c != '\n') {
-                    if (c == '-' && matchChar('-') && matchChar('>'))
-                        flags &= ~TSF_IN_HTML_COMMENT;
-                }
-            } else {
-                while ((c = getChar()) != EOF && c != '\n')
-                    continue;
-            }
+        skipline:
+            while ((c = getChar()) != EOF && c != '\n')
+                continue;
             ungetChar(c);
             cursor = (cursor - 1) & ntokensMask;
             goto retry;
         }
 
         /*
          * Look for a multi-line comment.
          */
@@ -1664,20 +1653,18 @@ TokenStream::getTokenInternal()
         break;
 
       case '%':
         tt = matchChar('=') ? TOK_MODASSIGN : TOK_MOD;
         break;
 
       case '-':
         if (matchChar('-')) {
-            if (peekChar() == '>' && !(flags & TSF_DIRTYLINE)) {
-                flags &= ~TSF_IN_HTML_COMMENT;
+            if (peekChar() == '>' && !(flags & TSF_DIRTYLINE))
                 goto skipline;
-            }
             tt = TOK_DEC;
         } else {
             tt = matchChar('=') ? TOK_SUBASSIGN : TOK_MINUS;
         }
         break;
 
       badchar:
       default:
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -248,17 +248,17 @@ struct Token {
     TokenPos            pos;            /* token position in file */
     union {
       private:
         friend struct Token;
         PropertyName *name;             /* non-numeric atom */
         JSAtom       *atom;             /* potentially-numeric atom */
         struct {
             double       value;         /* floating point number */
-            DecimalPoint decimalPoint;  /* literal contains . or exponent */
+            DecimalPoint decimalPoint;  /* literal contains '.' */
         } number;
         RegExpFlag      reflags;        /* regexp flags, use tokenbuf to access
                                            regexp chars */
     } u;
 
     /* Mutators */
 
     /*
@@ -319,38 +319,17 @@ enum TokenStreamFlags
 {
     TSF_EOF = 0x02,             /* hit end of file */
     TSF_EOL = 0x04,             /* an EOL was hit in whitespace or a multi-line comment */
     TSF_OPERAND = 0x08,         /* looking for operand, not operator */
     TSF_UNEXPECTED_EOF = 0x10,  /* unexpected end of input, i.e. TOK_EOF not at top-level. */
     TSF_KEYWORD_IS_NAME = 0x20, /* Ignore keywords and return TOK_NAME instead to the parser. */
     TSF_DIRTYLINE = 0x40,       /* non-whitespace since start of line */
     TSF_OCTAL_CHAR = 0x80,      /* observed a octal character escape */
-    TSF_HAD_ERROR = 0x100,      /* returned TOK_ERROR from getToken */
-
-    /*
-     * To handle the hard case of contiguous HTML comments, we want to clear the
-     * TSF_DIRTYINPUT flag at the end of each such comment.  But we'd rather not
-     * scan for --> within every //-style comment unless we have to.  So we set
-     * TSF_IN_HTML_COMMENT when a <!-- is scanned as an HTML begin-comment, and
-     * clear it (and TSF_DIRTYINPUT) when we scan --> either on a clean line, or
-     * only if (ts->flags & TSF_IN_HTML_COMMENT), in a //-style comment.
-     *
-     * This still works as before given a malformed comment hiding hack such as:
-     *
-     *    <script>
-     *      <!-- comment hiding hack #1
-     *      code goes here
-     *      // --> oops, markup for script-unaware browsers goes here!
-     *    </script>
-     *
-     * It does not cope with malformed comment hiding hacks where --> is hidden
-     * by C-style comments, or on a dirty line.  Such cases are already broken.
-     */
-    TSF_IN_HTML_COMMENT = 0x200
+    TSF_HAD_ERROR = 0x100       /* returned TOK_ERROR from getToken */
 };
 
 struct CompileError {
     JSContext *cx;
     JSErrorReport report;
     char *message;
     ErrorArgumentsType argumentsType;
     CompileError(JSContext *cx)
@@ -426,52 +405,35 @@ class MOZ_STACK_CLASS TokenStream
                                                        to power of 2 to avoid divmod by 3 */
     static const unsigned maxLookahead = 2;
     static const unsigned ntokensMask = ntokens - 1;
 
   public:
     typedef Vector<jschar, 32> CharBuffer;
 
     TokenStream(ExclusiveContext *cx, const CompileOptions &options,
-                const jschar *base, size_t length, StrictModeGetter *smg,
-                AutoKeepAtoms& keepAtoms);
+                const jschar *base, size_t length, StrictModeGetter *smg);
 
     ~TokenStream();
 
     /* Accessors. */
     bool onCurrentLine(const TokenPos &pos) const { return srcCoords.isOnThisLine(pos.end, lineno); }
     const Token &currentToken() const { return tokens[cursor]; }
     bool isCurrentTokenType(TokenKind type) const {
         return currentToken().type == type;
     }
-    bool isCurrentTokenType(TokenKind type1, TokenKind type2) const {
-        TokenKind type = currentToken().type;
-        return type == type1 || type == type2;
-    }
     const CharBuffer &getTokenbuf() const { return tokenbuf; }
     const char *getFilename() const { return filename; }
     unsigned getLineno() const { return lineno; }
     unsigned getColumn() const { return userbuf.addressOfNextRawChar() - linebase - 1; }
     JSPrincipals *getOriginPrincipals() const { return originPrincipals; }
     JSVersion versionNumber() const { return VersionNumber(options().version); }
     JSVersion versionWithFlags() const { return options().version; }
     bool hadError() const { return !!(flags & TSF_HAD_ERROR); }
 
-    bool isCurrentTokenEquality() const {
-        return TokenKindIsEquality(currentToken().type);
-    }
-
-    bool isCurrentTokenRelational() const {
-        return TokenKindIsRelational(currentToken().type);
-    }
-
-    bool isCurrentTokenShift() const {
-        return TokenKindIsShift(currentToken().type);
-    }
-
     bool isCurrentTokenAssignment() const {
         return TokenKindIsAssignment(currentToken().type);
     }
 
     /* Flag methods. */
     void setUnexpectedEOF(bool enabled = true) { setFlag(enabled, TSF_UNEXPECTED_EOF); }
 
     bool isUnexpectedEOF() const { return !!(flags & TSF_UNEXPECTED_EOF); }
@@ -913,17 +875,16 @@ class MOZ_STACK_CLASS TokenStream
     unsigned            lineno;         /* current line number */
     unsigned            flags;          /* flags -- see above */
     const jschar        *linebase;      /* start of current line;  points into userbuf */
     const jschar        *prevLinebase;  /* start of previous line;  NULL if on the first line */
     TokenBuf            userbuf;        /* user input buffer */
     const char          *filename;      /* input filename or null */
     jschar              *sourceMap;     /* source map's filename or null */
     CharBuffer          tokenbuf;       /* current token string buffer */
-    int8_t              oneCharTokens[128];  /* table of one-char tokens, indexed by 7-bit char */
     bool                maybeEOL[256];       /* probabilistic EOL lookup table */
     bool                maybeStrSpecial[256];/* speeds up string scanning */
     uint8_t             isExprEnding[TOK_LIMIT]; /* which tokens definitely terminate exprs? */
     ExclusiveContext    *const cx;
     JSPrincipals        *const originPrincipals;
     StrictModeGetter    *strictModeGetter; /* used to test for strict mode */
 
     /*
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -477,20 +477,22 @@ AutoGCRooter::trace(JSTracer *trc)
         AutoScriptVector::VectorImpl &vector = static_cast<AutoScriptVector *>(this)->vector;
         MarkScriptRootRange(trc, vector.length(), vector.begin(), "js::AutoScriptVector.vector");
         return;
       }
 
       case OBJOBJHASHMAP: {
         AutoObjectObjectHashMap::HashMapImpl &map = static_cast<AutoObjectObjectHashMap *>(this)->map;
         for (AutoObjectObjectHashMap::Enum e(map); !e.empty(); e.popFront()) {
-            mozilla::DebugOnly<JSObject *> key = e.front().key;
-            MarkObjectRoot(trc, const_cast<JSObject **>(&e.front().key), "AutoObjectObjectHashMap key");
-            JS_ASSERT(key == e.front().key);  // Needs rewriting for moving GC, see bug 726687.
             MarkObjectRoot(trc, &e.front().value, "AutoObjectObjectHashMap value");
+            JS_SET_TRACING_LOCATION(trc, (void *)&e.front().key);
+            JSObject *key = e.front().key;
+            MarkObjectRoot(trc, &key, "AutoObjectObjectHashMap key");
+            if (key != e.front().key)
+                e.rekeyFront(key);
         }
         return;
       }
 
       case OBJU32HASHMAP: {
         AutoObjectUnsigned32HashMap *self = static_cast<AutoObjectUnsigned32HashMap *>(this);
         AutoObjectUnsigned32HashMap::HashMapImpl &map = self->map;
         for (AutoObjectUnsigned32HashMap::Enum e(map); !e.empty(); e.popFront()) {
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -838,16 +838,28 @@ CodeGenerator::visitCallee(LCallee *lir)
     Address ptr(StackPointer, frameSize() + IonJSFrameLayout::offsetOfCalleeToken());
 
     masm.loadPtr(ptr, callee);
     masm.clearCalleeTag(callee, gen->info().executionMode());
     return true;
 }
 
 bool
+CodeGenerator::visitForceUseV(LForceUseV *lir)
+{
+    return true;
+}
+
+bool
+CodeGenerator::visitForceUseT(LForceUseT *lir)
+{
+    return true;
+}
+
+bool
 CodeGenerator::visitStart(LStart *lir)
 {
     return true;
 }
 
 bool
 CodeGenerator::visitReturn(LReturn *lir)
 {
--- a/js/src/ion/CodeGenerator.h
+++ b/js/src/ion/CodeGenerator.h
@@ -54,16 +54,18 @@ class CodeGenerator : public CodeGenerat
     bool visitLabel(LLabel *lir);
     bool visitNop(LNop *lir);
     bool visitOsiPoint(LOsiPoint *lir);
     bool visitGoto(LGoto *lir);
     bool visitTableSwitch(LTableSwitch *ins);
     bool visitTableSwitchV(LTableSwitchV *ins);
     bool visitParameter(LParameter *lir);
     bool visitCallee(LCallee *lir);
+    bool visitForceUseV(LForceUseV *lir);
+    bool visitForceUseT(LForceUseT *lir);
     bool visitStart(LStart *lir);
     bool visitReturn(LReturn *ret);
     bool visitDefVar(LDefVar *lir);
     bool visitDefFun(LDefFun *lir);
     bool visitOsrEntry(LOsrEntry *lir);
     bool visitOsrScopeChain(LOsrScopeChain *lir);
     bool visitStackArgT(LStackArgT *lir);
     bool visitStackArgV(LStackArgV *lir);
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -189,33 +189,28 @@ IonBuilder::getPolyCallTargets(types::St
             if (obj->as<JSFunction>().isInterpreted() &&
                 !obj->as<JSFunction>().getOrCreateScript(cx))
             {
                 return false;
             }
             DebugOnly<bool> appendOk = targets.append(obj);
             JS_ASSERT(appendOk);
         } else {
-            /* Temporarily disable heavyweight-function inlining. */
-            targets.clear();
-            return true;
-#if 0
             types::TypeObject *typeObj = calleeTypes->getTypeObject(i);
             JS_ASSERT(typeObj);
             if (!typeObj->isFunction() || !typeObj->interpretedFunction) {
                 targets.clear();
                 return true;
             }
             if (!typeObj->interpretedFunction->getOrCreateScript(cx))
                 return false;
             DebugOnly<bool> appendOk = targets.append(typeObj->interpretedFunction);
             JS_ASSERT(appendOk);
 
             *gotLambda = true;
-#endif
         }
     }
 
     // For now, only inline "singleton" lambda calls
     if (*gotLambda && targets.length() > 1)
         targets.clear();
 
     return true;
@@ -3522,16 +3517,21 @@ IonBuilder::inlineScriptedCall(CallInfo 
     // When profiling add Inline_Exit instruction to indicate end of inlined function.
     if (instrumentedProfiling())
         returnBlock->add(MFunctionBoundary::New(NULL, MFunctionBoundary::Inline_Exit));
 
     // Inherit the slots from current and pop |fun|.
     returnBlock->inheritSlots(current);
     returnBlock->pop();
 
+    // If callee is not a constant, add an MForceUse with the callee to make sure that
+    // it gets kept alive across the inlined body.
+    if (!callInfo.fun()->isConstant())
+        returnBlock->add(MForceUse::New(callInfo.fun()));
+
     // Accumulate return values.
     MIRGraphExits &exits = *inlineBuilder.graph().exitAccumulator();
     if (exits.length() == 0) {
         // Inlining of functions that have no exit is not supported.
         calleeScript->analysis()->setIonUninlineable();
         abortReason_ = AbortReason_Inlining;
         return false;
     }
--- a/js/src/ion/LIR-Common.h
+++ b/js/src/ion/LIR-Common.h
@@ -214,16 +214,33 @@ class LParameter : public LInstructionHe
 
 // Stack offset for a word-sized immutable input value to a frame.
 class LCallee : public LInstructionHelper<1, 0, 0>
 {
   public:
     LIR_HEADER(Callee)
 };
 
+class LForceUseV : public LInstructionHelper<0, BOX_PIECES, 0>
+{
+  public:
+    LIR_HEADER(ForceUseV)
+};
+
+class LForceUseT : public LInstructionHelper<0, 1, 0>
+{
+  public:
+    LIR_HEADER(ForceUseT)
+
+    LForceUseT(const LAllocation &value)
+    {
+        setOperand(0, value);
+    }
+};
+
 // Base class for control instructions (goto, branch, etc.)
 template <size_t Succs, size_t Operands, size_t Temps>
 class LControlInstructionHelper : public LInstructionHelper<0, Operands, Temps> {
 
     MBasicBlock *successors_[Succs];
 
   public:
     virtual size_t numSuccessors() const MOZ_FINAL MOZ_OVERRIDE { return Succs; }
--- a/js/src/ion/LOpcodes.h
+++ b/js/src/ion/LOpcodes.h
@@ -13,16 +13,18 @@
     _(OsiPoint)                     \
     _(MoveGroup)                    \
     _(Integer)                      \
     _(Pointer)                      \
     _(Double)                       \
     _(Value)                        \
     _(Parameter)                    \
     _(Callee)                       \
+    _(ForceUseV)                    \
+    _(ForceUseT)                    \
     _(TableSwitch)                  \
     _(TableSwitchV)                 \
     _(Goto)                         \
     _(NewParallelArray)             \
     _(NewArray)                     \
     _(NewObject)                    \
     _(NewSlots)                     \
     _(NewDeclEnvObject)             \
--- a/js/src/ion/Lowering.cpp
+++ b/js/src/ion/Lowering.cpp
@@ -56,16 +56,30 @@ LIRGenerator::visitParameter(MParameter 
 
 bool
 LIRGenerator::visitCallee(MCallee *ins)
 {
     return define(new LCallee(), ins);
 }
 
 bool
+LIRGenerator::visitForceUse(MForceUse *ins)
+{
+    if (ins->input()->type() == MIRType_Value) {
+        LForceUseV *lir = new LForceUseV();
+        if (!useBox(lir, 0, ins->input()));
+            return false;
+        return add(lir);
+    }
+
+    LForceUseT *lir = new LForceUseT(useAnyOrConstant(ins->input()));
+    return add(lir);
+}
+
+bool
 LIRGenerator::visitGoto(MGoto *ins)
 {
     return add(new LGoto(ins->target()));
 }
 
 bool
 LIRGenerator::visitTableSwitch(MTableSwitch *tableswitch)
 {
--- a/js/src/ion/Lowering.h
+++ b/js/src/ion/Lowering.h
@@ -75,16 +75,17 @@ class LIRGenerator : public LIRGenerator
   public:
     bool visitInstruction(MInstruction *ins);
     bool visitBlock(MBasicBlock *block);
 
     // Visitor hooks are explicit, to give CPU-specific versions a chance to
     // intercept without a bunch of explicit gunk in the .cpp.
     bool visitParameter(MParameter *param);
     bool visitCallee(MCallee *callee);
+    bool visitForceUse(MForceUse *forceUse);
     bool visitGoto(MGoto *ins);
     bool visitTableSwitch(MTableSwitch *tableswitch);
     bool visitNewSlots(MNewSlots *ins);
     bool visitNewParallelArray(MNewParallelArray *ins);
     bool visitNewArray(MNewArray *ins);
     bool visitNewObject(MNewObject *ins);
     bool visitNewDeclEnvObject(MNewDeclEnvObject *ins);
     bool visitNewCallObject(MNewCallObject *ins);
--- a/js/src/ion/MIR.h
+++ b/js/src/ion/MIR.h
@@ -991,16 +991,44 @@ class MCallee : public MNullaryInstructi
     static MCallee *New() {
         return new MCallee();
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
+// MForceUse exists to force the use of a resumePoint-recorded
+// instruction at a later point in time, so that the contents don't get
+// discarded when inlining.
+class MForceUse : public MUnaryInstruction
+{
+  public:
+    MForceUse(MDefinition *input)
+      : MUnaryInstruction(input)
+    {
+        setGuard();
+        setResultType(MIRType_None);
+    }
+
+  public:
+    INSTRUCTION_HEADER(ForceUse)
+
+    bool congruentTo(MDefinition *ins) const {
+        return false;
+    }
+
+    static MForceUse *New(MDefinition *input) {
+        return new MForceUse(input);
+    }
+    AliasSet getAliasSet() const {
+        return AliasSet::None();
+    }
+};
+
 class MControlInstruction : public MInstruction
 {
   public:
     MControlInstruction()
     { }
 
     virtual size_t numSuccessors() const = 0;
     virtual MBasicBlock *getSuccessor(size_t i) const = 0;
--- a/js/src/ion/MOpcodes.h
+++ b/js/src/ion/MOpcodes.h
@@ -9,16 +9,17 @@
 
 namespace js {
 namespace ion {
 
 #define MIR_OPCODE_LIST(_)                                                  \
     _(Constant)                                                             \
     _(Parameter)                                                            \
     _(Callee)                                                               \
+    _(ForceUse)                                                             \
     _(TableSwitch)                                                          \
     _(Goto)                                                                 \
     _(Test)                                                                 \
     _(TypeObjectDispatch)                                                   \
     _(FunctionDispatch)                                                     \
     _(PolyInlineDispatch)                                                   \
     _(Compare)                                                              \
     _(Phi)                                                                  \
--- a/js/src/ion/ParallelSafetyAnalysis.cpp
+++ b/js/src/ion/ParallelSafetyAnalysis.cpp
@@ -106,16 +106,17 @@ class ParallelSafetyVisitor : public MIn
     bool convertToBailout(MBasicBlock *block, MInstruction *ins);
 
     // I am taking the policy of blacklisting everything that's not
     // obviously safe for now.  We can loosen as we need.
 
     SAFE_OP(Constant)
     SAFE_OP(Parameter)
     SAFE_OP(Callee)
+    SAFE_OP(ForceUse)
     SAFE_OP(TableSwitch)
     SAFE_OP(Goto)
     SAFE_OP(Test)
     SAFE_OP(Compare)
     SAFE_OP(Phi)
     SAFE_OP(Beta)
     UNSAFE_OP(OsrValue)
     UNSAFE_OP(OsrScopeChain)
--- a/js/src/ion/arm/CodeGenerator-arm.cpp
+++ b/js/src/ion/arm/CodeGenerator-arm.cpp
@@ -166,16 +166,32 @@ CodeGeneratorARM::generateOutOfLineCode(
     }
 
     return true;
 }
 
 bool
 CodeGeneratorARM::bailoutIf(Assembler::Condition condition, LSnapshot *snapshot)
 {
+    CompileInfo &info = snapshot->mir()->block()->info();
+    switch (info.executionMode()) {
+
+      case ParallelExecution: {
+        // in parallel mode, make no attempt to recover, just signal an error.
+        OutOfLineAbortPar *ool = oolAbortPar(ParallelBailoutUnsupported,
+                                             snapshot->mir()->block(),
+                                             snapshot->mir()->pc());
+        masm.ma_b(ool->entry(), condition);
+        return true;
+      }
+      case SequentialExecution:
+        break;
+      default:
+        MOZ_ASSUME_UNREACHABLE("No such execution mode");
+    }
     if (!encode(snapshot))
         return false;
 
     // Though the assembler doesn't track all frame pushes, at least make sure
     // the known value makes sense. We can't use bailout tables if the stack
     // isn't properly aligned to the static frame size.
     JS_ASSERT_IF(frameClass_ != FrameSizeClass::None(),
                  frameClass_.frameSize() == masm.framePushed());
@@ -200,16 +216,17 @@ CodeGeneratorARM::bailoutIf(Assembler::C
 bool
 CodeGeneratorARM::bailoutFrom(Label *label, LSnapshot *snapshot)
 {
     JS_ASSERT(label->used());
     JS_ASSERT(!label->bound());
 
     CompileInfo &info = snapshot->mir()->block()->info();
     switch (info.executionMode()) {
+
       case ParallelExecution: {
         // in parallel mode, make no attempt to recover, just signal an error.
         OutOfLineAbortPar *ool = oolAbortPar(ParallelBailoutUnsupported,
                                              snapshot->mir()->block(),
                                              snapshot->mir()->pc());
         masm.retarget(label, ool->entry());
         return true;
       }
@@ -1901,18 +1918,19 @@ bool
 CodeGeneratorARM::visitSoftUDivOrMod(LSoftUDivOrMod *ins)
 {
     Register lhs = ToRegister(ins->lhs());
     Register rhs = ToRegister(ins->rhs());
     Register output = ToRegister(ins->output());
 
     JS_ASSERT(lhs == r0);
     JS_ASSERT(rhs == r1);
-    JS_ASSERT(ins->mirRaw()->isAsmJSUDiv() || ins->mirRaw()->isAsmJSUMod());
-    JS_ASSERT_IF(ins->mirRaw()->isAsmJSUDiv(), output == r0);
+    JS_ASSERT(ins->mirRaw()->isDiv() || ins->mirRaw()->isAsmJSUDiv() ||
+              ins->mirRaw()->isAsmJSUMod());
+    JS_ASSERT_IF(ins->mirRaw()->isDiv() || ins->mirRaw()->isAsmJSUDiv(), output == r0);
     JS_ASSERT_IF(ins->mirRaw()->isAsmJSUMod(), output == r1);
 
     Label afterDiv;
 
     masm.ma_cmp(rhs, Imm32(0));
     Label notzero;
     masm.ma_b(&notzero, Assembler::NonZero);
     masm.ma_mov(Imm32(0), output);
--- a/js/src/ion/arm/Lowering-arm.cpp
+++ b/js/src/ion/arm/Lowering-arm.cpp
@@ -458,17 +458,20 @@ LIRGeneratorARM::visitAsmJSNeg(MAsmJSNeg
 
 bool
 LIRGeneratorARM::lowerUDiv(MInstruction *div)
 {
     MDefinition *lhs = div->getOperand(0);
     MDefinition *rhs = div->getOperand(1);
 
     if (hasIDIV()) {
-        return lowerForALU(new LUDiv, div, lhs, rhs);
+        LUDiv *lir = new LUDiv;
+        lir->setOperand(0, useRegister(lhs));
+        lir->setOperand(1, useRegister(rhs));
+        return define(lir, div);
     } else {
         LSoftUDivOrMod *lir = new LSoftUDivOrMod(useFixed(lhs, r0), useFixed(rhs, r1),
                                                  tempFixed(r2), tempFixed(r3));
         return defineFixed(lir, div, LAllocation(AnyRegister(r0)));
     }
 }
 
 bool
@@ -479,17 +482,20 @@ LIRGeneratorARM::visitAsmJSUDiv(MAsmJSUD
 
 bool
 LIRGeneratorARM::lowerUMod(MInstruction *mod)
 {
     MDefinition *lhs = mod->getOperand(0);
     MDefinition *rhs = mod->getOperand(1);
 
     if (hasIDIV()) {
-        return lowerForALU(new LUMod, mod, lhs, rhs);
+        LUMod *lir = new LUMod;
+        lir->setOperand(0, useRegister(lhs));
+        lir->setOperand(1, useRegister(rhs));
+        return define(lir, mod);
     } else {
         LSoftUDivOrMod *lir = new LSoftUDivOrMod(useFixed(lhs, r0), useFixed(rhs, r1),
                                                  tempFixed(r2), tempFixed(r3));
         return defineFixed(lir, mod, LAllocation(AnyRegister(r1)));
     }
 }
 
 bool
--- a/js/src/ion/arm/MacroAssembler-arm.cpp
+++ b/js/src/ion/arm/MacroAssembler-arm.cpp
@@ -2014,18 +2014,18 @@ void
 MacroAssemblerARMCompat::store32(const Register &src, const Address &address)
 {
     storePtr(src, address);
 }
 
 void
 MacroAssemblerARMCompat::store32(const Imm32 &src, const Address &address)
 {
-    move32(src, ScratchRegister);
-    storePtr(ScratchRegister, address);
+    move32(src, secondScratchReg_);
+    storePtr(secondScratchReg_, address);
 }
 
 void
 MacroAssemblerARMCompat::store32(const Imm32 &imm, const BaseIndex &dest)
 {
     ma_mov(imm, secondScratchReg_);
     store32(secondScratchReg_, dest);
 }
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug898857.js
@@ -0,0 +1,6 @@
+function fillHeap() {
+  var x = 1, tmp;
+  for (var i = 0; i < 50000; ++i)
+    tmp <<=  x / 3;
+}
+RegExp({ toString: fillHeap });
--- a/js/src/jsanalyze.cpp
+++ b/js/src/jsanalyze.cpp
@@ -1822,16 +1822,18 @@ ScriptAnalysis::needsArgsObj(JSContext *
 bool
 ScriptAnalysis::needsArgsObj(JSContext *cx)
 {
     JS_ASSERT(script_->argumentsHasVarBinding());
 
     /*
      * Always construct arguments objects when in debug mode and for generator
      * scripts (generators can be suspended when speculation fails).
+     *
+     * FIXME: Don't build arguments for ES6 generator expressions.
      */
     if (cx->compartment()->debugMode() || script_->isGenerator)
         return true;
 
     /*
      * If the script has dynamic name accesses which could reach 'arguments',
      * the parser will already have checked to ensure there are no explicit
      * uses of 'arguments' in the function. If there are such uses, the script
--- a/js/src/jsatom.h
+++ b/js/src/jsatom.h
@@ -48,16 +48,26 @@ struct JsidHasher
 
 /*
  * Return a printable, lossless char[] representation of a string-type atom.
  * The lifetime of the result matches the lifetime of bytes.
  */
 extern const char *
 AtomToPrintableString(ExclusiveContext *cx, JSAtom *atom, JSAutoByteString *bytes);
 
+/* Compute a hash function from chars/length. */
+inline uint32_t
+HashChars(const jschar *chars, size_t length)
+{
+    uint32_t h = 0;
+    for (; length; chars++, length--)
+        h = JS_ROTATE_LEFT32(h, 4) ^ *chars;
+    return h;
+}
+
 class AtomStateEntry
 {
     uintptr_t bits;
 
     static const uintptr_t NO_TAG_MASK = uintptr_t(-1) - 1;
 
   public:
     AtomStateEntry() : bits(0) {}
@@ -90,17 +100,17 @@ struct AtomHasher
         const jschar    *chars;
         size_t          length;
         const JSAtom    *atom; /* Optional. */
 
         Lookup(const jschar *chars, size_t length) : chars(chars), length(length), atom(NULL) {}
         inline Lookup(const JSAtom *atom);
     };
 
-    static HashNumber hash(const Lookup &l) { return mozilla::HashString(l.chars, l.length); }
+    static HashNumber hash(const Lookup &l) { return HashChars(l.chars, l.length); }
     static inline bool match(const AtomStateEntry &entry, const Lookup &lookup);
 };
 
 typedef HashSet<AtomStateEntry, AtomHasher, SystemAllocPolicy> AtomSet;
 
 class PropertyName;
 
 }  /* namespace js */
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -514,17 +514,17 @@ static bool
 FindBody(JSContext *cx, HandleFunction fun, StableCharPtr chars, size_t length,
          size_t *bodyStart, size_t *bodyEnd)
 {
     // We don't need principals, since those are only used for error reporting.
     CompileOptions options(cx);
     options.setFileAndLine("internal-findBody", 0)
            .setVersion(fun->nonLazyScript()->getVersion());
     AutoKeepAtoms keepAtoms(cx->perThreadData);
-    TokenStream ts(cx, options, chars.get(), length, NULL, keepAtoms);
+    TokenStream ts(cx, options, chars.get(), length, NULL);
     int nest = 0;
     bool onward = true;
     // Skip arguments list.
     do {
         switch (ts.getToken()) {
           case TOK_NAME:
             if (nest == 0)
                 onward = false;
@@ -1439,17 +1439,17 @@ js::Function(JSContext *cx, unsigned arg
         /*
          * Initialize a tokenstream that reads from the given string.  No
          * StrictModeGetter is needed because this TokenStream won't report any
          * strict mode errors.  Any strict mode errors which might be reported
          * here (duplicate argument names, etc.) will be detected when we
          * compile the function body.
          */
         TokenStream ts(cx, options, collected_args.get(), args_length,
-                       /* strictModeGetter = */ NULL, keepAtoms);
+                       /* strictModeGetter = */ NULL);
 
         /* The argument string may be empty or contain no tokens. */
         TokenKind tt = ts.getToken();
         if (tt != TOK_EOF) {
             for (;;) {
                 /*
                  * Check that it's a name.  This also implicitly guards against
                  * TOK_ERROR, which was already reported.
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -1018,16 +1018,17 @@ js::CloseIterator(JSContext *cx, HandleO
 
             /*
              * Reset the enumerator; it may still be in the cached iterators
              * for this thread, and can be reused.
              */
             ni->props_cursor = ni->props_array;
         }
     } else if (obj->is<GeneratorObject>()) {
+        // FIXME: Only close legacy generators.
         return CloseGenerator(cx, obj);
     }
     return true;
 }
 
 bool
 js::UnwindIteratorForException(JSContext *cx, HandleObject obj)
 {
@@ -1620,31 +1621,34 @@ static JSBool
 CloseGenerator(JSContext *cx, HandleObject obj)
 {
     JSGenerator *gen = obj->as<GeneratorObject>().getGenerator();
     if (!gen) {
         /* Generator prototype object. */
         return true;
     }
 
+    // FIXME: Assert that gen is a legacy generator.
+
     if (gen->state == JSGEN_CLOSED)
         return true;
 
     return SendToGenerator(cx, JSGENOP_CLOSE, obj, gen, JS::UndefinedHandleValue);
 }
 
 JS_ALWAYS_INLINE bool
 IsGenerator(const Value &v)
 {
     return v.isObject() && v.toObject().is<GeneratorObject>();
 }
 
 JS_ALWAYS_INLINE bool
 generator_send_impl(JSContext *cx, CallArgs args)
 {
+    // FIXME: Change assertion to IsLegacyGenerator().
     JS_ASSERT(IsGenerator(args.thisv()));
 
     RootedObject thisObj(cx, &args.thisv().toObject());
 
     JSGenerator *gen = thisObj->as<GeneratorObject>().getGenerator();
     if (!gen || gen->state == JSGEN_CLOSED) {
         /* This happens when obj is the generator prototype. See bug 352885. */
         return js_ThrowStopIteration(cx);
@@ -1652,26 +1656,29 @@ generator_send_impl(JSContext *cx, CallA
 
     if (gen->state == JSGEN_NEWBORN && args.hasDefined(0)) {
         RootedValue val(cx, args[0]);
         js_ReportValueError(cx, JSMSG_BAD_GENERATOR_SEND,
                             JSDVG_SEARCH_STACK, val, NullPtr());
         return false;
     }
 
+    // FIXME: next() takes the send value as an optional argument in ES6
+    // generator objects.
     if (!SendToGenerator(cx, JSGENOP_SEND, thisObj, gen, args.get(0)))
         return false;
 
     args.rval().set(gen->fp->returnValue());
     return true;
 }
 
 JSBool
 generator_send(JSContext *cx, unsigned argc, Value *vp)
 {
+    // FIXME: send() is only a method on legacy generator objects.
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsGenerator, generator_send_impl>(cx, args);
 }
 
 JS_ALWAYS_INLINE bool
 generator_next_impl(JSContext *cx, CallArgs args)
 {
     JS_ASSERT(IsGenerator(args.thisv()));
@@ -1724,16 +1731,17 @@ generator_throw(JSContext *cx, unsigned 
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsGenerator, generator_throw_impl>(cx, args);
 }
 
 JS_ALWAYS_INLINE bool
 generator_close_impl(JSContext *cx, CallArgs args)
 {
+    // FIXME: Change assertion to IsLegacyGenerator().
     JS_ASSERT(IsGenerator(args.thisv()));
 
     RootedObject thisObj(cx, &args.thisv().toObject());
 
     JSGenerator *gen = thisObj->as<GeneratorObject>().getGenerator();
     if (!gen || gen->state == JSGEN_CLOSED) {
         /* This happens when obj is the generator prototype. See bug 352885. */
         args.rval().setUndefined();
@@ -1751,16 +1759,17 @@ generator_close_impl(JSContext *cx, Call
 
     args.rval().set(gen->fp->returnValue());
     return true;
 }
 
 JSBool
 generator_close(JSContext *cx, unsigned argc, Value *vp)
 {
+    // FIXME: close() is only a method on legacy generator objects.
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsGenerator, generator_close_impl>(cx, args);
 }
 
 #define JSPROP_ROPERM   (JSPROP_READONLY | JSPROP_PERMANENT)
 
 static const JSFunctionSpec generator_methods[] = {
     JS_FN("iterator",  iterator_iterator,  0, 0),
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -45,18 +45,18 @@
 using namespace js;
 using namespace js::types;
 
 using mozilla::PodCopy;
 using mozilla::RangedPtr;
 
 /*
  * If we're accumulating a decimal number and the number is >= 2^53, then the
- * fast result from the loop in GetPrefixInteger may be inaccurate. Call
- * js_strtod_harder to get the correct answer.
+ * fast result from the loop in Get{Prefix,Decimal}Integer may be inaccurate.
+ * Call js_strtod_harder to get the correct answer.
  */
 static bool
 ComputeAccurateDecimalInteger(ExclusiveContext *cx,
                               const jschar *start, const jschar *end, double *dp)
 {
     size_t length = end - start;
     char *cstr = cx->pod_malloc<char>(length + 1);
     if (!cstr)
@@ -135,17 +135,17 @@ ComputeAccurateBinaryBaseInteger(const j
     BinaryDigitReader bdr(base, start, end);
 
     /* Skip leading zeroes. */
     int bit;
     do {
         bit = bdr.nextDigit();
     } while (bit == 0);
 
-    JS_ASSERT(bit == 1); // guaranteed by GetPrefixInteger
+    JS_ASSERT(bit == 1); // guaranteed by Get{Prefix,Decimal}Integer
 
     /* Gather the 53 significant bits (including the leading 1). */
     double value = 1.0;
     for (int j = 52; j > 0; j--) {
         bit = bdr.nextDigit();
         if (bit < 0)
             return value;
         value = value * 2 + bit;
@@ -227,16 +227,40 @@ js::GetPrefixInteger(ExclusiveContext *c
     if (base == 10)
         return ComputeAccurateDecimalInteger(cx, start, s, dp);
     if ((base & (base - 1)) == 0)
         *dp = ComputeAccurateBinaryBaseInteger(start, s, base);
 
     return true;
 }
 
+bool
+js::GetDecimalInteger(ExclusiveContext *cx, const jschar *start, const jschar *end, double *dp)
+{
+    JS_ASSERT(start <= end);
+
+    const jschar *s = start;
+    double d = 0.0;
+    for (; s < end; s++) {
+        jschar c = *s;
+        JS_ASSERT('0' <= c && c <= '9');
+        int digit = c - '0';
+        d = d * 10 + digit;
+    }
+
+    *dp = d;
+
+    // If we haven't reached the limit of integer precision, we're done.
+    if (d < DOUBLE_INTEGRAL_PRECISION_LIMIT)
+        return true;
+
+    // Otherwise compute the correct integer from the prefix of valid digits.
+    return ComputeAccurateDecimalInteger(cx, start, s, dp);
+}
+
 static JSBool
 num_isNaN(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (args.length() == 0) {
         args.rval().setBoolean(true);
         return true;
--- a/js/src/jsnum.h
+++ b/js/src/jsnum.h
@@ -126,16 +126,24 @@ ParseDecimalNumber(const JS::TwoByteChar
  *
  * If [start, end) does not begin with a number with the specified base,
  * *dp == 0 and *endp == start upon return.
  */
 extern bool
 GetPrefixInteger(ExclusiveContext *cx, const jschar *start, const jschar *end, int base,
                  const jschar **endp, double *dp);
 
+/*
+ * This is like GetPrefixInteger, but only deals with base 10, and doesn't have
+ * and |endp| outparam.  It should only be used when the jschars are known to
+ * only contain digits.
+ */
+extern bool
+GetDecimalInteger(ExclusiveContext *cx, const jschar *start, const jschar *end, double *dp);
+
 extern bool
 StringToNumber(ExclusiveContext *cx, JSString *str, double *result);
 
 /* ES5 9.3 ToNumber, overwriting *vp with the appropriate number value. */
 JS_ALWAYS_INLINE bool
 ToNumber(JSContext *cx, JS::MutableHandleValue vp)
 {
 #ifdef DEBUG
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -402,16 +402,17 @@ js::XDRScript(XDRState<mode> *xdr, Handl
         ContainsDynamicNameAccess,
         FunHasExtensibleScope,
         FunNeedsDeclEnvObject,
         FunHasAnyAliasedFormal,
         ArgumentsHasVarBinding,
         NeedsArgsObj,
         IsGenerator,
         IsGeneratorExp,
+        IsLegacyGenerator,
         OwnSource,
         ExplicitUseStrict,
         SelfHosted
     };
 
     uint32_t length, lineno, nslots;
     uint32_t natoms, nsrcnotes, ntrynotes, nobjects, nregexps, nconsts, i;
     uint32_t prologLength, version;
@@ -492,16 +493,18 @@ js::XDRScript(XDRState<mode> *xdr, Handl
         if (script->analyzedArgsUsage() && script->needsArgsObj())
             scriptBits |= (1 << NeedsArgsObj);
         if (!enclosingScript || enclosingScript->scriptSource() != script->scriptSource())
             scriptBits |= (1 << OwnSource);
         if (script->isGenerator)
             scriptBits |= (1 << IsGenerator);
         if (script->isGeneratorExp)
             scriptBits |= (1 << IsGeneratorExp);
+        if (script->isLegacyGenerator)
+            scriptBits |= (1 << IsLegacyGenerator);
 
         JS_ASSERT(!script->compileAndGo);
         JS_ASSERT(!script->hasSingletons);
     }
 
     if (!xdr->codeUint32(&prologLength))
         return JS_FALSE;
     if (!xdr->codeUint32(&version))
@@ -591,16 +594,18 @@ js::XDRScript(XDRState<mode> *xdr, Handl
         if (scriptBits & (1 << ArgumentsHasVarBinding))
             script->setArgumentsHasVarBinding();
         if (scriptBits & (1 << NeedsArgsObj))
             script->setNeedsArgsObj(true);
         if (scriptBits & (1 << IsGenerator))
             script->isGenerator = true;
         if (scriptBits & (1 << IsGeneratorExp))
             script->isGeneratorExp = true;
+        if (scriptBits & (1 << IsLegacyGenerator))
+            script->isLegacyGenerator = true;
     }
 
     JS_STATIC_ASSERT(sizeof(jsbytecode) == 1);
     JS_STATIC_ASSERT(sizeof(jssrcnote) == 1);
 
     if (scriptBits & (1 << OwnSource)) {
         if (!script->scriptSource()->performXDR<mode>(xdr))
             return false;
@@ -1962,16 +1967,17 @@ JSScript::fullyInitFromEmitter(Exclusive
         script->ndefaults = funbox->ndefaults;
     }
 
     RootedFunction fun(cx, NULL);
     if (funbox) {
         JS_ASSERT(!bce->script->noScriptRval);
         script->isGenerator = funbox->isGenerator();
         script->isGeneratorExp = funbox->inGenexpLambda;
+        script->isLegacyGenerator = funbox->isLegacyGenerator();
         script->setFunction(funbox->function());
     }
 
     for (unsigned i = 0, n = script->bindings.numArgs(); i < n; ++i) {
         if (script->formalIsAliased(i)) {
             script->funHasAnyAliasedFormal = true;
             break;
         }
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -556,18 +556,26 @@ class JSScript : public js::gc::Cell
     bool            failedShapeGuard:1; /* script has had hoisted shape guard fail */
     bool            hadFrequentBailouts:1;
 #else
     bool            failedBoundsCheckPad:1;
     bool            failedShapeGuardPad:1;
     bool            hadFrequentBailoutsPad:1;
 #endif
     bool            invalidatedIdempotentCache:1; /* idempotent cache has triggered invalidation */
-    bool            isGenerator:1;    /* is a generator */
-    bool            isGeneratorExp:1; /* is a generator expression */
+
+    // All generators have isGenerator set to true.
+    bool            isGenerator:1;
+    // If the generator was created implicitly via a generator expression,
+    // isGeneratorExp will be true.
+    bool            isGeneratorExp:1;
+    // Generators are either legacy-style (JS 1.7+ starless generators with
+    // StopIteration), or ES6-style (function* with boxed return values).
+    bool            isLegacyGenerator:1;
+
     bool            hasScriptCounts:1;/* script has an entry in
                                          JSCompartment::scriptCountsMap */
     bool            hasDebugScript:1; /* script has an entry in
                                          JSCompartment::debugScriptMap */
     bool            hasFreezeConstraints:1; /* freeze constraints for stack
                                              * type sets have been generated */
 
   private:
--- a/js/src/tests/js1_8/genexps/regress-667131.js
+++ b/js/src/tests/js1_8/genexps/regress-667131.js
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 
 //-----------------------------------------------------------------------------
 var BUGNUMBER = 667131;
-var summary = 'yield ignored if maybeNoteGenerator called too late';
+var summary = 'yield ignored if maybeNoteLegacyGenerator called too late';
 var actual = '';
 var expect = '';
 
 function testGenerator(f, desc) {
     reportCompare(f.isGenerator(), true, desc + ": is generator");
     reportCompare(typeof f(), "object", desc + ": calling doesn't crash");
 }
 
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -825,16 +825,31 @@ CloneProperties(JSContext *cx, HandleObj
         /* Privates are not cloned, so be careful! */
         if (obj->hasPrivate())
             clone->setPrivate(obj->getPrivate());
     }
 
     return true;
 }
 
+static gc::AllocKind
+GetObjectAllocKindForClone(JSRuntime *rt, JSObject *obj)
+{
+    if (!gc::IsInsideNursery(rt, (void *)obj))
+        return obj->tenuredGetAllocKind();
+
+    if (obj->is<JSFunction>())
+        return obj->as<JSFunction>().getAllocKind();
+
+    gc::AllocKind kind = gc::GetGCObjectFixedSlotsKind(obj->numFixedSlots());
+    if (CanBeFinalizedInBackground(kind, obj->getClass()))
+        kind = GetBackgroundAllocKind(kind);
+    return kind;
+}
+
 static JSObject *
 CloneObject(JSContext *cx, HandleObject srcObj, CloneMemory &clonedObjects)
 {
     CloneMemory::AddPtr p = clonedObjects.lookupForAdd(srcObj.get());
     if (p)
         return p->value;
     RootedObject clone(cx);
     if (srcObj->is<JSFunction>()) {
@@ -864,17 +879,18 @@ CloneObject(JSContext *cx, HandleObject 
         if (!str)
             return NULL;
         clone = StringObject::create(cx, str);
     } else if (srcObj->is<ArrayObject>()) {
         clone = NewDenseEmptyArray(cx, NULL, TenuredObject);
     } else {
         JS_ASSERT(srcObj->isNative());
         clone = NewObjectWithGivenProto(cx, srcObj->getClass(), NULL, cx->global(),
-                                        srcObj->tenuredGetAllocKind(), SingletonObject);
+                                        GetObjectAllocKindForClone(cx->runtime(), srcObj),
+                                        SingletonObject);
     }
     if (!clone || !clonedObjects.relookupOrAdd(p, srcObj.get(), clone.get()) ||
         !CloneProperties(cx, srcObj, clone, clonedObjects))
     {
         return NULL;
     }
     return clone;
 }
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -21,17 +21,17 @@ namespace js {
  * Bytecode version number. Increment the subtrahend whenever JS bytecode
  * changes incompatibly.
  *
  * This version number is XDR'd near the front of xdr bytecode and
  * aborts deserialization if there is a mismatch between the current
  * and saved versions. If deserialization fails, the data should be
  * invalidated if possible.
  */
-static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 149);
+static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 150);
 
 class XDRBuffer {
   public:
     XDRBuffer(JSContext *cx)
       : context(cx), base(NULL), cursor(NULL), limit(NULL) { }
 
     JSContext *cx() const {
         return context;
--- a/js/xpconnect/crashtests/806751.html
+++ b/js/xpconnect/crashtests/806751.html
@@ -3,17 +3,17 @@
 <head>
 <script>
 
 function boom()
 {
   var frame = document.getElementById("frame");
   var frameWin = frame.contentWindow;
   var frameWinner = Object.create(frameWin);
-  var v = frameWinner.clearTimeout.bind(frameWinner);
+  var v = frameWinner.captureEvents.bind(frameWinner);
   frame.src = "local-file-not-found";
   setTimeout(function() { setTimeout(finish); v(0); });
 }
 
 function finish() {
   document.documentElement.removeAttribute('class');
 }
 
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -4,16 +4,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/. */
 
 /* Sharable code and data for wrapper around JSObjects. */
 
 #include "xpcprivate.h"
 #include "nsArrayEnumerator.h"
+#include "nsContentUtils.h"
 #include "nsWrapperCache.h"
 #include "XPCWrapper.h"
 #include "AccessCheck.h"
 #include "nsJSUtils.h"
 #include "mozilla/Attributes.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
@@ -1027,35 +1028,35 @@ nsXPCWrappedJSClass::CheckForException(X
                 // xpc->MarkErrorUnreported().
                 xpcc->ClearUnreportedError();
                 reportable = !JS_ReportPendingException(cx);
                 if (!xpcc->WasErrorReported())
                     reportable = true;
             }
 
             if (reportable) {
-#ifdef DEBUG
-                static const char line[] =
-                    "************************************************************\n";
-                static const char preamble[] =
-                    "* Call to xpconnect wrapped JSObject produced this error:  *\n";
-                static const char cant_get_text[] =
-                    "FAILED TO GET TEXT FROM EXCEPTION\n";
+                if (nsContentUtils::DOMWindowDumpEnabled()) {
+                    static const char line[] =
+                        "************************************************************\n";
+                    static const char preamble[] =
+                        "* Call to xpconnect wrapped JSObject produced this error:  *\n";
+                    static const char cant_get_text[] =
+                        "FAILED TO GET TEXT FROM EXCEPTION\n";
 
-                fputs(line, stdout);
-                fputs(preamble, stdout);
-                char* text;
-                if (NS_SUCCEEDED(xpc_exception->ToString(&text)) && text) {
-                    fputs(text, stdout);
-                    fputs("\n", stdout);
-                    nsMemory::Free(text);
-                } else
-                    fputs(cant_get_text, stdout);
-                fputs(line, stdout);
-#endif
+                    fputs(line, stdout);
+                    fputs(preamble, stdout);
+                    char* text;
+                    if (NS_SUCCEEDED(xpc_exception->ToString(&text)) && text) {
+                        fputs(text, stdout);
+                        fputs("\n", stdout);
+                        nsMemory::Free(text);
+                    } else
+                        fputs(cant_get_text, stdout);
+                    fputs(line, stdout);
+                }
 
                 // Log the exception to the JS Console, so that users can do
                 // something with it.
                 nsCOMPtr<nsIConsoleService> consoleService
                     (do_GetService(XPC_CONSOLE_CONTRACTID));
                 if (nullptr != consoleService) {
                     nsresult rv;
                     nsCOMPtr<nsIScriptError> scriptError;
--- a/js/xpconnect/src/dom_quickstubs.qsconf
+++ b/js/xpconnect/src/dom_quickstubs.qsconf
@@ -79,21 +79,17 @@ members = [
     'nsIBoxObject.x',
     'nsIBoxObject.y',
     'nsIBoxObject.screenX',
     'nsIBoxObject.screenY',
     'nsIBoxObject.width',
     'nsIBoxObject.height',
 
     # dom/indexedDB
-    'nsIIDBCursor.*',
-    'nsIIDBCursorWithValue.*',
     'nsIIDBKeyRange.*',
-    'nsIIDBRequest.*',
-    'nsIIDBOpenDBRequest.*',
     'nsIIndexedDatabaseManager.*',
 
     # dom/file
     'nsIDOMLockedFile.*',
 
     # dom/quota
     'nsIQuotaManager.*',
     'nsIQuotaRequest.*',
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -32,16 +32,18 @@
 #include "jsdIDebuggerService.h"
 #endif
 
 #include "XPCQuickStubs.h"
 
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/IDBIndexBinding.h"
 #include "mozilla/dom/IDBObjectStoreBinding.h"
+#include "mozilla/dom/IDBOpenDBRequestBinding.h"
+#include "mozilla/dom/IDBRequestBinding.h"
 #include "mozilla/dom/IDBTransactionBinding.h"
 #include "mozilla/dom/IDBVersionChangeEventBinding.h"
 #include "mozilla/dom/TextDecoderBinding.h"
 #include "mozilla/dom/TextEncoderBinding.h"
 #include "mozilla/dom/DOMErrorBinding.h"
 
 #include "nsWrapperCacheInlines.h"
 #include "nsCycleCollectionNoteRootCallback.h"
@@ -262,24 +264,23 @@ xpc::SystemErrorReporter(JSContext *cx, 
               NS_ConvertASCIItoUTF16(rep->filename),
               uclinebuf ? nsDependentString(uclinebuf) : EmptyString(),
               rep->lineno, column, rep->flags,
               "system javascript");
         if (NS_SUCCEEDED(rv))
             consoleService->LogMessage(errorObject);
     }
 
-    /* Log to stderr in debug builds. */
-#ifdef DEBUG
-    fprintf(stderr, "System JS : %s %s:%d\n"