Merge inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 28 Jan 2014 16:25:05 -0500
changeset 165628 7e79536aca0ae7b6117115e3889400d8ff450ba1
parent 165627 128c86a925d7f9ee71c61f90facef32e8ed63c1f (current diff)
parent 165561 50cfbf3d30de7789f44db29763e364c176b1dda1 (diff)
child 165629 2a8f945b28da1976805e3b922d6043661eed98f4
child 165675 52b83e4b3f8b6f5c549e287296f3af8396d947a8
child 165704 020c2d3fca927d9d2eccac91dd9078a87608a1e8
child 166167 43a5a5b96019583096122a8c682e6fd95eb11473
push id39002
push userryanvm@gmail.com
push dateTue, 28 Jan 2014 21:48:50 +0000
treeherdermozilla-inbound@7e79536aca0a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone29.0a1
first release with
nightly linux32
7e79536aca0a / 29.0a1 / 20140129030602 / files
nightly linux64
7e79536aca0a / 29.0a1 / 20140129030602 / files
nightly mac
7e79536aca0a / 29.0a1 / 20140129030602 / files
nightly win32
7e79536aca0a / 29.0a1 / 20140129030602 / files
nightly win64
7e79536aca0a / 29.0a1 / 20140129030602 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c.
--- a/accessible/src/generic/Accessible.cpp
+++ b/accessible/src/generic/Accessible.cpp
@@ -576,17 +576,16 @@ Accessible::VisibilityState()
     return states::INVISIBLE;
 
   // Walk the parent frame chain to see if there's invisible parent or the frame
   // is in background tab.
   if (!frame->StyleVisibility()->IsVisible())
     return states::INVISIBLE;
 
   nsIFrame* curFrame = frame;
-  nsPoint framePos(0, 0);
   do {
     nsView* view = curFrame->GetView();
     if (view && view->GetVisibility() == nsViewVisibility_kHide)
       return states::INVISIBLE;
 
     if (nsLayoutUtils::IsPopup(curFrame))
       return 0;
 
@@ -600,21 +599,21 @@ Accessible::VisibilityState()
         return states::OFFSCREEN;
 
       NS_NOTREACHED("Children of not selected deck panel are not accessible.");
       return states::INVISIBLE;
     }
 
     // If contained by scrollable frame then check that at least 12 pixels
     // around the object is visible, otherwise the object is offscreen.
-    framePos += curFrame->GetPosition();
     nsIScrollableFrame* scrollableFrame = do_QueryFrame(parentFrame);
     if (scrollableFrame) {
       nsRect scrollPortRect = scrollableFrame->GetScrollPortRect();
-      nsRect frameRect(framePos, frame->GetSize());
+      nsRect frameRect = nsLayoutUtils::TransformFrameRectToAncestor(
+        frame, frame->GetRectRelativeToSelf(), parentFrame);
       if (!scrollPortRect.Contains(frameRect)) {
         const nscoord kMinPixels = nsPresContext::CSSPixelsToAppUnits(12);
         scrollPortRect.Deflate(kMinPixels, kMinPixels);
         if (!scrollPortRect.Intersects(frameRect))
           return states::OFFSCREEN;
       }
     }
 
--- a/accessible/tests/mochitest/role/test_aria.html
+++ b/accessible/tests/mochitest/role/test_aria.html
@@ -125,16 +125,20 @@
       for (a in abstract_roles)
         testRole(abstract_roles[a], ROLE_SECTION);
 
       //////////////////////////////////////////////////////////////////////////
       // roles transformed by ARIA state attributes
       testRole("togglebutton", ROLE_TOGGLE_BUTTON);
 
       //////////////////////////////////////////////////////////////////////////
+      // ignore unknown roles, take first known
+      testRole("unknown_roles", ROLE_PUSHBUTTON);
+
+      //////////////////////////////////////////////////////////////////////////
       // misc roles
       testRole("note", ROLE_NOTE);
       testRole("scrollbar", ROLE_SCROLLBAR);
       testRole("dir", ROLE_LIST);
 
       //////////////////////////////////////////////////////////////////////////
       // test document role map update
       var testDoc = getAccessible(document, [nsIAccessibleDocument]);
@@ -295,16 +299,19 @@
   <div role="select" id="select">select</div>
   <!-- test abstract structure roles -->
   <div role="section" id="section">section</div>
   <div role="sectionhead" id="sectionhead">sectionhead</div>
 
   <!-- roles transformed by ARIA state attributes -->
   <button aria-pressed="true" id="togglebutton">
 
+  <!-- take the first known mappable role -->
+  <div role="wiggly:worm abc123 button" id="unknown_roles">worm button</div>
+
   <!-- misc roles -->
   <div role="note" id="note">note</div>
   <div role="scrollbar" id="scrollbar">scrollbar</div>
 
   <div id="dir" role="directory">
     <div role="listitem">A</div>
     <div role="listitem">B</div>
     <div role="listitem">C</div>
--- a/accessible/tests/mochitest/states/test_visibility.html
+++ b/accessible/tests/mochitest/states/test_visibility.html
@@ -114,16 +114,17 @@
     gDocURI += "  <li>item4</li><li>item5</li><li id='li_last'>item6</li>";
     gDocURI += "</ul>";
     gDocURI += "</body></html>";
 
     function doTests()
     {
       testStates("div", 0, 0, STATE_INVISIBLE | STATE_OFFSCREEN);
       testStates("div_off", STATE_OFFSCREEN, 0, STATE_INVISIBLE);
+      testStates("div_transformed", STATE_OFFSCREEN, 0, STATE_INVISIBLE);
       testStates("div_abschild", 0, 0, STATE_INVISIBLE | STATE_OFFSCREEN);
 
       gQueue = new eventQueue();
 
       gQueue.push(new addTabInvoker("about:blank", testBackgroundTab));
       gQueue.push(new loadURIInvoker(gDocURI, testScrolledOff));
 
       gQueue.onFinish = function() { closeBrowserWindow(); }
@@ -155,16 +156,19 @@
 
   <div id="outer_div">
 
     <!-- trivial cases -->
     <div id="div">div</div>
     <div id="div_off" style="position: absolute; left:-999px; top:-999px">
       offscreen!
     </div>
+    <div id="div_transformed" style="transform: translate(-999px, -999px);">
+      transformed!
+    </div>
 
     <!-- edge case: no rect but has out of flow child -->
     <div id="div_abschild">
       <p style="position: absolute; left: 120px; top:120px;">absolute</p>
     </div>
 
   </div>
 </body>
--- a/content/canvas/src/ImageData.cpp
+++ b/content/canvas/src/ImageData.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 et tw=78: */
 /* 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 "mozilla/dom/ImageData.h"
 
+#include "mozilla/CheckedInt.h"
 #include "mozilla/HoldDropJSObjects.h"
 #include "mozilla/dom/ImageDataBinding.h"
 
 #include "jsapi.h"
 
 namespace mozilla {
 namespace dom {
 
@@ -30,16 +31,69 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ImageData)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ImageData)
   tmp->DropData();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
+//static
+ImageData*
+ImageData::Constructor(const GlobalObject& aGlobal,
+                       const uint32_t aWidth,
+                       const uint32_t aHeight,
+                       ErrorResult& aRv)
+{
+  if (aWidth == 0 || aHeight == 0) {
+    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    return nullptr;
+  }
+  CheckedInt<uint32_t> length = CheckedInt<uint32_t>(aWidth) * aHeight * 4;
+  if (!length.isValid()) {
+    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    return nullptr;
+  }
+  JS::Rooted<JSObject*> obj(aGlobal.GetContext(), aGlobal.Get());
+  JSObject* data = Uint8ClampedArray::Create(aGlobal.GetContext(), obj,
+                                             length.value());
+  if (!data) {
+    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+    return nullptr;
+  }
+  return new ImageData(aWidth, aHeight, *data);
+}
+
+//static
+ImageData*
+ImageData::Constructor(const GlobalObject& aGlobal,
+                       const Uint8ClampedArray& aData,
+                       const uint32_t aWidth,
+                       const Optional<uint32_t>& aHeight,
+                       ErrorResult& aRv)
+{
+  uint32_t length = aData.Length();
+  if (length == 0 || length % 4) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return nullptr;
+  }
+  length /= 4;
+  if (aWidth == 0) {
+    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    return nullptr;
+  }
+  uint32_t height = length / aWidth;
+  if (length != aWidth * height ||
+      (aHeight.WasPassed() && aHeight.Value() != height)) {
+    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    return nullptr;
+  }
+  return new ImageData(aWidth, height, *aData.Obj());
+}
+
 void
 ImageData::HoldData()
 {
   mozilla::HoldJSObjects(this);
 }
 
 void
 ImageData::DropData()
--- a/content/canvas/src/ImageData.h
+++ b/content/canvas/src/ImageData.h
@@ -5,16 +5,18 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_ImageData_h
 #define mozilla_dom_ImageData_h
 
 #include "nsIDOMCanvasRenderingContext2D.h"
 
 #include "mozilla/Attributes.h"
+#include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/TypedArray.h"
 #include <stdint.h>
 
 #include "nsCycleCollectionParticipant.h"
 #include "nsTraceRefcnt.h"
 #include "js/GCAPI.h"
 
 namespace mozilla {
 namespace dom {
@@ -35,16 +37,27 @@ public:
   {
     MOZ_COUNT_DTOR(ImageData);
     DropData();
   }
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ImageData)
 
+  static ImageData* Constructor(const GlobalObject& aGlobal,
+                                const uint32_t aWidth,
+                                const uint32_t aHeight,
+                                ErrorResult& aRv);
+
+  static ImageData* Constructor(const GlobalObject& aGlobal,
+                                const Uint8ClampedArray& aData,
+                                const uint32_t aWidth,
+                                const Optional<uint32_t>& aHeight,
+                                ErrorResult& aRv);
+
   uint32_t Width() const
   {
     return mWidth;
   }
   uint32_t Height() const
   {
     return mHeight;
   }
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -1038,60 +1038,65 @@ WebGLContext::ForceClearFramebufferWithD
     // Scope to hide our variables.
     {
         // Sanity-check that all our state is set properly. Otherwise, when we
         // reset out state to what we *think* it is, we'll get it wrong.
 
         // Dither shouldn't matter when we're clearing to {0,0,0,0}.
         MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_SCISSOR_TEST) == mScissorTestEnabled);
 
-        realGLboolean colorWriteMask[4] = {2, 2, 2, 2};
-        GLfloat colorClearValue[4] = {-1.0f, -1.0f, -1.0f, -1.0f};
+        if (initializeColorBuffer) {
+            realGLboolean colorWriteMask[4] = {2, 2, 2, 2};
+            GLfloat colorClearValue[4] = {-1.0f, -1.0f, -1.0f, -1.0f};
 
-        gl->fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorWriteMask);
-        gl->fGetFloatv(LOCAL_GL_COLOR_CLEAR_VALUE, colorClearValue);
+            gl->fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorWriteMask);
+            gl->fGetFloatv(LOCAL_GL_COLOR_CLEAR_VALUE, colorClearValue);
 
-        MOZ_ASSERT(colorWriteMask[0] == mColorWriteMask[0] &&
-                   colorWriteMask[1] == mColorWriteMask[1] &&
-                   colorWriteMask[2] == mColorWriteMask[2] &&
-                   colorWriteMask[3] == mColorWriteMask[3]);
-        MOZ_ASSERT(IsShadowCorrect(mColorClearValue[0], colorClearValue[0]) &&
-                   IsShadowCorrect(mColorClearValue[1], colorClearValue[1]) &&
-                   IsShadowCorrect(mColorClearValue[2], colorClearValue[2]) &&
-                   IsShadowCorrect(mColorClearValue[3], colorClearValue[3]));
+            MOZ_ASSERT(colorWriteMask[0] == mColorWriteMask[0] &&
+                       colorWriteMask[1] == mColorWriteMask[1] &&
+                       colorWriteMask[2] == mColorWriteMask[2] &&
+                       colorWriteMask[3] == mColorWriteMask[3]);
+            MOZ_ASSERT(IsShadowCorrect(mColorClearValue[0], colorClearValue[0]) &&
+                       IsShadowCorrect(mColorClearValue[1], colorClearValue[1]) &&
+                       IsShadowCorrect(mColorClearValue[2], colorClearValue[2]) &&
+                       IsShadowCorrect(mColorClearValue[3], colorClearValue[3]));
+        }
+
+        if (initializeDepthBuffer) {
+            realGLboolean depthWriteMask = 2;
+            GLfloat depthClearValue = -1.0f;
 
 
-        realGLboolean depthWriteMask = 2;
-        GLfloat depthClearValue = -1.0f;
-
-        gl->fGetBooleanv(LOCAL_GL_DEPTH_WRITEMASK, &depthWriteMask);
-        gl->fGetFloatv(LOCAL_GL_DEPTH_CLEAR_VALUE, &depthClearValue);
+            gl->fGetBooleanv(LOCAL_GL_DEPTH_WRITEMASK, &depthWriteMask);
+            gl->fGetFloatv(LOCAL_GL_DEPTH_CLEAR_VALUE, &depthClearValue);
 
-        MOZ_ASSERT(depthWriteMask == mDepthWriteMask);
-        MOZ_ASSERT(IsShadowCorrect(mDepthClearValue, depthClearValue));
-
+            MOZ_ASSERT(depthWriteMask == mDepthWriteMask);
+            MOZ_ASSERT(IsShadowCorrect(mDepthClearValue, depthClearValue));
+        }
 
-        GLuint stencilWriteMaskFront = 0xdeadbad1;
-        GLuint stencilWriteMaskBack  = 0xdeadbad1;
-        GLuint stencilClearValue     = 0xdeadbad1;
+        if (initializeStencilBuffer) {
+            GLuint stencilWriteMaskFront = 0xdeadbad1;
+            GLuint stencilWriteMaskBack  = 0xdeadbad1;
+            GLuint stencilClearValue     = 0xdeadbad1;
 
-        gl->GetUIntegerv(LOCAL_GL_STENCIL_WRITEMASK,      &stencilWriteMaskFront);
-        gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_WRITEMASK, &stencilWriteMaskBack);
-        gl->GetUIntegerv(LOCAL_GL_STENCIL_CLEAR_VALUE,    &stencilClearValue);
+            gl->GetUIntegerv(LOCAL_GL_STENCIL_WRITEMASK,      &stencilWriteMaskFront);
+            gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_WRITEMASK, &stencilWriteMaskBack);
+            gl->GetUIntegerv(LOCAL_GL_STENCIL_CLEAR_VALUE,    &stencilClearValue);
+
+            GLuint stencilBits = 0;
+            gl->GetUIntegerv(LOCAL_GL_STENCIL_BITS, &stencilBits);
+            GLuint stencilMask = (GLuint(1) << stencilBits) - 1;
 
-        GLuint stencilBits = 0;
-        gl->GetUIntegerv(LOCAL_GL_STENCIL_BITS, &stencilBits);
-        GLuint stencilMask = (GLuint(1) << stencilBits) - 1;
-
-        MOZ_ASSERT( ( stencilWriteMaskFront & stencilMask) ==
-                    (mStencilWriteMaskFront & stencilMask) );
-        MOZ_ASSERT( ( stencilWriteMaskBack & stencilMask) ==
-                    (mStencilWriteMaskBack & stencilMask) );
-        MOZ_ASSERT( ( stencilClearValue & stencilMask) ==
-                    (mStencilClearValue & stencilMask) );
+            MOZ_ASSERT( ( stencilWriteMaskFront & stencilMask) ==
+                        (mStencilWriteMaskFront & stencilMask) );
+            MOZ_ASSERT( ( stencilWriteMaskBack & stencilMask) ==
+                        (mStencilWriteMaskBack & stencilMask) );
+            MOZ_ASSERT( ( stencilClearValue & stencilMask) ==
+                        (mStencilClearValue & stencilMask) );
+        }
     }
 #endif
 
     // Prepare GL state for clearing.
     gl->fDisable(LOCAL_GL_SCISSOR_TEST);
 
     if (initializeColorBuffer) {
 
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -633,40 +633,42 @@ WebGLContext::CopyTexSubImage2D(GLenum t
     GLsizei texHeight = imageInfo.Height();
 
     if (xoffset + width > texWidth || xoffset + width < 0)
       return ErrorInvalidValue("copyTexSubImage2D: xoffset+width is too large");
 
     if (yoffset + height > texHeight || yoffset + height < 0)
       return ErrorInvalidValue("copyTexSubImage2D: yoffset+height is too large");
 
-    GLenum format = imageInfo.InternalFormat();
-    bool texFormatRequiresAlpha = format == LOCAL_GL_RGBA ||
-                                  format == LOCAL_GL_ALPHA ||
-                                  format == LOCAL_GL_LUMINANCE_ALPHA;
+    GLenum internalFormat = imageInfo.InternalFormat();
+    bool texFormatRequiresAlpha = (internalFormat == LOCAL_GL_RGBA ||
+                                   internalFormat == LOCAL_GL_ALPHA ||
+                                   internalFormat == LOCAL_GL_LUMINANCE_ALPHA);
     bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment(0).HasAlpha()
                                                : bool(gl->GetPixelFormat().alpha > 0);
 
     if (texFormatRequiresAlpha && !fboFormatHasAlpha)
         return ErrorInvalidOperation("copyTexSubImage2D: texture format requires an alpha channel "
                                      "but the framebuffer doesn't have one");
 
-    if (format == LOCAL_GL_DEPTH_COMPONENT ||
-        format == LOCAL_GL_DEPTH_STENCIL)
+    if (IsGLDepthFormat(internalFormat) ||
+        IsGLDepthStencilFormat(internalFormat))
+    {
         return ErrorInvalidOperation("copyTexSubImage2D: a base internal format of DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
+    }
 
     if (mBoundFramebuffer)
         if (!mBoundFramebuffer->CheckAndInitializeAttachments())
             return ErrorInvalidFramebufferOperation("copyTexSubImage2D: incomplete framebuffer");
 
     if (imageInfo.HasUninitializedImageData()) {
         tex->DoDeferredImageInitialization(target, level);
     }
 
-    return CopyTexSubImage2D_base(target, level, format, xoffset, yoffset, x, y, width, height, true);
+    return CopyTexSubImage2D_base(target, level, internalFormat, xoffset, yoffset, x, y, width, height, true);
 }
 
 
 already_AddRefed<WebGLProgram>
 WebGLContext::CreateProgram()
 {
     if (IsContextLost())
         return nullptr;
@@ -1177,25 +1179,27 @@ WebGLContext::GenerateMipmap(GLenum targ
     if (!tex->HasImageInfoAt(imageTarget, 0))
     {
         return ErrorInvalidOperation("generateMipmap: Level zero of texture is not defined.");
     }
 
     if (!tex->IsFirstImagePowerOfTwo())
         return ErrorInvalidOperation("generateMipmap: Level zero of texture does not have power-of-two width and height.");
 
-    GLenum format = tex->ImageInfoAt(imageTarget, 0).InternalFormat();
-    if (IsTextureFormatCompressed(format))
+    GLenum internalFormat = tex->ImageInfoAt(imageTarget, 0).InternalFormat();
+    if (IsTextureFormatCompressed(internalFormat))
         return ErrorInvalidOperation("generateMipmap: Texture data at level zero is compressed.");
 
     if (IsExtensionEnabled(WEBGL_depth_texture) &&
-        (format == LOCAL_GL_DEPTH_COMPONENT || format == LOCAL_GL_DEPTH_STENCIL))
+        (IsGLDepthFormat(internalFormat) || IsGLDepthStencilFormat(internalFormat)))
+    {
         return ErrorInvalidOperation("generateMipmap: "
                                      "A texture that has a base internal format of "
                                      "DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
+    }
 
     if (!tex->AreAllLevel0ImageInfosEqual())
         return ErrorInvalidOperation("generateMipmap: The six faces of this cube map have different dimensions, format, or type.");
 
     tex->SetGeneratedMipmap();
 
     MakeContextCurrent();
 
@@ -4120,87 +4124,103 @@ BaseTypeAndSizeFromUniformType(GLenum uT
         default:
             return false;
     }
 
     return true;
 }
 
 
-WebGLTexelFormat mozilla::GetWebGLTexelFormat(GLenum format, GLenum type)
+WebGLTexelFormat mozilla::GetWebGLTexelFormat(GLenum internalformat, GLenum type)
 {
     //
     // WEBGL_depth_texture
-    if (format == LOCAL_GL_DEPTH_COMPONENT) {
+    if (internalformat == LOCAL_GL_DEPTH_COMPONENT) {
         switch (type) {
             case LOCAL_GL_UNSIGNED_SHORT:
                 return WebGLTexelFormat::D16;
             case LOCAL_GL_UNSIGNED_INT:
                 return WebGLTexelFormat::D32;
-            default:
-                MOZ_CRASH("Invalid WebGL texture format/type?");
         }
-    } else if (format == LOCAL_GL_DEPTH_STENCIL) {
+
+        MOZ_CRASH("Invalid WebGL texture format/type?");
+    }
+
+    if (internalformat == LOCAL_GL_DEPTH_STENCIL) {
         switch (type) {
             case LOCAL_GL_UNSIGNED_INT_24_8_EXT:
                 return WebGLTexelFormat::D24S8;
-            default:
-                MOZ_CRASH("Invalid WebGL texture format/type?");
         }
+
+        MOZ_CRASH("Invalid WebGL texture format/type?");
     }
 
+    if (internalformat == LOCAL_GL_DEPTH_COMPONENT16) {
+        return WebGLTexelFormat::D16;
+    }
+
+    if (internalformat == LOCAL_GL_DEPTH_COMPONENT32) {
+        return WebGLTexelFormat::D32;
+    }
+
+    if (internalformat == LOCAL_GL_DEPTH24_STENCIL8) {
+        return WebGLTexelFormat::D24S8;
+    }
 
     if (type == LOCAL_GL_UNSIGNED_BYTE) {
-        switch (format) {
+        switch (internalformat) {
             case LOCAL_GL_RGBA:
             case LOCAL_GL_SRGB_ALPHA_EXT:
                 return WebGLTexelFormat::RGBA8;
             case LOCAL_GL_RGB:
             case LOCAL_GL_SRGB_EXT:
                 return WebGLTexelFormat::RGB8;
             case LOCAL_GL_ALPHA:
                 return WebGLTexelFormat::A8;
             case LOCAL_GL_LUMINANCE:
                 return WebGLTexelFormat::R8;
             case LOCAL_GL_LUMINANCE_ALPHA:
                 return WebGLTexelFormat::RA8;
-            default:
-                MOZ_ASSERT(false, "Coding mistake?! Should never reach this point.");
-                return WebGLTexelFormat::BadFormat;
         }
-    } else if (type == LOCAL_GL_FLOAT) {
+
+        MOZ_CRASH("Invalid WebGL texture format/type?");
+    }
+
+    if (type == LOCAL_GL_FLOAT) {
         // OES_texture_float
-        switch (format) {
+        switch (internalformat) {
             case LOCAL_GL_RGBA:
+            case LOCAL_GL_RGBA32F:
                 return WebGLTexelFormat::RGBA32F;
             case LOCAL_GL_RGB:
                 return WebGLTexelFormat::RGB32F;
             case LOCAL_GL_ALPHA:
                 return WebGLTexelFormat::A32F;
             case LOCAL_GL_LUMINANCE:
                 return WebGLTexelFormat::R32F;
             case LOCAL_GL_LUMINANCE_ALPHA:
                 return WebGLTexelFormat::RA32F;
-            default:
-                MOZ_ASSERT(false, "Coding mistake?! Should never reach this point.");
-                return WebGLTexelFormat::BadFormat;
         }
-    } else {
-        switch (type) {
-            case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
-                return WebGLTexelFormat::RGBA4444;
-            case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
-                return WebGLTexelFormat::RGBA5551;
-            case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
-                return WebGLTexelFormat::RGB565;
-            default:
-                MOZ_ASSERT(false, "Coding mistake?! Should never reach this point.");
-                return WebGLTexelFormat::BadFormat;
-        }
+
+        MOZ_CRASH("Invalid WebGL texture format/type?");
     }
+
+    switch (type) {
+        case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
+           return WebGLTexelFormat::RGBA4444;
+        case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
+           return WebGLTexelFormat::RGBA5551;
+        case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
+           return WebGLTexelFormat::RGB565;
+        default:
+            MOZ_ASSERT(false, "Coding mistake?! Should never reach this point.");
+            return WebGLTexelFormat::BadFormat;
+    }
+
+    MOZ_CRASH("Invalid WebGL texture format/type?");
 }
 
 GLenum
 InternalFormatForFormatAndType(GLenum format, GLenum type, bool isGLES2)
 {
     // ES2 requires that format == internalformat; floating-point is
     // indicated purely by the type that's loaded.  For desktop GL, we
     // have to specify a floating point internal format.
--- a/content/canvas/src/WebGLContextUtils.cpp
+++ b/content/canvas/src/WebGLContextUtils.cpp
@@ -18,16 +18,35 @@
 
 #include "nsIDOMEvent.h"
 #include "nsIDOMDataContainerEvent.h"
 
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
 
+namespace mozilla {
+
+bool
+IsGLDepthFormat(GLenum internalFormat)
+{
+    return (internalFormat == LOCAL_GL_DEPTH_COMPONENT ||
+            internalFormat == LOCAL_GL_DEPTH_COMPONENT16 ||
+            internalFormat == LOCAL_GL_DEPTH_COMPONENT32);
+}
+
+bool
+IsGLDepthStencilFormat(GLenum internalFormat)
+{
+    return (internalFormat == LOCAL_GL_DEPTH_STENCIL ||
+            internalFormat == LOCAL_GL_DEPTH24_STENCIL8);
+}
+
+} // namespace mozilla
+
 void
 WebGLContext::GenerateWarning(const char *fmt, ...)
 {
     va_list ap;
     va_start(ap, fmt);
 
     GenerateWarning(fmt, ap);
 
@@ -62,18 +81,18 @@ WebGLContext::ShouldGenerateWarnings() c
     if (mMaxWarnings == -1) {
         return true;
     }
 
     return mAlreadyGeneratedWarnings < mMaxWarnings;
 }
 
 CheckedUint32
-WebGLContext::GetImageSize(GLsizei height, 
-                           GLsizei width, 
+WebGLContext::GetImageSize(GLsizei height,
+                           GLsizei width,
                            uint32_t pixelSize,
                            uint32_t packOrUnpackAlignment)
 {
     CheckedUint32 checked_plainRowSize = CheckedUint32(width) * pixelSize;
 
     // alignedRowSize = row size rounded up to next multiple of packAlignment
     CheckedUint32 checked_alignedRowSize = RoundedToNextMultipleOf(checked_plainRowSize, packOrUnpackAlignment);
 
@@ -86,17 +105,17 @@ WebGLContext::GetImageSize(GLsizei heigh
 
 void
 WebGLContext::SynthesizeGLError(GLenum err)
 {
     // If there is already a pending error, don't overwrite it;
     // but if there isn't, then we need to check for a gl error
     // that may have occurred before this one and use that code
     // instead.
-    
+
     MakeContextCurrent();
 
     UpdateWebGLErrorAndClearGLError();
 
     if (!mWebGLError)
         mWebGLError = err;
 }
 
@@ -192,42 +211,32 @@ WebGLContext::ErrorName(GLenum error)
             MOZ_ASSERT(false);
             return "[unknown WebGL error!]";
     }
 }
 
 bool
 WebGLContext::IsTextureFormatCompressed(GLenum format)
 {
-    switch(format) {
-        case LOCAL_GL_RGB:
-        case LOCAL_GL_RGBA:
-        case LOCAL_GL_ALPHA:
-        case LOCAL_GL_LUMINANCE:
-        case LOCAL_GL_LUMINANCE_ALPHA:
-        case LOCAL_GL_DEPTH_COMPONENT:
-        case LOCAL_GL_DEPTH_STENCIL:
-            return false;
-
+    switch (format) {
         case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
         case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
         case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
         case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
         case LOCAL_GL_ATC_RGB:
         case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
         case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
         case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
         case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
         case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
         case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
             return true;
+        default:
+            return false;
     }
-
-    MOZ_ASSERT(false, "Invalid WebGL texture format?");
-    return false;
 }
 
 void
 WebGLContext::UpdateWebGLErrorAndClearGLError(GLenum *currentGLError)
 {
     // get and clear GL error in ALL cases
     GLenum error = gl->GetAndClearError();
     if (currentGLError)
--- a/content/canvas/src/WebGLContextUtils.h
+++ b/content/canvas/src/WebGLContextUtils.h
@@ -7,16 +7,19 @@
 #define WEBGLCONTEXTUTILS_H_
 
 #include "WebGLContext.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/dom/BindingUtils.h"
 
 namespace mozilla {
 
+bool IsGLDepthFormat(GLenum internalFormat);
+bool IsGLDepthStencilFormat(GLenum internalFormat);
+
 template <typename WebGLObjectType>
 JS::Value
 WebGLContext::WebGLObjectAsJSValue(JSContext *cx, const WebGLObjectType *object, ErrorResult& rv) const
 {
     if (!object) {
         return JS::NullValue();
     }
     MOZ_ASSERT(this == object->Context());
--- a/content/canvas/src/WebGLFramebuffer.cpp
+++ b/content/canvas/src/WebGLFramebuffer.cpp
@@ -122,35 +122,87 @@ WebGLFramebuffer::Attachment::RectangleO
         return Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel);
     } else if (Renderbuffer()) {
         return *Renderbuffer();
     }
 
     MOZ_CRASH("Should not get here.");
 }
 
+/* The following IsValidFBOTextureXXX functions check the internal
+   format that is used by GL or GL ES texture formats.  This
+   corresponds to the state that is stored in
+   WebGLTexture::ImageInfo::InternalFormat()*/
 static inline bool
-IsValidAttachedTextureColorFormat(GLenum format)
+IsValidFBOTextureColorFormat(GLenum internalFormat)
 {
     return (
         /* linear 8-bit formats */
-        format == LOCAL_GL_ALPHA ||
-        format == LOCAL_GL_LUMINANCE ||
-        format == LOCAL_GL_LUMINANCE_ALPHA ||
-        format == LOCAL_GL_RGB ||
-        format == LOCAL_GL_RGBA ||
+        internalFormat == LOCAL_GL_ALPHA ||
+        internalFormat == LOCAL_GL_LUMINANCE ||
+        internalFormat == LOCAL_GL_LUMINANCE_ALPHA ||
+        internalFormat == LOCAL_GL_RGB ||
+        internalFormat == LOCAL_GL_RGBA ||
         /* sRGB 8-bit formats */
-        format == LOCAL_GL_SRGB_EXT ||
-        format == LOCAL_GL_SRGB_ALPHA_EXT ||
+        internalFormat == LOCAL_GL_SRGB_EXT ||
+        internalFormat == LOCAL_GL_SRGB_ALPHA_EXT ||
         /* linear float32 formats */
-        format ==  LOCAL_GL_ALPHA32F_ARB ||
-        format ==  LOCAL_GL_LUMINANCE32F_ARB ||
-        format ==  LOCAL_GL_LUMINANCE_ALPHA32F_ARB ||
-        format ==  LOCAL_GL_RGB32F_ARB ||
-        format ==  LOCAL_GL_RGBA32F_ARB);
+        internalFormat == LOCAL_GL_ALPHA32F_ARB ||
+        internalFormat == LOCAL_GL_LUMINANCE32F_ARB ||
+        internalFormat == LOCAL_GL_LUMINANCE_ALPHA32F_ARB ||
+        internalFormat == LOCAL_GL_RGB32F_ARB ||
+        internalFormat == LOCAL_GL_RGBA32F_ARB);
+}
+
+static inline bool
+IsValidFBOTextureDepthFormat(GLenum internalFormat)
+{
+    return (
+        internalFormat == LOCAL_GL_DEPTH_COMPONENT ||
+        internalFormat == LOCAL_GL_DEPTH_COMPONENT16 ||
+        internalFormat == LOCAL_GL_DEPTH_COMPONENT32);
+}
+
+static inline bool
+IsValidFBOTextureDepthStencilFormat(GLenum internalFormat)
+{
+    return (
+        internalFormat == LOCAL_GL_DEPTH_STENCIL ||
+        internalFormat == LOCAL_GL_DEPTH24_STENCIL8);
+}
+
+/* The following IsValidFBORenderbufferXXX functions check the internal
+   format that is stored by WebGLRenderbuffer::InternalFormat(). Valid
+   values can be found in WebGLContext::RenderbufferStorage. */
+static inline bool
+IsValidFBORenderbufferColorFormat(GLenum internalFormat)
+{
+    return (
+        internalFormat == LOCAL_GL_RGB565 ||
+        internalFormat == LOCAL_GL_RGB5_A1 ||
+        internalFormat == LOCAL_GL_RGBA4 ||
+        internalFormat == LOCAL_GL_SRGB8_ALPHA8_EXT);
+}
+
+static inline bool
+IsValidFBORenderbufferDepthFormat(GLenum internalFormat)
+{
+    return internalFormat == LOCAL_GL_DEPTH_COMPONENT16;
+}
+
+static inline bool
+IsValidFBORenderbufferDepthStencilFormat(GLenum internalFormat)
+{
+    return internalFormat == LOCAL_GL_DEPTH_STENCIL;
+}
+
+static inline bool
+IsValidFBORenderbufferStencilFormat(GLenum internalFormat)
+{
+    return internalFormat == LOCAL_GL_STENCIL_INDEX8;
 }
 
 bool
 WebGLFramebuffer::Attachment::IsComplete() const
 {
     if (!HasImage())
         return false;
 
@@ -159,47 +211,53 @@ WebGLFramebuffer::Attachment::IsComplete
     if (!rect.Width() ||
         !rect.Height())
     {
         return false;
     }
 
     if (mTexturePtr) {
         MOZ_ASSERT(mTexturePtr->HasImageInfoAt(mTexImageTarget, mTexImageLevel));
-        GLenum format = mTexturePtr->ImageInfoAt(mTexImageTarget, mTexImageLevel).InternalFormat();
+        const WebGLTexture::ImageInfo& imageInfo =
+            mTexturePtr->ImageInfoAt(mTexImageTarget, mTexImageLevel);
+        GLenum internalFormat = imageInfo.InternalFormat();
+
+        if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT)
+            return IsValidFBOTextureDepthFormat(internalFormat);
 
-        if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT) {
-            return format == LOCAL_GL_DEPTH_COMPONENT;
-        } else if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
-            return format == LOCAL_GL_DEPTH_STENCIL;
-        } else if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 &&
-                   mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + WebGLContext::sMaxColorAttachments))
+        if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
+            return IsValidFBOTextureDepthStencilFormat(internalFormat);
+
+        if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 &&
+            mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 +
+                                      WebGLContext::sMaxColorAttachments))
         {
-            return IsValidAttachedTextureColorFormat(format);
+            return IsValidFBOTextureColorFormat(internalFormat);
         }
         MOZ_ASSERT(false, "Invalid WebGL attachment point?");
         return false;
     }
 
     if (mRenderbufferPtr) {
-        GLenum format = mRenderbufferPtr->InternalFormat();
+        GLenum internalFormat = mRenderbufferPtr->InternalFormat();
+
+        if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT)
+            return IsValidFBORenderbufferDepthFormat(internalFormat);
+
+        if (mAttachmentPoint == LOCAL_GL_STENCIL_ATTACHMENT)
+            return IsValidFBORenderbufferStencilFormat(internalFormat);
 
-        if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT) {
-            return format == LOCAL_GL_DEPTH_COMPONENT16;
-        } else if (mAttachmentPoint == LOCAL_GL_STENCIL_ATTACHMENT) {
-            return format == LOCAL_GL_STENCIL_INDEX8;
-        } else if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
-            return format == LOCAL_GL_DEPTH_STENCIL;
-        } else if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 &&
-                   mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + WebGLContext::sMaxColorAttachments))
+        if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
+            return IsValidFBORenderbufferDepthStencilFormat(internalFormat);
+
+        if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 &&
+            mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 +
+                                      WebGLContext::sMaxColorAttachments))
         {
-            return format == LOCAL_GL_RGB565 ||
-                   format == LOCAL_GL_RGB5_A1 ||
-                   format == LOCAL_GL_RGBA4 ||
-                   format == LOCAL_GL_SRGB8_ALPHA8_EXT;
+            return IsValidFBORenderbufferColorFormat(internalFormat);
         }
         MOZ_ASSERT(false, "Invalid WebGL attachment point?");
         return false;
     }
 
     MOZ_ASSERT(false, "Should not get here.");
     return false;
 }
@@ -267,17 +325,17 @@ WebGLFramebuffer::FramebufferRenderbuffe
     case LOCAL_GL_STENCIL_ATTACHMENT:
         mStencilAttachment.SetRenderbuffer(wrb);
         break;
     case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
         mDepthStencilAttachment.SetRenderbuffer(wrb);
         break;
     default:
         // finish checking that the 'attachment' parameter is among the allowed values
-        if (!CheckColorAttachementNumber(attachment, "framebufferRenderbuffer")){
+        if (!CheckColorAttachmentNumber(attachment, "framebufferRenderbuffer")){
             return;
         }
 
         size_t colorAttachmentId = size_t(attachment - LOCAL_GL_COLOR_ATTACHMENT0);
         EnsureColorAttachments(colorAttachmentId);
         mColorAttachments[colorAttachmentId].SetRenderbuffer(wrb);
         break;
     }
@@ -324,17 +382,17 @@ WebGLFramebuffer::FramebufferTexture2D(G
         break;
     case LOCAL_GL_STENCIL_ATTACHMENT:
         mStencilAttachment.SetTexImage(wtex, textarget, level);
         break;
     case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
         mDepthStencilAttachment.SetTexImage(wtex, textarget, level);
         break;
     default:
-        if (!CheckColorAttachementNumber(attachment, "framebufferTexture2D"))
+        if (!CheckColorAttachmentNumber(attachment, "framebufferTexture2D"))
             return;
 
         size_t colorAttachmentId = size_t(attachment - LOCAL_GL_COLOR_ATTACHMENT0);
         EnsureColorAttachments(colorAttachmentId);
         mColorAttachments[colorAttachmentId].SetTexImage(wtex, textarget, level);
         break;
     }
 }
@@ -344,17 +402,17 @@ WebGLFramebuffer::GetAttachment(GLenum a
 {
     if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
         return mDepthStencilAttachment;
     if (attachment == LOCAL_GL_DEPTH_ATTACHMENT)
         return mDepthAttachment;
     if (attachment == LOCAL_GL_STENCIL_ATTACHMENT)
         return mStencilAttachment;
 
-    if (!CheckColorAttachementNumber(attachment, "getAttachment")) {
+    if (!CheckColorAttachmentNumber(attachment, "getAttachment")) {
         MOZ_ASSERT(false);
         return mColorAttachments[0];
     }
 
     size_t colorAttachmentId = attachment - LOCAL_GL_COLOR_ATTACHMENT0;
     if (colorAttachmentId >= mColorAttachments.Length()) {
         MOZ_ASSERT(false);
         return mColorAttachments[0];
@@ -614,17 +672,17 @@ WebGLFramebuffer::CheckAndInitializeAtta
     if (mStencilAttachment.HasUninitializedImageData())
         mStencilAttachment.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
     if (mDepthStencilAttachment.HasUninitializedImageData())
         mDepthStencilAttachment.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
 
     return true;
 }
 
-bool WebGLFramebuffer::CheckColorAttachementNumber(GLenum attachment, const char* functionName) const
+bool WebGLFramebuffer::CheckColorAttachmentNumber(GLenum attachment, const char* functionName) const
 {
     const char* const errorFormating = "%s: attachment: invalid enum value 0x%x";
 
     if (mContext->IsExtensionEnabled(WebGLContext::WEBGL_draw_buffers)) {
         if (attachment < LOCAL_GL_COLOR_ATTACHMENT0 ||
             attachment >= GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + mContext->mGLMaxColorAttachments))
         {
             mContext->ErrorInvalidEnum(errorFormating, functionName, attachment);
@@ -656,32 +714,62 @@ void WebGLFramebuffer::EnsureColorAttach
 
     mColorAttachments.SetLength(colorAttachmentId + 1);
 
     for (size_t i = colorAttachmentId; i >= currentAttachmentCount; i--) {
         mColorAttachments[i].mAttachmentPoint = LOCAL_GL_COLOR_ATTACHMENT0 + i;
     }
 }
 
+static void
+FinalizeDrawAndReadBuffers(GLContext* aGL, bool aColorBufferDefined)
+{
+    MOZ_ASSERT(aGL, "Expected a valid GLContext ptr.");
+    // GLES don't support DrawBuffer()/ReadBuffer.
+    // According to http://www.opengl.org/wiki/Framebuffer_Object
+    //
+    // Each draw buffers must either specify color attachment points that have images
+    // attached or must be GL_NONE​. (GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER​ when false).
+    //
+    // If the read buffer is set, then it must specify an attachment point that has an
+    // image attached. (GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER​ when false).
+    //
+    // Note that this test is not performed if OpenGL 4.2 or ARB_ES2_compatibility is
+    // available.
+    if (aGL->IsGLES2() ||
+        aGL->IsSupported(GLFeature::ES2_compatibility) ||
+        aGL->IsAtLeast(ContextProfile::OpenGL, 420))
+    {
+        return;
+    }
+
+    // TODO(djg): Assert that fDrawBuffer/fReadBuffer is not NULL.
+    GLenum colorBufferSource = aColorBufferDefined ? LOCAL_GL_COLOR_ATTACHMENT0 : LOCAL_GL_NONE;
+    aGL->fDrawBuffer(colorBufferSource);
+    aGL->fReadBuffer(colorBufferSource);
+}
+
 void
 WebGLFramebuffer::FinalizeAttachments() const
 {
     for (size_t i = 0; i < ColorAttachmentCount(); i++) {
         if (ColorAttachment(i).IsDefined())
             ColorAttachment(i).FinalizeAttachment(LOCAL_GL_COLOR_ATTACHMENT0 + i);
     }
 
     if (DepthAttachment().IsDefined())
         DepthAttachment().FinalizeAttachment(LOCAL_GL_DEPTH_ATTACHMENT);
 
     if (StencilAttachment().IsDefined())
         StencilAttachment().FinalizeAttachment(LOCAL_GL_STENCIL_ATTACHMENT);
 
     if (DepthStencilAttachment().IsDefined())
         DepthStencilAttachment().FinalizeAttachment(LOCAL_GL_DEPTH_STENCIL_ATTACHMENT);
+
+    FinalizeDrawAndReadBuffers(mContext->gl, ColorAttachment(0).IsDefined());
 }
 
 inline void
 ImplCycleCollectionUnlink(mozilla::WebGLFramebuffer::Attachment& aField)
 {
     aField.mTexturePtr = nullptr;
     aField.mRenderbufferPtr = nullptr;
 }
--- a/content/canvas/src/WebGLFramebuffer.h
+++ b/content/canvas/src/WebGLFramebuffer.h
@@ -163,17 +163,17 @@ public:
     virtual JSObject* WrapObject(JSContext* cx,
                                  JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebuffer)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLFramebuffer)
 
     bool CheckAndInitializeAttachments();
 
-    bool CheckColorAttachementNumber(GLenum attachment, const char* functionName) const;
+    bool CheckColorAttachmentNumber(GLenum attachment, const char* functionName) const;
 
     GLuint mGLName;
     bool mHasEverBeenBound;
 
     void EnsureColorAttachments(size_t colorAttachmentId);
 
     // we only store pointers to attached renderbuffers, not to attached textures, because
     // we will only need to initialize renderbuffers. Textures are already initialized.
--- a/content/canvas/src/WebGLTexelConversions.cpp
+++ b/content/canvas/src/WebGLTexelConversions.cpp
@@ -11,17 +11,17 @@ using namespace WebGLTexelConversions;
 
 namespace {
 
 /** @class WebGLImageConverter
  *
  * This class is just a helper to implement WebGLContext::ConvertImage below.
  *
  * Design comments:
- * 
+ *
  * WebGLContext::ConvertImage has to handle hundreds of format conversion paths.
  * It is important to minimize executable code size here. Instead of passing around
  * a large number of function parameters hundreds of times, we create a
  * WebGLImageConverter object once, storing these parameters, and then we call
  * the run() method on it.
  */
 class WebGLImageConverter
 {
@@ -376,9 +376,9 @@ WebGLContext::ConvertImage(size_t width,
     if (!converter.Success()) {
         // the dst image may be left uninitialized, so we better not try to
         // continue even in release builds. This should never happen anyway,
         // and would be a bug in our code.
         NS_RUNTIMEABORT("programming mistake in WebGL texture conversions");
     }
 }
 
-} // end namespace mozilla 
+} // end namespace mozilla
--- a/content/canvas/src/WebGLTexelConversions.h
+++ b/content/canvas/src/WebGLTexelConversions.h
@@ -90,16 +90,43 @@ template<MOZ_ENUM_CLASS_ENUM_TYPE(WebGLT
 struct IntermediateFormat
 {
     static const MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) Value
         = IsFloatFormat<Format>::Value
           ? WebGLTexelFormat::RGBA32F
           : WebGLTexelFormat::RGBA8;
 };
 
+inline GLenum
+GLFormatForTexelFormat(WebGLTexelFormat format) {
+    switch (format) {
+        case WebGLTexelFormat::R8:          return LOCAL_GL_LUMINANCE;
+        case WebGLTexelFormat::A8:          return LOCAL_GL_ALPHA;
+        case WebGLTexelFormat::RA8:         return LOCAL_GL_LUMINANCE_ALPHA;
+        case WebGLTexelFormat::RGBA5551:    return LOCAL_GL_RGBA;
+        case WebGLTexelFormat::RGBA4444:    return LOCAL_GL_RGBA;
+        case WebGLTexelFormat::RGB565:      return LOCAL_GL_RGB;
+        case WebGLTexelFormat::D16:         return LOCAL_GL_DEPTH_COMPONENT;
+        case WebGLTexelFormat::RGB8:        return LOCAL_GL_RGB;
+        case WebGLTexelFormat::RGBA8:       return LOCAL_GL_RGBA;
+        case WebGLTexelFormat::BGRA8:       return LOCAL_GL_BGRA;
+        case WebGLTexelFormat::BGRX8:       return LOCAL_GL_BGR;
+        case WebGLTexelFormat::R32F:        return LOCAL_GL_LUMINANCE;
+        case WebGLTexelFormat::A32F:        return LOCAL_GL_ALPHA;
+        case WebGLTexelFormat::D32:         return LOCAL_GL_DEPTH_COMPONENT;
+        case WebGLTexelFormat::D24S8:       return LOCAL_GL_DEPTH_STENCIL;
+        case WebGLTexelFormat::RA32F:       return LOCAL_GL_LUMINANCE_ALPHA;
+        case WebGLTexelFormat::RGB32F:      return LOCAL_GL_RGB;
+        case WebGLTexelFormat::RGBA32F:     return LOCAL_GL_RGBA;
+        default:
+            MOZ_CRASH("Unknown texel format. Coding mistake?");
+            return LOCAL_GL_INVALID_ENUM;
+    }
+}
+
 inline size_t TexelBytesForFormat(WebGLTexelFormat format) {
     switch (format) {
         case WebGLTexelFormat::R8:
         case WebGLTexelFormat::A8:
             return 1;
         case WebGLTexelFormat::RA8:
         case WebGLTexelFormat::RGBA5551:
         case WebGLTexelFormat::RGBA4444:
--- a/content/canvas/src/WebGLTexture.cpp
+++ b/content/canvas/src/WebGLTexture.cpp
@@ -425,20 +425,21 @@ WebGLTexture::DoDeferredImageInitializat
         = WebGLContext::GetImageSize(
                         imageInfo.mHeight,
                         imageInfo.mWidth,
                         texelsize,
                         mContext->mPixelStoreUnpackAlignment);
     MOZ_ASSERT(checked_byteLength.isValid()); // should have been checked earlier
     void *zeros = calloc(1, checked_byteLength.value());
 
+    GLenum format = WebGLTexelConversions::GLFormatForTexelFormat(texelformat);
     mContext->UpdateWebGLErrorAndClearGLError();
     mContext->gl->fTexImage2D(imageTarget, level, imageInfo.mInternalFormat,
                               imageInfo.mWidth, imageInfo.mHeight,
-                              0, imageInfo.mInternalFormat, imageInfo.mType,
+                              0, format, imageInfo.mType,
                               zeros);
     GLenum error = LOCAL_GL_NO_ERROR;
     mContext->UpdateWebGLErrorAndClearGLError(&error);
 
     free(zeros);
     SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData);
 
     if (error) {
--- a/content/canvas/test/mochitest.ini
+++ b/content/canvas/test/mochitest.ini
@@ -92,16 +92,17 @@ support-files =
 [test_bug902651.html]
 [test_canvas.html]
 [test_canvas_focusring.html]
 [test_canvas_font_setter.html]
 [test_canvas_strokeStyle_getter.html]
 [test_drawImageIncomplete.html]
 [test_drawImage_document_domain.html]
 [test_drawImage_edge_cases.html]
+[test_ImageData_ctor.html]
 [test_isPointInStroke.html]
 [test_mozDashOffset.html]
 [test_mozGetAsFile.html]
 [test_strokeText_throw.html]
 [test_toBlob.html]
 [test_toDataURL_alpha.html]
 [test_toDataURL_lowercase_ascii.html]
 [test_toDataURL_parameters.html]
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/test_ImageData_ctor.html
@@ -0,0 +1,80 @@
+<!DOCTYPE HTML><meta charset=utf-8>
+<title>Canvas test: ImageData</title>
+<script type="text/javascript" src="/resources/testharness.js"></script>
+<script type="text/javascript" src="/resources/testharnessreport.js"></script>
+<body>
+<div id="log"></div>
+<script>
+
+test(function() {
+  assert_throws(new TypeError(), function(){ new ImageData(); });
+  assert_throws(new TypeError(), function(){ new ImageData(1); });
+  assert_throws(new TypeError(), function(){ new ImageData(new Uint8ClampedArray([1,2,3,4])); });
+  assert_throws("IndexSizeError", function(){ new ImageData(0,0); });
+  assert_throws("IndexSizeError", function(){ new ImageData(0,1); });
+  assert_throws("IndexSizeError", function(){ new ImageData(1,0); });
+  new ImageData(1,1);
+  new ImageData(1,2);
+  new ImageData(1,3);
+  assert_throws("IndexSizeError", function(){ new ImageData(2,0); });
+  new ImageData(2,1);
+  new ImageData(2,2);
+  assert_throws("IndexSizeError", function(){ new ImageData(32768,32768); });
+  assert_throws("IndexSizeError", function(){ new ImageData(32768,32769); });
+  assert_throws("IndexSizeError", function(){ new ImageData(32769,32768); });
+  assert_throws("IndexSizeError", function(){ new ImageData(2,536870912); });
+  assert_throws("IndexSizeError", function(){ new ImageData(2,536870913); });
+  assert_throws("IndexSizeError", function(){ new ImageData(536870912,2); });
+  assert_throws("IndexSizeError", function(){ new ImageData(536870913,2); });
+  assert_throws("InvalidStateError", function(){ new ImageData(new Uint8ClampedArray([]),0); });
+  assert_throws("InvalidStateError", function(){ new ImageData(new Uint8ClampedArray([]),0,0); });
+  assert_throws("InvalidStateError", function(){ new ImageData(new Uint8ClampedArray([]),1); });
+  assert_throws("InvalidStateError", function(){ new ImageData(new Uint8ClampedArray([1]),1); });
+  assert_throws("InvalidStateError", function(){ new ImageData(new Uint8ClampedArray([1,2]),1); });
+  assert_throws("InvalidStateError", function(){ new ImageData(new Uint8ClampedArray([1,2,3]),1); });
+  assert_throws("InvalidStateError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4,5]),1); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4]),0); });
+  new ImageData(new Uint8ClampedArray([1,2,3,4]),1);
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4]),2); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),0); });
+  new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),1);
+  new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),2);
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),3); });
+  assert_throws("InvalidStateError", function(){ new ImageData(new Uint8ClampedArray([]),1,1); });
+  assert_throws("InvalidStateError", function(){ new ImageData(new Uint8ClampedArray([1]),1,1); });
+  assert_throws("InvalidStateError", function(){ new ImageData(new Uint8ClampedArray([1,2]),1,1); });
+  assert_throws("InvalidStateError", function(){ new ImageData(new Uint8ClampedArray([1,2,3]),1,1); });
+  assert_throws("InvalidStateError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4,5]),1,1); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4]),0,0); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4]),0,1); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4]),0,2); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4]),1,0); });
+  new ImageData(new Uint8ClampedArray([1,2,3,4]),1,1);
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4]),1,2); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4]),2,0); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4]),2,1); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4]),2,2); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),1,1); });
+  new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),1,2);
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),1,3); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),2,0); });
+  new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),2,1);
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),2,2); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),2,536870912); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),2,536870913); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),536870912,2); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),536870913,2); });
+}, "Test constructor arguments");
+
+test(function() {
+  var data = new Uint8ClampedArray([1,2,3,4,5,6,7,8]);
+  var imgData = new ImageData(data,1);
+  assert_equals(imgData.width, 1);
+  assert_equals(imgData.height, 2);
+  assert_array_equals(imgData.data, [1,2,3,4,5,6,7,8]);
+  data.set([8,7,6,5,4,3,2,1]);
+  assert_array_equals(imgData.data, [8,7,6,5,4,3,2,1]);
+}, "The data argument is not copied");
+
+</script>
+
--- a/content/canvas/test/test_canvas.html
+++ b/content/canvas/test/test_canvas.html
@@ -8358,19 +8358,26 @@ ok(imgdata.data[0] === 255, "imgdata.dat
 <script>
 
 function test_2d_imageData_object_ctor() {
 
 var canvas = document.getElementById('c280');
 var ctx = canvas.getContext('2d');
 
 ok(window.ImageData !== undefined, "window.ImageData !== undefined");
-try { var _thrown = false;
-  new window.ImageData(1,1);
-} catch (e) { _thrown = true; } finally { ok(_thrown, "should throw exception"); }
+
+var _thrown_outer = false;
+try {
+
+new window.ImageData(1,1);
+
+} catch (e) {
+    _thrown_outer = true;
+}
+ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception');
 
 
 }
 </script>
 
 <!-- [[[ test_2d.imageData.object.nan.html ]]] -->
 
 <p>Canvas test: 2d.imageData.object.nan</p>
--- a/content/canvas/test/webgl/conformance/resources/webgl-test-utils.js
+++ b/content/canvas/test/webgl/conformance/resources/webgl-test-utils.js
@@ -762,16 +762,60 @@ var loadTextFileAsync = function(url, ca
     };
     request.send(null);
   } catch (e) {
     log("failed to load: " + url);
     callback(false, '');
   }
 };
 
+// Add your prefix here.
+var browserPrefixes = [
+  "",
+  "MOZ_",
+  "OP_",
+  "WEBKIT_"
+];
+
+/**
+ * Given an extension name like WEBGL_compressed_texture_s3tc
+ * returns the name of the supported version extension, like
+ * WEBKIT_WEBGL_compressed_teture_s3tc
+ * @param {string} name Name of extension to look for
+ * @return {string} name of extension found or undefined if not
+ *     found.
+ */
+var getSupportedExtensionWithKnownPrefixes = function(gl, name) {
+  var supported = gl.getSupportedExtensions();
+  for (var ii = 0; ii < browserPrefixes.length; ++ii) {
+    var prefixedName = browserPrefixes[ii] + name;
+    if (supported.indexOf(prefixedName) >= 0) {
+      return prefixedName;
+    }
+  }
+};
+
+/**
+ * Given an extension name like WEBGL_compressed_texture_s3tc
+ * returns the supported version extension, like
+ * WEBKIT_WEBGL_compressed_teture_s3tc
+ * @param {string} name Name of extension to look for
+ * @return {WebGLExtension} The extension or undefined if not
+ *     found.
+ */
+var getExtensionWithKnownPrefixes = function(gl, name) {
+  for (var ii = 0; ii < browserPrefixes.length; ++ii) {
+    var prefixedName = browserPrefixes[ii] + name;
+    var ext = gl.getExtension(prefixedName);
+    if (ext) {
+      return ext;
+    }
+  }
+};
+
 /**
  * Recursively loads a file as a list. Each line is parsed for a relative
  * path. If the file ends in .txt the contents of that file is inserted in
  * the list.
  *
  * @param {string} url The url of the external file.
  * @param {!function(bool, Array<string>): void} callback that is sent a bool
  *     for success and the array of strings.
@@ -1272,19 +1316,21 @@ return {
   create3DContext: create3DContext,
   create3DContextWithWrapperThatThrowsOnGLError:
     create3DContextWithWrapperThatThrowsOnGLError,
   checkCanvas: checkCanvas,
   checkCanvasRect: checkCanvasRect,
   createColoredTexture: createColoredTexture,
   drawQuad: drawQuad,
   endsWith: endsWith,
+  getExtensionWithKnownPrefixes: getExtensionWithKnownPrefixes,
   getFileListAsync: getFileListAsync,
   getLastError: getLastError,
   getScript: getScript,
+  getSupportedExtensionWithKnownPrefixes: getSupportedExtensionWithKnownPrefixes,
   getUrlArguments: getUrlArguments,
   glEnumToString: glEnumToString,
   glErrorShouldBe: glErrorShouldBe,
   fillTexture: fillTexture,
   insertImage: insertImage,
   loadImageAsync: loadImageAsync,
   loadImagesAsync: loadImagesAsync,
   loadProgram: loadProgram,
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -50,18 +50,20 @@ MediaStreamGraphImpl::~MediaStreamGraphI
   STREAM_LOG(PR_LOG_DEBUG, ("MediaStreamGraph %p destroyed", this));
 }
 
 
 StreamTime
 MediaStreamGraphImpl::GetDesiredBufferEnd(MediaStream* aStream)
 {
   StreamTime current = mCurrentTime - aStream->mBufferStartTime;
+  // When waking up media decoders, we need a longer safety margin, as it can
+  // take more time to get new samples. A factor of two seem to work.
   return current +
-      MillisecondsToMediaTime(std::max(AUDIO_TARGET_MS, VIDEO_TARGET_MS));
+      2 * MillisecondsToMediaTime(std::max(AUDIO_TARGET_MS, VIDEO_TARGET_MS));
 }
 
 void
 MediaStreamGraphImpl::FinishStream(MediaStream* aStream)
 {
   if (aStream->mFinished)
     return;
   STREAM_LOG(PR_LOG_DEBUG, ("MediaStream %p will finish", aStream));
--- a/dom/events/TextComposition.cpp
+++ b/dom/events/TextComposition.cpp
@@ -26,27 +26,16 @@ TextComposition::TextComposition(nsPresC
                                  WidgetGUIEvent* aEvent) :
   mPresContext(aPresContext), mNode(aNode),
   mNativeContext(aEvent->widget->GetInputContext().mNativeIMEContext),
   mCompositionStartOffset(0), mCompositionTargetOffset(0),
   mIsSynthesizedForTests(aEvent->mFlags.mIsSynthesizedForTests)
 {
 }
 
-TextComposition::TextComposition(const TextComposition& aOther)
-{
-  mNativeContext = aOther.mNativeContext;
-  mPresContext = aOther.mPresContext;
-  mNode = aOther.mNode;
-  mLastData = aOther.mLastData;
-  mCompositionStartOffset = aOther.mCompositionStartOffset;
-  mCompositionTargetOffset = aOther.mCompositionTargetOffset;
-  mIsSynthesizedForTests = aOther.mIsSynthesizedForTests;
-}
-
 bool
 TextComposition::MatchesNativeContext(nsIWidget* aWidget) const
 {
   return mNativeContext == aWidget->GetInputContext().mNativeIMEContext;
 }
 
 void
 TextComposition::DispatchEvent(WidgetGUIEvent* aEvent,
@@ -113,25 +102,23 @@ TextComposition::DispatchCompsotionEvent
   nsContentUtils::AddScriptRunner(
     new CompositionEventDispatcher(mPresContext, mNode,
                                    aEventMessage, aData));
 }
 
 void
 TextComposition::SynthesizeCommit(bool aDiscard)
 {
-  // backup this instance and use it since this instance might be destroyed
-  // by nsIMEStateManager if this is managed by it.
-  TextComposition composition = *this;
-  nsAutoString data(aDiscard ? EmptyString() : composition.mLastData);
-  if (composition.mLastData != data) {
-    composition.DispatchCompsotionEventRunnable(NS_COMPOSITION_UPDATE, data);
-    composition.DispatchCompsotionEventRunnable(NS_TEXT_TEXT, data);
+  nsRefPtr<TextComposition> kungFuDeathGrip(this);
+  nsAutoString data(aDiscard ? EmptyString() : mLastData);
+  if (mLastData != data) {
+    DispatchCompsotionEventRunnable(NS_COMPOSITION_UPDATE, data);
+    DispatchCompsotionEventRunnable(NS_TEXT_TEXT, data);
   }
-  composition.DispatchCompsotionEventRunnable(NS_COMPOSITION_END, data);
+  DispatchCompsotionEventRunnable(NS_COMPOSITION_END, data);
 }
 
 nsresult
 TextComposition::NotifyIME(widget::NotificationToIME aNotification)
 {
   NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE);
   return nsIMEStateManager::NotifyIME(aNotification, mPresContext);
 }
@@ -197,68 +184,68 @@ TextComposition::CompositionEventDispatc
 /******************************************************************************
  * TextCompositionArray
  ******************************************************************************/
 
 TextCompositionArray::index_type
 TextCompositionArray::IndexOf(nsIWidget* aWidget)
 {
   for (index_type i = Length(); i > 0; --i) {
-    if (ElementAt(i - 1).MatchesNativeContext(aWidget)) {
+    if (ElementAt(i - 1)->MatchesNativeContext(aWidget)) {
       return i - 1;
     }
   }
   return NoIndex;
 }
 
 TextCompositionArray::index_type
 TextCompositionArray::IndexOf(nsPresContext* aPresContext)
 {
   for (index_type i = Length(); i > 0; --i) {
-    if (ElementAt(i - 1).GetPresContext() == aPresContext) {
+    if (ElementAt(i - 1)->GetPresContext() == aPresContext) {
       return i - 1;
     }
   }
   return NoIndex;
 }
 
 TextCompositionArray::index_type
 TextCompositionArray::IndexOf(nsPresContext* aPresContext,
                               nsINode* aNode)
 {
   index_type index = IndexOf(aPresContext);
   if (index == NoIndex) {
     return NoIndex;
   }
-  nsINode* node = ElementAt(index).GetEventTargetNode();
+  nsINode* node = ElementAt(index)->GetEventTargetNode();
   return node == aNode ? index : NoIndex;
 }
 
 TextComposition*
 TextCompositionArray::GetCompositionFor(nsIWidget* aWidget)
 {
   index_type i = IndexOf(aWidget);
-  return i != NoIndex ? &ElementAt(i) : nullptr;
+  return i != NoIndex ? ElementAt(i) : nullptr;
 }
 
 TextComposition*
 TextCompositionArray::GetCompositionFor(nsPresContext* aPresContext,
                                            nsINode* aNode)
 {
   index_type i = IndexOf(aPresContext, aNode);
-  return i != NoIndex ? &ElementAt(i) : nullptr;
+  return i != NoIndex ? ElementAt(i) : nullptr;
 }
 
 TextComposition*
 TextCompositionArray::GetCompositionInContent(nsPresContext* aPresContext,
                                               nsIContent* aContent)
 {
   // There should be only one composition per content object.
   for (index_type i = Length(); i > 0; --i) {
-    nsINode* node = ElementAt(i - 1).GetEventTargetNode();
+    nsINode* node = ElementAt(i - 1)->GetEventTargetNode();
     if (node && nsContentUtils::ContentIsDescendantOf(node, aContent)) {
-      return &ElementAt(i - 1);
+      return ElementAt(i - 1);
     }
   }
   return nullptr;
 }
 
 } // namespace mozilla
--- a/dom/events/TextComposition.h
+++ b/dom/events/TextComposition.h
@@ -26,23 +26,24 @@ namespace mozilla {
  * TextComposition represents a text composition.  This class stores the
  * composition event target and its presContext.  At dispatching the event via
  * this class, the instances use the stored event target.
  */
 
 class TextComposition MOZ_FINAL
 {
   friend class ::nsIMEStateManager;
+
+  NS_INLINE_DECL_REFCOUNTING(TextComposition)
+
 public:
   TextComposition(nsPresContext* aPresContext,
                   nsINode* aNode,
                   WidgetGUIEvent* aEvent);
 
-  TextComposition(const TextComposition& aOther);
-
   ~TextComposition()
   {
     // WARNING: mPresContext may be destroying, so, be careful if you touch it.
   }
 
   nsPresContext* GetPresContext() const { return mPresContext; }
   nsINode* GetEventTargetNode() const { return mNode; }
   // The latest CompositionEvent.data value except compositionstart event.
@@ -92,18 +93,20 @@ private:
   uint32_t mCompositionStartOffset;
   // Offset of the selected clause of the composition string from start of the
   // editor
   uint32_t mCompositionTargetOffset;
 
   // See the comment for IsSynthesizedForTests().
   bool mIsSynthesizedForTests;
 
-  // Hide the default constructor
+  // Hide the default constructor and copy constructor.
   TextComposition() {}
+  TextComposition(const TextComposition& aOther);
+
 
   /**
    * DispatchEvent() dispatches the aEvent to the mContent synchronously.
    * The caller must ensure that it's safe to dispatch the event.
    */
   void DispatchEvent(WidgetGUIEvent* aEvent,
                      nsEventStatus* aStatus,
                      nsDispatchingCallback* aCallBack);
@@ -158,17 +161,18 @@ private:
  * Managing with array is enough because only one composition is typically
  * there.  Even if user switches native IME context, it's very rare that
  * second or more composition is started.
  * It's assumed that this is used by nsIMEStateManager for storing all active
  * compositions in the process.  If the instance is it, each TextComposition
  * in the array can be destroyed by calling some methods of itself.
  */
 
-class TextCompositionArray MOZ_FINAL : public nsAutoTArray<TextComposition, 2>
+class TextCompositionArray MOZ_FINAL :
+  public nsAutoTArray<nsRefPtr<TextComposition>, 2>
 {
 public:
   index_type IndexOf(nsIWidget* aWidget);
   index_type IndexOf(nsPresContext* aPresContext);
   index_type IndexOf(nsPresContext* aPresContext, nsINode* aNode);
 
   TextComposition* GetCompositionFor(nsIWidget* aWidget);
   TextComposition* GetCompositionFor(nsPresContext* aPresContext,
--- a/dom/events/nsIMEStateManager.cpp
+++ b/dom/events/nsIMEStateManager.cpp
@@ -143,38 +143,36 @@ nsIMEStateManager::OnDestroyPresContext(
 nsresult
 nsIMEStateManager::OnRemoveContent(nsPresContext* aPresContext,
                                    nsIContent* aContent)
 {
   NS_ENSURE_ARG_POINTER(aPresContext);
 
   // First, if there is a composition in the aContent, clean up it.
   if (sTextCompositions) {
-    TextComposition* compositionInContent =
+    nsRefPtr<TextComposition> compositionInContent =
       sTextCompositions->GetCompositionInContent(aPresContext, aContent);
 
     if (compositionInContent) {
-      // Store the composition before accessing the native IME.
-      TextComposition storedComposition = *compositionInContent;
       // Try resetting the native IME state.  Be aware, typically, this method
       // is called during the content being removed.  Then, the native
       // composition events which are caused by following APIs are ignored due
       // to unsafe to run script (in PresShell::HandleEvent()).
       nsCOMPtr<nsIWidget> widget = aPresContext->GetRootWidget();
       if (widget) {
         nsresult rv =
-          storedComposition.NotifyIME(REQUEST_TO_CANCEL_COMPOSITION);
+          compositionInContent->NotifyIME(REQUEST_TO_CANCEL_COMPOSITION);
         if (NS_FAILED(rv)) {
-          storedComposition.NotifyIME(REQUEST_TO_COMMIT_COMPOSITION);
+          compositionInContent->NotifyIME(REQUEST_TO_COMMIT_COMPOSITION);
         }
         // By calling the APIs, the composition may have been finished normally.
         compositionInContent =
           sTextCompositions->GetCompositionFor(
-                               storedComposition.GetPresContext(),
-                               storedComposition.GetEventTargetNode());
+                               compositionInContent->GetPresContext(),
+                               compositionInContent->GetEventTargetNode());
       }
     }
 
     // If the compositionInContent is still available, we should finish the
     // composition just on the content forcibly.
     if (compositionInContent) {
       compositionInContent->SynthesizeCommit(true);
     }
@@ -553,22 +551,22 @@ nsIMEStateManager::DispatchCompositionEv
   if (!aEvent->mFlags.mIsTrusted || aEvent->mFlags.mPropagationStopped) {
     return;
   }
 
   EnsureTextCompositionArray();
 
   WidgetGUIEvent* GUIEvent = aEvent->AsGUIEvent();
 
-  TextComposition* composition =
+  nsRefPtr<TextComposition> composition =
     sTextCompositions->GetCompositionFor(GUIEvent->widget);
   if (!composition) {
     MOZ_ASSERT(GUIEvent->message == NS_COMPOSITION_START);
-    TextComposition newComposition(aPresContext, aEventTargetNode, GUIEvent);
-    composition = sTextCompositions->AppendElement(newComposition);
+    composition = new TextComposition(aPresContext, aEventTargetNode, GUIEvent);
+    sTextCompositions->AppendElement(composition);
   }
 #ifdef DEBUG
   else {
     MOZ_ASSERT(GUIEvent->message != NS_COMPOSITION_START);
   }
 #endif // #ifdef DEBUG
 
   // Dispatch the event on composing target.
@@ -588,17 +586,17 @@ nsIMEStateManager::DispatchCompositionEv
 
 // static
 nsresult
 nsIMEStateManager::NotifyIME(NotificationToIME aNotification,
                              nsIWidget* aWidget)
 {
   NS_ENSURE_TRUE(aWidget, NS_ERROR_INVALID_ARG);
 
-  TextComposition* composition = nullptr;
+  nsRefPtr<TextComposition> composition;
   if (sTextCompositions) {
     composition = sTextCompositions->GetCompositionFor(aWidget);
   }
   if (!composition || !composition->IsSynthesizedForTests()) {
     switch (aNotification) {
       case NOTIFY_IME_OF_CURSOR_POS_CHANGED:
         return aWidget->NotifyIME(aNotification);
       case REQUEST_TO_COMMIT_COMPOSITION:
@@ -613,64 +611,60 @@ nsIMEStateManager::NotifyIME(Notificatio
   }
 
   // If the composition is synthesized events for automated tests, we should
   // dispatch composition events for emulating the native composition behavior.
   // NOTE: The dispatched events are discarded if it's not safe to run script.
   switch (aNotification) {
     case REQUEST_TO_COMMIT_COMPOSITION: {
       nsCOMPtr<nsIWidget> widget(aWidget);
-      TextComposition backup = *composition;
-
       nsEventStatus status = nsEventStatus_eIgnore;
-      if (!backup.GetLastData().IsEmpty()) {
+      if (!composition->GetLastData().IsEmpty()) {
         WidgetTextEvent textEvent(true, NS_TEXT_TEXT, widget);
-        textEvent.theText = backup.GetLastData();
+        textEvent.theText = composition->GetLastData();
         textEvent.mFlags.mIsSynthesizedForTests = true;
         widget->DispatchEvent(&textEvent, status);
         if (widget->Destroyed()) {
           return NS_OK;
         }
       }
 
       status = nsEventStatus_eIgnore;
       WidgetCompositionEvent endEvent(true, NS_COMPOSITION_END, widget);
-      endEvent.data = backup.GetLastData();
+      endEvent.data = composition->GetLastData();
       endEvent.mFlags.mIsSynthesizedForTests = true;
       widget->DispatchEvent(&endEvent, status);
 
       return NS_OK;
     }
     case REQUEST_TO_CANCEL_COMPOSITION: {
       nsCOMPtr<nsIWidget> widget(aWidget);
-      TextComposition backup = *composition;
-
       nsEventStatus status = nsEventStatus_eIgnore;
-      if (!backup.GetLastData().IsEmpty()) {
+      if (!composition->GetLastData().IsEmpty()) {
         WidgetCompositionEvent updateEvent(true, NS_COMPOSITION_UPDATE, widget);
-        updateEvent.data = backup.GetLastData();
+        updateEvent.data = composition->GetLastData();
         updateEvent.mFlags.mIsSynthesizedForTests = true;
         widget->DispatchEvent(&updateEvent, status);
         if (widget->Destroyed()) {
           return NS_OK;
         }
 
         status = nsEventStatus_eIgnore;
         WidgetTextEvent textEvent(true, NS_TEXT_TEXT, widget);
-        textEvent.theText = backup.GetLastData();
+        textEvent.theText = composition->GetLastData();
         textEvent.mFlags.mIsSynthesizedForTests = true;
         widget->DispatchEvent(&textEvent, status);
         if (widget->Destroyed()) {
           return NS_OK;
         }
       }
 
       status = nsEventStatus_eIgnore;
       WidgetCompositionEvent endEvent(true, NS_COMPOSITION_END, widget);
-      endEvent.data = backup.GetLastData();
+      endEvent.data = composition->GetLastData();
       endEvent.mFlags.mIsSynthesizedForTests = true;
       widget->DispatchEvent(&endEvent, status);
 
       return NS_OK;
     }
     default:
       return NS_OK;
   }
@@ -1128,12 +1122,13 @@ nsIMEStateManager::GetFocusSelectionAndR
   NS_ASSERTION(sTextStateObserver->mSel && sTextStateObserver->mRootContent,
                "uninitialized text state observer");
   NS_ADDREF(*aSel = sTextStateObserver->mSel);
   NS_ADDREF(*aRoot = sTextStateObserver->mRootContent);
   return NS_OK;
 }
 
 TextComposition*
-nsIMEStateManager::GetTextComposition(nsIWidget* aWidget)
+nsIMEStateManager::GetTextCompositionFor(nsIWidget* aWidget)
 {
-  return sTextCompositions->GetCompositionFor(aWidget);
+  return sTextCompositions ?
+    sTextCompositions->GetCompositionFor(aWidget) : nullptr;
 }
--- a/dom/events/nsIMEStateManager.h
+++ b/dom/events/nsIMEStateManager.h
@@ -93,17 +93,17 @@ public:
                                        nsPresContext* aPresContext,
                                        mozilla::WidgetEvent* aEvent,
                                        nsEventStatus* aStatus,
                                        nsDispatchingCallback* aCallBack);
 
   /**
    * Get TextComposition from widget.
    */
-  static mozilla::TextComposition* GetTextComposition(nsIWidget* aWidget);
+  static mozilla::TextComposition* GetTextCompositionFor(nsIWidget* aWidget);
 
   /**
    * Send a notification to IME.  It depends on the IME or platform spec what
    * will occur (or not occur).
    */
   static nsresult NotifyIME(mozilla::widget::NotificationToIME aNotification,
                             nsIWidget* aWidget);
   static nsresult NotifyIME(mozilla::widget::NotificationToIME aNotification,
--- a/dom/indexedDB/AsyncConnectionHelper.cpp
+++ b/dom/indexedDB/AsyncConnectionHelper.cpp
@@ -15,16 +15,17 @@
 #include "nsProxyRelease.h"
 #include "nsThreadUtils.h"
 #include "nsWrapperCacheInlines.h"
 
 #include "IDBEvents.h"
 #include "IDBTransaction.h"
 #include "IndexedDatabaseManager.h"
 #include "ProfilerHelpers.h"
+#include "ReportInternalError.h"
 #include "TransactionThreadPool.h"
 
 #include "ipc/IndexedDBChild.h"
 #include "ipc/IndexedDBParent.h"
 
 using namespace mozilla;
 USING_INDEXEDDB_NAMESPACE
 using mozilla::dom::quota::QuotaManager;
@@ -54,38 +55,38 @@ inline
 nsresult
 ConvertCloneReadInfosToArrayInternal(
                                 JSContext* aCx,
                                 nsTArray<StructuredCloneReadInfo>& aReadInfos,
                                 JS::MutableHandle<JS::Value> aResult)
 {
   JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0, nullptr));
   if (!array) {
-    NS_WARNING("Failed to make array!");
+    IDB_WARNING("Failed to make array!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   if (!aReadInfos.IsEmpty()) {
     if (!JS_SetArrayLength(aCx, array, uint32_t(aReadInfos.Length()))) {
-      NS_WARNING("Failed to set array length!");
+      IDB_WARNING("Failed to set array length!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     for (uint32_t index = 0, count = aReadInfos.Length(); index < count;
          index++) {
       StructuredCloneReadInfo& readInfo = aReadInfos[index];
 
       JS::Rooted<JS::Value> val(aCx);
       if (!IDBObjectStore::DeserializeValue(aCx, readInfo, &val)) {
         NS_WARNING("Failed to decode!");
         return NS_ERROR_DOM_DATA_CLONE_ERR;
       }
 
       if (!JS_SetElement(aCx, array, index, val)) {
-        NS_WARNING("Failed to set array element!");
+        IDB_WARNING("Failed to set array element!");
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
     }
   }
 
   aResult.setObject(*array);
   return NS_OK;
 }
@@ -121,17 +122,17 @@ HelperBase::WrapNative(JSContext* aCx,
   NS_ASSERTION(mRequest, "Null request!");
 
   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);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
 void
 HelperBase::ReleaseMainThreadObjects()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@@ -241,17 +242,17 @@ AsyncConnectionHelper::Run()
       }
 
       case Success_ActorDisconnected: {
         // Nothing needs to be done here.
         break;
       }
 
       case Error: {
-        NS_WARNING("MaybeSendResultsToChildProcess failed!");
+        IDB_WARNING("MaybeSendResultsToChildProcess failed!");
         mResultCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
         if (mRequest) {
           mRequest->NotifyHelperSentResultsToChildProcess(mResultCode);
         }
         break;
       }
 
       default:
@@ -336,16 +337,17 @@ AsyncConnectionHelper::Run()
   }
   else {
     // NS_ERROR_NOT_AVAILABLE is our special code for "database is invalidated"
     // and we should fail with RECOVERABLE_ERR.
     if (rv == NS_ERROR_NOT_AVAILABLE) {
       mResultCode = NS_ERROR_DOM_INDEXEDDB_RECOVERABLE_ERR;
     }
     else {
+      IDB_REPORT_INTERNAL_ERR();
       mResultCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
   }
 
   if (setProgressHandler) {
     nsCOMPtr<mozIStorageProgressHandler> handler;
     rv = connection->RemoveProgressHandler(getter_AddRefs(handler));
     NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "RemoveProgressHandler failed!");
@@ -454,23 +456,23 @@ AsyncConnectionHelper::OnSuccess()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(mRequest, "Null request!");
 
   PROFILER_MAIN_THREAD_LABEL("IndexedDB", "AsyncConnectionHelper::OnSuccess");
 
   nsRefPtr<nsIDOMEvent> event = CreateSuccessEvent(mRequest);
   if (!event) {
-    NS_ERROR("Failed to create event!");
+    IDB_WARNING("Failed to create event!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   bool dummy;
   nsresult rv = mRequest->DispatchEvent(event, &dummy);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   WidgetEvent* internalEvent = event->GetInternalNSEvent();
   NS_ASSERTION(internalEvent, "This should never be null!");
 
   NS_ASSERTION(!mTransaction ||
                mTransaction->IsOpen() ||
                mTransaction->IsAborted(),
                "How else can this be closed?!");
--- a/dom/indexedDB/IDBCursor.cpp
+++ b/dom/indexedDB/IDBCursor.cpp
@@ -15,16 +15,17 @@
 #include "nsThreadUtils.h"
 
 #include "AsyncConnectionHelper.h"
 #include "IDBEvents.h"
 #include "IDBIndex.h"
 #include "IDBObjectStore.h"
 #include "IDBTransaction.h"
 #include "ProfilerHelpers.h"
+#include "ReportInternalError.h"
 #include "TransactionThreadPool.h"
 
 #include "ipc/IndexedDBChild.h"
 #include "ipc/IndexedDBParent.h"
 
 #include "IndexedDatabaseInlines.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/UnionTypes.h"
@@ -492,17 +493,17 @@ IDBCursor::ContinueInternal(const Key& a
       break;
 
     default:
       MOZ_ASSUME_UNREACHABLE("Unknown cursor type!");
   }
 
   nsresult rv = helper->DispatchToTransactionPool();
   if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch!");
+    IDB_WARNING("Failed to dispatch!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return;
   }
 
   mContinueCalled = true;
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBCursor)
@@ -993,29 +994,30 @@ CursorHelper::Dispatch(nsIEventTarget* a
 
   if (IndexedDatabaseManager::IsMainProcess()) {
     return AsyncConnectionHelper::Dispatch(aDatabaseThread);
   }
 
   // If we've been invalidated then there's no point sending anything to the
   // parent process.
   if (mCursor->Transaction()->Database()->IsInvalidated()) {
+    IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   IndexedDBCursorChild* cursorActor = mCursor->GetActorChild();
   NS_ASSERTION(cursorActor, "Must have an actor here!");
 
   CursorRequestParams params;
   nsresult rv = PackArgumentsForParentProcess(params);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NoDispatchEventTarget target;
   rv = AsyncConnectionHelper::Dispatch(&target);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mActor = new IndexedDBCursorRequestChild(this, mCursor, params.type());
   cursorActor->SendPIndexedDBRequestConstructor(mActor, params);
 
   return NS_OK;
 }
 
 nsresult
@@ -1041,38 +1043,38 @@ ContinueHelper::DoDatabaseWork(mozIStora
   else {
     query.Assign(mCursor->mContinueToQuery);
   }
   NS_ASSERTION(!query.IsEmpty(), "Bad query!");
 
   query.AppendInt(mCount);
 
   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = BindArgumentsToStatement(stmt);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NS_ASSERTION(mCount > 0, "Not ok!");
 
   bool hasResult;
   for (int32_t index = 0; index < mCount; index++) {
     rv = stmt->ExecuteStep(&hasResult);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     if (!hasResult) {
       break;
     }
   }
 
   if (hasResult) {
     rv = GatherResultsFromStatement(stmt);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
   else {
     mKey.Unset();
   }
 
   return NS_OK;
 }
 
@@ -1188,17 +1190,17 @@ ContinueHelper::UnpackResponseFromParent
 
   const SerializedStructuredCloneReadInfo& cloneInfo = response.cloneInfo();
 
   NS_ASSERTION((!cloneInfo.dataLength && !cloneInfo.data) ||
                (cloneInfo.dataLength && cloneInfo.data),
                "Inconsistent clone info!");
 
   if (!mCloneReadInfo.SetFromSerialized(cloneInfo)) {
-    NS_WARNING("Failed to copy clone buffer!");
+    IDB_WARNING("Failed to copy clone buffer!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   IDBObjectStore::ConvertActorsToBlobs(response.blobsChild(),
                                        mCloneReadInfo.mFiles);
   return NS_OK;
 }
 
@@ -1207,17 +1209,17 @@ ContinueObjectStoreHelper::BindArguments
                                                mozIStorageStatement* aStatement)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aStatement);
 
   // Bind object store id.
   nsresult rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("id"),
                                             mCursor->mObjectStore->Id());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NS_NAMED_LITERAL_CSTRING(currentKeyName, "current_key");
   NS_NAMED_LITERAL_CSTRING(rangeKeyName, "range_key");
 
   // Bind current key.
   const Key& currentKey = mCursor->mContinueToKey.IsUnset() ?
                           mCursor->mKey :
                           mCursor->mContinueToKey;
@@ -1269,17 +1271,17 @@ ContinueObjectStoreKeyHelper::GatherResu
 }
 
 nsresult
 ContinueIndexHelper::BindArgumentsToStatement(mozIStorageStatement* aStatement)
 {
   // Bind index id.
   nsresult rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("id"),
                                             mCursor->mIndex->Id());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NS_NAMED_LITERAL_CSTRING(currentKeyName, "current_key");
 
   // Bind current key.
   const Key& currentKey = mCursor->mContinueToKey.IsUnset() ?
                           mCursor->mKey :
                           mCursor->mContinueToKey;
 
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -24,16 +24,17 @@
 #include "IDBEvents.h"
 #include "IDBFactory.h"
 #include "IDBFileHandle.h"
 #include "IDBIndex.h"
 #include "IDBObjectStore.h"
 #include "IDBTransaction.h"
 #include "IDBFactory.h"
 #include "ProfilerHelpers.h"
+#include "ReportInternalError.h"
 #include "TransactionThreadPool.h"
 
 #include "ipc/IndexedDBChild.h"
 #include "ipc/IndexedDBParent.h"
 
 #include "mozilla/dom/IDBDatabaseBinding.h"
 
 USING_INDEXEDDB_NAMESPACE
@@ -413,39 +414,39 @@ IDBDatabase::CreateObjectStoreInternal(I
 
   nsRefPtr<ObjectStoreInfo> newInfo = new ObjectStoreInfo();
   *static_cast<ObjectStoreInfoGuts*>(newInfo.get()) = aInfo;
 
   newInfo->nextAutoIncrementId = aInfo.autoIncrement ? 1 : 0;
   newInfo->comittedAutoIncrementId = newInfo->nextAutoIncrementId;
 
   if (!databaseInfo->PutObjectStore(newInfo)) {
-    NS_WARNING("Put failed!");
+    IDB_WARNING("Put failed!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   // Don't leave this in the hash if we fail below!
   AutoRemoveObjectStore autoRemove(databaseInfo, newInfo->name);
 
   nsRefPtr<IDBObjectStore> objectStore =
     aTransaction->GetOrCreateObjectStore(newInfo->name, newInfo, true);
   if (!objectStore) {
-    NS_WARNING("Failed to get objectStore!");
+    IDB_WARNING("Failed to get objectStore!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   if (IndexedDatabaseManager::IsMainProcess()) {
     nsRefPtr<CreateObjectStoreHelper> helper =
       new CreateObjectStoreHelper(aTransaction, objectStore);
 
     nsresult rv = helper->DispatchToTransactionPool();
     if (NS_FAILED(rv)) {
-      NS_WARNING("Failed to dispatch!");
+      IDB_WARNING("Failed to dispatch!");
       aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
       return nullptr;
     }
   }
 
   autoRemove.forget();
 
   IDB_PROFILER_MARK("IndexedDB Pseudo-request: "
@@ -497,26 +498,26 @@ already_AddRefed<nsIDOMDOMStringList>
 IDBDatabase::GetObjectStoreNames(ErrorResult& aRv) const
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   DatabaseInfo* info = Info();
 
   nsAutoTArray<nsString, 10> objectStoreNames;
   if (!info->GetObjectStoreNames(objectStoreNames)) {
-    NS_WARNING("Couldn't get names!");
+    IDB_WARNING("Couldn't get names!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   nsRefPtr<nsDOMStringList> list(new nsDOMStringList());
   uint32_t count = objectStoreNames.Length();
   for (uint32_t index = 0; index < count; index++) {
     if (!list->Add(objectStoreNames[index])) {
-      NS_WARNING("Failed to add element");
+      IDB_WARNING("Failed to add element");
       aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
       return nullptr;
     }
   }
 
   return list.forget();
 }
 
@@ -585,17 +586,17 @@ IDBDatabase::DeleteObjectStore(const nsA
   }
 
   if (IndexedDatabaseManager::IsMainProcess()) {
     nsRefPtr<DeleteObjectStoreHelper> helper =
       new DeleteObjectStoreHelper(transaction, objectStoreInfo->id);
 
     nsresult rv = helper->DispatchToTransactionPool();
     if (NS_FAILED(rv)) {
-      NS_WARNING("Failed to dispatch!");
+      IDB_WARNING("Failed to dispatch!");
       aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
       return;
     }
   }
   else {
     IndexedDBTransactionChild* actor = transaction->GetActorChild();
     NS_ASSERTION(actor, "Must have an actor here!");
 
@@ -614,16 +615,17 @@ IDBDatabase::DeleteObjectStore(const nsA
 
 already_AddRefed<indexedDB::IDBTransaction>
 IDBDatabase::Transaction(const Sequence<nsString>& aStoreNames,
                          IDBTransactionMode aMode, ErrorResult& aRv)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (QuotaManager::IsShuttingDown()) {
+    IDB_REPORT_INTERNAL_ERR();
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   if (mClosed) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
     return nullptr;
   }
@@ -660,17 +662,17 @@ IDBDatabase::Transaction(const Sequence<
       aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR);
       return nullptr;
     }
   }
 
   nsRefPtr<IDBTransaction> transaction =
     IDBTransaction::Create(this, aStoreNames, transactionMode, false);
   if (!transaction) {
-    NS_WARNING("Failed to create the transaction!");
+    IDB_WARNING("Failed to create the transaction!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   IDB_PROFILER_MARK("IndexedDB Transaction %llu: database(%s).transaction(%s)",
                     "IDBTransaction[%llu] MT Started",
                     transaction->GetSerialNumber(), IDB_PROFILER_STRING(this),
                     IDB_PROFILER_STRING(transaction));
@@ -681,22 +683,23 @@ IDBDatabase::Transaction(const Sequence<
 already_AddRefed<IDBRequest>
 IDBDatabase::MozCreateFileHandle(const nsAString& aName,
                                  const Optional<nsAString>& aType,
                                  ErrorResult& aRv)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (!IndexedDatabaseManager::IsMainProcess()) {
-    NS_WARNING("Not supported yet!");
+    IDB_WARNING("Not supported yet!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   if (QuotaManager::IsShuttingDown()) {
+    IDB_REPORT_INTERNAL_ERR();
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   if (mClosed) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
     return nullptr;
   }
@@ -707,17 +710,17 @@ IDBDatabase::MozCreateFileHandle(const n
     new CreateFileHelper(this, request, aName,
                          aType.WasPassed() ? aType.Value() : EmptyString());
 
   QuotaManager* quotaManager = QuotaManager::Get();
   NS_ASSERTION(quotaManager, "We should definitely have a manager here");
 
   nsresult rv = helper->Dispatch(quotaManager->IOThread());
   if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch!");
+    IDB_WARNING("Failed to dispatch!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   return request.forget();
 }
 
 NS_IMETHODIMP
@@ -829,46 +832,46 @@ CreateObjectStoreHelper::DoDatabaseWork(
     return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
   }
 
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(NS_LITERAL_CSTRING(
     "INSERT INTO object_store (id, auto_increment, name, key_path) "
     "VALUES (:id, :auto_increment, :name, :key_path)"
   ));
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"),
                                        mObjectStore->Id());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("auto_increment"),
                              mObjectStore->IsAutoIncrement() ? 1 : 0);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mObjectStore->Name());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   const KeyPath& keyPath = mObjectStore->GetKeyPath();
   if (keyPath.IsValid()) {
     nsAutoString keyPathSerialization;
     keyPath.SerializeToString(keyPathSerialization);
     rv = stmt->BindStringByName(NS_LITERAL_CSTRING("key_path"),
                                 keyPathSerialization);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
   else {
     rv = stmt->BindNullByName(NS_LITERAL_CSTRING("key_path"));
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
   rv = stmt->Execute();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
 void
 CreateObjectStoreHelper::ReleaseMainThreadObjects()
 {
   mObjectStore = nullptr;
@@ -883,25 +886,25 @@ DeleteObjectStoreHelper::DoDatabaseWork(
 
   PROFILER_LABEL("IndexedDB", "DeleteObjectStoreHelper::DoDatabaseWork");
 
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(NS_LITERAL_CSTRING(
     "DELETE FROM object_store "
     "WHERE id = :id "
   ));
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), mObjectStoreId);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = stmt->Execute();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
 nsresult
 CreateFileHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   AssertIsOnIOThread();
@@ -912,44 +915,44 @@ CreateFileHelper::DoDatabaseWork(mozISto
   if (IndexedDatabaseManager::InLowDiskSpaceMode()) {
     NS_WARNING("Refusing to create file because disk space is low!");
     return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
   }
 
   FileManager* fileManager = mDatabase->Manager();
 
   mFileInfo = fileManager->GetNewFileInfo();
-  NS_ENSURE_TRUE(mFileInfo, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(mFileInfo, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   const int64_t& fileId = mFileInfo->Id();
 
   nsCOMPtr<nsIFile> directory = fileManager->EnsureJournalDirectory();
   NS_ENSURE_TRUE(directory, NS_ERROR_FAILURE);
 
   nsCOMPtr<nsIFile> file = fileManager->GetFileForId(directory, fileId);
   NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
 
   nsresult rv = file->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
   NS_ENSURE_SUCCESS(rv, rv);
 
   directory = fileManager->GetDirectory();
-  NS_ENSURE_TRUE(directory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(directory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   file = fileManager->GetFileForId(directory, fileId);
-  NS_ENSURE_TRUE(file, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(file, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = file->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
 nsresult
 CreateFileHelper::GetSuccessResult(JSContext* aCx,
                                    JS::MutableHandle<JS::Value> aVal)
 {
   nsRefPtr<IDBFileHandle> fileHandle =
     IDBFileHandle::Create(mDatabase, mName, mType, mFileInfo.forget());
-  NS_ENSURE_TRUE(fileHandle, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(fileHandle, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return WrapNative(aCx, NS_ISUPPORTS_CAST(nsIDOMFileHandle*, fileHandle),
                     aVal);
 }
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -39,16 +39,17 @@
 #include "CheckPermissionsHelper.h"
 #include "DatabaseInfo.h"
 #include "IDBDatabase.h"
 #include "IDBEvents.h"
 #include "IDBKeyRange.h"
 #include "IndexedDatabaseManager.h"
 #include "Key.h"
 #include "ProfilerHelpers.h"
+#include "ReportInternalError.h"
 #include "nsNetUtil.h"
 
 #include "ipc/IndexedDBChild.h"
 
 #define PREF_INDEXEDDB_ENABLED "dom.indexedDB.enabled"
 
 USING_INDEXEDDB_NAMESPACE
 USING_QUOTA_NAMESPACE
@@ -104,28 +105,28 @@ IDBFactory::Create(nsPIDOMWindow* aWindo
                    const nsACString& aASCIIOrigin,
                    ContentParent* aContentParent,
                    IDBFactory** aFactory)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aASCIIOrigin.IsEmpty() || nsContentUtils::IsCallerChrome(),
                "Non-chrome may not supply their own origin!");
 
-  NS_ENSURE_TRUE(aWindow, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(aWindow, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (aWindow->IsOuterWindow()) {
     aWindow = aWindow->GetCurrentInnerWindow();
-    NS_ENSURE_TRUE(aWindow, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_TRUE(aWindow, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
   // Make sure that the manager is up before we do anything here since lots of
   // decisions depend on which process we're running in.
   indexedDB::IndexedDatabaseManager* mgr =
     indexedDB::IndexedDatabaseManager::GetOrCreate();
-  NS_ENSURE_TRUE(mgr, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(mgr, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsresult rv;
 
   nsCString group(aGroup);
   nsCString origin(aASCIIOrigin);
   StoragePrivilege privilege;
   PersistenceType defaultPersistenceType;
   if (origin.IsEmpty()) {
@@ -149,17 +150,17 @@ IDBFactory::Create(nsPIDOMWindow* aWindo
   factory->mASCIIOrigin = origin;
   factory->mPrivilege = privilege;
   factory->mDefaultPersistenceType = defaultPersistenceType;
   factory->mWindow = aWindow;
   factory->mContentParent = aContentParent;
 
   if (!IndexedDatabaseManager::IsMainProcess()) {
     TabChild* tabChild = TabChild::GetFrom(aWindow);
-    NS_ENSURE_TRUE(tabChild, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_TRUE(tabChild, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     IndexedDBChild* actor = new IndexedDBChild(origin);
 
     bool allowed;
     tabChild->SendPIndexedDBConstructor(actor, group, origin, &allowed);
 
     if (!allowed) {
       actor->Send__delete__(actor);
@@ -186,17 +187,17 @@ IDBFactory::Create(JSContext* aCx,
   NS_ASSERTION(aOwningObject, "Null object!");
   NS_ASSERTION(JS_GetGlobalForObject(aCx, aOwningObject) == aOwningObject,
                "Not a global object!");
   NS_ASSERTION(nsContentUtils::IsCallerChrome(), "Only for chrome!");
 
   // Make sure that the manager is up before we do anything here since lots of
   // decisions depend on which process we're running in.
   IndexedDatabaseManager* mgr = IndexedDatabaseManager::GetOrCreate();
-  NS_ENSURE_TRUE(mgr, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(mgr, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsCString group;
   nsCString origin;
   StoragePrivilege privilege;
   PersistenceType defaultPersistenceType;
   QuotaManager::GetInfoForChrome(&group, &origin, &privilege,
                                  &defaultPersistenceType);
 
@@ -208,17 +209,17 @@ IDBFactory::Create(JSContext* aCx,
   factory->mOwningObject = aOwningObject;
   factory->mContentParent = aContentParent;
 
   mozilla::HoldJSObjects(factory.get());
   factory->mRootedOwningObject = true;
 
   if (!IndexedDatabaseManager::IsMainProcess()) {
     ContentChild* contentChild = ContentChild::GetSingleton();
-    NS_ENSURE_TRUE(contentChild, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_TRUE(contentChild, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     IndexedDBChild* actor = new IndexedDBChild(origin);
 
     contentChild->SendPIndexedDBConstructor(actor);
 
     actor->SetFactory(factory);
   }
 
@@ -367,17 +368,17 @@ IDBFactory::SetDefaultPragmas(mozIStorag
     // The "INSERT OR REPLACE" statement doesn't fire the update trigger,
     // instead it fires only the insert trigger. This confuses the update
     // refcount function. This behavior changes with enabled recursive triggers,
     // so the statement fires the delete trigger first and then the insert
     // trigger.
     "PRAGMA recursive_triggers = ON;";
 
   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(query));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
 inline
 bool
 IgnoreWhitespace(char16_t c)
 {
@@ -606,28 +607,28 @@ IDBFactory::OpenInternal(const nsAString
 
   if (aPrivilege == Chrome) {
     // Chrome privilege, ignore the persistence type parameter.
     aPersistenceType = PERSISTENCE_TYPE_PERSISTENT;
   }
 
   nsRefPtr<IDBOpenDBRequest> request =
     IDBOpenDBRequest::Create(this, window, scriptOwner);
-  NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsresult rv;
 
   if (IndexedDatabaseManager::IsMainProcess()) {
     nsRefPtr<OpenDatabaseHelper> openHelper =
       new OpenDatabaseHelper(request, aName, aGroup, aASCIIOrigin, aVersion,
                              aPersistenceType, aDeleting, mContentParent,
                              aPrivilege);
 
     rv = openHelper->Init();
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     if (!Preferences::GetBool(PREF_INDEXEDDB_ENABLED)) {
       openHelper->SetError(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
       rv = openHelper->WaitForOpenAllowed();
     }
     else {
       if (mPrivilege != Chrome &&
           aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
@@ -642,17 +643,17 @@ IDBFactory::OpenInternal(const nsAString
                              Nullable<PersistenceType>(aPersistenceType),
                              openHelper->Id(), permissionHelper);
       }
       else {
         // Chrome and temporary storage doesn't need to check the permission.
         rv = openHelper->WaitForOpenAllowed();
       }
     }
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
   else if (aDeleting) {
     nsCString databaseId;
     QuotaManager::GetStorageId(aPersistenceType, aASCIIOrigin, Client::IDB,
                                aName, databaseId);
     MOZ_ASSERT(!databaseId.IsEmpty());
 
     IndexedDBDeleteDatabaseRequestChild* actor =
@@ -793,16 +794,17 @@ IDBFactory::Open(nsIPrincipal* aPrincipa
   nsCString origin;
   StoragePrivilege privilege;
   PersistenceType defaultPersistenceType;
   if (aPrincipal) {
     rv = QuotaManager::GetInfoFromPrincipal(aPrincipal, &group, &origin,
                                             &privilege,
                                             &defaultPersistenceType);
     if (NS_FAILED(rv)) {
+      IDB_REPORT_INTERNAL_ERR();
       aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
       return nullptr;
     }
   }
   else {
     group = mGroup;
     origin = mASCIIOrigin;
     privilege = mPrivilege;
--- a/dom/indexedDB/IDBIndex.cpp
+++ b/dom/indexedDB/IDBIndex.cpp
@@ -20,16 +20,17 @@
 #include "AsyncConnectionHelper.h"
 #include "DatabaseInfo.h"
 #include "IDBCursor.h"
 #include "IDBEvents.h"
 #include "IDBKeyRange.h"
 #include "IDBObjectStore.h"
 #include "IDBTransaction.h"
 #include "ProfilerHelpers.h"
+#include "ReportInternalError.h"
 
 #include "ipc/IndexedDBChild.h"
 #include "ipc/IndexedDBParent.h"
 
 #include "IndexedDatabaseInlines.h"
 
 USING_INDEXEDDB_NAMESPACE
 using namespace mozilla::dom;
@@ -433,27 +434,27 @@ IDBIndex::GetInternal(IDBKeyRange* aKeyR
   IDBTransaction* transaction = mObjectStore->Transaction();
   if (!transaction->IsOpen()) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
     return nullptr;
   }
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   if (!request) {
-    NS_WARNING("Failed to generate request!");
+    IDB_WARNING("Failed to generate request!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   nsRefPtr<GetHelper> helper =
     new GetHelper(transaction, request, this, aKeyRange);
 
   nsresult rv = helper->DispatchToTransactionPool();
   if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch!");
+    IDB_WARNING("Failed to dispatch!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   IDB_PROFILER_MARK("IndexedDB Request %llu: "
                     "database(%s).transaction(%s).objectStore(%s).index(%s)."
                     "get(%s)",
                     "IDBRequest[%llu] MT IDBIndex.get()",
@@ -475,27 +476,27 @@ IDBIndex::GetKeyInternal(IDBKeyRange* aK
   IDBTransaction* transaction = mObjectStore->Transaction();
   if (!transaction->IsOpen()) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
     return nullptr;
   }
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   if (!request) {
-    NS_WARNING("Failed to generate request!");
+    IDB_WARNING("Failed to generate request!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   nsRefPtr<GetKeyHelper> helper =
     new GetKeyHelper(transaction, request, this, aKeyRange);
 
   nsresult rv = helper->DispatchToTransactionPool();
   if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch!");
+    IDB_WARNING("Failed to dispatch!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   IDB_PROFILER_MARK("IndexedDB Request %llu: "
                     "database(%s).transaction(%s).objectStore(%s).index(%s)."
                     "getKey(%s)",
                     "IDBRequest[%llu] MT IDBIndex.getKey()",
@@ -518,27 +519,27 @@ IDBIndex::GetAllInternal(IDBKeyRange* aK
   IDBTransaction* transaction = mObjectStore->Transaction();
   if (!transaction->IsOpen()) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
     return nullptr;
   }
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   if (!request) {
-    NS_WARNING("Failed to generate request!");
+    IDB_WARNING("Failed to generate request!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   nsRefPtr<GetAllHelper> helper =
     new GetAllHelper(transaction, request, this, aKeyRange, aLimit);
 
   nsresult rv = helper->DispatchToTransactionPool();
   if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch!");
+    IDB_WARNING("Failed to dispatch!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   IDB_PROFILER_MARK("IndexedDB Request %llu: "
                     "database(%s).transaction(%s).objectStore(%s).index(%s)."
                     "getAll(%s, %lu)",
                     "IDBRequest[%llu] MT IDBIndex.getAll()",
@@ -562,27 +563,27 @@ IDBIndex::GetAllKeysInternal(IDBKeyRange
   IDBTransaction* transaction = mObjectStore->Transaction();
   if (!transaction->IsOpen()) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
     return nullptr;
   }
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   if (!request) {
-    NS_WARNING("Failed to generate request!");
+    IDB_WARNING("Failed to generate request!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   nsRefPtr<GetAllKeysHelper> helper =
     new GetAllKeysHelper(transaction, request, this, aKeyRange, aLimit);
 
   nsresult rv = helper->DispatchToTransactionPool();
   if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch!");
+    IDB_WARNING("Failed to dispatch!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   IDB_PROFILER_MARK("IndexedDB Request %llu: "
                     "database(%s).transaction(%s).objectStore(%s).index(%s)."
                     "getAllKeys(%s, %lu)",
                     "IDBRequest[%llu] MT IDBIndex.getAllKeys()",
@@ -605,27 +606,27 @@ IDBIndex::CountInternal(IDBKeyRange* aKe
   IDBTransaction* transaction = mObjectStore->Transaction();
   if (!transaction->IsOpen()) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
     return nullptr;
   }
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   if (!request) {
-    NS_WARNING("Failed to generate request!");
+    IDB_WARNING("Failed to generate request!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   nsRefPtr<CountHelper> helper =
     new CountHelper(transaction, request, this, aKeyRange);
 
   nsresult rv = helper->DispatchToTransactionPool();
   if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch!");
+    IDB_WARNING("Failed to dispatch!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   IDB_PROFILER_MARK("IndexedDB Request %llu: "
                     "database(%s).transaction(%s).objectStore(%s).index(%s)."
                     "count(%s)",
                     "IDBRequest[%llu] MT IDBIndex.count()",
@@ -651,27 +652,27 @@ IDBIndex::OpenKeyCursorInternal(IDBKeyRa
     return nullptr;
   }
 
   IDBCursor::Direction direction =
     static_cast<IDBCursor::Direction>(aDirection);
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   if (!request) {
-    NS_WARNING("Failed to generate request!");
+    IDB_WARNING("Failed to generate request!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   nsRefPtr<OpenKeyCursorHelper> helper =
     new OpenKeyCursorHelper(transaction, request, this, aKeyRange, direction);
 
   nsresult rv = helper->DispatchToTransactionPool();
   if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch!");
+    IDB_WARNING("Failed to dispatch!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   IDB_PROFILER_MARK("IndexedDB Request %llu: "
                     "database(%s).transaction(%s).objectStore(%s).index(%s)."
                     "openKeyCursor(%s)",
                     "IDBRequest[%llu] MT IDBIndex.openKeyCursor()",
@@ -697,23 +698,23 @@ IDBIndex::OpenCursorInternal(IDBKeyRange
   if (!transaction->IsOpen()) {
     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
   }
 
   IDBCursor::Direction direction =
     static_cast<IDBCursor::Direction>(aDirection);
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
-  NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<OpenCursorHelper> helper =
     new OpenCursorHelper(transaction, request, this, aKeyRange, direction);
 
   nsresult rv = helper->DispatchToTransactionPool();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   IDB_PROFILER_MARK("IndexedDB Request %llu: "
                     "database(%s).transaction(%s).objectStore(%s).index(%s)."
                     "openCursor(%s)",
                     "IDBRequest[%llu] MT IDBIndex.openCursor()",
                     request->GetSerialNumber(),
                     IDB_PROFILER_STRING(ObjectStore()->Transaction()->
                                         Database()),
@@ -736,17 +737,17 @@ IDBIndex::OpenCursorFromChildProcess(IDB
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   IDBCursor::Direction direction =
     static_cast<IDBCursor::Direction>(aDirection);
 
   nsRefPtr<IDBCursor> cursor =
     IDBCursor::Create(aRequest, mObjectStore->Transaction(), this, direction,
                       Key(), EmptyCString(), EmptyCString(), aKey, aObjectKey);
-  NS_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   cursor.forget(_retval);
   return NS_OK;
 }
 
 nsresult
 IDBIndex::OpenCursorFromChildProcess(
                             IDBRequest* aRequest,
@@ -763,27 +764,27 @@ IDBIndex::OpenCursorFromChildProcess(
                "Inconsistent clone info!");
 
   IDBCursor::Direction direction =
     static_cast<IDBCursor::Direction>(aDirection);
 
   StructuredCloneReadInfo cloneInfo;
 
   if (!cloneInfo.SetFromSerialized(aCloneInfo)) {
-    NS_WARNING("Failed to copy clone buffer!");
+    IDB_WARNING("Failed to copy clone buffer!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   cloneInfo.mFiles.SwapElements(aBlobs);
 
   nsRefPtr<IDBCursor> cursor =
     IDBCursor::Create(aRequest, mObjectStore->Transaction(), this, direction,
                       Key(), EmptyCString(), EmptyCString(), aKey, aObjectKey,
                       cloneInfo);
-  NS_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NS_ASSERTION(!cloneInfo.mCloneBuffer.data(), "Should have swapped!");
 
   cursor.forget(_retval);
   return NS_OK;
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBIndex)
@@ -964,27 +965,27 @@ IDBIndex::OpenCursor(JSContext* aCx,
     aRv = IDBKeyRange::FromJSVal(aCx, aRange.Value(), getter_AddRefs(keyRange));
     ENSURE_SUCCESS(aRv, nullptr);
   }
 
   IDBCursor::Direction direction = IDBCursor::ConvertDirection(aDirection);
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   if (!request) {
-    NS_WARNING("Failed to generate request!");
+    IDB_WARNING("Failed to generate request!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   nsRefPtr<OpenCursorHelper> helper =
     new OpenCursorHelper(transaction, request, this, keyRange, direction);
 
   nsresult rv = helper->DispatchToTransactionPool();
   if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch!");
+    IDB_WARNING("Failed to dispatch!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<IDBRequest>
@@ -1046,29 +1047,30 @@ IndexHelper::Dispatch(nsIEventTarget* aD
 
   if (IndexedDatabaseManager::IsMainProcess()) {
     return AsyncConnectionHelper::Dispatch(aDatabaseThread);
   }
 
   // If we've been invalidated then there's no point sending anything to the
   // parent process.
   if (mIndex->ObjectStore()->Transaction()->Database()->IsInvalidated()) {
+    IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   IndexedDBIndexChild* indexActor = mIndex->GetActorChild();
   NS_ASSERTION(indexActor, "Must have an actor here!");
 
   IndexRequestParams params;
   nsresult rv = PackArgumentsForParentProcess(params);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NoDispatchEventTarget target;
   rv = AsyncConnectionHelper::Dispatch(&target);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mActor = new IndexedDBIndexRequestChild(this, mIndex, params.type());
   indexActor->SendPIndexedDBRequestConstructor(mActor, params);
 
   return NS_OK;
 }
 
 nsresult
@@ -1095,30 +1097,30 @@ GetKeyHelper::DoDatabaseWork(mozIStorage
 
   nsCString query = NS_LITERAL_CSTRING("SELECT object_data_key FROM ") +
                     indexTable +
                     NS_LITERAL_CSTRING(" WHERE index_id = :index_id") +
                     keyRangeClause +
                     NS_LITERAL_CSTRING(" LIMIT 1");
 
   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
                                       mIndex->Id());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = mKeyRange->BindToStatement(stmt);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasResult;
   rv = stmt->ExecuteStep(&hasResult);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (hasResult) {
     rv = mKey.SetFromStatement(stmt, 0);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
@@ -1221,30 +1223,30 @@ GetHelper::DoDatabaseWork(mozIStorageCon
                                        "INNER JOIN ") + indexTable +
                     NS_LITERAL_CSTRING(" AS index_table ON object_data.id = ") +
                     NS_LITERAL_CSTRING("index_table.object_data_id WHERE "
                                        "index_id = :index_id") +
                     keyRangeClause +
                     NS_LITERAL_CSTRING(" LIMIT 1");
 
   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
                                       mIndex->Id());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = mKeyRange->BindToStatement(stmt);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasResult;
   rv = stmt->ExecuteStep(&hasResult);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (hasResult) {
     rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 0, 1,
       mDatabase, mCloneReadInfo);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
@@ -1350,17 +1352,17 @@ GetHelper::UnpackResponseFromParentProce
   const GetResponse& getResponse = aResponseValue.get_GetResponse();
   const SerializedStructuredCloneReadInfo& cloneInfo = getResponse.cloneInfo();
 
   NS_ASSERTION((!cloneInfo.dataLength && !cloneInfo.data) ||
                (cloneInfo.dataLength && cloneInfo.data),
                "Inconsistent clone info!");
 
   if (!mCloneReadInfo.SetFromSerialized(cloneInfo)) {
-    NS_WARNING("Failed to copy clone buffer!");
+    IDB_WARNING("Failed to copy clone buffer!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   IDBObjectStore::ConvertActorsToBlobs(getResponse.blobsChild(),
                                        mCloneReadInfo.mFiles);
   return NS_OK;
 }
 
@@ -1393,23 +1395,23 @@ GetAllKeysHelper::DoDatabaseWork(mozISto
   }
 
   nsCString query = NS_LITERAL_CSTRING("SELECT object_data_key FROM ") +
                     tableName +
                     NS_LITERAL_CSTRING(" WHERE index_id = :index_id") +
                     keyRangeClause + limitClause;
 
   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
                                       mIndex->Id());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (mKeyRange) {
     rv = mKeyRange->BindToStatement(stmt);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   mKeys.SetCapacity(std::min<uint32_t>(50, mLimit));
 
@@ -1420,17 +1422,17 @@ GetAllKeysHelper::DoDatabaseWork(mozISto
     }
 
     Key* key = mKeys.AppendElement();
     NS_ASSERTION(key, "This shouldn't fail!");
 
     rv = key->SetFromStatement(stmt, 0);
     NS_ENSURE_SUCCESS(rv, rv);
   }
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
 nsresult
 GetAllKeysHelper::GetSuccessResult(JSContext* aCx,
                                    JS::MutableHandle<JS::Value> aVal)
 {
@@ -1441,39 +1443,39 @@ GetAllKeysHelper::GetSuccessResult(JSCon
                              "GetAllKeysHelper::GetSuccessResult "
                              "[IDBIndex.cpp]");
 
   nsTArray<Key> keys;
   mKeys.SwapElements(keys);
 
   JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0, nullptr));
   if (!array) {
-    NS_WARNING("Failed to make array!");
+    IDB_WARNING("Failed to make array!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   if (!keys.IsEmpty()) {
     if (!JS_SetArrayLength(aCx, array, uint32_t(keys.Length()))) {
-      NS_WARNING("Failed to set array length!");
+      IDB_WARNING("Failed to set array length!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     for (uint32_t index = 0, count = keys.Length(); index < count; index++) {
       const Key& key = keys[index];
       NS_ASSERTION(!key.IsUnset(), "Bad key!");
 
       JS::Rooted<JS::Value> value(aCx);
       nsresult rv = key.ToJSVal(aCx, &value);
       if (NS_FAILED(rv)) {
         NS_WARNING("Failed to get jsval for key!");
         return rv;
       }
 
       if (!JS_SetElement(aCx, array, index, value)) {
-        NS_WARNING("Failed to set array element!");
+        IDB_WARNING("Failed to set array element!");
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
     }
   }
 
   aVal.setObject(*array);
   return NS_OK;
 }
@@ -1577,23 +1579,23 @@ GetAllHelper::DoDatabaseWork(mozIStorage
   nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM object_data "
                                        "INNER JOIN ") + indexTable +
                     NS_LITERAL_CSTRING(" AS index_table ON object_data.id = "
                                        "index_table.object_data_id "
                                        "WHERE index_id = :index_id") +
                     keyRangeClause + limitClause;
 
   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
                                       mIndex->Id());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (mKeyRange) {
     rv = mKeyRange->BindToStatement(stmt);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   mCloneReadInfos.SetCapacity(50);
 
@@ -1605,17 +1607,17 @@ GetAllHelper::DoDatabaseWork(mozIStorage
 
     StructuredCloneReadInfo* readInfo = mCloneReadInfos.AppendElement();
     NS_ASSERTION(readInfo, "This shouldn't fail!");
 
     rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 0, 1,
       mDatabase, *readInfo);
     NS_ENSURE_SUCCESS(rv, rv);
   }
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
 nsresult
 GetAllHelper::GetSuccessResult(JSContext* aCx,
                                JS::MutableHandle<JS::Value> aVal)
 {
@@ -1756,17 +1758,17 @@ GetAllHelper::UnpackResponseFromParentPr
   mCloneReadInfos.SetCapacity(cloneInfos.Length());
 
   for (uint32_t index = 0; index < cloneInfos.Length(); index++) {
     const SerializedStructuredCloneReadInfo srcInfo = cloneInfos[index];
     const InfallibleTArray<PBlobChild*>& blobs = blobArrays[index].blobsChild();
 
     StructuredCloneReadInfo* destInfo = mCloneReadInfos.AppendElement();
     if (!destInfo->SetFromSerialized(srcInfo)) {
-      NS_WARNING("Failed to copy clone buffer!");
+      IDB_WARNING("Failed to copy clone buffer!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     IDBObjectStore::ConvertActorsToBlobs(blobs, destInfo->mFiles);
   }
 
   return NS_OK;
 }
@@ -1816,32 +1818,32 @@ OpenKeyCursorHelper::DoDatabaseWork(mozI
   nsCString firstQuery = NS_LITERAL_CSTRING("SELECT value, object_data_key "
                                             "FROM ") + table +
                          NS_LITERAL_CSTRING(" WHERE index_id = :index_id") +
                          keyRangeClause + directionClause +
                          NS_LITERAL_CSTRING(" LIMIT 1");
 
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(firstQuery);
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
                                       mIndex->Id());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (mKeyRange) {
     rv = mKeyRange->BindToStatement(stmt);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   bool hasResult;
   rv = stmt->ExecuteStep(&hasResult);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (!hasResult) {
     mKey.Unset();
     return NS_OK;
   }
 
   rv = mKey.SetFromStatement(stmt, 0);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -1944,32 +1946,32 @@ OpenKeyCursorHelper::EnsureCursor()
 {
   if (mCursor || mKey.IsUnset()) {
     return NS_OK;
   }
 
   nsRefPtr<IDBCursor> cursor =
     IDBCursor::Create(mRequest, mTransaction, mIndex, mDirection, mRangeKey,
                       mContinueQuery, mContinueToQuery, mKey, mObjectKey);
-  NS_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mCursor.swap(cursor);
   return NS_OK;
 }
 
 nsresult
 OpenKeyCursorHelper::GetSuccessResult(JSContext* aCx,
                                       JS::MutableHandle<JS::Value> aVal)
 {
   nsresult rv = EnsureCursor();
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (mCursor) {
     rv = WrapNative(aCx, mCursor, aVal);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
   else {
     aVal.setUndefined();
   }
 
   return NS_OK;
 }
 
@@ -2094,18 +2096,17 @@ OpenKeyCursorHelper::UnpackResponseFromP
           response.get_PIndexedDBCursorChild());
 
       mCursor = actor->ForgetStrongCursor();
       NS_ASSERTION(mCursor, "This should never be null!");
 
     } break;
 
     default:
-      NS_NOTREACHED("Unknown response union type!");
-      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+      MOZ_CRASH();
   }
 
   return NS_OK;
 }
 
 nsresult
 OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
@@ -2161,31 +2162,31 @@ OpenCursorHelper::DoDatabaseWork(mozISto
     NS_LITERAL_CSTRING(" AS index_table INNER JOIN object_data ON "
                        "index_table.object_data_id = object_data.id "
                        "WHERE index_table.index_id = :id") +
     keyRangeClause + directionClause +
     NS_LITERAL_CSTRING(" LIMIT 1");
 
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(firstQuery);
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), mIndex->Id());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (mKeyRange) {
     rv = mKeyRange->BindToStatement(stmt);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   bool hasResult;
   rv = stmt->ExecuteStep(&hasResult);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (!hasResult) {
     mKey.Unset();
     return NS_OK;
   }
 
   rv = mKey.SetFromStatement(stmt, 0);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -2299,17 +2300,17 @@ OpenCursorHelper::EnsureCursor()
   NS_ASSERTION(mSerializedCloneReadInfo.data &&
                mSerializedCloneReadInfo.dataLength,
                "Shouldn't be possible!");
 
   nsRefPtr<IDBCursor> cursor =
     IDBCursor::Create(mRequest, mTransaction, mIndex, mDirection, mRangeKey,
                       mContinueQuery, mContinueToQuery, mKey, mObjectKey,
                       mCloneReadInfo);
-  NS_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NS_ASSERTION(!mCloneReadInfo.mCloneBuffer.data(), "Should have swapped!");
 
   mCursor.swap(cursor);
   return NS_OK;
 }
 
 void
@@ -2472,38 +2473,38 @@ CountHelper::DoDatabaseWork(mozIStorageC
     }
   }
 
   nsCString query = NS_LITERAL_CSTRING("SELECT count(*) FROM ") + table +
                     NS_LITERAL_CSTRING(" WHERE index_id = :id") +
                     keyRangeClause;
 
   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), mIndex->Id());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (mKeyRange) {
     if (!mKeyRange->Lower().IsUnset()) {
       rv = mKeyRange->Lower().BindToStatement(stmt, lowerKeyName);
       NS_ENSURE_SUCCESS(rv, rv);
     }
     if (!mKeyRange->Upper().IsUnset()) {
       rv = mKeyRange->Upper().BindToStatement(stmt, upperKeyName);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   bool hasResult;
   rv = stmt->ExecuteStep(&hasResult);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-  NS_ENSURE_TRUE(hasResult, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(hasResult, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mCount = stmt->AsInt64(0);
   return NS_OK;
 }
 
 nsresult
 CountHelper::GetSuccessResult(JSContext* aCx,
                               JS::MutableHandle<JS::Value> aVal)
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -37,16 +37,17 @@
 #include "IDBFileHandle.h"
 #include "IDBIndex.h"
 #include "IDBKeyRange.h"
 #include "IDBTransaction.h"
 #include "DatabaseInfo.h"
 #include "DictionaryHelpers.h"
 #include "KeyPath.h"
 #include "ProfilerHelpers.h"
+#include "ReportInternalError.h"
 
 #include "ipc/IndexedDBChild.h"
 #include "ipc/IndexedDBParent.h"
 
 #include "IndexedDatabaseInlines.h"
 #include "nsCharSeparatedTokenizer.h"
 
 #define FILE_COPY_BUFFER_SIZE 32768
@@ -1042,22 +1043,24 @@ IDBObjectStore::AppendIndexUpdateInfo(
     return NS_OK;
   }
 
   if (!JSVAL_IS_PRIMITIVE(val) &&
       JS_IsArrayObject(aCx, JSVAL_TO_OBJECT(val))) {
     JS::Rooted<JSObject*> array(aCx, JSVAL_TO_OBJECT(val));
     uint32_t arrayLength;
     if (!JS_GetArrayLength(aCx, array, &arrayLength)) {
+      IDB_REPORT_INTERNAL_ERR();
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     for (uint32_t arrayIndex = 0; arrayIndex < arrayLength; arrayIndex++) {
       JS::Rooted<JS::Value> arrayItem(aCx);
       if (!JS_GetElement(aCx, array, arrayIndex, &arrayItem)) {
+        IDB_REPORT_INTERNAL_ERR();
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
 
       Key value;
       if (NS_FAILED(value.SetFromJSVal(aCx, arrayItem)) ||
           value.IsUnset()) {
         // Not a value we can do anything with, ignore it.
         continue;
@@ -1214,57 +1217,58 @@ IDBObjectStore::GetStructuredCloneReadIn
                  "Bad value type!");
   }
 #endif
 
   const uint8_t* blobData;
   uint32_t blobDataLength;
   nsresult rv = aStatement->GetSharedBlob(aDataIndex, &blobDataLength,
                                           &blobData);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   const char* compressed = reinterpret_cast<const char*>(blobData);
   size_t compressedLength = size_t(blobDataLength);
 
   static const fallible_t fallible = fallible_t();
 
   size_t uncompressedLength;
   if (!snappy::GetUncompressedLength(compressed, compressedLength,
                                      &uncompressedLength)) {
-    NS_WARNING("Snappy can't determine uncompressed length!");
+    IDB_WARNING("Snappy can't determine uncompressed length!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   nsAutoArrayPtr<char> uncompressed(new (fallible) char[uncompressedLength]);
   NS_ENSURE_TRUE(uncompressed, NS_ERROR_OUT_OF_MEMORY);
 
   if (!snappy::RawUncompress(compressed, compressedLength,
                              uncompressed.get())) {
-    NS_WARNING("Snappy can't determine uncompressed length!");
+    IDB_WARNING("Snappy can't determine uncompressed length!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   JSAutoStructuredCloneBuffer& buffer = aInfo.mCloneBuffer;
   if (!buffer.copy(reinterpret_cast<const uint64_t *>(uncompressed.get()),
                    uncompressedLength)) {
+    IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   bool isNull;
   rv = aStatement->GetIsNull(aFileIdsIndex, &isNull);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (!isNull) {
     nsString ids;
     rv = aStatement->GetString(aFileIdsIndex, ids);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     nsAutoTArray<int64_t, 10> array;
     rv = ConvertFileIdsToArray(ids, array);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     FileManager* fileManager = aDatabase->Manager();
 
     for (uint32_t i = 0; i < array.Length(); i++) {
       const int64_t& id = array[i];
 
       nsRefPtr<FileInfo> fileInfo = fileManager->GetFileInfo(id);
       NS_ASSERTION(fileInfo, "Null file info!");
@@ -1765,40 +1769,41 @@ IDBObjectStore::ConvertBlobsToActors(
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aContentParent, "Null contentParent!");
   NS_ASSERTION(aFileManager, "Null file manager!");
 
   if (!aFiles.IsEmpty()) {
     nsCOMPtr<nsIFile> directory = aFileManager->GetDirectory();
     if (!directory) {
-      NS_WARNING("Failed to get directory!");
+      IDB_WARNING("Failed to get directory!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     uint32_t fileCount = aFiles.Length();
     aActors.SetCapacity(fileCount);
 
     for (uint32_t index = 0; index < fileCount; index++) {
       const StructuredCloneFile& file = aFiles[index];
       NS_ASSERTION(file.mFileInfo, "This should never be null!");
 
       nsCOMPtr<nsIFile> nativeFile =
         aFileManager->GetFileForId(directory, file.mFileInfo->Id());
       if (!nativeFile) {
-        NS_WARNING("Failed to get file!");
+        IDB_WARNING("Failed to get file!");
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
 
       nsCOMPtr<nsIDOMBlob> blob = new nsDOMFileFile(nativeFile, file.mFileInfo);
 
       BlobParent* actor =
         aContentParent->GetOrCreateActorForBlob(blob);
       if (!actor) {
         // This can only fail if the child has crashed.
+        IDB_REPORT_INTERNAL_ERR();
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
 
       aActors.AppendElement(actor);
     }
   }
 
   return NS_OK;
@@ -1926,28 +1931,28 @@ IDBObjectStore::AddOrPut(JSContext* aCx,
   JS::Rooted<JS::Value> value(aCx, aValue);
   aRv = GetAddInfo(aCx, value, keyval, cloneWriteInfo, key, updateInfo);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   if (!request) {
-    NS_WARNING("Failed to generate request!");
+    IDB_WARNING("Failed to generate request!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   nsRefPtr<AddHelper> helper =
     new AddHelper(mTransaction, request, this, cloneWriteInfo, key,
                   aOverwrite, updateInfo);
 
   nsresult rv = helper->DispatchToTransactionPool();
   if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch!");
+    IDB_WARNING("Failed to dispatch!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
 #ifdef IDB_PROFILER_USE_MARKS
   if (aOverwrite) {
     IDB_PROFILER_MARK("IndexedDB Request %llu: "
                       "database(%s).transaction(%s).objectStore(%s).%s(%s)",
@@ -1989,21 +1994,21 @@ IDBObjectStore::AddOrPutInternal(
     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
   }
 
   if (!IsWriteAllowed()) {
     return NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR;
   }
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
-  NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   StructuredCloneWriteInfo cloneWriteInfo;
   if (!cloneWriteInfo.SetFromSerialized(aCloneWriteInfo)) {
-    NS_WARNING("Failed to copy structured clone buffer!");
+    IDB_WARNING("Failed to copy structured clone buffer!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   if (!aBlobs.IsEmpty()) {
     FileManager* fileManager = Transaction()->Database()->Manager();
     NS_ASSERTION(fileManager, "Null file manager?!");
 
     uint32_t length = aBlobs.Length();
@@ -2016,22 +2021,22 @@ IDBObjectStore::AddOrPutInternal(
 
       nsRefPtr<FileInfo> fileInfo = Transaction()->GetFileInfo(blob);
       if (!fileInfo) {
         fileInfo = blob->GetFileInfo(fileManager);
 
         if (!fileInfo) {
           fileInfo = fileManager->GetNewFileInfo();
           if (!fileInfo) {
-            NS_WARNING("Failed to get new file info!");
+            IDB_WARNING("Failed to get new file info!");
             return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
           }
 
           if (NS_FAILED(blob->GetInternalStream(getter_AddRefs(inputStream)))) {
-            NS_WARNING("Failed to get internal steam!");
+            IDB_WARNING("Failed to get internal steam!");
             return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
           }
 
           // XXXbent This is where we should send a message back to the child to
           //         update the file id.
 
           Transaction()->AddFileInfo(blob, fileInfo);
         }
@@ -2048,17 +2053,17 @@ IDBObjectStore::AddOrPutInternal(
 
   nsTArray<IndexUpdateInfo> updateInfo(aUpdateInfoArray);
 
   nsRefPtr<AddHelper> helper =
     new AddHelper(mTransaction, request, this, cloneWriteInfo, key, aOverwrite,
                   updateInfo);
 
   nsresult rv = helper->DispatchToTransactionPool();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
 #ifdef IDB_PROFILER_USE_MARKS
   if (aOverwrite) {
     IDB_PROFILER_MARK("IndexedDB Request %llu: "
                       "database(%s).transaction(%s).objectStore(%s).%s(%s)",
                       "IDBRequest[%llu] MT IDBObjectStore.put()",
                       request->GetSerialNumber(),
                       IDB_PROFILER_STRING(Transaction()->Database()),
@@ -2090,27 +2095,27 @@ IDBObjectStore::GetInternal(IDBKeyRange*
 
   if (!mTransaction->IsOpen()) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
     return nullptr;
   }
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   if (!request) {
-    NS_WARNING("Failed to generate request!");
+    IDB_WARNING("Failed to generate request!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   nsRefPtr<GetHelper> helper =
     new GetHelper(mTransaction, request, this, aKeyRange);
 
   nsresult rv = helper->DispatchToTransactionPool();
   if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch!");
+    IDB_WARNING("Failed to dispatch!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   IDB_PROFILER_MARK("IndexedDB Request %llu: "
                     "database(%s).transaction(%s).objectStore(%s).get(%s)",
                     "IDBRequest[%llu] MT IDBObjectStore.get()",
                     request->GetSerialNumber(),
@@ -2129,27 +2134,27 @@ IDBObjectStore::GetAllInternal(IDBKeyRan
 
   if (!mTransaction->IsOpen()) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
     return nullptr;
   }
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   if (!request) {
-    NS_WARNING("Failed to generate request!");
+    IDB_WARNING("Failed to generate request!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   nsRefPtr<GetAllHelper> helper =
     new GetAllHelper(mTransaction, request, this, aKeyRange, aLimit);
 
   nsresult rv = helper->DispatchToTransactionPool();
   if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch!");
+    IDB_WARNING("Failed to dispatch!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   IDB_PROFILER_MARK("IndexedDB Request %llu: "
                     "database(%s).transaction(%s).objectStore(%s)."
                     "getAll(%s, %lu)",
                     "IDBRequest[%llu] MT IDBObjectStore.getAll()",
@@ -2170,27 +2175,27 @@ IDBObjectStore::GetAllKeysInternal(IDBKe
 
   if (!mTransaction->IsOpen()) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
     return nullptr;
   }
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   if (!request) {
-    NS_WARNING("Failed to generate request!");
+    IDB_WARNING("Failed to generate request!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   nsRefPtr<GetAllKeysHelper> helper =
     new GetAllKeysHelper(mTransaction, request, this, aKeyRange, aLimit);
 
   nsresult rv = helper->DispatchToTransactionPool();
   if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch!");
+    IDB_WARNING("Failed to dispatch!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   IDB_PROFILER_MARK("IndexedDB Request %llu: "
                     "database(%s).transaction(%s).objectStore(%s)."
                     "getAllKeys(%s, %lu)",
                     "IDBRequest[%llu] MT IDBObjectStore.getAllKeys()",
@@ -2217,27 +2222,27 @@ IDBObjectStore::DeleteInternal(IDBKeyRan
 
   if (!IsWriteAllowed()) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
     return nullptr;
   }
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   if (!request) {
-    NS_WARNING("Failed to generate request!");
+    IDB_WARNING("Failed to generate request!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   nsRefPtr<DeleteHelper> helper =
     new DeleteHelper(mTransaction, request, this, aKeyRange);
 
   nsresult rv = helper->DispatchToTransactionPool();
   if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch!");
+    IDB_WARNING("Failed to dispatch!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   IDB_PROFILER_MARK("IndexedDB Request %llu: "
                     "database(%s).transaction(%s).objectStore(%s).delete(%s)",
                     "IDBRequest[%llu] MT IDBObjectStore.delete()",
                     request->GetSerialNumber(),
@@ -2260,26 +2265,26 @@ IDBObjectStore::Clear(ErrorResult& aRv)
 
   if (!IsWriteAllowed()) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
     return nullptr;
   }
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   if (!request) {
-    NS_WARNING("Failed to generate request!");
+    IDB_WARNING("Failed to generate request!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   nsRefPtr<ClearHelper> helper(new ClearHelper(mTransaction, request, this));
 
   nsresult rv = helper->DispatchToTransactionPool();
   if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch!");
+    IDB_WARNING("Failed to dispatch!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   IDB_PROFILER_MARK("IndexedDB Request %llu: "
                     "database(%s).transaction(%s).objectStore(%s).clear()",
                     "IDBRequest[%llu] MT IDBObjectStore.clear()",
                     request->GetSerialNumber(),
@@ -2297,26 +2302,26 @@ IDBObjectStore::CountInternal(IDBKeyRang
 
   if (!mTransaction->IsOpen()) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
     return nullptr;
   }
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   if (!request) {
-    NS_WARNING("Failed to generate request!");
+    IDB_WARNING("Failed to generate request!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   nsRefPtr<CountHelper> helper =
     new CountHelper(mTransaction, request, this, aKeyRange);
   nsresult rv = helper->DispatchToTransactionPool();
   if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch!");
+    IDB_WARNING("Failed to dispatch!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   IDB_PROFILER_MARK("IndexedDB Request %llu: "
                     "database(%s).transaction(%s).objectStore(%s).count(%s)",
                     "IDBRequest[%llu] MT IDBObjectStore.count()",
                     request->GetSerialNumber(),
@@ -2338,27 +2343,27 @@ IDBObjectStore::OpenCursorInternal(IDBKe
     return nullptr;
   }
 
   IDBCursor::Direction direction =
     static_cast<IDBCursor::Direction>(aDirection);
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   if (!request) {
-    NS_WARNING("Failed to generate request!");
+    IDB_WARNING("Failed to generate request!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   nsRefPtr<OpenCursorHelper> helper =
     new OpenCursorHelper(mTransaction, request, this, aKeyRange, direction);
 
   nsresult rv = helper->DispatchToTransactionPool();
   if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch!");
+    IDB_WARNING("Failed to dispatch!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   IDB_PROFILER_MARK("IndexedDB Request %llu: "
                     "database(%s).transaction(%s).objectStore(%s)."
                     "openCursor(%s, %s)",
                     "IDBRequest[%llu] MT IDBObjectStore.openCursor()",
@@ -2386,26 +2391,26 @@ IDBObjectStore::OpenCursorFromChildProce
                "Inconsistent clone info!");
 
   IDBCursor::Direction direction =
     static_cast<IDBCursor::Direction>(aDirection);
 
   StructuredCloneReadInfo cloneInfo;
 
   if (!cloneInfo.SetFromSerialized(aCloneInfo)) {
-    NS_WARNING("Failed to copy clone buffer!");
+    IDB_WARNING("Failed to copy clone buffer!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   cloneInfo.mFiles.SwapElements(aBlobs);
 
   nsRefPtr<IDBCursor> cursor =
     IDBCursor::Create(aRequest, mTransaction, this, direction, Key(),
                       EmptyCString(), EmptyCString(), aKey, cloneInfo);
-  NS_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NS_ASSERTION(!cloneInfo.mCloneBuffer.data(), "Should have swapped!");
 
   cursor.forget(_retval);
   return NS_OK;
 }
 
 nsresult
@@ -2417,17 +2422,17 @@ IDBObjectStore::OpenCursorFromChildProce
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aRequest);
 
   auto direction = static_cast<IDBCursor::Direction>(aDirection);
 
   nsRefPtr<IDBCursor> cursor =
     IDBCursor::Create(aRequest, mTransaction, this, direction, Key(),
                       EmptyCString(), EmptyCString(), aKey);
-  NS_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   cursor.forget(_retval);
   return NS_OK;
 }
 
 already_AddRefed<IDBRequest>
 IDBObjectStore::OpenKeyCursorInternal(IDBKeyRange* aKeyRange, size_t aDirection,
                                       ErrorResult& aRv)
@@ -2436,29 +2441,29 @@ IDBObjectStore::OpenKeyCursorInternal(ID
 
   if (!mTransaction->IsOpen()) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
     return nullptr;
   }
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   if (!request) {
-    NS_WARNING("Failed to generate request!");
+    IDB_WARNING("Failed to generate request!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   auto direction = static_cast<IDBCursor::Direction>(aDirection);
 
   nsRefPtr<OpenKeyCursorHelper> helper =
     new OpenKeyCursorHelper(mTransaction, request, this, aKeyRange, direction);
 
   nsresult rv = helper->DispatchToTransactionPool();
   if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch!");
+    IDB_WARNING("Failed to dispatch!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   IDB_PROFILER_MARK("IndexedDB Request %llu: "
                     "database(%s).transaction(%s).objectStore(%s)."
                     "openKeyCursor(%s, %s)",
                     "IDBRequest[%llu] MT IDBObjectStore.openKeyCursor()",
@@ -2501,17 +2506,17 @@ IDBObjectStore::CreateIndexInternal(cons
   mCreatedIndexes.AppendElement(index);
 
   if (IndexedDatabaseManager::IsMainProcess()) {
     nsRefPtr<CreateIndexHelper> helper =
       new CreateIndexHelper(mTransaction, index);
 
     nsresult rv = helper->DispatchToTransactionPool();
     if (NS_FAILED(rv)) {
-      NS_WARNING("Failed to dispatch!");
+      IDB_WARNING("Failed to dispatch!");
       aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
       return nullptr;
     }
   }
 
   autoRemove.forget();
 
   IDB_PROFILER_MARK("IndexedDB Pseudo-request: "
@@ -2556,23 +2561,23 @@ IDBObjectStore::Index(const nsAString& a
       retval = index;
       break;
     }
   }
 
   if (!retval) {
     retval = IDBIndex::Create(this, indexInfo, false);
     if (!retval) {
-      NS_WARNING("Failed to create index!");
+      IDB_WARNING("Failed to create index!");
       aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
       return nullptr;
     }
 
     if (!mCreatedIndexes.AppendElement(retval)) {
-      NS_WARNING("Out of memory!");
+      IDB_WARNING("Out of memory!");
       aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
       return nullptr;
     }
   }
 
   return retval.forget();
 }
 
@@ -2654,17 +2659,17 @@ IDBObjectStore::GetIndexNames(ErrorResul
   names.SetCapacity(count);
 
   for (uint32_t index = 0; index < count; index++) {
     names.InsertElementSorted(mInfo->indexes[index].name);
   }
 
   for (uint32_t index = 0; index < count; index++) {
     if (!list->Add(names[index])) {
-      NS_WARNING("Failed to add element!");
+      IDB_WARNING("Failed to add element!");
       aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
       return nullptr;
     }
   }
 
   return list.forget();
 }
 
@@ -2898,17 +2903,17 @@ IDBObjectStore::DeleteIndex(const nsAStr
   }
 
   if (IndexedDatabaseManager::IsMainProcess()) {
     nsRefPtr<DeleteIndexHelper> helper =
       new DeleteIndexHelper(mTransaction, this, aName);
 
     nsresult rv = helper->DispatchToTransactionPool();
     if (NS_FAILED(rv)) {
-      NS_WARNING("Failed to dispatch!");
+      IDB_WARNING("Failed to dispatch!");
       aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
       return;
     }
   }
   else {
     NS_ASSERTION(mActorChild, "Must have an actor here!");
 
     mActorChild->SendDeleteIndex(nsString(aName));
@@ -3011,34 +3016,34 @@ CopyData(nsIInputStream* aInputStream, n
 
   nsresult rv;
 
   do {
     char copyBuffer[FILE_COPY_BUFFER_SIZE];
 
     uint32_t numRead;
     rv = aInputStream->Read(copyBuffer, sizeof(copyBuffer), &numRead);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     if (!numRead) {
       break;
     }
 
     uint32_t numWrite;
     rv = aOutputStream->Write(copyBuffer, numRead, &numWrite);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     if (numWrite < numRead) {
       // Must have hit the quota limit.
       return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
     }
   } while (true);
 
   rv = aOutputStream->Flush();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
 void
 ObjectStoreHelper::ReleaseMainThreadObjects()
 {
   mObjectStore = nullptr;
@@ -3054,29 +3059,30 @@ ObjectStoreHelper::Dispatch(nsIEventTarg
 
   if (IndexedDatabaseManager::IsMainProcess()) {
     return AsyncConnectionHelper::Dispatch(aDatabaseThread);
   }
 
   // If we've been invalidated then there's no point sending anything to the
   // parent process.
   if (mObjectStore->Transaction()->Database()->IsInvalidated()) {
+    IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   IndexedDBObjectStoreChild* objectStoreActor = mObjectStore->GetActorChild();
   NS_ASSERTION(objectStoreActor, "Must have an actor here!");
 
   ObjectStoreRequestParams params;
   nsresult rv = PackArgumentsForParentProcess(params);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NoDispatchEventTarget target;
   rv = AsyncConnectionHelper::Dispatch(&target);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mActor =
     new IndexedDBObjectStoreRequestChild(this, mObjectStore, params.type());
   objectStoreActor->SendPIndexedDBRequestConstructor(mActor, params);
 
   return NS_OK;
 }
 
@@ -3087,18 +3093,17 @@ NoRequestObjectStoreHelper::ReleaseMainT
   mObjectStore = nullptr;
   AsyncConnectionHelper::ReleaseMainThreadObjects();
 }
 
 nsresult
 NoRequestObjectStoreHelper::UnpackResponseFromParentProcess(
                                             const ResponseValue& aResponseValue)
 {
-  NS_NOTREACHED("Should never get here!");
-  return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  MOZ_CRASH();
 }
 
 AsyncConnectionHelper::ChildProcessSendResult
 NoRequestObjectStoreHelper::SendResponseToChildProcess(nsresult aResultCode)
 {
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   return Success_NotSent;
 }
@@ -3155,36 +3160,37 @@ AddHelper::DoDatabaseWork(mozIStorageCon
   nsCOMPtr<mozIStorageStatement> stmt = !mOverwrite || keyUnset ?
     mTransaction->GetCachedStatement(
       "INSERT INTO object_data (object_store_id, key_value, data, file_ids) "
       "VALUES (:osid, :key_value, :data, :file_ids)") :
     mTransaction->GetCachedStatement(
       "INSERT OR REPLACE INTO object_data (object_store_id, key_value, data, "
                                           "file_ids) "
       "VALUES (:osid, :key_value, :data, :file_ids)");
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NS_ASSERTION(!keyUnset || mObjectStore->IsAutoIncrement(),
                "Should have key unless autoincrement");
 
   int64_t autoIncrementNum = 0;
 
   if (mObjectStore->IsAutoIncrement()) {
     if (keyUnset) {
       autoIncrementNum = mObjectStore->Info()->nextAutoIncrementId;
 
       MOZ_ASSERT(autoIncrementNum > 0,
                  "Generated key must always be a positive integer");
 
       if (autoIncrementNum > (1LL << 53)) {
+        IDB_REPORT_INTERNAL_ERR();
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
 
       mKey.SetFromInteger(autoIncrementNum);
     }
     else if (mKey.IsFloat() &&
              mKey.ToFloat() >= mObjectStore->Info()->nextAutoIncrementId) {
       autoIncrementNum = floor(mKey.ToFloat());
@@ -3220,56 +3226,56 @@ AddHelper::DoDatabaseWork(mozIStorageCon
                       &compressedLength);
 
   const uint8_t* dataBuffer =
     reinterpret_cast<const uint8_t*>(compressed.get());
   size_t dataBufferLength = compressedLength;
 
   rv = stmt->BindBlobByName(NS_LITERAL_CSTRING("data"), dataBuffer,
                             dataBufferLength);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   // Handle blobs
   uint32_t length = mCloneWriteInfo.mFiles.Length();
   if (length) {
     nsRefPtr<FileManager> fileManager = mDatabase->Manager();
 
     nsCOMPtr<nsIFile> directory = fileManager->GetDirectory();
-    NS_ENSURE_TRUE(directory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_TRUE(directory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     nsCOMPtr<nsIFile> journalDirectory = fileManager->EnsureJournalDirectory();
-    NS_ENSURE_TRUE(journalDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_TRUE(journalDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     nsAutoString fileIds;
 
     for (uint32_t index = 0; index < length; index++) {
       StructuredCloneFile& cloneFile = mCloneWriteInfo.mFiles[index];
 
       FileInfo* fileInfo = cloneFile.mFileInfo;
       nsIInputStream* inputStream = cloneFile.mInputStream;
 
       int64_t id = fileInfo->Id();
       if (inputStream) {
         // Create a journal file first
         nsCOMPtr<nsIFile> nativeFile =
           fileManager->GetFileForId(journalDirectory, id);
-        NS_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+        IDB_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
         rv = nativeFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
-        NS_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+        IDB_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
         // Now we can copy the blob
         nativeFile = fileManager->GetFileForId(directory, id);
-        NS_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+        IDB_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
         IDBDatabase* database = mObjectStore->Transaction()->Database();
         nsRefPtr<FileOutputStream> outputStream =
           FileOutputStream::Create(database->Type(), database->Group(),
                                    database->Origin(), nativeFile);
-        NS_ENSURE_TRUE(outputStream, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+        IDB_ENSURE_TRUE(outputStream, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
         rv = CopyData(inputStream, outputStream);
         NS_ENSURE_SUCCESS(rv, rv);
 
         cloneFile.mFile->AddFileInfo(fileInfo);
       }
 
       if (index) {
@@ -3278,37 +3284,37 @@ AddHelper::DoDatabaseWork(mozIStorageCon
       fileIds.AppendInt(id);
     }
 
     rv = stmt->BindStringByName(NS_LITERAL_CSTRING("file_ids"), fileIds);
   }
   else {
     rv = stmt->BindNullByName(NS_LITERAL_CSTRING("file_ids"));
   }
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = stmt->Execute();
   if (rv == NS_ERROR_STORAGE_CONSTRAINT) {
     NS_ASSERTION(!keyUnset, "Generated key had a collision!?");
     return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
   }
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   int64_t objectDataId;
   rv = aConnection->GetLastInsertRowID(&objectDataId);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   // Update our indexes if needed.
   if (mOverwrite || !mIndexUpdateInfo.IsEmpty()) {
     rv = IDBObjectStore::UpdateIndexes(mTransaction, osid, mKey, mOverwrite,
                                        objectDataId, mIndexUpdateInfo);
     if (rv == NS_ERROR_STORAGE_CONSTRAINT) {
       return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
     }
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
   if (autoIncrementNum) {
     mObjectStore->Info()->nextAutoIncrementId = autoIncrementNum + 1;
   }
 
   return NS_OK;
 }
@@ -3360,16 +3366,17 @@ AddHelper::PackArgumentsForParentProcess
       const StructuredCloneFile& file = files[index];
 
       NS_ASSERTION(file.mFile, "This should never be null!");
       NS_ASSERTION(!file.mFileInfo, "This is not yet supported!");
 
       BlobChild* actor =
         contentChild->GetOrCreateActorForBlob(file.mFile);
       if (!actor) {
+        IDB_REPORT_INTERNAL_ERR();
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
       blobsChild.AppendElement(actor);
     }
   }
 
   if (mOverwrite) {
     PutParams putParams;
@@ -3447,30 +3454,30 @@ GetHelper::DoDatabaseWork(mozIStorageCon
 
   NS_ASSERTION(!keyRangeClause.IsEmpty(), "Huh?!");
 
   nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM object_data "
                                        "WHERE object_store_id = :osid") +
                     keyRangeClause + NS_LITERAL_CSTRING(" LIMIT 1");
 
   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv =
     stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), mObjectStore->Id());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = mKeyRange->BindToStatement(stmt);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasResult;
   rv = stmt->ExecuteStep(&hasResult);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (hasResult) {
     rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 0, 1,
       mDatabase, mCloneReadInfo);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
@@ -3577,17 +3584,17 @@ GetHelper::UnpackResponseFromParentProce
   const GetResponse& getResponse = aResponseValue.get_GetResponse();
   const SerializedStructuredCloneReadInfo& cloneInfo = getResponse.cloneInfo();
 
   NS_ASSERTION((!cloneInfo.dataLength && !cloneInfo.data) ||
                (cloneInfo.dataLength && cloneInfo.data),
                "Inconsistent clone info!");
 
   if (!mCloneReadInfo.SetFromSerialized(cloneInfo)) {
-    NS_WARNING("Failed to copy clone buffer!");
+    IDB_WARNING("Failed to copy clone buffer!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   IDBObjectStore::ConvertActorsToBlobs(getResponse.blobsChild(),
                                        mCloneReadInfo.mFiles);
   return NS_OK;
 }
 
@@ -3605,29 +3612,29 @@ DeleteHelper::DoDatabaseWork(mozIStorage
 
   NS_ASSERTION(!keyRangeClause.IsEmpty(), "Huh?!");
 
   nsCString query = NS_LITERAL_CSTRING("DELETE FROM object_data "
                                        "WHERE object_store_id = :osid") +
                     keyRangeClause;
 
   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
                                       mObjectStore->Id());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = mKeyRange->BindToStatement(stmt);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = stmt->Execute();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
 nsresult
 DeleteHelper::GetSuccessResult(JSContext* aCx,
                                JS::MutableHandle<JS::Value> aVal)
 {
@@ -3698,26 +3705,26 @@ ClearHelper::DoDatabaseWork(mozIStorageC
   NS_ASSERTION(aConnection, "Passed a null connection!");
 
   PROFILER_LABEL("IndexedDB", "ClearHelper::DoDatabaseWork");
 
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(
       NS_LITERAL_CSTRING("DELETE FROM object_data "
                          "WHERE object_store_id = :osid"));
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
                                       mObjectStore->Id());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = stmt->Execute();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
 nsresult
 ClearHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@@ -3802,32 +3809,32 @@ OpenCursorHelper::DoDatabaseWork(mozISto
   nsCString firstQuery = NS_LITERAL_CSTRING("SELECT key_value, data, file_ids "
                                             "FROM object_data "
                                             "WHERE object_store_id = :id") +
                          keyRangeClause + directionClause +
                          NS_LITERAL_CSTRING(" LIMIT 1");
 
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(firstQuery);
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"),
                                       mObjectStore->Id());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (mKeyRange) {
     rv = mKeyRange->BindToStatement(stmt);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   bool hasResult;
   rv = stmt->ExecuteStep(&hasResult);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (!hasResult) {
     mKey.Unset();
     return NS_OK;
   }
 
   rv = mKey.SetFromStatement(stmt, 0);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -3904,34 +3911,34 @@ OpenCursorHelper::EnsureCursor()
   NS_ASSERTION(mSerializedCloneReadInfo.data &&
                mSerializedCloneReadInfo.dataLength,
                "Shouldn't be possible!");
 
   nsRefPtr<IDBCursor> cursor =
     IDBCursor::Create(mRequest, mTransaction, mObjectStore, mDirection,
                       mRangeKey, mContinueQuery, mContinueToQuery, mKey,
                       mCloneReadInfo);
-  NS_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NS_ASSERTION(!mCloneReadInfo.mCloneBuffer.data(), "Should have swapped!");
 
   mCursor.swap(cursor);
   return NS_OK;
 }
 
 nsresult
 OpenCursorHelper::GetSuccessResult(JSContext* aCx,
                                    JS::MutableHandle<JS::Value> aVal)
 {
   nsresult rv = EnsureCursor();
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (mCursor) {
     rv = WrapNative(aCx, mCursor, aVal);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
   else {
     aVal.setUndefined();
   }
 
   return NS_OK;
 }
 
@@ -4093,18 +4100,17 @@ OpenCursorHelper::UnpackResponseFromPare
           response.get_PIndexedDBCursorChild());
 
       mCursor = actor->ForgetStrongCursor();
       NS_ASSERTION(mCursor, "This should never be null!");
 
     } break;
 
     default:
-      NS_NOTREACHED("Unknown response union type!");
-      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+      MOZ_CRASH();
   }
 
   return NS_OK;
 }
 
 nsresult
 OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
 {
@@ -4144,31 +4150,31 @@ OpenKeyCursorHelper::DoDatabaseWork(mozI
       MOZ_ASSUME_UNREACHABLE("Unknown direction type!");
   }
 
   nsCString firstQuery = queryStart + keyRangeClause + directionClause +
                          openLimit + NS_LITERAL_CSTRING("1");
 
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(firstQuery);
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(id, mObjectStore->Id());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (mKeyRange) {
     rv = mKeyRange->BindToStatement(stmt);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   bool hasResult;
   rv = stmt->ExecuteStep(&hasResult);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (!hasResult) {
     mKey.Unset();
     return NS_OK;
   }
 
   rv = mKey.SetFromStatement(stmt, 0);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -4234,17 +4240,17 @@ OpenKeyCursorHelper::EnsureCursor()
 
   if (mCursor || mKey.IsUnset()) {
     return NS_OK;
   }
 
   mCursor = IDBCursor::Create(mRequest, mTransaction, mObjectStore, mDirection,
                               mRangeKey, mContinueQuery, mContinueToQuery,
                               mKey);
-  NS_ENSURE_TRUE(mCursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(mCursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
 nsresult
 OpenKeyCursorHelper::GetSuccessResult(JSContext* aCx,
                                       JS::MutableHandle<JS::Value> aVal)
 {
@@ -4254,17 +4260,17 @@ OpenKeyCursorHelper::GetSuccessResult(JS
                              "OpenKeyCursorHelper::GetSuccessResult "
                              "[IDBObjectStore.cpp]");
 
   nsresult rv = EnsureCursor();
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (mCursor) {
     rv = WrapNative(aCx, mCursor, aVal);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
   else {
     aVal.setUndefined();
   }
 
   return NS_OK;
 }
 
@@ -4425,44 +4431,44 @@ CreateIndexHelper::DoDatabaseWork(mozISt
 
   // Insert the data into the database.
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(
     "INSERT INTO object_store_index (id, name, key_path, unique_index, "
       "multientry, object_store_id) "
     "VALUES (:id, :name, :key_path, :unique, :multientry, :osid)"
   );
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"),
                                       mIndex->Id());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mIndex->Name());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsAutoString keyPathSerialization;
   mIndex->GetKeyPath().SerializeToString(keyPathSerialization);
   rv = stmt->BindStringByName(NS_LITERAL_CSTRING("key_path"),
                               keyPathSerialization);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("unique"),
                              mIndex->IsUnique() ? 1 : 0);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("multientry"),
                              mIndex->IsMultiEntry() ? 1 : 0);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
                              mIndex->ObjectStore()->Id());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (NS_FAILED(stmt->Execute())) {
     return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
   }
 
 #ifdef DEBUG
   {
     int64_t id;
@@ -4489,41 +4495,41 @@ CreateIndexHelper::ReleaseMainThreadObje
 
 nsresult
 CreateIndexHelper::InsertDataFromObjectStore(mozIStorageConnection* aConnection)
 {
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(
       NS_LITERAL_CSTRING("SELECT id, data, file_ids, key_value FROM "
                          "object_data WHERE object_store_id = :osid"));
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
                                       mIndex->ObjectStore()->Id());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  NS_ENSURE_TRUE(sTLSIndex != BAD_TLS_INDEX,
-                 NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  IDB_ENSURE_TRUE(sTLSIndex != BAD_TLS_INDEX, 
+                                    NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   bool hasResult;
   rv = stmt->ExecuteStep(&hasResult);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   if (!hasResult) {
     // Bail early if we have no data to avoid creating the below runtime
     return NS_OK;
   }
 
   ThreadLocalJSRuntime* tlsEntry =
     reinterpret_cast<ThreadLocalJSRuntime*>(PR_GetThreadPrivate(sTLSIndex));
 
   if (!tlsEntry) {
     tlsEntry = ThreadLocalJSRuntime::Create();
-    NS_ENSURE_TRUE(tlsEntry, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_TRUE(tlsEntry, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     PR_SetThreadPrivate(sTLSIndex, tlsEntry);
   }
 
   JSContext* cx = tlsEntry->Context();
   JSAutoRequest ar(cx);
   JSAutoCompartment ac(cx, tlsEntry->Global());
 
@@ -4562,17 +4568,17 @@ CreateIndexHelper::InsertDataFromObjectS
     rv = key.SetFromStatement(stmt, 3);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = IDBObjectStore::UpdateIndexes(mTransaction, mIndex->Id(),
                                        key, false, objectDataID, updateInfo);
     NS_ENSURE_SUCCESS(rv, rv);
 
   } while (NS_SUCCEEDED(rv = stmt->ExecuteStep(&hasResult)) && hasResult);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
 void
 CreateIndexHelper::DestroyTLSEntry(void* aPtr)
 {
   delete reinterpret_cast<ThreadLocalJSRuntime *>(aPtr);
@@ -4586,22 +4592,22 @@ DeleteIndexHelper::DoDatabaseWork(mozISt
 
   PROFILER_LABEL("IndexedDB", "DeleteIndexHelper::DoDatabaseWork");
 
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(
       "DELETE FROM object_store_index "
       "WHERE name = :name "
     );
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mName);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (NS_FAILED(stmt->Execute())) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
   }
 
   return NS_OK;
 }
 
@@ -4652,23 +4658,23 @@ GetAllHelper::DoDatabaseWork(mozIStorage
                                        "WHERE object_store_id = :osid") +
                     keyRangeClause +
                     NS_LITERAL_CSTRING(" ORDER BY key_value ASC") +
                     limitClause;
 
   mCloneReadInfos.SetCapacity(50);
 
   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
                                       mObjectStore->Id());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (mKeyRange) {
     if (!mKeyRange->Lower().IsUnset()) {
       rv = mKeyRange->Lower().BindToStatement(stmt, lowerKeyName);
       NS_ENSURE_SUCCESS(rv, rv);
     }
     if (!mKeyRange->Upper().IsUnset()) {
       rv = mKeyRange->Upper().BindToStatement(stmt, upperKeyName);
@@ -4684,17 +4690,17 @@ GetAllHelper::DoDatabaseWork(mozIStorage
 
     StructuredCloneReadInfo* readInfo = mCloneReadInfos.AppendElement();
     NS_ASSERTION(readInfo, "Shouldn't fail since SetCapacity succeeded!");
 
     rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 0, 1,
       mDatabase, *readInfo);
     NS_ENSURE_SUCCESS(rv, rv);
   }
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
 nsresult
 GetAllHelper::GetSuccessResult(JSContext* aCx,
                                JS::MutableHandle<JS::Value> aVal)
 {
@@ -4832,17 +4838,17 @@ GetAllHelper::UnpackResponseFromParentPr
   mCloneReadInfos.SetCapacity(cloneInfos.Length());
 
   for (uint32_t index = 0; index < cloneInfos.Length(); index++) {
     const SerializedStructuredCloneReadInfo srcInfo = cloneInfos[index];
     const InfallibleTArray<PBlobChild*>& blobs = blobArrays[index].blobsChild();
 
     StructuredCloneReadInfo* destInfo = mCloneReadInfos.AppendElement();
     if (!destInfo->SetFromSerialized(srcInfo)) {
-      NS_WARNING("Failed to copy clone buffer!");
+      IDB_WARNING("Failed to copy clone buffer!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     IDBObjectStore::ConvertActorsToBlobs(blobs, destInfo->mFiles);
   }
 
   return NS_OK;
 }
@@ -4874,22 +4880,22 @@ GetAllKeysHelper::DoDatabaseWork(mozISto
   nsCString query = NS_LITERAL_CSTRING("SELECT ") + keyValue +
                     NS_LITERAL_CSTRING(" FROM object_data WHERE "
                                        "object_store_id = :") +
                     osid + keyRangeClause +
                     NS_LITERAL_CSTRING(" ORDER BY key_value ASC") +
                     limitClause;
 
   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(osid, mObjectStore->Id());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (mKeyRange) {
     rv = mKeyRange->BindToStatement(stmt);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   mKeys.SetCapacity(std::min<uint32_t>(50, mLimit));
 
@@ -4900,17 +4906,17 @@ GetAllKeysHelper::DoDatabaseWork(mozISto
     }
 
     Key* key = mKeys.AppendElement();
     NS_ASSERTION(key, "This shouldn't fail!");
 
     rv = key->SetFromStatement(stmt, 0);
     NS_ENSURE_SUCCESS(rv, rv);
   }
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
 nsresult
 GetAllKeysHelper::GetSuccessResult(JSContext* aCx,
                                    JS::MutableHandle<JS::Value> aVal)
 {
@@ -4921,39 +4927,39 @@ GetAllKeysHelper::GetSuccessResult(JSCon
                              "GetAllKeysHelper::GetSuccessResult "
                              "[IDBObjectStore.cpp]");
 
   nsTArray<Key> keys;
   mKeys.SwapElements(keys);
 
   JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0, nullptr));
   if (!array) {
-    NS_WARNING("Failed to make array!");
+    IDB_WARNING("Failed to make array!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   if (!keys.IsEmpty()) {
     if (!JS_SetArrayLength(aCx, array, keys.Length())) {
-      NS_WARNING("Failed to set array length!");
+      IDB_WARNING("Failed to set array length!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     for (uint32_t index = 0, count = keys.Length(); index < count; index++) {
       const Key& key = keys[index];
       MOZ_ASSERT(!key.IsUnset());
 
       JS::Rooted<JS::Value> value(aCx);
       nsresult rv = key.ToJSVal(aCx, &value);
       if (NS_FAILED(rv)) {
         NS_WARNING("Failed to get jsval for key!");
         return rv;
       }
 
       if (!JS_SetElement(aCx, array, index, value)) {
-        NS_WARNING("Failed to set array element!");
+        IDB_WARNING("Failed to set array element!");
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
     }
   }
 
   aVal.setObject(*array);
   return NS_OK;
 }
@@ -5074,39 +5080,39 @@ CountHelper::DoDatabaseWork(mozIStorageC
     }
   }
 
   nsCString query = NS_LITERAL_CSTRING("SELECT count(*) FROM object_data "
                                        "WHERE object_store_id = :osid") +
                     keyRangeClause;
 
   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
                                       mObjectStore->Id());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (mKeyRange) {
     if (!mKeyRange->Lower().IsUnset()) {
       rv = mKeyRange->Lower().BindToStatement(stmt, lowerKeyName);
       NS_ENSURE_SUCCESS(rv, rv);
     }
     if (!mKeyRange->Upper().IsUnset()) {
       rv = mKeyRange->Upper().BindToStatement(stmt, upperKeyName);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   bool hasResult;
   rv = stmt->ExecuteStep(&hasResult);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-  NS_ENSURE_TRUE(hasResult, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(hasResult, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mCount = stmt->AsInt64(0);
   return NS_OK;
 }
 
 nsresult
 CountHelper::GetSuccessResult(JSContext* aCx,
                               JS::MutableHandle<JS::Value> aVal)
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -25,16 +25,17 @@
 
 #include "AsyncConnectionHelper.h"
 #include "IDBCursor.h"
 #include "IDBEvents.h"
 #include "IDBFactory.h"
 #include "IDBIndex.h"
 #include "IDBObjectStore.h"
 #include "IDBTransaction.h"
+#include "ReportInternalError.h"
 
 namespace {
 
 #ifdef MOZ_ENABLE_PROFILER_SPS
 uint64_t gNextRequestSerialNumber = 1;
 #endif
 
 } // anonymous namespace
@@ -182,17 +183,17 @@ IDBRequest::NotifyHelperCompleted(Helper
   // we never completed.
   if (NS_FAILED(CheckInnerWindowCorrectness())) {
     return NS_OK;
   }
 
   // Otherwise we need to get the result from the helper.
   AutoPushJSContext cx(GetJSContext());
   if (!cx) {
-    NS_WARNING("Failed to get safe JSContext!");
+    IDB_WARNING("Failed to get safe JSContext!");
     rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     SetError(rv);
     return rv;
   }
 
   JS::Rooted<JSObject*> global(cx, IDBWrapperCache::GetParentObject());
   NS_ASSERTION(global, "This should never be null!");
 
--- a/dom/indexedDB/IDBTransaction.cpp
+++ b/dom/indexedDB/IDBTransaction.cpp
@@ -24,16 +24,17 @@
 #include "AsyncConnectionHelper.h"
 #include "DatabaseInfo.h"
 #include "IDBCursor.h"
 #include "IDBEvents.h"
 #include "IDBFactory.h"
 #include "IDBObjectStore.h"
 #include "IndexedDatabaseManager.h"
 #include "ProfilerHelpers.h"
+#include "ReportInternalError.h"
 #include "TransactionThreadPool.h"
 
 #include "ipc/IndexedDBChild.h"
 
 #define SAVEPOINT_NAME "savepoint"
 
 using namespace mozilla::dom;
 USING_INDEXEDDB_NAMESPACE
@@ -675,17 +676,17 @@ IDBTransaction::GetObjectStoreNames(Erro
   }
   else {
     arrayOfNames = &mObjectStoreNames;
   }
 
   uint32_t count = arrayOfNames->Length();
   for (uint32_t index = 0; index < count; index++) {
     if (!list->Add(arrayOfNames->ElementAt(index))) {
-      NS_WARNING("Failed to add element!");
+      IDB_WARNING("Failed to add element!");
       aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
       return nullptr;
     }
   }
 
   return list.forget();
 }
 
@@ -709,17 +710,17 @@ IDBTransaction::ObjectStore(const nsAStr
   if (!info) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR);
     return nullptr;
   }
 
   nsRefPtr<IDBObjectStore> objectStore =
     GetOrCreateObjectStore(aName, info, false);
   if (!objectStore) {
-    NS_WARNING("Failed to get or create object store!");
+    IDB_WARNING("Failed to get or create object store!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   return objectStore.forget();
 }
 
 nsresult
@@ -824,17 +825,17 @@ CommitHelper::Run()
         mTransaction->mError = new DOMError(mTransaction->GetOwner(), mAbortCode);
       }
     }
     else {
       event = CreateGenericEvent(mTransaction,
                                  NS_LITERAL_STRING(COMPLETE_EVT_STR),
                                  eDoesNotBubble, eNotCancelable);
     }
-    NS_ENSURE_TRUE(event, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_TRUE(event, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     if (mListener) {
       mListener->NotifyTransactionPreComplete(mTransaction);
     }
 
     IDB_PROFILER_MARK("IndexedDB Transaction %llu: Complete (rv = %lu)",
                       "IDBTransaction[%llu] MT Complete",
                       mTransaction->GetSerialNumber(), mAbortCode);
@@ -856,28 +857,31 @@ CommitHelper::Run()
 
     return NS_OK;
   }
 
   PROFILER_LABEL("IndexedDB", "CommitHelper::Run");
 
   IDBDatabase* database = mTransaction->Database();
   if (database->IsInvalidated()) {
+    IDB_REPORT_INTERNAL_ERR();
     mAbortCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   if (mConnection) {
     QuotaManager::SetCurrentWindow(database->GetOwner());
 
     if (NS_SUCCEEDED(mAbortCode) && mUpdateFileRefcountFunction &&
         NS_FAILED(mUpdateFileRefcountFunction->WillCommit(mConnection))) {
+      IDB_REPORT_INTERNAL_ERR();
       mAbortCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     if (NS_SUCCEEDED(mAbortCode) && NS_FAILED(WriteAutoIncrementCounts())) {
+      IDB_REPORT_INTERNAL_ERR();
       mAbortCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     if (NS_SUCCEEDED(mAbortCode)) {
       NS_NAMED_LITERAL_CSTRING(release, "COMMIT TRANSACTION");
       nsresult rv = mConnection->ExecuteSimpleSQL(release);
       if (NS_SUCCEEDED(rv)) {
         if (mUpdateFileRefcountFunction) {
@@ -886,16 +890,17 @@ CommitHelper::Run()
         CommitAutoIncrementCounts();
       }
       else if (rv == NS_ERROR_FILE_NO_DEVICE_SPACE) {
         // mozstorage translates SQLITE_FULL to NS_ERROR_FILE_NO_DEVICE_SPACE,
         // which we know better as NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR.
         mAbortCode = NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
       }
       else {
+        IDB_REPORT_INTERNAL_ERR();
         mAbortCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
     }
 
     if (NS_FAILED(mAbortCode)) {
       if (mUpdateFileRefcountFunction) {
         mUpdateFileRefcountFunction->DidAbort();
       }
--- a/dom/indexedDB/Key.cpp
+++ b/dom/indexedDB/Key.cpp
@@ -2,16 +2,18 @@
 /* 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 "mozilla/FloatingPoint.h"
 
 #include "Key.h"
+#include "ReportInternalError.h"
+
 #include "jsfriendapi.h"
 #include "nsAlgorithm.h"
 #include "nsJSUtils.h"
 #include "xpcpublic.h"
 #include "mozilla/Endian.h"
 #include <algorithm>
 
 USING_INDEXEDDB_NAMESPACE
@@ -107,16 +109,17 @@ Key::EncodeJSValInternal(JSContext* aCx,
   NS_ENSURE_TRUE(aRecursionDepth < MaxRecursionDepth, NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
 
   static_assert(eMaxType * MaxArrayCollapse < 256,
                 "Unable to encode jsvals.");
 
   if (aVal.isString()) {
     nsDependentJSString str;
     if (!str.init(aCx, aVal)) {
+      IDB_REPORT_INTERNAL_ERR();
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
     EncodeString(str, aTypeOffset);
     return NS_OK;
   }
 
   if (aVal.isNumber()) {
     double d = aVal.toNumber();
@@ -137,22 +140,24 @@ Key::EncodeJSValInternal(JSContext* aCx,
         aTypeOffset = 0;
       }
       NS_ASSERTION((aTypeOffset % eMaxType) == 0 &&
                    aTypeOffset < (eMaxType * MaxArrayCollapse),
                    "Wrong typeoffset");
 
       uint32_t length;
       if (!JS_GetArrayLength(aCx, obj, &length)) {
+        IDB_REPORT_INTERNAL_ERR();
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
 
       for (uint32_t index = 0; index < length; index++) {
         JS::Rooted<JS::Value> val(aCx);
         if (!JS_GetElement(aCx, obj, index, &val)) {
+          IDB_REPORT_INTERNAL_ERR();
           return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
         }
 
         nsresult rv = EncodeJSValInternal(aCx, val, aTypeOffset,
                                           aRecursionDepth + 1);
         if (NS_FAILED(rv)) {
           return rv;
         }
@@ -184,16 +189,17 @@ Key::DecodeJSValInternal(const unsigned 
                          uint16_t aRecursionDepth)
 {
   NS_ENSURE_TRUE(aRecursionDepth < MaxRecursionDepth, NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
 
   if (*aPos - aTypeOffset >= eArray) {
     JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0, nullptr));
     if (!array) {
       NS_WARNING("Failed to make array!");
+      IDB_REPORT_INTERNAL_ERR();
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     aTypeOffset += eMaxType;
 
     if (aTypeOffset == eMaxType * MaxArrayCollapse) {
       ++aPos;
       aTypeOffset = 0;
@@ -205,38 +211,40 @@ Key::DecodeJSValInternal(const unsigned 
       nsresult rv = DecodeJSValInternal(aPos, aEnd, aCx, aTypeOffset,
                                         &val, aRecursionDepth + 1);
       NS_ENSURE_SUCCESS(rv, rv);
 
       aTypeOffset = 0;
 
       if (!JS_SetElement(aCx, array, index++, val)) {
         NS_WARNING("Failed to set array element!");
+        IDB_REPORT_INTERNAL_ERR();
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
     }
 
     NS_ASSERTION(aPos >= aEnd || (*aPos % eMaxType) == eTerminator,
                  "Should have found end-of-array marker");
     ++aPos;
 
     aVal.setObject(*array);
   }
   else if (*aPos - aTypeOffset == eString) {
     nsString key;
     DecodeString(aPos, aEnd, key);
     if (!xpc::StringToJsval(aCx, key, aVal)) {
+      IDB_REPORT_INTERNAL_ERR();
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
   }
   else if (*aPos - aTypeOffset == eDate) {
     double msec = static_cast<double>(DecodeNumber(aPos, aEnd));
     JSObject* date = JS_NewDateObjectMsec(aCx, msec);
     if (!date) {
-      NS_WARNING("Failed to make date!");
+      IDB_WARNING("Failed to make date!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     aVal.setObject(*date);
   }
   else if (*aPos - aTypeOffset == eFloat) {
     aVal.setDouble(DecodeNumber(aPos, aEnd));
   }
--- a/dom/indexedDB/KeyPath.cpp
+++ b/dom/indexedDB/KeyPath.cpp
@@ -2,16 +2,17 @@
 /* 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 "KeyPath.h"
 #include "IDBObjectStore.h"
 #include "Key.h"
+#include "ReportInternalError.h"
 
 #include "nsCharSeparatedTokenizer.h"
 #include "nsJSUtils.h"
 #include "xpcpublic.h"
 
 #include "mozilla/dom/BindingDeclarations.h"
 
 USING_INDEXEDDB_NAMESPACE
@@ -109,23 +110,23 @@ GetJSValFromKeyPathString(JSContext* aCx
     if (!targetObject) {
       // We're still walking the chain of existing objects
       if (!obj) {
         return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
       }
 
       bool ok = JS_HasUCProperty(aCx, obj, keyPathChars, keyPathLen,
                                  &hasProp);
-      NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+      IDB_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
       if (hasProp) {
         // Get if the property exists...
         JS::Rooted<JS::Value> intermediate(aCx);
         bool ok = JS_GetUCProperty(aCx, obj, keyPathChars, keyPathLen, &intermediate);
-        NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+        IDB_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
         // Treat explicitly undefined as an error.
         if (intermediate == JSVAL_VOID) {
           return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
         }
         if (tokenizer.hasMoreTokens()) {
           // ...and walk to it if there are more steps...
           if (JSVAL_IS_PRIMITIVE(intermediate)) {
@@ -157,41 +158,45 @@ GetJSValFromKeyPathString(JSContext* aCx
       *aKeyJSVal = JSVAL_VOID;
 
       if (tokenizer.hasMoreTokens()) {
         // If we're not at the end, we need to add a dummy object to the
         // chain.
         JS::Rooted<JSObject*> dummy(aCx, JS_NewObject(aCx, nullptr, JS::NullPtr(),
                                                       JS::NullPtr()));
         if (!dummy) {
+          IDB_REPORT_INTERNAL_ERR();
           rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
           break;
         }
 
         if (!JS_DefineUCProperty(aCx, obj, token.BeginReading(),
                                  token.Length(),
                                  OBJECT_TO_JSVAL(dummy), nullptr, nullptr,
                                  JSPROP_ENUMERATE)) {
+          IDB_REPORT_INTERNAL_ERR();
           rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
           break;
         }
 
         obj = dummy;
       }
       else {
         JS::Rooted<JSObject*> dummy(aCx, JS_NewObject(aCx, &IDBObjectStore::sDummyPropJSClass,
                                                       JS::NullPtr(), JS::NullPtr()));
         if (!dummy) {
+          IDB_REPORT_INTERNAL_ERR();
           rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
           break;
         }
 
         if (!JS_DefineUCProperty(aCx, obj, token.BeginReading(),
                                  token.Length(), OBJECT_TO_JSVAL(dummy),
                                  nullptr, nullptr, JSPROP_ENUMERATE)) {
+          IDB_REPORT_INTERNAL_ERR();
           rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
           break;
         }
 
         obj = dummy;
       }
     }
   }
@@ -205,19 +210,20 @@ GetJSValFromKeyPathString(JSContext* aCx
   if (targetObject) {
     // If this fails, we lose, and the web page sees a magical property
     // appear on the object :-(
     bool succeeded;
     if (!JS_DeleteUCProperty2(aCx, targetObject,
                               targetObjectPropName.get(),
                               targetObjectPropName.Length(),
                               &succeeded)) {
+      IDB_REPORT_INTERNAL_ERR();
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
-    NS_ENSURE_TRUE(succeeded, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_TRUE(succeeded, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
   return rv;
 }
 
 } // anonymous namespace
 
@@ -395,16 +401,17 @@ KeyPath::ExtractKeyAsJSVal(JSContext* aC
                                             value.address(),
                                             DoNotCreateProperties, nullptr,
                                             nullptr);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     if (!JS_SetElement(aCx, arrayObj, i, value)) {
+      IDB_REPORT_INTERNAL_ERR();
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
   }
 
   *aOutVal = OBJECT_TO_JSVAL(arrayObj);
   return NS_OK;
 }
 
@@ -492,39 +499,42 @@ KeyPath::DeserializeFromString(const nsA
 
 nsresult
 KeyPath::ToJSVal(JSContext* aCx, JS::MutableHandle<JS::Value> aValue) const
 {
   if (IsArray()) {
     uint32_t len = mStrings.Length();
     JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, len, nullptr));
     if (!array) {
-      NS_WARNING("Failed to make array!");
+      IDB_WARNING("Failed to make array!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     for (uint32_t i = 0; i < len; ++i) {
       JS::Rooted<JS::Value> val(aCx);
       nsString tmp(mStrings[i]);
       if (!xpc::StringToJsval(aCx, tmp, &val)) {
+        IDB_REPORT_INTERNAL_ERR();
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
 
       if (!JS_SetElement(aCx, array, i, val)) {
+        IDB_REPORT_INTERNAL_ERR();
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
     }
 
     aValue.setObject(*array);
     return NS_OK;
   }
 
   if (IsString()) {
     nsString tmp(mStrings[0]);
     if (!xpc::StringToJsval(aCx, tmp, aValue)) {
+      IDB_REPORT_INTERNAL_ERR();
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
     return NS_OK;
   }
 
   aValue.setNull();
   return NS_OK;
 }
--- a/dom/indexedDB/OpenDatabaseHelper.cpp
+++ b/dom/indexedDB/OpenDatabaseHelper.cpp
@@ -19,16 +19,17 @@
 #include "nsThreadUtils.h"
 #include "snappy/snappy.h"
 
 #include "Client.h"
 #include "IDBEvents.h"
 #include "IDBFactory.h"
 #include "IndexedDatabaseManager.h"
 #include "ProfilerHelpers.h"
+#include "ReportInternalError.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 USING_INDEXEDDB_NAMESPACE
 USING_QUOTA_NAMESPACE
 
 namespace {
 
@@ -1781,16 +1782,17 @@ OpenDatabaseHelper::DoDatabaseWork()
   AssertIsOnIOThread();
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
 
   PROFILER_LABEL("IndexedDB", "OpenDatabaseHelper::DoDatabaseWork");
 
   mState = eFiringEvents; // In case we fail somewhere along the line.
 
   if (QuotaManager::IsShuttingDown()) {
+    IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   NS_ASSERTION(mOpenDBRequest, "This should never be null!");
 
   // This will be null for non-window contexts.
   nsPIDOMWindow* window = mOpenDBRequest->GetOwner();
 
@@ -1800,71 +1802,72 @@ OpenDatabaseHelper::DoDatabaseWork()
 
   QuotaManager* quotaManager = QuotaManager::Get();
   NS_ASSERTION(quotaManager, "This should never be null!");
 
   nsresult rv =
     quotaManager->EnsureOriginIsInitialized(mPersistenceType, mGroup,
                                             mASCIIOrigin, mTrackingQuota,
                                             getter_AddRefs(dbDirectory));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = dbDirectory->Append(NS_LITERAL_STRING(IDB_DIRECTORY_NAME));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   bool exists;
   rv = dbDirectory->Exists(&exists);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (!exists) {
     rv = dbDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 #ifdef DEBUG
   else {
     bool isDirectory;
     NS_ASSERTION(NS_SUCCEEDED(dbDirectory->IsDirectory(&isDirectory)) &&
                 isDirectory, "Should have caught this earlier!");
   }
 #endif
 
   nsAutoString filename;
   rv = GetDatabaseFilename(mName, filename);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsCOMPtr<nsIFile> dbFile;
   rv = dbDirectory->Clone(getter_AddRefs(dbFile));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = dbFile->Append(filename + NS_LITERAL_STRING(".sqlite"));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = dbFile->GetPath(mDatabaseFilePath);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsCOMPtr<nsIFile> fmDirectory;
   rv = dbDirectory->Clone(getter_AddRefs(fmDirectory));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = fmDirectory->Append(filename);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsCOMPtr<mozIStorageConnection> connection;
   rv = CreateDatabaseConnection(dbFile, fmDirectory, mName, mPersistenceType,
                                 mGroup, mASCIIOrigin,
                                 getter_AddRefs(connection));
   if (NS_FAILED(rv) &&
       NS_ERROR_GET_MODULE(rv) != NS_ERROR_MODULE_DOM_INDEXEDDB) {
+    IDB_REPORT_INTERNAL_ERR();
     rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = IDBFactory::LoadDatabaseInformation(connection, mDatabaseId,
                                            &mCurrentVersion, mObjectStores);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (mForDeletion) {
     mState = eDeletePending;
     return NS_OK;
   }
 
   for (uint32_t i = 0; i < mObjectStores.Length(); i++) {
     nsRefPtr<ObjectStoreInfo>& objectStoreInfo = mObjectStores[i];
@@ -1903,17 +1906,17 @@ OpenDatabaseHelper::DoDatabaseWork()
 
   nsRefPtr<FileManager> fileManager =
     mgr->GetFileManager(mPersistenceType, mASCIIOrigin, mName);
   if (!fileManager) {
     fileManager = new FileManager(mPersistenceType, mGroup, mASCIIOrigin,
                                   mPrivilege, mName);
 
     rv = fileManager->Init(fmDirectory, connection);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     mgr->AddFileManager(fileManager);
   }
 
   mFileManager = fileManager.forget();
 
   return NS_OK;
 }
@@ -1971,17 +1974,17 @@ OpenDatabaseHelper::CreateDatabaseConnec
 
     rv = aFMDirectory->Exists(&exists);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (exists) {
       bool isDirectory;
       rv = aFMDirectory->IsDirectory(&isDirectory);
       NS_ENSURE_SUCCESS(rv, rv);
-      NS_ENSURE_TRUE(isDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+      IDB_ENSURE_TRUE(isDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
       rv = aFMDirectory->Remove(true);
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(connection));
   }
   NS_ENSURE_SUCCESS(rv, rv);
@@ -1994,22 +1997,22 @@ OpenDatabaseHelper::CreateDatabaseConnec
 
   // Check to make sure that the database schema is correct.
   int32_t schemaVersion;
   rv = connection->GetSchemaVersion(&schemaVersion);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Unknown schema will fail origin initialization too
   if (!schemaVersion && aName.IsVoid()) {
-    NS_WARNING("Unable to open IndexedDB database, schema is not set!");
+    IDB_WARNING("Unable to open IndexedDB database, schema is not set!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   if (schemaVersion > kSQLiteSchemaVersion) {
-    NS_WARNING("Unable to open IndexedDB database, schema is too high!");
+    IDB_WARNING("Unable to open IndexedDB database, schema is too high!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   bool vacuumNeeded = false;
 
   if (schemaVersion != kSQLiteSchemaVersion) {
 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
     if (!schemaVersion) {
@@ -2039,23 +2042,23 @@ OpenDatabaseHelper::CreateDatabaseConnec
                    schemaVersion == kSQLiteSchemaVersion,
                    "CreateTables set a bad schema version!");
 
       nsCOMPtr<mozIStorageStatement> stmt;
       nsresult rv = connection->CreateStatement(NS_LITERAL_CSTRING(
         "INSERT INTO database (name) "
         "VALUES (:name)"
       ), getter_AddRefs(stmt));
-      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+      IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
       rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), aName);
-      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+      IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
       rv = stmt->Execute();
-      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+      IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     }
     else  {
       // This logic needs to change next time we change the schema!
       static_assert(kSQLiteSchemaVersion == int32_t((14 << 4) + 0),
                     "Need upgrade code from schema version increase.");
 
       while (schemaVersion != kSQLiteSchemaVersion) {
         if (schemaVersion == 4) {
@@ -2087,16 +2090,17 @@ OpenDatabaseHelper::CreateDatabaseConnec
           rv = UpgradeSchemaFrom12_0To13_0(connection, &vacuumNeeded);
         }
         else if (schemaVersion == MakeSchemaVersion(13, 0)) {
           rv = UpgradeSchemaFrom13_0To14_0(connection);
         }
         else {
           NS_WARNING("Unable to open IndexedDB database, no upgrade path is "
                      "available!");
+          IDB_REPORT_INTERNAL_ERR();
           return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
         }
         NS_ENSURE_SUCCESS(rv, rv);
 
         rv = connection->GetSchemaVersion(&schemaVersion);
         NS_ENSURE_SUCCESS(rv, rv);
       }
 
@@ -2131,30 +2135,30 @@ OpenDatabaseHelper::StartSetVersion()
 
   nsresult rv = EnsureSuccessResult();
   NS_ENSURE_SUCCESS(rv, rv);
 
   Sequence<nsString> storesToOpen;
   nsRefPtr<IDBTransaction> transaction =
     IDBTransaction::Create(mDatabase, storesToOpen,
                            IDBTransaction::VERSION_CHANGE, true);
-  NS_ENSURE_TRUE(transaction, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_TRUE(transaction, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<SetVersionHelper> helper =
     new SetVersionHelper(transaction, mOpenDBRequest, this, mRequestedVersion,
                          mCurrentVersion);
 
   QuotaManager* quotaManager = QuotaManager::Get();
   NS_ASSERTION(quotaManager, "This should never be null!");
 
   rv = quotaManager->AcquireExclusiveAccess(
              mDatabase, mDatabase->Origin(), helper,
              &VersionChangeEventsRunnable::QueueVersionChange<SetVersionHelper>,
              helper);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   // The SetVersionHelper is responsible for dispatching us back to the
   // main thread again and changing the state to eSetVersionCompleted.
   mState = eSetVersionPending;
   return NS_OK;
 }
 
 nsresult
@@ -2174,17 +2178,17 @@ OpenDatabaseHelper::StartDelete()
 
   QuotaManager* quotaManager = QuotaManager::Get();
   NS_ASSERTION(quotaManager, "This should never be null!");
 
   rv = quotaManager->AcquireExclusiveAccess(
          mDatabase, mDatabase->Origin(), helper,
          &VersionChangeEventsRunnable::QueueVersionChange<DeleteDatabaseHelper>,
          helper);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   // The DeleteDatabaseHelper is responsible for dispatching us back to the
   // main thread again and changing the state to eDeleteCompleted.
   mState = eDeletePending;
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -2369,37 +2373,37 @@ OpenDatabaseHelper::EnsureSuccessResult(
     newInfo->name = mName;
     newInfo->group = mGroup;
     newInfo->origin = mASCIIOrigin;
     newInfo->persistenceType = mPersistenceType;
     newInfo->id = mDatabaseId;
     newInfo->filePath = mDatabaseFilePath;
 
     if (!DatabaseInfo::Put(newInfo)) {
-      NS_ERROR("Failed to add to hash!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     newInfo.swap(dbInfo);
 
     nsresult rv = IDBFactory::SetDatabaseMetadata(dbInfo, mCurrentVersion,
                                                   mObjectStores);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     NS_ASSERTION(mObjectStores.IsEmpty(), "Should have swapped!");
   }
 
   dbInfo->nextObjectStoreId = mLastObjectStoreId + 1;
   dbInfo->nextIndexId = mLastIndexId + 1;
 
   nsRefPtr<IDBDatabase> database =
     IDBDatabase::Create(mOpenDBRequest, mOpenDBRequest->Factory(),
                         dbInfo.forget(), mASCIIOrigin, mFileManager,
                         mContentParent);
   if (!database) {
+    IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   NS_ASSERTION(!mDatabase, "Shouldn't have a database yet!");
   mDatabase.swap(database);
 
   return NS_OK;
 }
@@ -2533,21 +2537,21 @@ SetVersionHelper::DoDatabaseWork(mozISto
 
   PROFILER_LABEL("IndexedDB", "SetVersionHelper::DoDatabaseWork");
 
   nsCOMPtr<mozIStorageStatement> stmt;
   nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
     "UPDATE database "
     "SET version = :version"
   ), getter_AddRefs(stmt));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("version"),
                              mRequestedVersion);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (NS_FAILED(stmt->Execute())) {
     return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
   }
 
   return NS_OK;
 }
 
@@ -2658,98 +2662,98 @@ DeleteDatabaseHelper::DoDatabaseWork(moz
 
   QuotaManager* quotaManager = QuotaManager::Get();
   NS_ASSERTION(quotaManager, "This should never fail!");
 
   nsCOMPtr<nsIFile> directory;
   nsresult rv = quotaManager->GetDirectoryForOrigin(mPersistenceType,
                                                     mASCIIOrigin,
                                                     getter_AddRefs(directory));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NS_ASSERTION(directory, "What?");
 
   rv = directory->Append(NS_LITERAL_STRING(IDB_DIRECTORY_NAME));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsAutoString filename;
   rv = GetDatabaseFilename(mName, filename);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsCOMPtr<nsIFile> dbFile;
   rv = directory->Clone(getter_AddRefs(dbFile));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = dbFile->Append(filename + NS_LITERAL_STRING(".sqlite"));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   bool exists = false;
   rv = dbFile->Exists(&exists);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (exists) {
     int64_t fileSize;
 
     if (privilege != Chrome) {
       rv = dbFile->GetFileSize(&fileSize);
-      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+      IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     }
 
     rv = dbFile->Remove(false);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     if (privilege != Chrome) {
       QuotaManager* quotaManager = QuotaManager::Get();
       NS_ASSERTION(quotaManager, "Shouldn't be null!");
 
       quotaManager->DecreaseUsageForOrigin(mPersistenceType, mGroup,
                                            mASCIIOrigin, fileSize);
     }
   }
 
   nsCOMPtr<nsIFile> dbJournalFile;
   rv = directory->Clone(getter_AddRefs(dbJournalFile));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = dbJournalFile->Append(filename + NS_LITERAL_STRING(".sqlite-journal"));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = dbJournalFile->Exists(&exists);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (exists) {
     rv = dbJournalFile->Remove(false);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
   nsCOMPtr<nsIFile> fmDirectory;
   rv = directory->Clone(getter_AddRefs(fmDirectory));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = fmDirectory->Append(filename);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = fmDirectory->Exists(&exists);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (exists) {
     bool isDirectory;
     rv = fmDirectory->IsDirectory(&isDirectory);
     NS_ENSURE_SUCCESS(rv, rv);
-    NS_ENSURE_TRUE(isDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_TRUE(isDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     uint64_t usage = 0;
 
     if (privilege != Chrome) {
       rv = FileManager::GetUsage(fmDirectory, &usage);
-      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+      IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     }
 
     rv = fmDirectory->Remove(true);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     if (privilege != Chrome) {
       QuotaManager* quotaManager = QuotaManager::Get();
       NS_ASSERTION(quotaManager, "Shouldn't be null!");
 
       quotaManager->DecreaseUsageForOrigin(mPersistenceType, mGroup,
                                            mASCIIOrigin, usage);
     }
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/ReportInternalError.cpp
@@ -0,0 +1,32 @@
+/* -*- 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 "ReportInternalError.h"
+
+#include "mozilla/IntegerPrintfMacros.h"
+
+#include "nsContentUtils.h"
+#include "nsPrintfCString.h"
+
+BEGIN_INDEXEDDB_NAMESPACE
+
+void
+ReportInternalError(const char* aFile, uint32_t aLine, const char* aStr)
+{
+  // Get leaf of file path
+  for (const char* p = aFile; *p; ++p) {
+    if (*p == '/' && *(p + 1)) {
+      aFile = p + 1;
+    }
+  }
+
+  nsContentUtils::LogSimpleConsoleError(
+    NS_ConvertUTF8toUTF16(nsPrintfCString(
+                          "IndexedDB %s: %s:%lu", aStr, aFile, aLine)),
+    "indexedDB");
+}
+
+END_INDEXEDDB_NAMESPACE
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/ReportInternalError.h
@@ -0,0 +1,51 @@
+/* -*- 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/. */
+
+#ifndef mozilla_dom_indexeddb_reportinternalerror_h__
+#define mozilla_dom_indexeddb_reportinternalerror_h__
+
+#include "nsDebug.h"
+
+#include "IndexedDatabase.h"
+
+#define IDB_WARNING(x)                                                         \
+  mozilla::dom::indexedDB::ReportInternalError(__FILE__, __LINE__, x);         \
+  NS_WARNING(x)
+
+#define IDB_REPORT_INTERNAL_ERR()                                              \
+  mozilla::dom::indexedDB::ReportInternalError(__FILE__, __LINE__,             \
+                                               "UnknownErr")
+
+// Based on NS_ENSURE_TRUE
+#define IDB_ENSURE_TRUE(x, ret)                                                \
+  do {                                                                         \
+    if (MOZ_UNLIKELY(!(x))) {                                                  \
+       IDB_REPORT_INTERNAL_ERR();                                              \
+       NS_WARNING("IDB_ENSURE_TRUE(" #x ") failed");                           \
+       return ret;                                                             \
+    }                                                                          \
+  } while(0)
+
+// Based on NS_ENSURE_SUCCESS
+#define IDB_ENSURE_SUCCESS(res, ret)                                           \
+  do {                                                                         \
+    nsresult __rv = res; /* Don't evaluate |res| more than once */             \
+    if (NS_FAILED(__rv)) {                                                     \
+      IDB_REPORT_INTERNAL_ERR();                                               \
+      NS_ENSURE_SUCCESS_BODY(res, ret)                                         \
+      return ret;                                                              \
+    }                                                                          \
+  } while(0)
+
+
+BEGIN_INDEXEDDB_NAMESPACE
+
+void
+ReportInternalError(const char* aFile, uint32_t aLine, const char* aStr);
+
+END_INDEXEDDB_NAMESPACE
+
+#endif  // mozilla_dom_indexeddb_reportinternalerror_h__
--- a/dom/indexedDB/moz.build
+++ b/dom/indexedDB/moz.build
@@ -57,16 +57,17 @@ UNIFIED_SOURCES += [
     'TransactionThreadPool.cpp',
 ]
 
 # These files cannot be built in unified mode because of name collisions
 SOURCES += [
     'IDBCursor.cpp',
     'IDBIndex.cpp',
     'IDBObjectStore.cpp',
+    'ReportInternalError.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'gklayout'
 LOCAL_INCLUDES += [
--- a/dom/webidl/ImageData.webidl
+++ b/dom/webidl/ImageData.webidl
@@ -5,16 +5,18 @@
  *
  * The origin of this IDL file is
  * http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#imagedata
  *
  * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and Opera Software ASA.
  * You are granted a license to use, reproduce and create derivative works of this document.
  */
 
+[Constructor(unsigned long sw, unsigned long sh),
+ Constructor(Uint8ClampedArray data, unsigned long sw, optional unsigned long sh)]
 interface ImageData {
  [Constant]
  readonly attribute unsigned long width;
  [Constant]
  readonly attribute unsigned long height;
  [Constant, StoreInSlot]
  readonly attribute Uint8ClampedArray data;
 };
--- a/dom/xslt/xslt/txXSLTNumber.cpp
+++ b/dom/xslt/xslt/txXSLTNumber.cpp
@@ -1,24 +1,27 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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 "mozilla/ArrayUtils.h"
 #include "mozilla/FloatingPoint.h"
 
 #include "txXSLTNumber.h"
 #include "nsGkAtoms.h"
 #include "txCore.h"
 #include <math.h>
 #include "txExpr.h"
 #include "txXSLTPatterns.h"
 #include "txIXPathContext.h"
 #include "txXPathTreeWalker.h"
 
+#include <algorithm>
+
 nsresult txXSLTNumber::createNumber(Expr* aValueExpr, txPattern* aCountPattern,
                                     txPattern* aFromPattern, LevelType aLevel,
                                     Expr* aGroupSize, Expr* aGroupSeparator,
                                     Expr* aFormat, txIEvalContext* aContext,
                                     nsAString& aResult)
 {
     aResult.Truncate();
     nsresult rv = NS_OK;
@@ -414,307 +417,320 @@ txXSLTNumber::getPrevInDocumentOrder(txX
         while (aWalker.moveToLastChild()) {
             // do nothing
         }
         return true;
     }
     return aWalker.moveToParent();
 }
 
-#define TX_CHAR_RANGE(ch, a, b) if (ch < a) return false; \
-    if (ch <= b) return true
-#define TX_MATCH_CHAR(ch, a) if (ch < a) return false; \
-    if (ch == a) return true
+struct CharRange {
+    char16_t lower;             // inclusive
+    char16_t upper;             // inclusive
+
+    bool operator<(const CharRange& other) const {
+        return upper < other.lower;
+    }
+};
 
 bool txXSLTNumber::isAlphaNumeric(char16_t ch)
 {
-    TX_CHAR_RANGE(ch, 0x0030, 0x0039);
-    TX_CHAR_RANGE(ch, 0x0041, 0x005A);
-    TX_CHAR_RANGE(ch, 0x0061, 0x007A);
-    TX_MATCH_CHAR(ch, 0x00AA);
-    TX_CHAR_RANGE(ch, 0x00B2, 0x00B3);
-    TX_MATCH_CHAR(ch, 0x00B5);
-    TX_CHAR_RANGE(ch, 0x00B9, 0x00BA);
-    TX_CHAR_RANGE(ch, 0x00BC, 0x00BE);
-    TX_CHAR_RANGE(ch, 0x00C0, 0x00D6);
-    TX_CHAR_RANGE(ch, 0x00D8, 0x00F6);
-    TX_CHAR_RANGE(ch, 0x00F8, 0x021F);
-    TX_CHAR_RANGE(ch, 0x0222, 0x0233);
-    TX_CHAR_RANGE(ch, 0x0250, 0x02AD);
-    TX_CHAR_RANGE(ch, 0x02B0, 0x02B8);
-    TX_CHAR_RANGE(ch, 0x02BB, 0x02C1);
-    TX_CHAR_RANGE(ch, 0x02D0, 0x02D1);
-    TX_CHAR_RANGE(ch, 0x02E0, 0x02E4);
-    TX_MATCH_CHAR(ch, 0x02EE);
-    TX_MATCH_CHAR(ch, 0x037A);
-    TX_MATCH_CHAR(ch, 0x0386);
-    TX_CHAR_RANGE(ch, 0x0388, 0x038A);
-    TX_MATCH_CHAR(ch, 0x038C);
-    TX_CHAR_RANGE(ch, 0x038E, 0x03A1);
-    TX_CHAR_RANGE(ch, 0x03A3, 0x03CE);
-    TX_CHAR_RANGE(ch, 0x03D0, 0x03D7);
-    TX_CHAR_RANGE(ch, 0x03DA, 0x03F3);
-    TX_CHAR_RANGE(ch, 0x0400, 0x0481);
-    TX_CHAR_RANGE(ch, 0x048C, 0x04C4);
-    TX_CHAR_RANGE(ch, 0x04C7, 0x04C8);
-    TX_CHAR_RANGE(ch, 0x04CB, 0x04CC);
-    TX_CHAR_RANGE(ch, 0x04D0, 0x04F5);
-    TX_CHAR_RANGE(ch, 0x04F8, 0x04F9);
-    TX_CHAR_RANGE(ch, 0x0531, 0x0556);
-    TX_MATCH_CHAR(ch, 0x0559);
-    TX_CHAR_RANGE(ch, 0x0561, 0x0587);
-    TX_CHAR_RANGE(ch, 0x05D0, 0x05EA);
-    TX_CHAR_RANGE(ch, 0x05F0, 0x05F2);
-    TX_CHAR_RANGE(ch, 0x0621, 0x063A);
-    TX_CHAR_RANGE(ch, 0x0640, 0x064A);
-    TX_CHAR_RANGE(ch, 0x0660, 0x0669);
-    TX_CHAR_RANGE(ch, 0x0671, 0x06D3);
-    TX_MATCH_CHAR(ch, 0x06D5);
-    TX_CHAR_RANGE(ch, 0x06E5, 0x06E6);
-    TX_CHAR_RANGE(ch, 0x06F0, 0x06FC);
-    TX_MATCH_CHAR(ch, 0x0710);
-    TX_CHAR_RANGE(ch, 0x0712, 0x072C);
-    TX_CHAR_RANGE(ch, 0x0780, 0x07A5);
-    TX_CHAR_RANGE(ch, 0x0905, 0x0939);
-    TX_MATCH_CHAR(ch, 0x093D);
-    TX_MATCH_CHAR(ch, 0x0950);
-    TX_CHAR_RANGE(ch, 0x0958, 0x0961);
-    TX_CHAR_RANGE(ch, 0x0966, 0x096F);
-    TX_CHAR_RANGE(ch, 0x0985, 0x098C);
-    TX_CHAR_RANGE(ch, 0x098F, 0x0990);
-    TX_CHAR_RANGE(ch, 0x0993, 0x09A8);
-    TX_CHAR_RANGE(ch, 0x09AA, 0x09B0);
-    TX_MATCH_CHAR(ch, 0x09B2);
-    TX_CHAR_RANGE(ch, 0x09B6, 0x09B9);
-    TX_CHAR_RANGE(ch, 0x09DC, 0x09DD);
-    TX_CHAR_RANGE(ch, 0x09DF, 0x09E1);
-    TX_CHAR_RANGE(ch, 0x09E6, 0x09F1);
-    TX_CHAR_RANGE(ch, 0x09F4, 0x09F9);
-    TX_CHAR_RANGE(ch, 0x0A05, 0x0A0A);
-    TX_CHAR_RANGE(ch, 0x0A0F, 0x0A10);
-    TX_CHAR_RANGE(ch, 0x0A13, 0x0A28);
-    TX_CHAR_RANGE(ch, 0x0A2A, 0x0A30);
-    TX_CHAR_RANGE(ch, 0x0A32, 0x0A33);
-    TX_CHAR_RANGE(ch, 0x0A35, 0x0A36);
-    TX_CHAR_RANGE(ch, 0x0A38, 0x0A39);
-    TX_CHAR_RANGE(ch, 0x0A59, 0x0A5C);
-    TX_MATCH_CHAR(ch, 0x0A5E);
-    TX_CHAR_RANGE(ch, 0x0A66, 0x0A6F);
-    TX_CHAR_RANGE(ch, 0x0A72, 0x0A74);
-    TX_CHAR_RANGE(ch, 0x0A85, 0x0A8B);
-    TX_MATCH_CHAR(ch, 0x0A8D);
-    TX_CHAR_RANGE(ch, 0x0A8F, 0x0A91);
-    TX_CHAR_RANGE(ch, 0x0A93, 0x0AA8);
-    TX_CHAR_RANGE(ch, 0x0AAA, 0x0AB0);
-    TX_CHAR_RANGE(ch, 0x0AB2, 0x0AB3);
-    TX_CHAR_RANGE(ch, 0x0AB5, 0x0AB9);
-    TX_MATCH_CHAR(ch, 0x0ABD);
-    TX_MATCH_CHAR(ch, 0x0AD0);
-    TX_MATCH_CHAR(ch, 0x0AE0);
-    TX_CHAR_RANGE(ch, 0x0AE6, 0x0AEF);
-    TX_CHAR_RANGE(ch, 0x0B05, 0x0B0C);
-    TX_CHAR_RANGE(ch, 0x0B0F, 0x0B10);
-    TX_CHAR_RANGE(ch, 0x0B13, 0x0B28);
-    TX_CHAR_RANGE(ch, 0x0B2A, 0x0B30);
-    TX_CHAR_RANGE(ch, 0x0B32, 0x0B33);
-    TX_CHAR_RANGE(ch, 0x0B36, 0x0B39);
-    TX_MATCH_CHAR(ch, 0x0B3D);
-    TX_CHAR_RANGE(ch, 0x0B5C, 0x0B5D);
-    TX_CHAR_RANGE(ch, 0x0B5F, 0x0B61);
-    TX_CHAR_RANGE(ch, 0x0B66, 0x0B6F);
-    TX_CHAR_RANGE(ch, 0x0B85, 0x0B8A);
-    TX_CHAR_RANGE(ch, 0x0B8E, 0x0B90);
-    TX_CHAR_RANGE(ch, 0x0B92, 0x0B95);
-    TX_CHAR_RANGE(ch, 0x0B99, 0x0B9A);
-    TX_MATCH_CHAR(ch, 0x0B9C);
-    TX_CHAR_RANGE(ch, 0x0B9E, 0x0B9F);
-    TX_CHAR_RANGE(ch, 0x0BA3, 0x0BA4);
-    TX_CHAR_RANGE(ch, 0x0BA8, 0x0BAA);
-    TX_CHAR_RANGE(ch, 0x0BAE, 0x0BB5);
-    TX_CHAR_RANGE(ch, 0x0BB7, 0x0BB9);
-    TX_CHAR_RANGE(ch, 0x0BE7, 0x0BF2);
-    TX_CHAR_RANGE(ch, 0x0C05, 0x0C0C);
-    TX_CHAR_RANGE(ch, 0x0C0E, 0x0C10);
-    TX_CHAR_RANGE(ch, 0x0C12, 0x0C28);
-    TX_CHAR_RANGE(ch, 0x0C2A, 0x0C33);
-    TX_CHAR_RANGE(ch, 0x0C35, 0x0C39);
-    TX_CHAR_RANGE(ch, 0x0C60, 0x0C61);
-    TX_CHAR_RANGE(ch, 0x0C66, 0x0C6F);
-    TX_CHAR_RANGE(ch, 0x0C85, 0x0C8C);
-    TX_CHAR_RANGE(ch, 0x0C8E, 0x0C90);
-    TX_CHAR_RANGE(ch, 0x0C92, 0x0CA8);
-    TX_CHAR_RANGE(ch, 0x0CAA, 0x0CB3);
-    TX_CHAR_RANGE(ch, 0x0CB5, 0x0CB9);
-    TX_MATCH_CHAR(ch, 0x0CDE);
-    TX_CHAR_RANGE(ch, 0x0CE0, 0x0CE1);
-    TX_CHAR_RANGE(ch, 0x0CE6, 0x0CEF);
-    TX_CHAR_RANGE(ch, 0x0D05, 0x0D0C);
-    TX_CHAR_RANGE(ch, 0x0D0E, 0x0D10);
-    TX_CHAR_RANGE(ch, 0x0D12, 0x0D28);
-    TX_CHAR_RANGE(ch, 0x0D2A, 0x0D39);
-    TX_CHAR_RANGE(ch, 0x0D60, 0x0D61);
-    TX_CHAR_RANGE(ch, 0x0D66, 0x0D6F);
-    TX_CHAR_RANGE(ch, 0x0D85, 0x0D96);
-    TX_CHAR_RANGE(ch, 0x0D9A, 0x0DB1);
-    TX_CHAR_RANGE(ch, 0x0DB3, 0x0DBB);
-    TX_MATCH_CHAR(ch, 0x0DBD);
-    TX_CHAR_RANGE(ch, 0x0DC0, 0x0DC6);
-    TX_CHAR_RANGE(ch, 0x0E01, 0x0E30);
-    TX_CHAR_RANGE(ch, 0x0E32, 0x0E33);
-    TX_CHAR_RANGE(ch, 0x0E40, 0x0E46);
-    TX_CHAR_RANGE(ch, 0x0E50, 0x0E59);
-    TX_CHAR_RANGE(ch, 0x0E81, 0x0E82);
-    TX_MATCH_CHAR(ch, 0x0E84);
-    TX_CHAR_RANGE(ch, 0x0E87, 0x0E88);
-    TX_MATCH_CHAR(ch, 0x0E8A);
-    TX_MATCH_CHAR(ch, 0x0E8D);
-    TX_CHAR_RANGE(ch, 0x0E94, 0x0E97);
-    TX_CHAR_RANGE(ch, 0x0E99, 0x0E9F);
-    TX_CHAR_RANGE(ch, 0x0EA1, 0x0EA3);
-    TX_MATCH_CHAR(ch, 0x0EA5);
-    TX_MATCH_CHAR(ch, 0x0EA7);
-    TX_CHAR_RANGE(ch, 0x0EAA, 0x0EAB);
-    TX_CHAR_RANGE(ch, 0x0EAD, 0x0EB0);
-    TX_CHAR_RANGE(ch, 0x0EB2, 0x0EB3);
-    TX_MATCH_CHAR(ch, 0x0EBD);
-    TX_CHAR_RANGE(ch, 0x0EC0, 0x0EC4);
-    TX_MATCH_CHAR(ch, 0x0EC6);
-    TX_CHAR_RANGE(ch, 0x0ED0, 0x0ED9);
-    TX_CHAR_RANGE(ch, 0x0EDC, 0x0EDD);
-    TX_MATCH_CHAR(ch, 0x0F00);
-    TX_CHAR_RANGE(ch, 0x0F20, 0x0F33);
-    TX_CHAR_RANGE(ch, 0x0F40, 0x0F47);
-    TX_CHAR_RANGE(ch, 0x0F49, 0x0F6A);
-    TX_CHAR_RANGE(ch, 0x0F88, 0x0F8B);
-    TX_CHAR_RANGE(ch, 0x1000, 0x1021);
-    TX_CHAR_RANGE(ch, 0x1023, 0x1027);
-    TX_CHAR_RANGE(ch, 0x1029, 0x102A);
-    TX_CHAR_RANGE(ch, 0x1040, 0x1049);
-    TX_CHAR_RANGE(ch, 0x1050, 0x1055);
-    TX_CHAR_RANGE(ch, 0x10A0, 0x10C5);
-    TX_CHAR_RANGE(ch, 0x10D0, 0x10F6);
-    TX_CHAR_RANGE(ch, 0x1100, 0x1159);
-    TX_CHAR_RANGE(ch, 0x115F, 0x11A2);
-    TX_CHAR_RANGE(ch, 0x11A8, 0x11F9);
-    TX_CHAR_RANGE(ch, 0x1200, 0x1206);
-    TX_CHAR_RANGE(ch, 0x1208, 0x1246);
-    TX_MATCH_CHAR(ch, 0x1248);
-    TX_CHAR_RANGE(ch, 0x124A, 0x124D);
-    TX_CHAR_RANGE(ch, 0x1250, 0x1256);
-    TX_MATCH_CHAR(ch, 0x1258);
-    TX_CHAR_RANGE(ch, 0x125A, 0x125D);
-    TX_CHAR_RANGE(ch, 0x1260, 0x1286);
-    TX_MATCH_CHAR(ch, 0x1288);
-    TX_CHAR_RANGE(ch, 0x128A, 0x128D);
-    TX_CHAR_RANGE(ch, 0x1290, 0x12AE);
-    TX_MATCH_CHAR(ch, 0x12B0);
-    TX_CHAR_RANGE(ch, 0x12B2, 0x12B5);
-    TX_CHAR_RANGE(ch, 0x12B8, 0x12BE);
-    TX_MATCH_CHAR(ch, 0x12C0);
-    TX_CHAR_RANGE(ch, 0x12C2, 0x12C5);
-    TX_CHAR_RANGE(ch, 0x12C8, 0x12CE);
-    TX_CHAR_RANGE(ch, 0x12D0, 0x12D6);
-    TX_CHAR_RANGE(ch, 0x12D8, 0x12EE);
-    TX_CHAR_RANGE(ch, 0x12F0, 0x130E);
-    TX_MATCH_CHAR(ch, 0x1310);
-    TX_CHAR_RANGE(ch, 0x1312, 0x1315);
-    TX_CHAR_RANGE(ch, 0x1318, 0x131E);
-    TX_CHAR_RANGE(ch, 0x1320, 0x1346);
-    TX_CHAR_RANGE(ch, 0x1348, 0x135A);
-    TX_CHAR_RANGE(ch, 0x1369, 0x137C);
-    TX_CHAR_RANGE(ch, 0x13A0, 0x13F4);
-    TX_CHAR_RANGE(ch, 0x1401, 0x166C);
-    TX_CHAR_RANGE(ch, 0x166F, 0x1676);
-    TX_CHAR_RANGE(ch, 0x1681, 0x169A);
-    TX_CHAR_RANGE(ch, 0x16A0, 0x16EA);
-    TX_CHAR_RANGE(ch, 0x16EE, 0x16F0);
-    TX_CHAR_RANGE(ch, 0x1780, 0x17B3);
-    TX_CHAR_RANGE(ch, 0x17E0, 0x17E9);
-    TX_CHAR_RANGE(ch, 0x1810, 0x1819);
-    TX_CHAR_RANGE(ch, 0x1820, 0x1877);
-    TX_CHAR_RANGE(ch, 0x1880, 0x18A8);
-    TX_CHAR_RANGE(ch, 0x1E00, 0x1E9B);
-    TX_CHAR_RANGE(ch, 0x1EA0, 0x1EF9);
-    TX_CHAR_RANGE(ch, 0x1F00, 0x1F15);
-    TX_CHAR_RANGE(ch, 0x1F18, 0x1F1D);
-    TX_CHAR_RANGE(ch, 0x1F20, 0x1F45);
-    TX_CHAR_RANGE(ch, 0x1F48, 0x1F4D);
-    TX_CHAR_RANGE(ch, 0x1F50, 0x1F57);
-    TX_MATCH_CHAR(ch, 0x1F59);
-    TX_MATCH_CHAR(ch, 0x1F5B);
-    TX_MATCH_CHAR(ch, 0x1F5D);
-    TX_CHAR_RANGE(ch, 0x1F5F, 0x1F7D);
-    TX_CHAR_RANGE(ch, 0x1F80, 0x1FB4);
-    TX_CHAR_RANGE(ch, 0x1FB6, 0x1FBC);
-    TX_MATCH_CHAR(ch, 0x1FBE);
-    TX_CHAR_RANGE(ch, 0x1FC2, 0x1FC4);
-    TX_CHAR_RANGE(ch, 0x1FC6, 0x1FCC);
-    TX_CHAR_RANGE(ch, 0x1FD0, 0x1FD3);
-    TX_CHAR_RANGE(ch, 0x1FD6, 0x1FDB);
-    TX_CHAR_RANGE(ch, 0x1FE0, 0x1FEC);
-    TX_CHAR_RANGE(ch, 0x1FF2, 0x1FF4);
-    TX_CHAR_RANGE(ch, 0x1FF6, 0x1FFC);
-    TX_MATCH_CHAR(ch, 0x2070);
-    TX_CHAR_RANGE(ch, 0x2074, 0x2079);
-    TX_CHAR_RANGE(ch, 0x207F, 0x2089);
-    TX_MATCH_CHAR(ch, 0x2102);
-    TX_MATCH_CHAR(ch, 0x2107);
-    TX_CHAR_RANGE(ch, 0x210A, 0x2113);
-    TX_MATCH_CHAR(ch, 0x2115);
-    TX_CHAR_RANGE(ch, 0x2119, 0x211D);
-    TX_MATCH_CHAR(ch, 0x2124);
-    TX_MATCH_CHAR(ch, 0x2126);
-    TX_MATCH_CHAR(ch, 0x2128);
-    TX_CHAR_RANGE(ch, 0x212A, 0x212D);
-    TX_CHAR_RANGE(ch, 0x212F, 0x2131);
-    TX_CHAR_RANGE(ch, 0x2133, 0x2139);
-    TX_CHAR_RANGE(ch, 0x2153, 0x2183);
-    TX_CHAR_RANGE(ch, 0x2460, 0x249B);
-    TX_MATCH_CHAR(ch, 0x24EA);
-    TX_CHAR_RANGE(ch, 0x2776, 0x2793);
-    TX_CHAR_RANGE(ch, 0x3005, 0x3007);
-    TX_CHAR_RANGE(ch, 0x3021, 0x3029);
-    TX_CHAR_RANGE(ch, 0x3031, 0x3035);
-    TX_CHAR_RANGE(ch, 0x3038, 0x303A);
-    TX_CHAR_RANGE(ch, 0x3041, 0x3094);
-    TX_CHAR_RANGE(ch, 0x309D, 0x309E);
-    TX_CHAR_RANGE(ch, 0x30A1, 0x30FA);
-    TX_CHAR_RANGE(ch, 0x30FC, 0x30FE);
-    TX_CHAR_RANGE(ch, 0x3105, 0x312C);
-    TX_CHAR_RANGE(ch, 0x3131, 0x318E);
-    TX_CHAR_RANGE(ch, 0x3192, 0x3195);
-    TX_CHAR_RANGE(ch, 0x31A0, 0x31B7);
-    TX_CHAR_RANGE(ch, 0x3220, 0x3229);
-    TX_CHAR_RANGE(ch, 0x3280, 0x3289);
-    TX_MATCH_CHAR(ch, 0x3400);
-    TX_MATCH_CHAR(ch, 0x4DB5);
-    TX_MATCH_CHAR(ch, 0x4E00);
-    TX_MATCH_CHAR(ch, 0x9FA5);
-    TX_CHAR_RANGE(ch, 0xA000, 0xA48C);
-    TX_MATCH_CHAR(ch, 0xAC00);
-    TX_MATCH_CHAR(ch, 0xD7A3);
-    TX_CHAR_RANGE(ch, 0xF900, 0xFA2D);
-    TX_CHAR_RANGE(ch, 0xFB00, 0xFB06);
-    TX_CHAR_RANGE(ch, 0xFB13, 0xFB17);
-    TX_MATCH_CHAR(ch, 0xFB1D);
-    TX_CHAR_RANGE(ch, 0xFB1F, 0xFB28);
-    TX_CHAR_RANGE(ch, 0xFB2A, 0xFB36);
-    TX_CHAR_RANGE(ch, 0xFB38, 0xFB3C);
-    TX_MATCH_CHAR(ch, 0xFB3E);
-    TX_CHAR_RANGE(ch, 0xFB40, 0xFB41);
-    TX_CHAR_RANGE(ch, 0xFB43, 0xFB44);
-    TX_CHAR_RANGE(ch, 0xFB46, 0xFBB1);
-    TX_CHAR_RANGE(ch, 0xFBD3, 0xFD3D);
-    TX_CHAR_RANGE(ch, 0xFD50, 0xFD8F);
-    TX_CHAR_RANGE(ch, 0xFD92, 0xFDC7);
-    TX_CHAR_RANGE(ch, 0xFDF0, 0xFDFB);
-    TX_CHAR_RANGE(ch, 0xFE70, 0xFE72);
-    TX_MATCH_CHAR(ch, 0xFE74);
-    TX_CHAR_RANGE(ch, 0xFE76, 0xFEFC);
-    TX_CHAR_RANGE(ch, 0xFF10, 0xFF19);
-    TX_CHAR_RANGE(ch, 0xFF21, 0xFF3A);
-    TX_CHAR_RANGE(ch, 0xFF41, 0xFF5A);
-    TX_CHAR_RANGE(ch, 0xFF66, 0xFFBE);
-    TX_CHAR_RANGE(ch, 0xFFC2, 0xFFC7);
-    TX_CHAR_RANGE(ch, 0xFFCA, 0xFFCF);
-    TX_CHAR_RANGE(ch, 0xFFD2, 0xFFD7);
-    return false;
+    static const CharRange alphanumericRanges[] = {
+        { 0x0030, 0x0039 },
+        { 0x0041, 0x005A },
+        { 0x0061, 0x007A },
+        { 0x00AA, 0x00AA },
+        { 0x00B2, 0x00B3 },
+        { 0x00B5, 0x00B5 },
+        { 0x00B9, 0x00BA },
+        { 0x00BC, 0x00BE },
+        { 0x00C0, 0x00D6 },
+        { 0x00D8, 0x00F6 },
+        { 0x00F8, 0x021F },
+        { 0x0222, 0x0233 },
+        { 0x0250, 0x02AD },
+        { 0x02B0, 0x02B8 },
+        { 0x02BB, 0x02C1 },
+        { 0x02D0, 0x02D1 },
+        { 0x02E0, 0x02E4 },
+        { 0x02EE, 0x02EE },
+        { 0x037A, 0x037A },
+        { 0x0386, 0x0386 },
+        { 0x0388, 0x038A },
+        { 0x038C, 0x038C },
+        { 0x038E, 0x03A1 },
+        { 0x03A3, 0x03CE },
+        { 0x03D0, 0x03D7 },
+        { 0x03DA, 0x03F3 },
+        { 0x0400, 0x0481 },
+        { 0x048C, 0x04C4 },
+        { 0x04C7, 0x04C8 },
+        { 0x04CB, 0x04CC },
+        { 0x04D0, 0x04F5 },
+        { 0x04F8, 0x04F9 },
+        { 0x0531, 0x0556 },
+        { 0x0559, 0x0559 },
+        { 0x0561, 0x0587 },
+        { 0x05D0, 0x05EA },
+        { 0x05F0, 0x05F2 },
+        { 0x0621, 0x063A },
+        { 0x0640, 0x064A },
+        { 0x0660, 0x0669 },
+        { 0x0671, 0x06D3 },
+        { 0x06D5, 0x06D5 },
+        { 0x06E5, 0x06E6 },
+        { 0x06F0, 0x06FC },
+        { 0x0710, 0x0710 },
+        { 0x0712, 0x072C },
+        { 0x0780, 0x07A5 },
+        { 0x0905, 0x0939 },
+        { 0x093D, 0x093D },
+        { 0x0950, 0x0950 },
+        { 0x0958, 0x0961 },
+        { 0x0966, 0x096F },
+        { 0x0985, 0x098C },
+        { 0x098F, 0x0990 },
+        { 0x0993, 0x09A8 },
+        { 0x09AA, 0x09B0 },
+        { 0x09B2, 0x09B2 },
+        { 0x09B6, 0x09B9 },
+        { 0x09DC, 0x09DD },
+        { 0x09DF, 0x09E1 },
+        { 0x09E6, 0x09F1 },
+        { 0x09F4, 0x09F9 },
+        { 0x0A05, 0x0A0A },
+        { 0x0A0F, 0x0A10 },
+        { 0x0A13, 0x0A28 },
+        { 0x0A2A, 0x0A30 },
+        { 0x0A32, 0x0A33 },
+        { 0x0A35, 0x0A36 },
+        { 0x0A38, 0x0A39 },
+        { 0x0A59, 0x0A5C },
+        { 0x0A5E, 0x0A5E },
+        { 0x0A66, 0x0A6F },
+        { 0x0A72, 0x0A74 },
+        { 0x0A85, 0x0A8B },
+        { 0x0A8D, 0x0A8D },
+        { 0x0A8F, 0x0A91 },
+        { 0x0A93, 0x0AA8 },
+        { 0x0AAA, 0x0AB0 },
+        { 0x0AB2, 0x0AB3 },
+        { 0x0AB5, 0x0AB9 },
+        { 0x0ABD, 0x0ABD },
+        { 0x0AD0, 0x0AD0 },
+        { 0x0AE0, 0x0AE0 },
+        { 0x0AE6, 0x0AEF },
+        { 0x0B05, 0x0B0C },
+        { 0x0B0F, 0x0B10 },
+        { 0x0B13, 0x0B28 },
+        { 0x0B2A, 0x0B30 },
+        { 0x0B32, 0x0B33 },
+        { 0x0B36, 0x0B39 },
+        { 0x0B3D, 0x0B3D },
+        { 0x0B5C, 0x0B5D },
+        { 0x0B5F, 0x0B61 },
+        { 0x0B66, 0x0B6F },
+        { 0x0B85, 0x0B8A },
+        { 0x0B8E, 0x0B90 },
+        { 0x0B92, 0x0B95 },
+        { 0x0B99, 0x0B9A },
+        { 0x0B9C, 0x0B9C },
+        { 0x0B9E, 0x0B9F },
+        { 0x0BA3, 0x0BA4 },
+        { 0x0BA8, 0x0BAA },
+        { 0x0BAE, 0x0BB5 },
+        { 0x0BB7, 0x0BB9 },
+        { 0x0BE7, 0x0BF2 },
+        { 0x0C05, 0x0C0C },
+        { 0x0C0E, 0x0C10 },
+        { 0x0C12, 0x0C28 },
+        { 0x0C2A, 0x0C33 },
+        { 0x0C35, 0x0C39 },
+        { 0x0C60, 0x0C61 },
+        { 0x0C66, 0x0C6F },
+        { 0x0C85, 0x0C8C },
+        { 0x0C8E, 0x0C90 },
+        { 0x0C92, 0x0CA8 },
+        { 0x0CAA, 0x0CB3 },
+        { 0x0CB5, 0x0CB9 },
+        { 0x0CDE, 0x0CDE },
+        { 0x0CE0, 0x0CE1 },
+        { 0x0CE6, 0x0CEF },
+        { 0x0D05, 0x0D0C },
+        { 0x0D0E, 0x0D10 },
+        { 0x0D12, 0x0D28 },
+        { 0x0D2A, 0x0D39 },
+        { 0x0D60, 0x0D61 },
+        { 0x0D66, 0x0D6F },
+        { 0x0D85, 0x0D96 },
+        { 0x0D9A, 0x0DB1 },
+        { 0x0DB3, 0x0DBB },
+        { 0x0DBD, 0x0DBD },
+        { 0x0DC0, 0x0DC6 },
+        { 0x0E01, 0x0E30 },
+        { 0x0E32, 0x0E33 },
+        { 0x0E40, 0x0E46 },
+        { 0x0E50, 0x0E59 },
+        { 0x0E81, 0x0E82 },
+        { 0x0E84, 0x0E84 },
+        { 0x0E87, 0x0E88 },
+        { 0x0E8A, 0x0E8A },
+        { 0x0E8D, 0x0E8D },
+        { 0x0E94, 0x0E97 },
+        { 0x0E99, 0x0E9F },
+        { 0x0EA1, 0x0EA3 },
+        { 0x0EA5, 0x0EA5 },
+        { 0x0EA7, 0x0EA7 },
+        { 0x0EAA, 0x0EAB },
+        { 0x0EAD, 0x0EB0 },
+        { 0x0EB2, 0x0EB3 },
+        { 0x0EBD, 0x0EBD },
+        { 0x0EC0, 0x0EC4 },
+        { 0x0EC6, 0x0EC6 },
+        { 0x0ED0, 0x0ED9 },
+        { 0x0EDC, 0x0EDD },
+        { 0x0F00, 0x0F00 },
+        { 0x0F20, 0x0F33 },
+        { 0x0F40, 0x0F47 },
+        { 0x0F49, 0x0F6A },
+        { 0x0F88, 0x0F8B },
+        { 0x1000, 0x1021 },
+        { 0x1023, 0x1027 },
+        { 0x1029, 0x102A },
+        { 0x1040, 0x1049 },
+        { 0x1050, 0x1055 },
+        { 0x10A0, 0x10C5 },
+        { 0x10D0, 0x10F6 },
+        { 0x1100, 0x1159 },
+        { 0x115F, 0x11A2 },
+        { 0x11A8, 0x11F9 },
+        { 0x1200, 0x1206 },
+        { 0x1208, 0x1246 },
+        { 0x1248, 0x1248 },
+        { 0x124A, 0x124D },
+        { 0x1250, 0x1256 },
+        { 0x1258, 0x1258 },
+        { 0x125A, 0x125D },
+        { 0x1260, 0x1286 },
+        { 0x1288, 0x1288 },
+        { 0x128A, 0x128D },
+        { 0x1290, 0x12AE },
+        { 0x12B0, 0x12B0 },
+        { 0x12B2, 0x12B5 },
+        { 0x12B8, 0x12BE },
+        { 0x12C0, 0x12C0 },
+        { 0x12C2, 0x12C5 },
+        { 0x12C8, 0x12CE },
+        { 0x12D0, 0x12D6 },
+        { 0x12D8, 0x12EE },
+        { 0x12F0, 0x130E },
+        { 0x1310, 0x1310 },
+        { 0x1312, 0x1315 },
+        { 0x1318, 0x131E },
+        { 0x1320, 0x1346 },
+        { 0x1348, 0x135A },
+        { 0x1369, 0x137C },
+        { 0x13A0, 0x13F4 },
+        { 0x1401, 0x166C },
+        { 0x166F, 0x1676 },
+        { 0x1681, 0x169A },
+        { 0x16A0, 0x16EA },
+        { 0x16EE, 0x16F0 },
+        { 0x1780, 0x17B3 },
+        { 0x17E0, 0x17E9 },
+        { 0x1810, 0x1819 },
+        { 0x1820, 0x1877 },
+        { 0x1880, 0x18A8 },
+        { 0x1E00, 0x1E9B },
+        { 0x1EA0, 0x1EF9 },
+        { 0x1F00, 0x1F15 },
+        { 0x1F18, 0x1F1D },
+        { 0x1F20, 0x1F45 },
+        { 0x1F48, 0x1F4D },
+        { 0x1F50, 0x1F57 },
+        { 0x1F59, 0x1F59 },
+        { 0x1F5B, 0x1F5B },
+        { 0x1F5D, 0x1F5D },
+        { 0x1F5F, 0x1F7D },
+        { 0x1F80, 0x1FB4 },
+        { 0x1FB6, 0x1FBC },
+        { 0x1FBE, 0x1FBE },
+        { 0x1FC2, 0x1FC4 },
+        { 0x1FC6, 0x1FCC },
+        { 0x1FD0, 0x1FD3 },
+        { 0x1FD6, 0x1FDB },
+        { 0x1FE0, 0x1FEC },
+        { 0x1FF2, 0x1FF4 },
+        { 0x1FF6, 0x1FFC },
+        { 0x2070, 0x2070 },
+        { 0x2074, 0x2079 },
+        { 0x207F, 0x2089 },
+        { 0x2102, 0x2102 },
+        { 0x2107, 0x2107 },
+        { 0x210A, 0x2113 },
+        { 0x2115, 0x2115 },
+        { 0x2119, 0x211D },
+        { 0x2124, 0x2124 },
+        { 0x2126, 0x2126 },
+        { 0x2128, 0x2128 },
+        { 0x212A, 0x212D },
+        { 0x212F, 0x2131 },
+        { 0x2133, 0x2139 },
+        { 0x2153, 0x2183 },
+        { 0x2460, 0x249B },
+        { 0x24EA, 0x24EA },
+        { 0x2776, 0x2793 },
+        { 0x3005, 0x3007 },
+        { 0x3021, 0x3029 },
+        { 0x3031, 0x3035 },
+        { 0x3038, 0x303A },
+        { 0x3041, 0x3094 },
+        { 0x309D, 0x309E },
+        { 0x30A1, 0x30FA },
+        { 0x30FC, 0x30FE },
+        { 0x3105, 0x312C },
+        { 0x3131, 0x318E },
+        { 0x3192, 0x3195 },
+        { 0x31A0, 0x31B7 },
+        { 0x3220, 0x3229 },
+        { 0x3280, 0x3289 },
+        { 0x3400, 0x3400 },
+        { 0x4DB5, 0x4DB5 },
+        { 0x4E00, 0x4E00 },
+        { 0x9FA5, 0x9FA5 },
+        { 0xA000, 0xA48C },
+        { 0xAC00, 0xAC00 },
+        { 0xD7A3, 0xD7A3 },
+        { 0xF900, 0xFA2D },
+        { 0xFB00, 0xFB06 },
+        { 0xFB13, 0xFB17 },
+        { 0xFB1D, 0xFB1D },
+        { 0xFB1F, 0xFB28 },
+        { 0xFB2A, 0xFB36 },
+        { 0xFB38, 0xFB3C },
+        { 0xFB3E, 0xFB3E },
+        { 0xFB40, 0xFB41 },
+        { 0xFB43, 0xFB44 },
+        { 0xFB46, 0xFBB1 },
+        { 0xFBD3, 0xFD3D },
+        { 0xFD50, 0xFD8F },
+        { 0xFD92, 0xFDC7 },
+        { 0xFDF0, 0xFDFB },
+        { 0xFE70, 0xFE72 },
+        { 0xFE74, 0xFE74 },
+        { 0xFE76, 0xFEFC },
+        { 0xFF10, 0xFF19 },
+        { 0xFF21, 0xFF3A },
+        { 0xFF41, 0xFF5A },
+        { 0xFF66, 0xFFBE },
+        { 0xFFC2, 0xFFC7 },
+        { 0xFFCA, 0xFFCF },
+        { 0xFFD2, 0xFFD7 }
+    };
+
+    CharRange search = { ch, ch };
+    const CharRange* end = mozilla::ArrayEnd(alphanumericRanges);
+    const CharRange* element = std::lower_bound(&alphanumericRanges[0], end, search);
+    if (element == end) {
+        return false;
+    }
+    return element->lower <= ch && ch <= element->upper;
 }
new file mode 100644
--- /dev/null
+++ b/gfx/gl/GLDebugUtils.cpp
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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 "GLDebugUtils.h"
+#include "GLConsts.h"
+
+namespace mozilla {
+namespace gl {
+
+const char*
+GLenumToStr(GLenum e) {
+    switch (e) {
+#define HANDLE_GL_ENUM(x) case LOCAL_##x: return #x
+        HANDLE_GL_ENUM(GL_TRIANGLES);
+        HANDLE_GL_ENUM(GL_TRIANGLE_STRIP);
+        HANDLE_GL_ENUM(GL_TRIANGLE_FAN);
+        HANDLE_GL_ENUM(GL_FRAMEBUFFER);
+        HANDLE_GL_ENUM(GL_RENDERBUFFER);
+        HANDLE_GL_ENUM(GL_DEPTH_ATTACHMENT);
+        HANDLE_GL_ENUM(GL_STENCIL_ATTACHMENT);
+        HANDLE_GL_ENUM(GL_DEPTH_STENCIL_ATTACHMENT);
+        HANDLE_GL_ENUM(GL_TEXTURE_2D);
+        HANDLE_GL_ENUM(GL_TEXTURE_CUBE_MAP_NEGATIVE_X);
+        HANDLE_GL_ENUM(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y);
+        HANDLE_GL_ENUM(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
+        HANDLE_GL_ENUM(GL_TEXTURE_CUBE_MAP_POSITIVE_X);
+        HANDLE_GL_ENUM(GL_TEXTURE_CUBE_MAP_POSITIVE_Y);
+        HANDLE_GL_ENUM(GL_TEXTURE_CUBE_MAP_POSITIVE_Z);
+        HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT0);
+        HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT1);
+        HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT2);
+        HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT3);
+        HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT4);
+        HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT5);
+        HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT6);
+        HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT7);
+        HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT8);
+        HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT9);
+        HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT10);
+        HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT11);
+        HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT12);
+        HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT13);
+        HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT14);
+        HANDLE_GL_ENUM(GL_COLOR_ATTACHMENT15);
+        HANDLE_GL_ENUM(GL_UNSIGNED_BYTE);
+        HANDLE_GL_ENUM(GL_UNSIGNED_SHORT);
+        HANDLE_GL_ENUM(GL_UNSIGNED_INT);
+        HANDLE_GL_ENUM(GL_RGBA);
+        HANDLE_GL_ENUM(GL_DEPTH_COMPONENT);
+#undef HANDLE_GL_ENUM
+    }
+
+    return "(unknown)";
+}
+
+} // namespace gl
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/gl/GLDebugUtils.h
@@ -0,0 +1,19 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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 GLDEBUGUTILS_H_
+#define GLDEBUGUTILS_H_
+
+#include "GLTypes.h"
+
+namespace mozilla {
+namespace gl {
+
+const char* GLenumToStr(GLenum e);
+
+} // namespace gl
+} // namespace mozilla
+
+#endif // !GLDEBUGUTILS_H_
--- a/gfx/gl/GLLibraryEGL.cpp
+++ b/gfx/gl/GLLibraryEGL.cpp
@@ -27,26 +27,22 @@ static const char *sEGLExtensionNames[] 
     "EGL_EXT_create_context_robustness",
     "EGL_KHR_image",
     "EGL_KHR_fence_sync",
     nullptr
 };
 
 #if defined(ANDROID)
 
+static bool sUseApitraceInitialized = false;
+static bool sUseApitrace = false;
+
 static PRLibrary* LoadApitraceLibrary()
 {
-    static bool sUseApitraceInitialized = false;
-    static bool sUseApitrace = false;
-
-    if (!sUseApitraceInitialized) {
-        sUseApitrace = Preferences::GetBool("gfx.apitrace.enabled", false);
-        sUseApitraceInitialized = true;
-    }
-
+    MOZ_ASSERT(sUseApitraceInitialized);
     if (!sUseApitrace) {
         return nullptr;
     }
 
     static PRLibrary* sApitraceLibrary = nullptr;
 
     if (sApitraceLibrary)
         return sApitraceLibrary;
@@ -100,16 +96,23 @@ LoadLibraryForEGLOnWindows(const nsAStri
 
 bool
 GLLibraryEGL::EnsureInitialized()
 {
     if (mInitialized) {
         return true;
     }
 
+#if defined(ANDROID)
+    if (!sUseApitraceInitialized) {
+        sUseApitrace = Preferences::GetBool("gfx.apitrace.enabled", false);
+        sUseApitraceInitialized = true;
+    }
+#endif // ANDROID
+
     mozilla::ScopedGfxFeatureReporter reporter("EGL");
 
 #ifdef XP_WIN
 #ifdef MOZ_WEBGL
     if (!mEGLLibrary) {
         // On Windows, the GLESv2, EGL and DXSDK libraries are shipped with libxul and
         // we should look for them there. We have to load the libs in this
         // order, because libEGL.dll depends on libGLESv2.dll which depends on the DXSDK
--- a/gfx/gl/moz.build
+++ b/gfx/gl/moz.build
@@ -116,16 +116,17 @@ else:
 UNIFIED_SOURCES += [
     'DecomposeIntoNoRepeatTriangles.cpp',
     'GfxTexturesReporter.cpp',
     'GLBlitHelper.cpp',
     'GLBlitTextureImageHelper.cpp',
     'GLContext.cpp',
     'GLContextFeatures.cpp',
     'GLContextTypes.cpp',
+    'GLDebugUtils.cpp',
     'GLLibraryEGL.cpp',
     'GLLibraryLoader.cpp',
     'GLReadTexImageHelper.cpp',
     'GLScreenBuffer.cpp',
     'GLSharedHandleHelpers.cpp',
     'GLTextureImage.cpp',
     'GLUploadHelpers.cpp',
     'ScopedGLHelpers.cpp',
--- a/gfx/layers/D3D9SurfaceImage.cpp
+++ b/gfx/layers/D3D9SurfaceImage.cpp
@@ -167,10 +167,72 @@ D3D9SurfaceImage::DeprecatedGetAsSurface
            mSize.width * 4);
   }
 
   systemMemorySurface->UnlockRect();
 
   return surface.forget();
 }
 
+TemporaryRef<gfx::SourceSurface>
+D3D9SurfaceImage::GetAsSourceSurface()
+{
+  NS_ENSURE_TRUE(mTexture, nullptr);
+
+  HRESULT hr;
+  RefPtr<gfx::DataSourceSurface> surface = gfx::Factory::CreateDataSourceSurface(mSize, gfx::SurfaceFormat::B8G8R8X8);
+
+  if (!surface) {
+    NS_WARNING("Failed to created SourceSurface for D3D9SurfaceImage.");
+    return nullptr;
+  }
+
+  // Ensure that the texture is ready to be used.
+  EnsureSynchronized();
+
+  // Readback the texture from GPU memory into system memory, so that
+  // we can copy it into the Cairo image. This is expensive.
+  RefPtr<IDirect3DSurface9> textureSurface;
+  hr = mTexture->GetSurfaceLevel(0, byRef(textureSurface));
+  NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
+
+  RefPtr<IDirect3DDevice9> device;
+  hr = mTexture->GetDevice(byRef(device));
+  NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
+
+  RefPtr<IDirect3DSurface9> systemMemorySurface;
+  hr = device->CreateOffscreenPlainSurface(mDesc.Width,
+                                           mDesc.Height,
+                                           D3DFMT_X8R8G8B8,
+                                           D3DPOOL_SYSTEMMEM,
+                                           byRef(systemMemorySurface),
+                                           0);
+  NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
+
+  hr = device->GetRenderTargetData(textureSurface, systemMemorySurface);
+  NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
+
+  D3DLOCKED_RECT rect;
+  hr = systemMemorySurface->LockRect(&rect, nullptr, 0);
+  NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
+
+  gfx::DataSourceSurface::MappedSurface mappedSurface;
+  if (!surface->Map(gfx::DataSourceSurface::WRITE, &mappedSurface)) {
+    systemMemorySurface->UnlockRect();
+    return nullptr;
+  }
+
+  const unsigned char* src = (const unsigned char*)(rect.pBits);
+  const unsigned srcPitch = rect.Pitch;
+  for (int y = 0; y < mSize.height; y++) {
+    memcpy(mappedSurface.mData + mappedSurface.mStride * y,
+           (unsigned char*)(src) + srcPitch * y,
+           mSize.width * 4);
+  }
+
+  systemMemorySurface->UnlockRect();
+  surface->Unmap();
+
+  return surface;
+}
+
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/D3D9SurfaceImage.h
+++ b/gfx/layers/D3D9SurfaceImage.h
@@ -42,16 +42,17 @@ public:
   // If the operation to copy the original resource to the shared resource
   // hasn't finished yet, this function blocks until the synchronization is
   // complete.
   HANDLE GetShareHandle();
 
   gfx::IntSize GetSize() MOZ_OVERRIDE;
 
   already_AddRefed<gfxASurface> DeprecatedGetAsSurface() MOZ_OVERRIDE;
+  virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() MOZ_OVERRIDE;
 
 private:
 
   // Blocks the calling thread until the copy operation started in SetData()
   // is complete, whereupon the texture is safe to use.
   void EnsureSynchronized();
 
   gfx::IntSize mSize;
--- a/gfx/layers/GrallocImages.cpp
+++ b/gfx/layers/GrallocImages.cpp
@@ -279,16 +279,111 @@ GrallocImage::DeprecatedGetAsSurface()
   if (rv) {
     NS_WARNING("OMX color conversion failed");
     return nullptr;
   }
 
   return imageSurface.forget();
 }
 
+TemporaryRef<gfx::SourceSurface>
+GrallocImage::GetAsSourceSurface()
+{
+  android::sp<GraphicBuffer> graphicBuffer =
+    GrallocBufferActor::GetFrom(GetSurfaceDescriptor());
+
+  void *buffer;
+  int32_t rv =
+    graphicBuffer->lock(android::GraphicBuffer::USAGE_SW_READ_OFTEN, &buffer);
+
+  if (rv) {
+    NS_WARNING("Couldn't lock graphic buffer");
+    return nullptr;
+  }
+
+  GraphicBufferAutoUnlock unlock(graphicBuffer);
+
+  uint32_t format = graphicBuffer->getPixelFormat();
+  uint32_t omxFormat = 0;
+
+  for (int i = 0; sColorIdMap[i]; i += 2) {
+    if (sColorIdMap[i] == format) {
+      omxFormat = sColorIdMap[i + 1];
+      break;
+    }
+  }
+
+  if (!omxFormat) {
+    NS_WARNING("Unknown color format");
+    return nullptr;
+  }
+
+  RefPtr<gfx::DataSourceSurface> surface
+    = gfx::Factory::CreateDataSourceSurface(GetSize(), gfx::SurfaceFormat::R5G6B5);
+
+  uint32_t width = GetSize().width;
+  uint32_t height = GetSize().height;
+
+  gfx::DataSourceSurface::MappedSurface mappedSurface;
+  if (!surface->Map(gfx::DataSourceSurface::WRITE, &mappedSurface)) {
+    NS_WARNING("Could not map DataSourceSurface");
+    return nullptr;
+  }
+
+  if (format == HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO) {
+    // The Adreno hardware decoder aligns image dimensions to a multiple of 32,
+    // so we have to account for that here
+    uint32_t alignedWidth = ALIGN(width, 32);
+    uint32_t alignedHeight = ALIGN(height, 32);
+    uint32_t uvOffset = ALIGN(alignedHeight * alignedWidth, 4096);
+    uint32_t uvStride = 2 * ALIGN(width / 2, 32);
+    uint8_t* buffer_as_bytes = static_cast<uint8_t*>(buffer);
+    ConvertYVU420SPToRGB565(buffer, alignedWidth,
+                            buffer_as_bytes + uvOffset, uvStride,
+                            mappedSurface.mData,
+                            width, height);
+
+    surface->Unmap();
+    return surface;
+  }
+  else if (format == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
+    uint32_t uvOffset = height * width;
+    ConvertYVU420SPToRGB565(buffer, width,
+                            buffer + uvOffset, width,
+                            mappedSurface.mData,
+                            width, height);
+
+    surface->Unmap();
+    return surface;
+  }
+
+  android::ColorConverter colorConverter((OMX_COLOR_FORMATTYPE)omxFormat,
+                                         OMX_COLOR_Format16bitRGB565);
+
+  if (!colorConverter.isValid()) {
+    NS_WARNING("Invalid color conversion");
+    return nullptr;
+  }
+
+  rv = colorConverter.convert(buffer, width, height,
+                              0, 0, width - 1, height - 1 /* source crop */,
+                              mappedSurface.mData, width, height,
+                              0, 0, width - 1, height - 1 /* dest crop */);
+
+  surface->Unmap();
+
+  if (rv) {
+    NS_WARNING("OMX color conversion failed");
+    return nullptr;
+  }
+
+  return surface;
+}
+
+
 TextureClient*
 GrallocImage::GetTextureClient()
 {
   if (!mTextureClient) {
     const SurfaceDescriptor& sd = GetSurfaceDescriptor();
     if (sd.type() != SurfaceDescriptor::TSurfaceDescriptorGralloc) {
       return nullptr;
     }
--- a/gfx/layers/GrallocImages.h
+++ b/gfx/layers/GrallocImages.h
@@ -122,16 +122,17 @@ public:
     HAL_PIXEL_FORMAT_YCbCr_420_P            = 0x103,
     HAL_PIXEL_FORMAT_YCbCr_420_SP           = 0x109,
     HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO    = 0x10A,
     HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED     = 0x7FA30C03,
     HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS     = 0x7FA30C04,
   };
 
   virtual already_AddRefed<gfxASurface> DeprecatedGetAsSurface();
+  virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() MOZ_OVERRIDE;
 
   void* GetNativeBuffer()
   {
     if (IsValid()) {
       return GrallocBufferActor::GetFrom(GetSurfaceDescriptor())->getNativeBuffer();
     } else {
       return nullptr;
     }
--- a/gfx/layers/SharedTextureImage.h
+++ b/gfx/layers/SharedTextureImage.h
@@ -34,16 +34,21 @@ public:
   const Data* GetData() { return &mData; }
 
   gfx::IntSize GetSize() { return mData.mSize; }
 
   virtual already_AddRefed<gfxASurface> DeprecatedGetAsSurface() {
     return nullptr;
   }
 
+  virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() MOZ_OVERRIDE
+  {
+    return nullptr;
+  }
+
   SharedTextureImage() : Image(nullptr, SHARED_TEXTURE) {}
 
 private:
   Data mData;
 };
 
 } // layers
 } // mozilla
--- a/gfx/layers/d3d10/ImageLayerD3D10.cpp
+++ b/gfx/layers/d3d10/ImageLayerD3D10.cpp
@@ -489,16 +489,96 @@ RemoteDXGITextureImage::DeprecatedGetAsS
            mSize.width * 4);
   }
 
   softTexture->Unmap(0);
 
   return surface.forget();
 }
 
+TemporaryRef<gfx::SourceSurface>
+RemoteDXGITextureImage::GetAsSourceSurface()
+{
+  nsRefPtr<ID3D10Device1> device =
+    gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
+  if (!device) {
+    NS_WARNING("Cannot readback from shared texture because no D3D10 device is available.");
+    return nullptr;
+  }
+
+  TextureD3D10BackendData* data = GetD3D10TextureBackendData(device);
+
+  if (!data) {
+    return nullptr;
+  }
+
+  nsRefPtr<IDXGIKeyedMutex> keyedMutex;
+
+  if (FAILED(data->mTexture->QueryInterface(IID_IDXGIKeyedMutex, getter_AddRefs(keyedMutex)))) {
+    NS_WARNING("Failed to QueryInterface for IDXGIKeyedMutex, strange.");
+    return nullptr;
+  }
+
+  if (FAILED(keyedMutex->AcquireSync(0, 0))) {
+    NS_WARNING("Failed to acquire sync for keyedMutex, plugin failed to release?");
+    return nullptr;
+  }
+
+  D3D10_TEXTURE2D_DESC desc;
+
+  data->mTexture->GetDesc(&desc);
+
+  desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ;
+  desc.BindFlags = 0;
+  desc.MiscFlags = 0;
+  desc.Usage = D3D10_USAGE_STAGING;
+
+  nsRefPtr<ID3D10Texture2D> softTexture;
+  HRESULT hr = device->CreateTexture2D(&desc, nullptr, getter_AddRefs(softTexture));
+
+  if (FAILED(hr)) {
+    NS_WARNING("Failed to create 2D staging texture.");
+    return nullptr;
+  }
+
+  device->CopyResource(softTexture, data->mTexture);
+  keyedMutex->ReleaseSync(0);
+
+  RefPtr<gfx::DataSourceSurface> surface
+    = gfx::Factory::CreateDataSourceSurface(mSize,
+                                            mFormat == RemoteImageData::BGRX32
+                                              ? gfx::SurfaceFormat::B8G8R8X8
+                                              : gfx::SurfaceFormat::B8G8R8A8);
+
+  if (!surface) {
+    NS_WARNING("Failed to create SourceSurface for DXGI texture.");
+    return nullptr;
+  }
+
+  gfx::DataSourceSurface::MappedSurface mappedSurface;
+  if (!surface->Map(gfx::DataSourceSurface::WRITE, &mappedSurface)) {
+    NS_WARNING("Failed to map source surface");
+    return nullptr;
+  }
+
+  D3D10_MAPPED_TEXTURE2D mapped;
+  softTexture->Map(0, D3D10_MAP_READ, 0, &mapped);
+
+  for (int y = 0; y < mSize.height; y++) {
+    memcpy(mappedSurface.mData + mappedSurface.mStride * y,
+           (unsigned char*)(mapped.pData) + mapped.RowPitch * y,
+           mSize.width * 4);
+  }
+
+  softTexture->Unmap(0);
+  surface->Unmap();
+
+  return surface;
+}
+
 TextureD3D10BackendData*
 RemoteDXGITextureImage::GetD3D10TextureBackendData(ID3D10Device *aDevice)
 {
   if (GetBackendData(mozilla::layers::LayersBackend::LAYERS_D3D10)) {
     TextureD3D10BackendData *data =
       static_cast<TextureD3D10BackendData*>(GetBackendData(mozilla::layers::LayersBackend::LAYERS_D3D10));
 
     nsRefPtr<ID3D10Device> device;
--- a/gfx/layers/d3d10/ImageLayerD3D10.h
+++ b/gfx/layers/d3d10/ImageLayerD3D10.h
@@ -56,16 +56,17 @@ struct TextureD3D10BackendData : public 
   nsRefPtr<ID3D10ShaderResourceView> mSRView;
 };
 
 class RemoteDXGITextureImage : public Image {
 public:
   RemoteDXGITextureImage() : Image(nullptr, REMOTE_IMAGE_DXGI_TEXTURE) {}
 
   already_AddRefed<gfxASurface> DeprecatedGetAsSurface();
+  virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() MOZ_OVERRIDE;
 
   IntSize GetSize() { return mSize; }
 
   TextureD3D10BackendData *GetD3D10TextureBackendData(ID3D10Device *aDevice);
 
   IntSize mSize;
   RemoteImageData::Format mFormat;
   HANDLE mHandle;
--- a/gfx/layers/d3d9/DeviceManagerD3D9.h
+++ b/gfx/layers/d3d9/DeviceManagerD3D9.h
@@ -34,18 +34,18 @@ const int CBvLayerQuad = 10;
 const int CBfLayerOpacity = 0;
 const int CBvColor = 0;
 
 enum DeviceManagerState {
   // The device and swap chain are OK.
   DeviceOK,
   // The device or swap chain are in a bad state, and we should not render.
   DeviceFail,
-  // The device is lost, the user should forget the current device manager
-  // and create a new one.
+  // The device is lost and cannot be reset, the user should forget the
+  // current device manager and create a new one.
   DeviceMustRecreate,
 };
 
 
 /**
  * This structure is used to pass rectangles to our shader constant. We can use
  * this for passing rectangular areas to SetVertexShaderConstant. In the format
  * of a 4 component float(x,y,width,height). Our vertex shader can then use
--- a/gfx/layers/ipc/SharedRGBImage.cpp
+++ b/gfx/layers/ipc/SharedRGBImage.cpp
@@ -131,16 +131,22 @@ DeprecatedSharedRGBImage::AllocateBuffer
 }
 
 already_AddRefed<gfxASurface>
 DeprecatedSharedRGBImage::DeprecatedGetAsSurface()
 {
   return nullptr;
 }
 
+TemporaryRef<gfx::SourceSurface>
+DeprecatedSharedRGBImage::GetAsSourceSurface()
+{
+  return nullptr;
+}
+
 bool
 DeprecatedSharedRGBImage::ToSurfaceDescriptor(SurfaceDescriptor& aResult)
 {
   if (!mAllocated) {
     return false;
   }
   this->AddRef();
   aResult = RGBImage(*mShmem,
--- a/gfx/layers/ipc/SharedRGBImage.h
+++ b/gfx/layers/ipc/SharedRGBImage.h
@@ -56,16 +56,17 @@ public:
 
   virtual uint8_t *GetBuffer() MOZ_OVERRIDE;
 
   gfx::IntSize GetSize();
   size_t GetBufferSize();
 
   static uint8_t BytesPerPixel(gfxImageFormat aImageFormat);
   already_AddRefed<gfxASurface> DeprecatedGetAsSurface();
+  virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() MOZ_OVERRIDE;
 
   /**
    * Setup the Surface descriptor to contain this image's shmem, while keeping
    * ownership of the shmem.
    * if the operation succeeds, return true and AddRef this DeprecatedSharedRGBImage.
    */
   bool ToSurfaceDescriptor(SurfaceDescriptor& aResult);
 
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -3410,16 +3410,48 @@ if test -n "$MOZ_VALGRIND"; then
         AC_MSG_ERROR(
             [--enable-valgrind specified but Valgrind is not installed]))
     AC_DEFINE(MOZ_VALGRIND)
     MOZ_VALGRIND=1
 fi
 AC_SUBST(MOZ_VALGRIND)
 
 dnl ========================================================
+dnl = Use ARM JIT code simulator. Requires an x86 build.
+dnl ========================================================
+dnl Also define JS_CODEGEN_ARM in this case. If the simulator is not used,
+dnl JS_CODEGEN_foo is defined if JS_CPU_foo is defined.
+MOZ_ARG_ENABLE_BOOL(arm-simulator,
+[  --enable-arm-simulator Enable ARM simulator for JIT code],
+    JS_ARM_SIMULATOR=1,
+    JS_ARM_SIMULATOR= )
+if test -n "$JS_ARM_SIMULATOR"; then
+    if test "$CPU_ARCH" != "x86"; then
+        AC_MSG_ERROR([The ARM simulator only works on x86.])
+    fi
+    AC_DEFINE(JS_ARM_SIMULATOR)
+    AC_DEFINE(JS_CODEGEN_ARM)
+    JS_CODEGEN_ARM=1
+elif test "$CPU_ARCH" = "x86"; then
+    AC_DEFINE(JS_CODEGEN_X86)
+    JS_CODEGEN_X86=1
+elif test "$CPU_ARCH" = "x86_64"; then
+    AC_DEFINE(JS_CODEGEN_X64)
+    JS_CODEGEN_X64=1
+elif test "$CPU_ARCH" = "arm"; then
+    AC_DEFINE(JS_CODEGEN_ARM)
+    JS_CODEGEN_ARM=1
+fi
+
+AC_SUBST(JS_ARM_SIMULATOR)
+AC_SUBST(JS_CODEGEN_ARM)
+AC_SUBST(JS_CODEGEN_X86)
+AC_SUBST(JS_CODEGEN_X64)
+
+dnl ========================================================
 dnl jprof
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(jprof,
 [  --enable-jprof          Enable jprof profiling tool (needs mozilla/tools/jprof). Implies --enable-profiling.],
     MOZ_JPROF=1,
     MOZ_JPROF= )
 if test -n "$MOZ_JPROF"; then
     MOZ_PROFILING=1
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -684,20 +684,16 @@ js::Nursery::collect(JSRuntime *rt, JS::
 
     if (isEmpty())
         return;
 
     TIME_START(total);
 
     AutoStopVerifyingBarriers av(rt, false);
 
-    TIME_START(waitBgSweep);
-    rt->gcHelperThread.waitBackgroundSweepEnd();
-    TIME_END(waitBgSweep);
-
     /* Move objects pointed to by roots from the nursery to the major heap. */
     MinorCollectionTracer trc(rt, this);
 
     /* Mark the store buffer. This must happen first. */
     StoreBuffer &sb = rt->gcStoreBuffer;
     TIME_START(markValues);
     sb.markValues(&trc);
     TIME_END(markValues);
@@ -808,28 +804,27 @@ js::Nursery::collect(JSRuntime *rt, JS::
 
 #ifdef PROFILE_NURSERY
     int64_t totalTime = TIME_TOTAL(total);
 
     if (totalTime >= GCReportThreshold) {
         static bool printedHeader = false;
         if (!printedHeader) {
             fprintf(stderr,
-                    "MinorGC: Reason               PRate  Size Time   WaitBg mkVals mkClls mkSlts mkWCll mkRVal mkRCll mkGnrc ckTbls mkRntm mkDbgr clrNOC collct updtIn resize pretnr frSlts clrSB  sweep\n");
+                    "MinorGC: Reason               PRate  Size Time   mkVals mkClls mkSlts mkWCll mkRVal mkRCll mkGnrc ckTbls mkRntm mkDbgr clrNOC collct updtIn resize pretnr frSlts clrSB  sweep\n");
             printedHeader = true;
         }
 
 #define FMT " %6" PRIu64
         fprintf(stderr,
-                "MinorGC: %20s %5.1f%% %4d" FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT "\n",
+                "MinorGC: %20s %5.1f%% %4d" FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT "\n",
                 js::gcstats::ExplainReason(reason),
                 promotionRate * 100,
                 numActiveChunks_,
                 totalTime,
-                TIME_TOTAL(waitBgSweep),
                 TIME_TOTAL(markValues),
                 TIME_TOTAL(markCells),
                 TIME_TOTAL(markSlots),
                 TIME_TOTAL(markWholeCells),
                 TIME_TOTAL(markRelocatableValues),
                 TIME_TOTAL(markRelocatableCells),
                 TIME_TOTAL(markGenericEntries),
                 TIME_TOTAL(checkHashTables),
--- a/js/src/gc/StoreBuffer.cpp
+++ b/js/src/gc/StoreBuffer.cpp
@@ -105,32 +105,40 @@ StoreBuffer::MonoTypeBuffer<T>::compactR
 
     duplicates.clear();
 }
 
 template <typename T>
 void
 StoreBuffer::MonoTypeBuffer<T>::compact(StoreBuffer *owner)
 {
-    if (!storage_)
-        return;
+    JS_ASSERT(storage_);
+    compactRemoveDuplicates(owner);
+    usedAtLastCompact_ = storage_->used();
+}
 
-    compactRemoveDuplicates(owner);
+template <typename T>
+void
+StoreBuffer::MonoTypeBuffer<T>::maybeCompact(StoreBuffer *owner)
+{
+    JS_ASSERT(storage_);
+    if (storage_->used() != usedAtLastCompact_)
+        compact(owner);
 }
 
 template <typename T>
 void
 StoreBuffer::MonoTypeBuffer<T>::mark(StoreBuffer *owner, JSTracer *trc)
 {
     JS_ASSERT(owner->isEnabled());
     ReentrancyGuard g(*owner);
     if (!storage_)
         return;
 
-    compact(owner);
+    maybeCompact(owner);
     for (LifoAlloc::Enum e(*storage_); !e.empty(); e.popFront<T>()) {
         T *edge = e.get<T>();
         if (edge->isNullEdge())
             continue;
         edge->mark(trc);
 
     }
 }
--- a/js/src/gc/StoreBuffer.h
+++ b/js/src/gc/StoreBuffer.h
@@ -86,47 +86,52 @@ class StoreBuffer
      * This buffer holds only a single type of edge. Using this buffer is more
      * efficient than the generic buffer when many writes will be to the same
      * type of edge: e.g. Value or Cell*.
      */
     template<typename T>
     struct MonoTypeBuffer
     {
         LifoAlloc *storage_;
+        size_t usedAtLastCompact_;
 
-        explicit MonoTypeBuffer() : storage_(nullptr) {}
+        explicit MonoTypeBuffer() : storage_(nullptr), usedAtLastCompact_(0) {}
         ~MonoTypeBuffer() { js_delete(storage_); }
 
         bool init() {
             if (!storage_)
                 storage_ = js_new<LifoAlloc>(LifoAllocBlockSize);
             clear();
             return bool(storage_);
         }
 
         void clear() {
             if (!storage_)
                 return;
 
             storage_->used() ? storage_->releaseAll() : storage_->freeAll();
+            usedAtLastCompact_ = 0;
         }
 
         bool isAboutToOverflow() const {
             return !storage_->isEmpty() && storage_->availableInCurrentChunk() < MinAvailableSize;
         }
 
         /* Compaction algorithms. */
         void compactRemoveDuplicates(StoreBuffer *owner);
 
         /*
          * Attempts to reduce the usage of the buffer by removing unnecessary
          * entries.
          */
         virtual void compact(StoreBuffer *owner);
 
+        /* Compacts if any entries have been added since the last compaction. */
+        void maybeCompact(StoreBuffer *owner);
+
         /* Add one item to the buffer. */
         void put(StoreBuffer *owner, const T &t) {
             JS_ASSERT(storage_);
 
             T *tp = storage_->new_<T>(t);
             if (!tp)
                 CrashAtUnhandlableOOM("Failed to allocate for MonoTypeBuffer::put.");
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-961741.js
@@ -0,0 +1,5 @@
+function r() {
+    for (var x in undefined) {}
+}
+setObjectMetadataCallback(true);
+r();
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -1484,29 +1484,29 @@ class MOZ_STACK_CLASS ModuleCompiler
     void finishFunctionBodies() {
         JS_ASSERT(!finishedFunctionBodies_);
         masm_.align(AsmJSPageSize);
         finishedFunctionBodies_ = true;
         module_->initFunctionBytes(masm_.size());
     }
 
     void setInterpExitOffset(unsigned exitIndex) {
-#if defined(JS_CPU_ARM)
+#if defined(JS_CODEGEN_ARM)
         masm_.flush();
 #endif
         module_->exit(exitIndex).initInterpOffset(masm_.size());
     }
     void setIonExitOffset(unsigned exitIndex) {
-#if defined(JS_CPU_ARM)
+#if defined(JS_CODEGEN_ARM)
         masm_.flush();
 #endif
         module_->exit(exitIndex).initIonOffset(masm_.size());
     }
     void setEntryOffset(unsigned exportIndex) {
-#if defined(JS_CPU_ARM)
+#if defined(JS_CODEGEN_ARM)
         masm_.flush();
 #endif
         module_->exportedFunction(exportIndex).initCodeOffset(masm_.size());
     }
 
     void buildCompilationTimeReport(bool storedInCache, ScopedJSFreePtr<char> *out) {
         ScopedJSFreePtr<char> slowFuns;
 #ifndef JS_MORE_DETERMINISTIC
@@ -1538,17 +1538,17 @@ class MOZ_STACK_CLASS ModuleCompiler
     bool extractModule(ScopedJSDeletePtr<AsmJSModule> *module, AsmJSStaticLinkData *linkData)
     {
         module_->initCharsEnd(parser_.tokenStream.currentToken().pos.end);
 
         masm_.finish();
         if (masm_.oom())
             return false;
 
-#if defined(JS_CPU_ARM)
+#if defined(JS_CODEGEN_ARM)
         // Now that compilation has finished, we need to update offsets to
         // reflect actual offsets (an ARM distinction).
         for (unsigned i = 0; i < module_->numHeapAccesses(); i++) {
             AsmJSHeapAccess &a = module_->heapAccess(i);
             a.setOffset(masm_.actualOffset(a.offset()));
         }
 #endif
 
@@ -1619,31 +1619,31 @@ class MOZ_STACK_CLASS ModuleCompiler
                 AsmJSStaticLinkData::RelativeLink link;
                 link.patchAtOffset = tableBaseOffset + elemIndex * sizeof(uint8_t*);
                 link.targetOffset = masm_.actualOffset(table.elem(elemIndex).code()->offset());
                 if (!linkData->relativeLinks.append(link))
                     return false;
             }
         }
 
-#if defined(JS_CPU_X86)
+#if defined(JS_CODEGEN_X86)
         // Global data accesses in x86 need to be patched with the absolute
         // address of the global. Globals are allocated sequentially after the
         // code section so we can just use an RelativeLink.
         for (unsigned i = 0; i < globalAccesses_.length(); i++) {
             AsmJSGlobalAccess a = globalAccesses_[i];
             AsmJSStaticLinkData::RelativeLink link;
             link.patchAtOffset = masm_.labelOffsetToPatchOffset(a.patchAt.offset());
             link.targetOffset = module_->offsetOfGlobalData() + a.globalDataOffset;
             if (!linkData->relativeLinks.append(link))
                 return false;
         }
 #endif
 
-#if defined(JS_CPU_X64)
+#if defined(JS_CODEGEN_X64)
         // Global data accesses on x64 use rip-relative addressing and thus do
         // not need patching after deserialization.
         uint8_t *code = module_->codeBase();
         for (unsigned i = 0; i < globalAccesses_.length(); i++) {
             AsmJSGlobalAccess a = globalAccesses_[i];
             masm_.patchAsmJSGlobalAccess(a.patchAt, code, module_->globalData(), a.globalDataOffset);
         }
 #endif
@@ -5749,19 +5749,26 @@ CheckModuleReturn(ModuleCompiler &m)
     return true;
 }
 
 // All registers except the stack pointer.
 static const RegisterSet AllRegsExceptSP =
     RegisterSet(GeneralRegisterSet(Registers::AllMask &
                                    ~(uint32_t(1) << Registers::StackPointer)),
                 FloatRegisterSet(FloatRegisters::AllMask));
+#if defined(JS_CPU_ARM)
+// The ARM system ABI also includes d15 in the non volatile float registers.
+static const RegisterSet NonVolatileRegs =
+    RegisterSet(GeneralRegisterSet(Registers::NonVolatileMask),
+                    FloatRegisterSet(FloatRegisters::NonVolatileMask | (1 << FloatRegisters::d15)));
+#else
 static const RegisterSet NonVolatileRegs =
     RegisterSet(GeneralRegisterSet(Registers::NonVolatileMask),
                 FloatRegisterSet(FloatRegisters::NonVolatileMask));
+#endif
 
 static void
 LoadAsmJSActivationIntoRegister(MacroAssembler &masm, Register reg)
 {
     masm.movePtr(AsmJSImm_Runtime, reg);
     size_t offset = offsetof(JSRuntime, mainThread) +
                     PerThreadData::offsetOfAsmJSActivationStackReadOnly();
     masm.loadPtr(Address(reg, offset), reg);
@@ -5831,31 +5838,31 @@ GenerateEntry(ModuleCompiler &m, const A
     // they can be restored.
     Register activation = ABIArgGenerator::NonArgReturnVolatileReg0;
     LoadAsmJSActivationIntoRegister(masm, activation);
     masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfErrorRejoinSP()));
 
     // ARM has a globally-pinned GlobalReg (x64 uses RIP-relative addressing,
     // x86 uses immediates in effective addresses) and NaN register (used as
     // part of the out-of-bounds handling in heap loads/stores).
-#if defined(JS_CPU_ARM)
+#if defined(JS_CODEGEN_ARM)
     masm.movePtr(IntArgReg1, GlobalReg);
     masm.ma_vimm(GenericNaN(), NANReg);
 #endif
 
     // ARM and x64 have a globally-pinned HeapReg (x86 uses immediates in
     // effective addresses).
-#if defined(JS_CPU_X64) || defined(JS_CPU_ARM)
+#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM)
     masm.loadPtr(Address(IntArgReg1, m.module().heapOffset()), HeapReg);
 #endif
 
     // Get 'argv' into a non-arg register and save it on the stack.
     Register argv = ABIArgGenerator::NonArgReturnVolatileReg0;
     Register scratch = ABIArgGenerator::NonArgReturnVolatileReg1;
-#if defined(JS_CPU_X86)
+#if defined(JS_CODEGEN_X86)
     masm.loadPtr(Address(StackPointer, NativeFrameSize + masm.framePushed()), argv);
 #else
     masm.movePtr(IntArgReg0, argv);
 #endif
     masm.Push(argv);
 
     // Bump the stack for the call.
     const ModuleCompiler::Func &func = *m.lookupFunction(exportedFunc.name());
@@ -6041,17 +6048,17 @@ FillArgumentArray(ModuleCompiler &m, con
           case ABIArg::FPU: {
               masm.canonicalizeDouble(i->fpu());
               masm.storeDouble(i->fpu(), dstAddr);
               break;
           }
           case ABIArg::Stack:
             if (i.mirType() == MIRType_Int32) {
                 Address src(StackPointer, offsetToCallerStackArgs + i->offsetFromArgBase());
-#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
                 masm.load32(src, scratch);
                 masm.storeValue(JSVAL_TYPE_INT32, scratch, dstAddr);
 #else
                 masm.memIntToValue(src, dstAddr);
 #endif
             } else {
                 JS_ASSERT(i.mirType() == MIRType_Double);
                 Address src(StackPointer, offsetToCallerStackArgs + i->offsetFromArgBase());
@@ -6068,17 +6075,17 @@ static void
 GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit,
                            unsigned exitIndex, Label *throwLabel)
 {
     MacroAssembler &masm = m.masm();
     masm.align(CodeAlignment);
     m.setInterpExitOffset(exitIndex);
     masm.setFramePushed(0);
 
-#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
     MIRType typeArray[] = { MIRType_Pointer,   // cx
                             MIRType_Pointer,   // exitDatum
                             MIRType_Int32,     // argc
                             MIRType_Pointer }; // argv
     MIRTypeVector invokeArgTypes(m.cx());
     invokeArgTypes.infallibleAppend(typeArray, ArrayLength(typeArray));
 
     // Reserve space for a call to InvokeFromAsmJS_* and an array of values
@@ -6286,48 +6293,48 @@ GenerateFFIIonExit(ModuleCompiler &m, co
 {
     MacroAssembler &masm = m.masm();
     masm.align(CodeAlignment);
     m.setIonExitOffset(exitIndex);
     masm.setFramePushed(0);
 
     RegisterSet restoreSet = RegisterSet::Intersect(RegisterSet::All(),
                                                     RegisterSet::Not(RegisterSet::Volatile()));
-#if defined(JS_CPU_ARM)
+#if defined(JS_CODEGEN_ARM)
     masm.Push(lr);
 #endif
     masm.PushRegsInMask(restoreSet);
 
     // Arguments are in the following order on the stack:
     // descriptor | callee | argc | this | arg1 | arg2 | ...
 
     // Reserve and align space for the arguments
     MIRTypeVector emptyVector(m.cx());
     unsigned argBytes = 3 * sizeof(size_t) + (1 + exit.sig().args().length()) * sizeof(Value);
     unsigned extraBytes = 0;
-#if defined(JS_CPU_ARM)
+#if defined(JS_CODEGEN_ARM)
     extraBytes += sizeof(size_t);
 #endif
     unsigned stackDec = StackDecrementForCall(masm, emptyVector, argBytes + extraBytes);
     masm.reserveStack(stackDec - extraBytes);
 
     // 1. Descriptor
     uint32_t descriptor = MakeFrameDescriptor(masm.framePushed() + extraBytes, IonFrame_Entry);
     masm.storePtr(ImmWord(uintptr_t(descriptor)), Address(StackPointer, 0));
 
     // 2. Callee
     Register callee = ABIArgGenerator::NonArgReturnVolatileReg0;
     Register scratch = ABIArgGenerator::NonArgReturnVolatileReg1;
 
     // 2.1. Get ExitDatum
     unsigned globalDataOffset = m.module().exitIndexToGlobalDataOffset(exitIndex);
-#if defined(JS_CPU_X64)
+#if defined(JS_CODEGEN_X64)
     CodeOffsetLabel label2 = masm.leaRipRelative(callee);
     m.addGlobalAccess(AsmJSGlobalAccess(label2.offset(), globalDataOffset));
-#elif defined(JS_CPU_X86)
+#elif defined(JS_CODEGEN_X86)
     CodeOffsetLabel label2 = masm.movlWithPatch(Imm32(0), callee);
     m.addGlobalAccess(AsmJSGlobalAccess(label2.offset(), globalDataOffset));
 #else
     masm.lea(Operand(GlobalReg, globalDataOffset), callee);
 #endif
 
     // 2.2. Get callee
     masm.loadPtr(Address(callee, offsetof(AsmJSModule::ExitDatum, fun)), callee);
@@ -6340,17 +6347,17 @@ GenerateFFIIonExit(ModuleCompiler &m, co
     masm.storePtr(ImmWord(uintptr_t(argc)), Address(StackPointer, 2 * sizeof(size_t)));
 
     // 4. |this| value
     masm.storeValue(UndefinedValue(), Address(StackPointer, 3 * sizeof(size_t)));
 
     // 5. Fill the arguments
     unsigned offsetToArgs = 3 * sizeof(size_t) + sizeof(Value);
     unsigned offsetToCallerStackArgs = masm.framePushed();
-#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
     offsetToCallerStackArgs += NativeFrameSize;
 #else
     offsetToCallerStackArgs += ShadowStackSpace;
 #endif
     FillArgumentArray(m, exit.sig().args(), offsetToArgs, offsetToCallerStackArgs, scratch);
 
     // Get the pointer to the ion code
     Label done, oolConvert;
@@ -6368,22 +6375,22 @@ GenerateFFIIonExit(ModuleCompiler &m, co
     LoadAsmJSActivationIntoRegister(masm, callee);
     masm.push(scratch);
     masm.setupUnalignedABICall(1, scratch);
     masm.passABIArg(callee);
     masm.callWithABI(AsmJSImm_EnableActivationFromAsmJS);
     masm.pop(scratch);
 
     // 2. Call
-#if defined(JS_CPU_ARM) && defined(DEBUG)
+#if defined(JS_CODEGEN_ARM) && defined(DEBUG)
     // ARM still needs to push, before stack is aligned
     masm.Push(scratch);
 #endif
     AssertStackAlignment(masm);
-#if defined(JS_CPU_ARM) && defined(DEBUG)
+#if defined(JS_CODEGEN_ARM) && defined(DEBUG)
     masm.freeStack(sizeof(size_t));
 #endif
     masm.callIon(scratch);
     masm.freeStack(stackDec - extraBytes);
 
     masm.push(JSReturnReg_Type);
     masm.push(JSReturnReg_Data);
     LoadAsmJSActivationIntoRegister(masm, callee);
@@ -6452,30 +6459,30 @@ GenerateFFIExit(ModuleCompiler &m, const
 // all the frames.
 static bool
 GenerateStackOverflowExit(ModuleCompiler &m, Label *throwLabel)
 {
     MacroAssembler &masm = m.masm();
     masm.align(CodeAlignment);
     masm.bind(&m.stackOverflowLabel());
 
-#if defined(JS_CPU_X86)
+#if defined(JS_CODEGEN_X86)
     // Ensure that at least one slot is pushed for passing 'cx' below.
     masm.push(Imm32(0));
 #endif
 
     // We know that StackPointer is word-aligned, but nothing past that. Thus,
     // we must align StackPointer dynamically. Don't worry about restoring
     // StackPointer since throwLabel will clobber StackPointer immediately.
     masm.andPtr(Imm32(~(StackAlignment - 1)), StackPointer);
     if (ShadowStackSpace)
         masm.subPtr(Imm32(ShadowStackSpace), StackPointer);
 
     // Prepare the arguments for the call to js_ReportOverRecursed.
-#if defined(JS_CPU_X86)
+#if defined(JS_CODEGEN_X86)
     LoadAsmJSActivationIntoRegister(masm, eax);
     LoadJSContextFromActivation(masm, eax, eax);
     masm.storePtr(eax, Address(StackPointer, 0));
 #else
     LoadAsmJSActivationIntoRegister(masm, IntArgReg0);
     LoadJSContextFromActivation(masm, IntArgReg0, IntArgReg0);
 #endif
     masm.call(AsmJSImm_ReportOverRecursed);
@@ -6494,17 +6501,17 @@ GenerateStackOverflowExit(ModuleCompiler
 // stack so that it can be popped directly into PC.
 static bool
 GenerateOperationCallbackExit(ModuleCompiler &m, Label *throwLabel)
 {
     MacroAssembler &masm = m.masm();
     masm.align(CodeAlignment);
     masm.bind(&m.operationCallbackLabel());
 
-#ifndef JS_CPU_ARM
+#ifndef JS_CODEGEN_ARM
     // Be very careful here not to perturb the machine state before saving it
     // to the stack. In particular, add/sub instructions may set conditions in
     // the flags register.
     masm.push(Imm32(0));            // space for resumePC
     masm.pushFlags();               // after this we are safe to use sub
     masm.setFramePushed(0);         // set to zero so we can use masm.framePushed() below
     masm.PushRegsInMask(AllRegsExceptSP); // save all GP/FP registers (except SP)
 
@@ -6514,29 +6521,29 @@ GenerateOperationCallbackExit(ModuleComp
     // Store resumePC into the reserved space.
     LoadAsmJSActivationIntoRegister(masm, activation);
     masm.loadPtr(Address(activation, AsmJSActivation::offsetOfResumePC()), scratch);
     masm.storePtr(scratch, Address(StackPointer, masm.framePushed() + sizeof(void*)));
 
     // We know that StackPointer is word-aligned, but not necessarily
     // stack-aligned, so we need to align it dynamically.
     masm.mov(StackPointer, ABIArgGenerator::NonVolatileReg);
-#if defined(JS_CPU_X86)
+#if defined(JS_CODEGEN_X86)
     // Ensure that at least one slot is pushed for passing 'cx' below.
     masm.push(Imm32(0));
 #endif
     masm.andPtr(Imm32(~(StackAlignment - 1)), StackPointer);
     if (ShadowStackSpace)
         masm.subPtr(Imm32(ShadowStackSpace), StackPointer);
 
     // argument 0: cx
-#if defined(JS_CPU_X86)
+#if defined(JS_CODEGEN_X86)
     LoadJSContextFromActivation(masm, activation, scratch);
     masm.storePtr(scratch, Address(StackPointer, 0));
-#elif defined(JS_CPU_X64)
+#elif defined(JS_CODEGEN_X64)
     LoadJSContextFromActivation(masm, activation, IntArgReg0);
 #endif
 
     masm.call(AsmJSImm_HandleExecutionInterrupt);
     masm.branchIfFalseBool(ReturnReg, throwLabel);
 
     // Restore the StackPointer to it's position before the call.
     masm.mov(ABIArgGenerator::NonVolatileReg, StackPointer);
--- a/js/src/jit/AsmJS.h
+++ b/js/src/jit/AsmJS.h
@@ -81,17 +81,17 @@ static const size_t AsmJSAllocationGranu
 
 // These functions define the valid heap lengths.
 extern uint32_t
 RoundUpToNextValidAsmJSHeapLength(uint32_t length);
 
 extern bool
 IsValidAsmJSHeapLength(uint32_t length);
 
-#ifdef JS_CPU_X64
+#ifdef JS_CODEGEN_X64
 // On x64, the internal ArrayBuffer data array is inflated to 4GiB (only the
 // byteLength portion of which is accessible) so that out-of-bounds accesses
 // (made using a uint32 index) are guaranteed to raise a SIGSEGV.
 static const size_t AsmJSBufferProtectedSize = 4 * 1024ULL * 1024ULL * 1024ULL;
 #endif
 
 #ifdef JS_ION
 
--- a/js/src/jit/AsmJSModule.cpp
+++ b/js/src/jit/AsmJSModule.cpp
@@ -39,29 +39,29 @@ void
 AsmJSModule::initHeap(Handle<ArrayBufferObject*> heap, JSContext *cx)
 {
     JS_ASSERT(linked_);
     JS_ASSERT(!maybeHeap_);
     maybeHeap_ = heap;
     heapDatum() = heap->dataPointer();
 
     JS_ASSERT(IsValidAsmJSHeapLength(heap->byteLength()));
-#if defined(JS_CPU_X86)
+#if defined(JS_CODEGEN_X86)
     uint8_t *heapOffset = heap->dataPointer();
     void *heapLength = (void*)heap->byteLength();
     for (unsigned i = 0; i < heapAccesses_.length(); i++) {
         const jit::AsmJSHeapAccess &access = heapAccesses_[i];
         if (access.hasLengthCheck())
             JSC::X86Assembler::setPointer(access.patchLengthAt(code_), heapLength);
         void *addr = access.patchOffsetAt(code_);
         uint32_t disp = reinterpret_cast<uint32_t>(JSC::X86Assembler::getPointer(addr));
         JS_ASSERT(disp <= INT32_MAX);
         JSC::X86Assembler::setPointer(addr, (void *)(heapOffset + disp));
     }
-#elif defined(JS_CPU_ARM)
+#elif defined(JS_CODEGEN_ARM)
     uint32_t heapLength = heap->byteLength();
     for (unsigned i = 0; i < heapAccesses_.length(); i++) {
         jit::Assembler::updateBoundsCheck(heapLength,
                                           (jit::Instruction*)(heapAccesses_[i].offset() + code_));
     }
     // We already know the exact extent of areas that need to be patched, just make sure we
     // flush all of them at once.
     jit::AutoFlushCache::updateTop(uintptr_t(code_), pod.codeBytes_);
@@ -175,17 +175,17 @@ InvokeFromAsmJS_Ignore(JSContext *cx, in
 int32_t
 InvokeFromAsmJS_ToInt32(JSContext *cx, int32_t exitIndex, int32_t argc, Value *argv);
 
 int32_t
 InvokeFromAsmJS_ToNumber(JSContext *cx, int32_t exitIndex, int32_t argc, Value *argv);
 
 }
 
-#if defined(JS_CPU_ARM)
+#if defined(JS_CODEGEN_ARM)
 extern "C" {
 
 extern int
 __aeabi_idivmod(int, int);
 
 extern int
 __aeabi_uidivmod(int, int);
 
@@ -222,17 +222,17 @@ AddressOf(AsmJSImmKind kind, ExclusiveCo
       case AsmJSImm_CoerceInPlace_ToNumber:
         return FuncCast(CoerceInPlace_ToNumber);
       case AsmJSImm_ToInt32:
         return FuncCast<int32_t (double)>(js::ToInt32);
       case AsmJSImm_EnableActivationFromAsmJS:
         return FuncCast(EnableActivationFromAsmJS);
       case AsmJSImm_DisableActivationFromAsmJS:
         return FuncCast(DisableActivationFromAsmJS);
-#if defined(JS_CPU_ARM)
+#if defined(JS_CODEGEN_ARM)
       case AsmJSImm_aeabi_idivmod:
         return FuncCast(__aeabi_idivmod);
       case AsmJSImm_aeabi_uidivmod:
         return FuncCast(__aeabi_uidivmod);
 #endif
       case AsmJSImm_ModD:
         return FuncCast(NumberMod);
       case AsmJSImm_SinD:
@@ -727,25 +727,25 @@ GetCPUID(uint32_t *cpuId)
 {
     enum Arch {
         X86 = 0x1,
         X64 = 0x2,
         ARM = 0x3,
         ARCH_BITS = 2
     };
 
-#if defined(JS_CPU_X86)
+#if defined(JS_CODEGEN_X86)
     JS_ASSERT(uint32_t(JSC::MacroAssembler::getSSEState()) <= (UINT32_MAX >> ARCH_BITS));
     *cpuId = X86 | (JSC::MacroAssembler::getSSEState() << ARCH_BITS);
     return true;
-#elif defined(JS_CPU_X64)
+#elif defined(JS_CODEGEN_X64)
     JS_ASSERT(uint32_t(JSC::MacroAssembler::getSSEState()) <= (UINT32_MAX >> ARCH_BITS));
     *cpuId = X64 | (JSC::MacroAssembler::getSSEState() << ARCH_BITS);
     return true;
-#elif defined(JS_CPU_ARM)
+#elif defined(JS_CODEGEN_ARM)
     JS_ASSERT(GetARMFlags() <= (UINT32_MAX >> ARCH_BITS));
     *cpuId = ARM | (GetARMFlags() << ARCH_BITS);
     return true;
 #else
     return false;
 #endif
 }
 
--- a/js/src/jit/AsmJSSignalHandlers.cpp
+++ b/js/src/jit/AsmJSSignalHandlers.cpp
@@ -182,17 +182,17 @@ class AutoSetHandlingSignal
 
     ~AutoSetHandlingSignal()
     {
         JS_ASSERT(rt->handlingSignal);
         rt->handlingSignal = false;
     }
 };
 
-#if defined(JS_CPU_X64)
+#if defined(JS_CODEGEN_X64)
 template <class T>
 static void
 SetXMMRegToNaN(bool isFloat32, T *xmm_reg)
 {
     if (isFloat32) {
         JS_STATIC_ASSERT(sizeof(T) == 4 * sizeof(float));
         float *floats = reinterpret_cast<float*>(xmm_reg);
         floats[0] = GenericNaN();
@@ -245,17 +245,17 @@ LookupHeapAccess(const AsmJSModule &modu
 # include <signal.h>
 # include <sys/mman.h>
 #endif
 
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
 # include <sys/ucontext.h> // for ucontext_t, mcontext_t
 #endif
 
-#if defined(JS_CPU_X64)
+#if defined(JS_CODEGEN_X64)
 # if defined(__DragonFly__)
 #  include <machine/npx.h> // for union savefpu
 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
        defined(__NetBSD__) || defined(__OpenBSD__)
 #  include <machine/fpu.h> // for struct savefpu/fxsave64
 # endif
 #endif
 
@@ -335,17 +335,17 @@ static bool IsSignalHandlingBroken() { r
 #if !defined(XP_MACOSX)
 static uint8_t **
 ContextToPC(CONTEXT *context)
 {
     JS_STATIC_ASSERT(sizeof(PC_sig(context)) == sizeof(void*));
     return reinterpret_cast<uint8_t**>(&PC_sig(context));
 }
 
-# if defined(JS_CPU_X64)
+# if defined(JS_CODEGEN_X64)
 static void
 SetRegisterToCoercedUndefined(CONTEXT *context, bool isFloat32, AnyRegister reg)
 {
     if (reg.isFloat()) {
         switch (reg.fpu().code()) {
           case JSC::X86Registers::xmm0:  SetXMMRegToNaN(isFloat32, &XMM_sig(context, 0)); break;
           case JSC::X86Registers::xmm1:  SetXMMRegToNaN(isFloat32, &XMM_sig(context, 1)); break;
           case JSC::X86Registers::xmm2:  SetXMMRegToNaN(isFloat32, &XMM_sig(context, 2)); break;
@@ -381,17 +381,17 @@ SetRegisterToCoercedUndefined(CONTEXT *c
           case JSC::X86Registers::r12: R12_sig(context) = 0; break;
           case JSC::X86Registers::r13: R13_sig(context) = 0; break;
           case JSC::X86Registers::r14: R14_sig(context) = 0; break;
           case JSC::X86Registers::r15: R15_sig(context) = 0; break;
           default: MOZ_CRASH();
         }
     }
 }
-# endif  // JS_CPU_X64
+# endif  // JS_CODEGEN_X64
 #endif   // !XP_MACOSX
 
 #if defined(XP_WIN)
 
 static bool
 HandleException(PEXCEPTION_POINTERS exception)
 {
     EXCEPTION_RECORD *record = exception->ExceptionRecord;
@@ -436,17 +436,17 @@ HandleException(PEXCEPTION_POINTERS exce
         activation->setResumePC(pc);
         *ppc = module.operationCallbackExit();
         DWORD oldProtect;
         if (!VirtualProtect(module.codeBase(), module.functionBytes(), PAGE_EXECUTE, &oldProtect))
             MOZ_CRASH();
         return true;
     }
 
-# if defined(JS_CPU_X64)
+# if defined(JS_CODEGEN_X64)
     // These checks aren't necessary, but, since we can, check anyway to make
     // sure we aren't covering up a real bug.
     if (!module.maybeHeap() ||
         faultingAddress < module.maybeHeap() ||
         faultingAddress >= module.maybeHeap() + AsmJSBufferProtectedSize)
     {
         return false;
     }
@@ -485,26 +485,26 @@ AsmJSExceptionHandler(LPEXCEPTION_POINTE
 }
 
 #elif defined(XP_MACOSX)
 # include <mach/exc.h>
 
 static uint8_t **
 ContextToPC(x86_thread_state_t &state)
 {
-# if defined(JS_CPU_X64)
+# if defined(JS_CODEGEN_X64)
     JS_STATIC_ASSERT(sizeof(state.uts.ts64.__rip) == sizeof(void*));
     return reinterpret_cast<uint8_t**>(&state.uts.ts64.__rip);
 # else
     JS_STATIC_ASSERT(sizeof(state.uts.ts32.__eip) == sizeof(void*));
     return reinterpret_cast<uint8_t**>(&state.uts.ts32.__eip);
 # endif
 }
 
-# if defined(JS_CPU_X64)
+# if defined(JS_CODEGEN_X64)
 static bool
 SetRegisterToCoercedUndefined(mach_port_t rtThread, x86_thread_state64_t &state,
                               const AsmJSHeapAccess &heapAccess)
 {
     if (heapAccess.loadedReg().isFloat()) {
         kern_return_t kret;
 
         x86_float_state64_t fstate;
@@ -634,17 +634,17 @@ HandleMachException(JSRuntime *rt, const
         *ppc = module.operationCallbackExit();
         mprotect(module.codeBase(), module.functionBytes(), PROT_EXEC);
 
         // Update the thread state with the new pc.
         kret = thread_set_state(rtThread, x86_THREAD_STATE, (thread_state_t)&state, x86_THREAD_STATE_COUNT);
         return kret == KERN_SUCCESS;
     }
 
-# if defined(JS_CPU_X64)
+# if defined(JS_CODEGEN_X64)
     // These checks aren't necessary, but, since we can, check anyway to make
     // sure we aren't covering up a real bug.
     if (!module.maybeHeap() ||
         faultingAddress < module.maybeHeap() ||
         faultingAddress >= module.maybeHeap() + AsmJSBufferProtectedSize)
     {
         return false;
     }
@@ -873,17 +873,17 @@ HandleSignal(int signum, siginfo_t *info
     // interrupted.
     if (module.containsPC(faultingAddress)) {
         activation->setResumePC(pc);
         *ppc = module.operationCallbackExit();
         mprotect(module.codeBase(), module.functionBytes(), PROT_EXEC);
         return true;
     }
 
-# if defined(JS_CPU_X64)
+# if defined(JS_CODEGEN_X64)
     // These checks aren't necessary, but, since we can, check anyway to make
     // sure we aren't covering up a real bug.
     if (!module.maybeHeap() ||
         faultingAddress < module.maybeHeap() ||
         faultingAddress >= module.maybeHeap() + AsmJSBufferProtectedSize)
     {
         return false;
     }
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -332,22 +332,22 @@ struct BaselineStackBuilder
         }
 
         JS_ASSERT(type == IonFrame_Rectifier);
         // Rectifier - behaviour depends on the frame preceding the rectifier frame, and
         // whether the arch is x86 or not.  The x86 rectifier frame saves the frame pointer,
         // so we can calculate it directly.  For other archs, the previous frame pointer
         // is stored on the stack in the frame that precedes the rectifier frame.
         size_t priorOffset = IonJSFrameLayout::Size() + topFrame->prevFrameLocalSize();
-#if defined(JS_CPU_X86)
+#if defined(JS_CODEGEN_X86)
         // On X86, the FramePointer is pushed as the first value in the Rectifier frame.
         JS_ASSERT(BaselineFrameReg == FramePointer);
         priorOffset -= sizeof(void *);
         return virtualPointerAtStackOffset(priorOffset);
-#elif defined(JS_CPU_X64) || defined(JS_CPU_ARM)
+#elif defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM)
         // On X64 and ARM, the frame pointer save location depends on the caller of the
         // the rectifier frame.
         BufferPointer<IonRectifierFrameLayout> priorFrame =
             pointerAtStackOffset<IonRectifierFrameLayout>(priorOffset);
         FrameType priorType = priorFrame->prevType();
         JS_ASSERT(priorType == IonFrame_OptimizedJS || priorType == IonFrame_BaselineStub);
 
         // If the frame preceding the rectifier is an OptimizedJS frame, then once again
@@ -959,17 +959,17 @@ InitFromBailout(JSContext *cx, HandleScr
                     if (caller && bailoutKind == Bailout_ArgumentCheck) {
                         IonSpew(IonSpew_BaselineBailouts, "      Setting PCidx on innermost "
                                 "inlined frame's parent's SPS entry (%s:%d) (pcIdx=%d)!",
                                 caller->filename(), caller->lineno(), caller->pcToOffset(callerPC));
                         cx->runtime()->spsProfiler.updatePC(caller, callerPC);
                     } else if (bailoutKind != Bailout_ArgumentCheck) {
                         IonSpew(IonSpew_BaselineBailouts,
                                 "      Popping SPS entry for innermost inlined frame's SPS entry");
-                        cx->runtime()->spsProfiler.exit(cx, script, fun);
+                        cx->runtime()->spsProfiler.exit(script, fun);
                     }
                 }
             } else {
                 opReturnAddr = nativeCodeForPC;
             }
             builder.setResumeAddr(opReturnAddr);
             IonSpew(IonSpew_BaselineBailouts, "      Set resumeAddr=%p", opReturnAddr);
         }
@@ -1136,17 +1136,17 @@ InitFromBailout(JSContext *cx, HandleScr
     // |  ReturnAddr   |
     // +===============+
 
     IonSpew(IonSpew_BaselineBailouts, "      [RECTIFIER FRAME]");
 
     size_t startOfRectifierFrame = builder.framePushed();
 
     // On x86-only, the frame pointer is saved again in the rectifier frame.
-#if defined(JS_CPU_X86)
+#if defined(JS_CODEGEN_X86)
     if (!builder.writePtr(prevFramePtr, "PrevFramePtr-X86Only"))
         return false;
 #endif
 
     // Push undefined for missing arguments.
     for (unsigned i = 0; i < (calleeFun->nargs() - actualArgc); i++) {
         if (!builder.writeValue(UndefinedValue(), "FillerVal"))
             return false;
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -409,17 +409,17 @@ BaselineCompiler::emitOutOfLinePostBarri
 {
     masm.bind(&postBarrierSlot_);
 
     Register objReg = R2.scratchReg();
     GeneralRegisterSet regs(GeneralRegisterSet::All());
     regs.take(objReg);
     regs.take(BaselineFrameReg);
     Register scratch = regs.takeAny();
-#if defined(JS_CPU_ARM)
+#if defined(JS_CODEGEN_ARM)
     // On ARM, save the link register before calling.  It contains the return
     // address.  The |masm.ret()| later will pop this into |pc| to return.
     masm.push(lr);
 #endif
 
     masm.setupUnalignedABICall(2, scratch);
     masm.movePtr(ImmPtr(cx->runtime()), scratch);
     masm.passABIArg(scratch);
--- a/js/src/jit/BaselineCompiler.h
+++ b/js/src/jit/BaselineCompiler.h
@@ -5,19 +5,19 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jit_BaselineCompiler_h
 #define jit_BaselineCompiler_h
 
 #ifdef JS_ION
 
 #include "jit/FixedList.h"
-#if defined(JS_CPU_X86)
+#if defined(JS_CODEGEN_X86)
 # include "jit/x86/BaselineCompiler-x86.h"
-#elif defined(JS_CPU_X64)
+#elif defined(JS_CODEGEN_X64)
 # include "jit/x64/BaselineCompiler-x64.h"
 #else
 # include "jit/arm/BaselineCompiler-arm.h"
 #endif
 
 namespace js {
 namespace jit {
 
--- a/js/src/jit/BaselineHelpers.h
+++ b/js/src/jit/BaselineHelpers.h
@@ -4,21 +4,21 @@
  * 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 jit_BaselineHelpers_h
 #define jit_BaselineHelpers_h
 
 #ifdef JS_ION
 
-#if defined(JS_CPU_X86)
+#if defined(JS_CODEGEN_X86)
 # include "jit/x86/BaselineHelpers-x86.h"
-#elif defined(JS_CPU_X64)
+#elif defined(JS_CODEGEN_X64)
 # include "jit/x64/BaselineHelpers-x64.h"
-#elif defined(JS_CPU_ARM)
+#elif defined(JS_CODEGEN_ARM)
 # include "jit/arm/BaselineHelpers-arm.h"
 #else
 # error "Unknown architecture!"
 #endif
 
 namespace js {
 namespace jit {
 
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -576,17 +576,17 @@ ICStubCompiler::getStubCode()
     // Check for existing cached stubcode.
     uint32_t stubKey = getKey();
     JitCode *stubCode = comp->getStubCode(stubKey);
     if (stubCode)
         return stubCode;
 
     // Compile new stubcode.
     MacroAssembler masm;
-#ifdef JS_CPU_ARM
+#ifdef JS_CODEGEN_ARM
     masm.setSecondScratchReg(BaselineSecondScratchReg);
 #endif
 
     AutoFlushCache afc("ICStubCompiler::getStubCode", cx->runtime()->jitRuntime());
     if (!generateStubCode(masm))
         return nullptr;
     Linker linker(masm);
     Rooted<JitCode *> newStubCode(cx, linker.newCode<CanGC>(cx, JSC::BASELINE_CODE));
@@ -707,17 +707,17 @@ ICStubCompiler::emitPostWriteBarrierSlot
 
     Label skipBarrier;
     Label isTenured;
     masm.branchPtr(Assembler::Below, obj, ImmWord(nursery.start()), &isTenured);
     masm.branchPtr(Assembler::Below, obj, ImmWord(nursery.heapEnd()), &skipBarrier);
     masm.bind(&isTenured);
 
     // void PostWriteBarrier(JSRuntime *rt, JSObject *obj);
-#ifdef JS_CPU_ARM
+#ifdef JS_CODEGEN_ARM
     saveRegs.add(BaselineTailCallReg);
 #endif
     saveRegs = GeneralRegisterSet::Intersect(saveRegs, GeneralRegisterSet::Volatile());
     masm.PushRegsInMask(saveRegs);
     masm.setupUnalignedABICall(2, scratch);
     masm.movePtr(ImmPtr(cx->runtime()), scratch);
     masm.passABIArg(scratch);
     masm.passABIArg(obj);
@@ -1036,30 +1036,30 @@ DoProfilerFallback(JSContext *cx, Baseli
     mozilla::DebugOnly<ICEntry *> icEntry = stub->icEntry();
 
     FallbackICSpew(cx, stub, "Profiler");
 
     SPSProfiler *profiler = &cx->runtime()->spsProfiler;
 
     // Manually enter SPS this time.
     JS_ASSERT(profiler->enabled());
-    if (!cx->runtime()->spsProfiler.enter(cx, script, func))
+    if (!cx->runtime()->spsProfiler.enter(script, func))
         return false;
     frame->setPushedSPSFrame();
 
     // Unlink any existing PushFunction stub (which may hold stale 'const char *' to
     // the profile string.
     JS_ASSERT_IF(icEntry->firstStub() != stub,
                  icEntry->firstStub()->isProfiler_PushFunction() &&
                  icEntry->firstStub()->next() == stub);
     stub->unlinkStubsWithKind(cx, ICStub::Profiler_PushFunction);
     JS_ASSERT(icEntry->firstStub() == stub);
 
     // Generate the string to use to identify this stack frame.
-    const char *string = profiler->profileString(cx, script, func);
+    const char *string = profiler->profileString(script, func);
     if (string == nullptr)
         return false;
 
     IonSpew(IonSpew_BaselineIC, "  Generating Profiler_PushFunction stub for %s:%d",
             script->filename(), script->lineno());
 
     // Create a new optimized stub.
     ICProfiler_PushFunction::Compiler compiler(cx, string, script);
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -1044,23 +1044,23 @@ class ICStubCompiler
     // Some stubs need to emit SPS profiler updates.  This emits the guarding
     // jitcode for those stubs.  If profiling is not enabled, jumps to the
     // given label.
     void guardProfilingEnabled(MacroAssembler &masm, Register scratch, Label *skip);
 
     inline GeneralRegisterSet availableGeneralRegs(size_t numInputs) const {
         GeneralRegisterSet regs(GeneralRegisterSet::All());
         JS_ASSERT(!regs.has(BaselineStackReg));
-#ifdef JS_CPU_ARM
+#ifdef JS_CODEGEN_ARM
         JS_ASSERT(!regs.has(BaselineTailCallReg));
         regs.take(BaselineSecondScratchReg);
 #endif
         regs.take(BaselineFrameReg);
         regs.take(BaselineStubReg);
-#ifdef JS_CPU_X64
+#ifdef JS_CODEGEN_X64
         regs.take(ExtractTemp0);
         regs.take(ExtractTemp1);
 #endif
 
         switch (numInputs) {
           case 0:
             break;
           case 1:
--- a/js/src/jit/BaselineRegisters.h
+++ b/js/src/jit/BaselineRegisters.h
@@ -4,19 +4,19 @@
  * 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 jit_BaselineRegisters_h
 #define jit_BaselineRegisters_h
 
 #ifdef JS_ION
 
-#if defined(JS_CPU_X86)
+#if defined(JS_CODEGEN_X86)
 # include "jit/x86/BaselineRegisters-x86.h"
-#elif defined(JS_CPU_X64)
+#elif defined(JS_CODEGEN_X64)
 # include "jit/x64/BaselineRegisters-x64.h"
 #else
 # include "jit/arm/BaselineRegisters-arm.h"
 #endif
 
 namespace js {
 namespace jit {
 
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -7749,38 +7749,38 @@ CodeGenerator::visitFunctionBoundary(LFu
             }
 
             sps_.leave(masm, temp);
             if (!sps_.enterInlineFrame())
                 return false;
             // fallthrough
 
         case MFunctionBoundary::Enter:
-            if (sps_.slowAssertions()) {
+            if (gen->options.spsSlowAssertionsEnabled()) {
                 saveLive(lir);
                 pushArg(ImmGCPtr(lir->script()));
                 if (!callVM(SPSEnterInfo, lir))
                     return false;
                 restoreLive(lir);
                 sps_.pushManual(lir->script(), masm, temp);
                 return true;
             }
 
-            return sps_.push(GetIonContext()->cx, lir->script(), masm, temp);
+            return sps_.push(lir->script(), masm, temp);
 
         case MFunctionBoundary::Inline_Exit:
             // all inline returns were covered with ::Exit, so we just need to
             // maintain the state of inline frames currently active and then
             // reenter the caller
             sps_.leaveInlineFrame();
             sps_.reenter(masm, temp);
             return true;
 
         case MFunctionBoundary::Exit:
-            if (sps_.slowAssertions()) {
+            if (gen->options.spsSlowAssertionsEnabled()) {
                 saveLive(lir);
                 pushArg(ImmGCPtr(lir->script()));
                 // Once we've exited, then we shouldn't emit instrumentation for
                 // the corresponding reenter() because we no longer have a
                 // frame.
                 sps_.skipNextReenter();
                 if (!callVM(SPSExitInfo, lir))
                     return false;
@@ -7895,17 +7895,17 @@ CodeGenerator::visitHaveSameClass(LHaveS
     return true;
 }
 
 bool
 CodeGenerator::visitAsmJSCall(LAsmJSCall *ins)
 {
     MAsmJSCall *mir = ins->mir();
 
-#if defined(JS_CPU_ARM) && !defined(JS_CPU_ARM_HARDFP)
+#if defined(JS_CODEGEN_ARM) && !defined(JS_CODEGEN_ARM_HARDFP)
     if (mir->callee().which() == MAsmJSCall::Callee::Builtin) {
         for (unsigned i = 0, e = ins->numOperands(); i < e; i++) {
             LAllocation *a = ins->getOperand(i);
             if (a->isFloatReg()) {
                 FloatRegister fr = ToFloatRegister(a);
                 int srcId = fr.code() * 2;
                 masm.ma_vxfer(fr, Register::FromCode(srcId), Register::FromCode(srcId+1));
             }
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -7,21 +7,21 @@
 #ifndef jit_CodeGenerator_h
 #define jit_CodeGenerator_h
 
 #include "jit/IonCaches.h"
 #if defined(JS_ION_PERF)
 # include "jit/PerfSpewer.h"
 #endif
 
-#if defined(JS_CPU_X86)
+#if defined(JS_CODEGEN_X86)
 # include "jit/x86/CodeGenerator-x86.h"
-#elif defined(JS_CPU_X64)
+#elif defined(JS_CODEGEN_X64)
 # include "jit/x64/CodeGenerator-x64.h"
-#elif defined(JS_CPU_ARM)
+#elif defined(JS_CODEGEN_ARM)
 # include "jit/arm/CodeGenerator-arm.h"
 #else
 #error "CPU Not Supported"
 #endif
 
 namespace js {
 namespace jit {
 
--- a/js/src/jit/CompileWrappers.cpp
+++ b/js/src/jit/CompileWrappers.cpp
@@ -249,17 +249,20 @@ AutoLockForCompilation::AutoLockForCompi
                                                MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
 {
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     init(compartment->compartment()->runtimeFromAnyThread());
 }
 #endif
 
 JitCompileOptions::JitCompileOptions()
-  : cloneSingletons_(false)
+  : cloneSingletons_(false),
+    spsSlowAssertionsEnabled_(false)
 {
 }
 
 JitCompileOptions::JitCompileOptions(JSContext *cx)
 {
     JS::CompartmentOptions &options = cx->compartment()->options();
     cloneSingletons_ = options.cloneSingletons(cx);
+    spsSlowAssertionsEnabled_ = cx->runtime()->spsProfiler.enabled() &&
+                                cx->runtime()->spsProfiler.slowAssertionsEnabled();
 }
--- a/js/src/jit/CompileWrappers.h
+++ b/js/src/jit/CompileWrappers.h
@@ -123,18 +123,23 @@ class JitCompileOptions
   public:
     JitCompileOptions();
     JitCompileOptions(JSContext *cx);
 
     bool cloneSingletons() const {
         return cloneSingletons_;
     }
 
+    bool spsSlowAssertionsEnabled() const {
+        return spsSlowAssertionsEnabled_;
+    }
+
   private:
     bool cloneSingletons_;
+    bool spsSlowAssertionsEnabled_;
 };
 
 
 } // namespace jit
 } // namespace js
 
 #endif // JS_ION
 
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -1566,24 +1566,19 @@ OffThreadCompilationAvailable(JSContext 
 {
     // Even if off thread compilation is enabled, compilation must still occur
     // on the main thread in some cases. Do not compile off thread during an
     // incremental GC, as this may trip incremental read barriers.
     //
     // Skip off thread compilation if PC count profiling is enabled, as
     // CodeGenerator::maybeCreateScriptCounts will not attach script profiles
     // when running off thread.
-    //
-    // Also skip off thread compilation if the SPS profiler is enabled, as it
-    // stores strings in the spsProfiler data structure, which is not protected
-    // by a lock.
     return cx->runtime()->canUseParallelIonCompilation()
         && cx->runtime()->gcIncrementalState == gc::NO_INCREMENTAL
-        && !cx->runtime()->profilingScripts
-        && !cx->runtime()->spsProfiler.enabled();
+        && !cx->runtime()->profilingScripts;
 }
 
 static void
 TrackAllProperties(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->hasSingletonType());
 
     for (Shape::Range<NoGC> range(obj->lastProperty()); !range.empty(); range.popFront())
@@ -1730,18 +1725,17 @@ IonCompile(JSContext *cx, JSScript *scri
         // enabled when offthread compilation is disabled. So don't watch for
         // proper use of the compilation lock.
         ionCompiling.construct();
     }
 
     Maybe<AutoProtectHeapForIonCompilation> protect;
     if (js_JitOptions.checkThreadSafety &&
         cx->runtime()->gcIncrementalState == gc::NO_INCREMENTAL &&
-        !cx->runtime()->profilingScripts &&
-        !cx->runtime()->spsProfiler.enabled())
+        !cx->runtime()->profilingScripts)
     {
         protect.construct(cx->runtime());
     }
 
     IonSpewNewFunction(graph, builderScript);
 
     bool succeeded = builder->build();
     builder->clearForBackEnd();
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -38,17 +38,17 @@ void
 CodeLocationJump::repoint(JitCode *code, MacroAssembler *masm)
 {
     JS_ASSERT(state_ == Relative);
     size_t new_off = (size_t)raw_;
 #ifdef JS_SMALL_BRANCH
     size_t jumpTableEntryOffset = reinterpret_cast<size_t>(jumpTableEntry_);
 #endif
     if (masm != nullptr) {
-#ifdef JS_CPU_X64
+#ifdef JS_CODEGEN_X64
         JS_ASSERT((uint64_t)raw_ <= UINT32_MAX);
 #endif
         new_off = masm->actualOffset((uintptr_t)raw_);
 #ifdef JS_SMALL_BRANCH
         jumpTableEntryOffset = masm->actualIndex(jumpTableEntryOffset);
 #endif
     }
     raw_ = code->raw() + new_off;
@@ -59,17 +59,17 @@ CodeLocationJump::repoint(JitCode *code,
 }
 
 void
 CodeLocationLabel::repoint(JitCode *code, MacroAssembler *masm)
 {
      JS_ASSERT(state_ == Relative);
      size_t new_off = (size_t)raw_;
      if (masm != nullptr) {
-#ifdef JS_CPU_X64
+#ifdef JS_CODEGEN_X64
         JS_ASSERT((uint64_t)raw_ <= UINT32_MAX);
 #endif
         new_off = masm->actualOffset((uintptr_t)raw_);
      }
      JS_ASSERT(new_off < code->instructionsSize());
 
      raw_ = code->raw() + new_off;
      setAbsolute();
--- a/js/src/jit/IonCaches.h
+++ b/js/src/jit/IonCaches.h
@@ -2,17 +2,17 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 jit_IonCaches_h
 #define jit_IonCaches_h
 
-#ifdef JS_CPU_ARM
+#ifdef JS_CODEGEN_ARM
 # include "jit/arm/Assembler-arm.h"
 #endif
 #include "jit/Registers.h"
 #include "jit/shared/Assembler-shared.h"
 
 namespace js {
 
 class LockedJSContext;
@@ -342,25 +342,25 @@ class RepatchIonCache : public IonCache
 {
   protected:
     class RepatchStubAppender;
 
     CodeLocationJump initialJump_;
     CodeLocationJump lastJump_;
 
     // Offset from the initial jump to the rejoin label.
-#ifdef JS_CPU_ARM
+#ifdef JS_CODEGEN_ARM
     static const size_t REJOIN_LABEL_OFFSET = 4;
 #else
     static const size_t REJOIN_LABEL_OFFSET = 0;
 #endif
 
     CodeLocationLabel rejoinLabel() const {
         uint8_t *ptr = initialJump_.raw();
-#ifdef JS_CPU_ARM
+#ifdef JS_CODEGEN_ARM
         uint32_t i = 0;
         while (i < REJOIN_LABEL_OFFSET)
             ptr = Assembler::nextInstruction(ptr, &i);
 #endif
         return CodeLocationLabel(ptr);
     }
 
   public:
@@ -1037,17 +1037,17 @@ class GetPropertyParIC : public Parallel
         name_(name),
         output_(output),
         hasTypedArrayLengthStub_(false)
     {
     }
 
     CACHE_HEADER(GetPropertyPar)
 
-#ifdef JS_CPU_X86
+#ifdef JS_CODEGEN_X86
     // x86 lacks a general purpose scratch register for dispatch caches and
     // must be given one manually.
     void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
 #endif
 
     void reset();
 
     Register object() const {
@@ -1096,17 +1096,17 @@ class GetElementParIC : public ParallelI
         output_(output),
         monitoredResult_(monitoredResult),
         allowDoubleResult_(allowDoubleResult)
     {
     }
 
     CACHE_HEADER(GetElementPar)
 
-#ifdef JS_CPU_X86
+#ifdef JS_CODEGEN_X86
     // x86 lacks a general purpose scratch register for dispatch caches and
     // must be given one manually.
     void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
 #endif
 
     Register object() const {
         return object_;
     }
@@ -1157,17 +1157,17 @@ class SetPropertyParIC : public Parallel
         value_(value),
         strict_(strict),
         needsTypeBarrier_(needsTypeBarrier)
     {
     }
 
     CACHE_HEADER(SetPropertyPar)
 
-#ifdef JS_CPU_X86
+#ifdef JS_CODEGEN_X86
     // x86 lacks a general purpose scratch register for dispatch caches and
     // must be given one manually.
     void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
 #endif
 
     Register object() const {
         return object_;
     }
@@ -1217,17 +1217,17 @@ class SetElementParIC : public ParallelI
         value_(value),
         strict_(strict),
         guardHoles_(guardHoles)
     {
     }
 
     CACHE_HEADER(SetElementPar)
 
-#ifdef JS_CPU_X86
+#ifdef JS_CODEGEN_X86
     // x86 lacks a general purpose scratch register for dispatch caches and
     // must be given one manually.
     void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
 #endif
 
     Register object() const {
         return object_;
     }
--- a/js/src/jit/IonLinker.h
+++ b/js/src/jit/IonLinker.h
@@ -77,17 +77,17 @@ class Linker
     }
 
     template <AllowGC allowGC>
     JitCode *newCode(JSContext *cx, JSC::CodeKind kind) {
         return newCode<allowGC>(cx, cx->compartment()->jitCompartment()->execAlloc(), kind);
     }
 
     JitCode *newCodeForIonScript(JSContext *cx) {
-#ifdef JS_CPU_ARM
+#ifdef JS_CODEGEN_ARM
         // ARM does not yet use implicit interrupt checks, see bug 864220.
         return newCode<CanGC>(cx, JSC::ION_CODE);
 #else
         // The caller must lock the runtime against operation callback triggers,
         // as the triggering thread may use the executable allocator below.
         JS_ASSERT(cx->runtime()->currentThreadOwnsOperationCallbackLock());
 
         JSC::ExecutableAllocator *alloc = cx->runtime()->jitRuntime()->getIonAlloc(cx);
--- a/js/src/jit/IonMacroAssembler.cpp
+++ b/js/src/jit/IonMacroAssembler.cpp
@@ -240,24 +240,24 @@ template void MacroAssembler::guardType(
                                         Register scratch, Label *miss);
 
 void
 MacroAssembler::PushRegsInMask(RegisterSet set)
 {
     int32_t diffF = set.fpus().size() * sizeof(double);
     int32_t diffG = set.gprs().size() * sizeof(intptr_t);
 
-#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
     // On x86, always use push to push the integer registers, as it's fast
     // on modern hardware and it's a small instruction.
     for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); iter++) {
         diffG -= sizeof(intptr_t);
         Push(*iter);
     }
-#elif defined(JS_CPU_ARM)
+#elif defined(JS_CODEGEN_ARM)
     if (set.gprs().size() > 1) {
         adjustFrame(diffG);
         startDataTransferM(IsStore, StackPointer, DB, WriteBack);
         for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); iter++) {
             diffG -= sizeof(intptr_t);
             transferReg(*iter);
         }
         finishDataTransfer();
@@ -272,17 +272,17 @@ MacroAssembler::PushRegsInMask(RegisterS
     reserveStack(diffG);
     for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); iter++) {
         diffG -= sizeof(intptr_t);
         storePtr(*iter, Address(StackPointer, diffG));
     }
 #endif
     JS_ASSERT(diffG == 0);
 
-#ifdef JS_CPU_ARM
+#ifdef JS_CODEGEN_ARM
     adjustFrame(diffF);
     diffF += transferMultipleByRuns(set.fpus(), IsStore, StackPointer, DB);
 #else
     reserveStack(diffF);
     for (FloatRegisterBackwardIterator iter(set.fpus()); iter.more(); iter++) {
         diffF -= sizeof(double);
         storeDouble(*iter, Address(StackPointer, diffF));
     }
@@ -293,17 +293,17 @@ MacroAssembler::PushRegsInMask(RegisterS
 void
 MacroAssembler::PopRegsInMaskIgnore(RegisterSet set, RegisterSet ignore)
 {
     int32_t diffG = set.gprs().size() * sizeof(intptr_t);
     int32_t diffF = set.fpus().size() * sizeof(double);
     const int32_t reservedG = diffG;
     const int32_t reservedF = diffF;
 
-#ifdef JS_CPU_ARM
+#ifdef JS_CODEGEN_ARM
     // ARM can load multiple registers at once, but only if we want back all
     // the registers we previously saved to the stack.
     if (ignore.empty(true)) {
         diffF -= transferMultipleByRuns(set.fpus(), IsLoad, StackPointer, IA);
         adjustFrame(-reservedF);
     } else
 #endif
     {
@@ -311,28 +311,28 @@ MacroAssembler::PopRegsInMaskIgnore(Regi
             diffF -= sizeof(double);
             if (!ignore.has(*iter))
                 loadDouble(Address(StackPointer, diffF), *iter);
         }
         freeStack(reservedF);
     }
     JS_ASSERT(diffF == 0);
 
-#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
     // On x86, use pop to pop the integer registers, if we're not going to
     // ignore any slots, as it's fast on modern hardware and it's a small
     // instruction.
     if (ignore.empty(false)) {
         for (GeneralRegisterForwardIterator iter(set.gprs()); iter.more(); iter++) {
             diffG -= sizeof(intptr_t);
             Pop(*iter);
         }
     } else
 #endif
-#ifdef JS_CPU_ARM
+#ifdef JS_CODEGEN_ARM
     if (set.gprs().size() > 1 && ignore.empty(false)) {
         startDataTransferM(IsLoad, StackPointer, IA, WriteBack);
         for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); iter++) {
             diffG -= sizeof(intptr_t);
             transferReg(*iter);
         }
         finishDataTransfer();
         adjustFrame(-reservedG);
@@ -533,17 +533,17 @@ template void MacroAssembler::loadFromTy
 template void MacroAssembler::loadFromTypedArray(int arrayType, const BaseIndex &src, const ValueOperand &dest,
                                                  bool allowDouble, Register temp, Label *fail);
 
 // Note: this function clobbers the input register.
 void
 MacroAssembler::clampDoubleToUint8(FloatRegister input, Register output)
 {
     JS_ASSERT(input != ScratchFloatReg);
-#ifdef JS_CPU_ARM
+#ifdef JS_CODEGEN_ARM
     ma_vimm(0.5, ScratchFloatReg);
     if (hasVFPv3()) {
         Label notSplit;
         ma_vadd(input, ScratchFloatReg, ScratchFloatReg);
         // Convert the double into an unsigned fixed point value with 24 bits of
         // precision. The resulting number will look like 0xII.DDDDDD
         as_vcvtFixed(ScratchFloatReg, false, 24, true);
         // Move the fixed point value into an integer register
@@ -988,17 +988,17 @@ MacroAssembler::generateBailoutTail(Regi
             pop(BaselineStubReg);
             pop(BaselineTailCallReg);
             pop(BaselineFrameReg);
             popValue(R0);
 
             // Discard exit frame.
             addPtr(Imm32(IonExitFrameLayout::SizeWithFooter()), StackPointer);
 
-#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
             push(BaselineTailCallReg);
 #endif
             jump(Address(BaselineStubReg, ICStub::offsetOfStubCode()));
         }
 
         //
         // Resuming into main jitcode.
         //
--- a/js/src/jit/IonMacroAssembler.h
+++ b/js/src/jit/IonMacroAssembler.h
@@ -6,21 +6,21 @@
 
 #ifndef jit_IonMacroAssembler_h
 #define jit_IonMacroAssembler_h
 
 #ifdef JS_ION
 
 #include "jscompartment.h"
 
-#if defined(JS_CPU_X86)
+#if defined(JS_CODEGEN_X86)
 # include "jit/x86/MacroAssembler-x86.h"
-#elif defined(JS_CPU_X64)
+#elif defined(JS_CODEGEN_X64)
 # include "jit/x64/MacroAssembler-x64.h"
-#elif defined(JS_CPU_ARM)
+#elif defined(JS_CODEGEN_ARM)
 # include "jit/arm/MacroAssembler-arm.h"
 #endif
 #include "jit/IonInstrumentation.h"
 #include "jit/JitCompartment.h"
 #include "jit/VMFunctions.h"
 #include "vm/ProxyObject.h"
 #include "vm/Shape.h"
 
@@ -199,49 +199,49 @@ class MacroAssembler : public MacroAssem
             constructRoot(cx);
 
         if (!icx->temp) {
             JS_ASSERT(cx);
             alloc_.construct(cx);
         }
 
         moveResolver_.setAllocator(*icx->temp);
-#ifdef JS_CPU_ARM
+#ifdef JS_CODEGEN_ARM
         initWithAllocator();
         m_buffer.id = icx->getNextAssemblerId();
 #endif
     }
 
     // This constructor should only be used when there is no IonContext active
     // (for example, Trampoline-$(ARCH).cpp and IonCaches.cpp).
     MacroAssembler(JSContext *cx, IonScript *ion = nullptr)
       : enoughMemory_(true),
         embedsNurseryPointers_(false),
         sps_(nullptr)
     {
         constructRoot(cx);
         ionContext_.construct(cx, (js::jit::TempAllocator *)nullptr);
         alloc_.construct(cx);
         moveResolver_.setAllocator(*ionContext_.ref().temp);
-#ifdef JS_CPU_ARM
+#ifdef JS_CODEGEN_ARM
         initWithAllocator();
         m_buffer.id = GetIonContext()->getNextAssemblerId();
 #endif
         if (ion)
             setFramePushed(ion->frameSize());
     }
 
     // asm.js compilation handles its own IonContet-pushing
     struct AsmJSToken {};
     MacroAssembler(AsmJSToken)
       : enoughMemory_(true),
         embedsNurseryPointers_(false),
         sps_(nullptr)
     {
-#ifdef JS_CPU_ARM
+#ifdef JS_CODEGEN_ARM
         initWithAllocator();
         m_buffer.id = 0;
 #endif
     }
 
     void setInstrumentation(IonInstrumentation *sps) {
         sps_ = sps;
     }
--- a/js/src/jit/IonTypes.h
+++ b/js/src/jit/IonTypes.h
@@ -57,40 +57,64 @@ BailoutKindString(BailoutKind kind)
       case Bailout_BaselineInfo:
         return "Bailout_BaselineInfo";
       default:
         MOZ_ASSUME_UNREACHABLE("Invalid BailoutKind");
     }
 }
 #endif
 
+static const uint32_t ELEMENT_TYPE_BITS = 4;
+static const uint32_t ELEMENT_TYPE_SHIFT = 0;
+static const uint32_t ELEMENT_TYPE_MASK = (1 << ELEMENT_TYPE_BITS) - 1;
+static const uint32_t VECTOR_SCALE_BITS = 2;
+static const uint32_t VECTOR_SCALE_SHIFT = ELEMENT_TYPE_BITS + ELEMENT_TYPE_SHIFT;
+static const uint32_t VECTOR_SCALE_MASK = (1 << VECTOR_SCALE_BITS) - 1;
+
 // The ordering of this enumeration is important: Anything < Value is a
 // specialized type. Furthermore, anything < String has trivial conversion to
 // a number.
 enum MIRType
 {
     MIRType_Undefined,
     MIRType_Null,
     MIRType_Boolean,
     MIRType_Int32,
     MIRType_Double,
     MIRType_Float32,
     MIRType_String,
     MIRType_Object,
     MIRType_Magic,
     MIRType_Value,
-    MIRType_None,         // Invalid, used as a placeholder.
-    MIRType_Slots,        // A slots vector
-    MIRType_Elements,     // An elements vector
-    MIRType_Pointer,      // An opaque pointer that receives no special treatment
-    MIRType_Shape,        // A Shape pointer.
-    MIRType_ForkJoinSlice // js::ForkJoinSlice*
+    MIRType_None,          // Invalid, used as a placeholder.
+    MIRType_Slots,         // A slots vector
+    MIRType_Elements,      // An elements vector
+    MIRType_Pointer,       // An opaque pointer that receives no special treatment
+    MIRType_Shape,         // A Shape pointer.
+    MIRType_ForkJoinSlice, // js::ForkJoinSlice*
+    MIRType_Last = MIRType_ForkJoinSlice,
+    MIRType_Float32x4 = MIRType_Float32 | (2 << VECTOR_SCALE_SHIFT),
+    MIRType_Int32x4   = MIRType_Int32   | (2 << VECTOR_SCALE_SHIFT),
+    MIRType_Doublex2  = MIRType_Double  | (1 << VECTOR_SCALE_SHIFT)
 };
 
 static inline MIRType
+ElementType(MIRType type)
+{
+    JS_STATIC_ASSERT(MIRType_Last <= ELEMENT_TYPE_MASK);
+    return static_cast<MIRType>((type >> ELEMENT_TYPE_SHIFT) & ELEMENT_TYPE_MASK);
+}
+
+static inline uint32_t
+VectorSize(MIRType type)
+{
+    return 1 << ((type >> VECTOR_SCALE_SHIFT) & VECTOR_SCALE_MASK);
+}
+
+static inline MIRType
 MIRTypeFromValueType(JSValueType type)
 {
     switch (type) {
       case JSVAL_TYPE_DOUBLE:
         return MIRType_Double;
       case JSVAL_TYPE_INT32:
         return MIRType_Int32;
       case JSVAL_TYPE_UNDEFINED:
--- a/js/src/jit/LIR.h
+++ b/js/src/jit/LIR.h
@@ -1536,24 +1536,24 @@ LAllocation::toRegister() const
 #elif defined(JS_PUNBOX64)
 # define BOX_OUTPUT_ACCESSORS()                                             \
     const LDefinition *outputValue() {                                      \
         return getDef(0);                                                   \
     }
 #endif
 
 #include "jit/LIR-Common.h"
-#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
-# if defined(JS_CPU_X86)
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
+# if defined(JS_CODEGEN_X86)
 #  include "jit/x86/LIR-x86.h"
-# elif defined(JS_CPU_X64)
+# elif defined(JS_CODEGEN_X64)
 #  include "jit/x64/LIR-x64.h"
 # endif
 # include "jit/shared/LIR-x86-shared.h"
-#elif defined(JS_CPU_ARM)
+#elif defined(JS_CODEGEN_ARM)
 # include "jit/arm/LIR-arm.h"
 #endif
 
 #undef LIR_HEADER
 
 namespace js {
 namespace jit {
 
--- a/js/src/jit/LOpcodes.h
+++ b/js/src/jit/LOpcodes.h
@@ -285,21 +285,21 @@
     _(AsmJSCheckOverRecursed)       \
     _(CheckInterruptPar)            \
     _(RecompileCheck)               \
     _(AssertRangeI)                 \
     _(AssertRangeD)                 \
     _(AssertRangeF)                 \
     _(AssertRangeV)
 
-#if defined(JS_CPU_X86)
+#if defined(JS_CODEGEN_X86)
 # include "jit/x86/LOpcodes-x86.h"
-#elif defined(JS_CPU_X64)
+#elif defined(JS_CODEGEN_X64)
 # include "jit/x64/LOpcodes-x64.h"
-#elif defined(JS_CPU_ARM)
+#elif defined(JS_CODEGEN_ARM)
 # include "jit/arm/LOpcodes-arm.h"
 #endif
 
 #define LIR_OPCODE_LIST(_)          \
     LIR_COMMON_OPCODE_LIST(_)       \
     LIR_CPU_OPCODE_LIST(_)
 
 #endif /* jit_LOpcodes_h */
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -2101,17 +2101,17 @@ LIRGenerator::visitGuardThreadExclusive(
 }
 
 bool
 LIRGenerator::visitInterruptCheck(MInterruptCheck *ins)
 {
     // Implicit interrupt checks require asm.js signal handlers to be
     // installed. ARM does not yet use implicit interrupt checks, see
     // bug 864220.
-#ifndef JS_CPU_ARM
+#ifndef JS_CODEGEN_ARM
     if (GetIonContext()->runtime->signalHandlersInstalled()) {
         LInterruptCheckImplicit *lir = new(alloc()) LInterruptCheckImplicit();
         return add(lir, ins) && assignSafepoint(lir, ins);
     }
 #endif
 
     LInterruptCheck *lir = new(alloc()) LInterruptCheck();
     return add(lir, ins) && assignSafepoint(lir, ins);
@@ -3270,18 +3270,17 @@ LIRGenerator::visitCallInstanceOf(MCallI
 bool
 LIRGenerator::visitFunctionBoundary(MFunctionBoundary *ins)
 {
     LFunctionBoundary *lir = new(alloc()) LFunctionBoundary(temp());
     if (!add(lir, ins))
         return false;
     // If slow assertions are enabled, then this node will result in a callVM
     // out to a C++ function for the assertions, so we will need a safepoint.
-    return !GetIonContext()->runtime->spsProfiler().slowAssertionsEnabled() ||
-           assignSafepoint(lir, ins);
+    return !gen->options.spsSlowAssertionsEnabled() || assignSafepoint(lir, ins);
 }
 
 bool
 LIRGenerator::visitIsCallable(MIsCallable *ins)
 {
     JS_ASSERT(ins->object()->type() == MIRType_Object);
     JS_ASSERT(ins->type() == MIRType_Boolean);
     return define(new(alloc()) LIsCallable(useRegister(ins->object())), ins);
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -6,21 +6,21 @@
 
 #ifndef jit_Lowering_h
 #define jit_Lowering_h
 
 // This file declares the structures that are used for attaching LIR to a
 // MIRGraph.
 
 #include "jit/LIR.h"
-#if defined(JS_CPU_X86)
+#if defined(JS_CODEGEN_X86)
 # include "jit/x86/Lowering-x86.h"
-#elif defined(JS_CPU_X64)
+#elif defined(JS_CODEGEN_X64)
 # include "jit/x64/Lowering-x64.h"
-#elif defined(JS_CPU_ARM)
+#elif defined(JS_CODEGEN_ARM)
 # include "jit/arm/Lowering-arm.h"
 #else
 # error "CPU!"
 #endif
 
 namespace js {
 namespace jit {
 
--- a/js/src/jit/MoveEmitter.h
+++ b/js/src/jit/MoveEmitter.h
@@ -2,17 +2,17 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 jit_MoveEmitter_h
 #define jit_MoveEmitter_h
 
-#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
 # include "jit/shared/MoveEmitter-x86-shared.h"
-#elif defined(JS_CPU_ARM)
+#elif defined(JS_CODEGEN_ARM)
 # include "jit/arm/MoveEmitter-arm.h"
 #else
 # error "CPU Not Supported"
 #endif
 
 #endif /* jit_MoveEmitter_h */
--- a/js/src/jit/RegisterAllocator.h
+++ b/js/src/jit/RegisterAllocator.h
@@ -303,20 +303,20 @@ class RegisterAllocator
     RegisterAllocator(MIRGenerator *mir, LIRGenerator *lir, LIRGraph &graph)
       : mir(mir),
         lir(lir),
         graph(graph),
         allRegisters_(RegisterSet::All())
     {
         if (FramePointer != InvalidReg && mir->instrumentedProfiling())
             allRegisters_.take(AnyRegister(FramePointer));
-#if defined(JS_CPU_X64)
+#if defined(JS_CODEGEN_X64)
         if (mir->compilingAsmJS())
             allRegisters_.take(AnyRegister(HeapReg));
-#elif defined(JS_CPU_ARM)
+#elif defined(JS_CODEGEN_ARM)
         if (mir->compilingAsmJS()) {
             allRegisters_.take(AnyRegister(HeapReg));
             allRegisters_.take(AnyRegister(GlobalReg));
             allRegisters_.take(AnyRegister(NANReg));
         }
 #endif
     }
 
--- a/js/src/jit/RegisterSets.h
+++ b/js/src/jit/RegisterSets.h
@@ -804,65 +804,65 @@ class ABIArg
 // Summarizes a heap access made by asm.js code that needs to be patched later
 // and/or looked up by the asm.js signal handlers. Different architectures need
 // to know different things (x64: offset and length, ARM: where to patch in
 // heap length, x86: where to patch in heap length and base) hence the massive
 // #ifdefery.
 class AsmJSHeapAccess
 {
     uint32_t offset_;
-#if defined(JS_CPU_X86)
+#if defined(JS_CODEGEN_X86)
     uint8_t cmpDelta_;  // the number of bytes from the cmp to the load/store instruction
 #endif
-#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
     uint8_t opLength_;  // the length of the load/store instruction
     uint8_t isFloat32Load_;
     AnyRegister::Code loadedReg_ : 8;
 #endif
 
     JS_STATIC_ASSERT(AnyRegister::Total < UINT8_MAX);
 
   public:
     AsmJSHeapAccess() {}
-#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
     // If 'cmp' equals 'offset' or if it is not supplied then the
     // cmpDelta_ is zero indicating that there is no length to patch.
     AsmJSHeapAccess(uint32_t offset, uint32_t after, ArrayBufferView::ViewType vt,
                     AnyRegister loadedReg, uint32_t cmp = UINT32_MAX)
       : offset_(offset),
-# if defined(JS_CPU_X86)
+# if defined(JS_CODEGEN_X86)
         cmpDelta_(cmp == UINT32_MAX ? 0 : offset - cmp),
 # endif
         opLength_(after - offset),
         isFloat32Load_(vt == ArrayBufferView::TYPE_FLOAT32),
         loadedReg_(loadedReg.code())
     {}
     AsmJSHeapAccess(uint32_t offset, uint8_t after, uint32_t cmp = UINT32_MAX)
       : offset_(offset),
-# if defined(JS_CPU_X86)
+# if defined(JS_CODEGEN_X86)
         cmpDelta_(cmp == UINT32_MAX ? 0 : offset - cmp),
 # endif
         opLength_(after - offset),
         isFloat32Load_(false),
         loadedReg_(UINT8_MAX)
     {}
-#elif defined(JS_CPU_ARM)
+#elif defined(JS_CODEGEN_ARM)
     explicit AsmJSHeapAccess(uint32_t offset)
       : offset_(offset)
     {}
 #endif
 
     uint32_t offset() const { return offset_; }
     void setOffset(uint32_t offset) { offset_ = offset; }
-#if defined(JS_CPU_X86)
+#if defined(JS_CODEGEN_X86)
     bool hasLengthCheck() const { return cmpDelta_ > 0; }
     void *patchLengthAt(uint8_t *code) const { return code + (offset_ - cmpDelta_); }
     void *patchOffsetAt(uint8_t *code) const { return code + (offset_ + opLength_); }
 #endif
-#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
     unsigned opLength() const { return opLength_; }
     bool isLoad() const { return loadedReg_ != UINT8_MAX; }
     bool isFloat32Load() const { return isFloat32Load_; }
     AnyRegister loadedReg() const { return AnyRegister::FromCode(loadedReg_); }
 #endif
 };
 
 typedef Vector<AsmJSHeapAccess, 0, IonAllocPolicy> AsmJSHeapAccessVector;
--- a/js/src/jit/Registers.h
+++ b/js/src/jit/Registers.h
@@ -5,21 +5,21 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jit_Registers_h
 #define jit_Registers_h
 
 #include "mozilla/Array.h"
 
 #include "jit/IonTypes.h"
-#if defined(JS_CPU_X86)
+#if defined(JS_CODEGEN_X86)
 # include "jit/x86/Architecture-x86.h"
-#elif defined(JS_CPU_X64)
+#elif defined(JS_CODEGEN_X64)
 # include "jit/x64/Architecture-x64.h"
-#elif defined(JS_CPU_ARM)
+#elif defined(JS_CODEGEN_ARM)
 # include "jit/arm/Architecture-arm.h"
 #endif
 
 namespace js {
 namespace jit {
 
 struct Register {
     typedef Registers Codes;
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -521,23 +521,23 @@ JSObject *
 NewStringObject(JSContext *cx, HandleString str)
 {
     return StringObject::create(cx, str);
 }
 
 bool
 SPSEnter(JSContext *cx, HandleScript script)
 {
-    return cx->runtime()->spsProfiler.enter(cx, script, script->functionNonDelazifying());
+    return cx->runtime()->spsProfiler.enter(script, script->functionNonDelazifying());
 }
 
 bool
 SPSExit(JSContext *cx, HandleScript script)
 {
-    cx->runtime()->spsProfiler.exit(cx, script, script->functionNonDelazifying());
+    cx->runtime()->spsProfiler.exit(script, script->functionNonDelazifying());
     return true;
 }
 
 bool
 OperatorIn(JSContext *cx, HandleValue key, HandleObject obj, bool *out)
 {
     RootedId id(cx);
     if (!ValueToId<CanGC>(cx, key, &id))
@@ -727,17 +727,17 @@ DebugEpilogue(JSContext *cx, BaselineFra
         DebugScopes::onPopCall(frame, cx);
     } else if (frame->isStrictEvalFrame()) {
         JS_ASSERT_IF(frame->hasCallObj(), frame->scopeChain()->as<CallObject>().isForEval());
         DebugScopes::onPopStrictEvalScope(frame);
     }
 
     // If the frame has a pushed SPS frame, make sure to pop it.
     if (frame->hasPushedSPSFrame()) {
-        cx->runtime()->spsProfiler.exit(cx, frame->script(), frame->maybeFun());
+        cx->runtime()->spsProfiler.exit(frame->script(), frame->maybeFun());
         // Unset the pushedSPSFrame flag because DebugEpilogue may get called before
         // probes::ExitScript in baseline during exception handling, and we don't
         // want to double-pop SPS frames.
         frame->unsetPushedSPSFrame();
     }
 
     if (!ok) {
         // Pop this frame by updating ionTop, so that the exception handling
--- a/js/src/jit/arm/Architecture-arm.h
+++ b/js/src/jit/arm/Architecture-arm.h
@@ -7,17 +7,17 @@
 #ifndef jit_arm_Architecture_arm_h
 #define jit_arm_Architecture_arm_h
 
 #include <limits.h>
 #include <stdint.h>
 
 // gcc appears to use __ARM_PCS_VFP to denote that the target is a hard-float target.
 #ifdef __ARM_PCS_VFP
-#define JS_CPU_ARM_HARDFP
+#define JS_CODEGEN_ARM_HARDFP
 #endif
 namespace js {
 namespace jit {
 
 // In bytes: slots needed for potential memory->memory move spills.
 //   +8 for cycles
 //   +4 for gpr spills
 //   +8 for double spills
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -2097,17 +2097,17 @@ class InstructionIterator {
     Instruction *cur() const {
         return i;
     }
 };
 
 static const uint32_t NumIntArgRegs = 4;
 static const uint32_t NumFloatArgRegs = 8;
 
-#ifdef JS_CPU_ARM_HARDFP
+#ifdef JS_CODEGEN_ARM_HARDFP
 static inline bool
 GetIntArgReg(uint32_t usedIntArgs, uint32_t usedFloatArgs, Register *out)
 {
    if (usedIntArgs >= NumIntArgRegs)
         return false;
     *out = Register::FromCode(usedIntArgs);
     return true;
 }
--- a/js/src/jit/arm/CodeGenerator-arm.h
+++ b/js/src/jit/arm/CodeGenerator-arm.h
@@ -171,17 +171,17 @@ class CodeGeneratorARM : public CodeGene
     bool visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr *ins);
     bool visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc *ins);
 
     bool visitAsmJSPassStackArg(LAsmJSPassStackArg *ins);
 
     bool generateInvalidateEpilogue();
   protected:
     void postAsmJSCall(LAsmJSCall *lir) {
-#ifndef JS_CPU_ARM_HARDFP
+#ifndef JS_CODEGEN_ARM_HARDFP
         if (lir->mir()->callee().which() == MAsmJSCall::Callee::Builtin) {
             switch (lir->mir()->type()) {
               case MIRType_Double:
                 masm.ma_vxfer(r0, r1, d0);
                 break;
               case MIRType_Float32:
                 masm.as_vxfer(r0, InvalidReg, VFPRegister(d0).singleOverlay(),
                               Assembler::CoreToFloat);
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -3474,17 +3474,17 @@ MacroAssemblerARMCompat::breakpoint(Cond
 
 void
 MacroAssemblerARMCompat::setupABICall(uint32_t args)
 {
     JS_ASSERT(!inCall_);
     inCall_ = true;
     args_ = args;
     passedArgs_ = 0;
-#ifdef JS_CPU_ARM_HARDFP
+#ifdef JS_CODEGEN_ARM_HARDFP
     usedIntSlots_ = 0;
     usedFloatSlots_ = 0;
     padding_ = 0;
 #else
     usedSlots_ = 0;
 #endif
     floatArgsInGPR[0] = MoveOperand();
     floatArgsInGPR[1] = MoveOperand();
@@ -3507,17 +3507,17 @@ MacroAssemblerARMCompat::setupUnalignedA
     dynamicAlignment_ = true;
 
     ma_mov(sp, scratch);
 
     // Force sp to be aligned
     ma_and(Imm32(~(StackAlignment - 1)), sp, sp);
     ma_push(scratch);
 }
-#ifdef JS_CPU_ARM_HARDFP
+#ifdef JS_CODEGEN_ARM_HARDFP
 void
 MacroAssemblerARMCompat::passABIArg(const MoveOperand &from, MoveOp::Type type)
 {
     MoveOperand to;
     ++passedArgs_;
     if (!enoughMemory_)
         return;
     switch (type) {
@@ -3626,17 +3626,17 @@ void MacroAssemblerARMCompat::checkStack
     breakpoint(NonZero);
 #endif
 }
 
 void
 MacroAssemblerARMCompat::callWithABIPre(uint32_t *stackAdjust)
 {
     JS_ASSERT(inCall_);
-#ifdef JS_CPU_ARM_HARDFP
+#ifdef JS_CODEGEN_ARM_HARDFP
     *stackAdjust = ((usedIntSlots_ > NumIntArgRegs) ? usedIntSlots_ - NumIntArgRegs : 0) * sizeof(intptr_t);
     *stackAdjust += 2*((usedFloatSlots_ > NumFloatArgRegs) ? usedFloatSlots_ - NumFloatArgRegs : 0) * sizeof(intptr_t);
 #else
     *stackAdjust = ((usedSlots_ > NumIntArgRegs) ? usedSlots_ - NumIntArgRegs : 0) * sizeof(intptr_t);
 #endif
     if (!dynamicAlignment_) {
         *stackAdjust += ComputeByteAlignment(framePushed_ + *stackAdjust, StackAlignment);
     } else {
@@ -3688,23 +3688,23 @@ MacroAssemblerARMCompat::callWithABIPre(
 void
 MacroAssemblerARMCompat::callWithABIPost(uint32_t stackAdjust, MoveOp::Type result)
 {
     if (secondScratchReg_ != lr)
         ma_mov(secondScratchReg_, lr);
 
     switch (result) {
       case MoveOp::DOUBLE:
-#ifndef JS_CPU_ARM_HARDFP
+#ifndef JS_CODEGEN_ARM_HARDFP
         // Move double from r0/r1 to ReturnFloatReg.
         as_vxfer(r0, r1, ReturnFloatReg, CoreToFloat);
         break;
 #endif
       case MoveOp::FLOAT32:
-#ifndef JS_CPU_ARM_HARDFP
+#ifndef JS_CODEGEN_ARM_HARDFP
         // Move float32 from r0 to ReturnFloatReg.
         as_vxfer(r0, InvalidReg, VFPRegister(d0).singleOverlay(), CoreToFloat);
         break;
 #endif
       case MoveOp::GENERAL:
         break;
 
       default:
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -439,17 +439,17 @@ class MacroAssemblerARMCompat : public M
     // Number of bytes the stack is adjusted inside a call to C. Calls to C may
     // not be nested.
     bool inCall_;
     uint32_t args_;
     // The actual number of arguments that were passed, used to assert that
     // the initial number of arguments declared was correct.
     uint32_t passedArgs_;
 
-#ifdef JS_CPU_ARM_HARDFP
+#ifdef JS_CODEGEN_ARM_HARDFP
     uint32_t usedIntSlots_;
     uint32_t usedFloatSlots_;
     uint32_t padding_;
 #else
     // ARM treats arguments as a vector in registers/memory, that looks like:
     // { r0, r1, r2, r3, [sp], [sp,+4], [sp,+8] ... }
     // usedSlots_ keeps track of how many of these have been used.
     // It bears a passing resemblance to passedArgs_, but a single argument
--- a/js/src/jit/shared/Assembler-shared.h
+++ b/js/src/jit/shared/Assembler-shared.h
@@ -12,17 +12,17 @@
 #include <limits.h>
 
 #include "jsworkers.h"
 
 #include "jit/IonAllocPolicy.h"
 #include "jit/Registers.h"
 #include "jit/RegisterSets.h"
 
-#if defined(JS_CPU_X64) || defined(JS_CPU_ARM)
+#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM)
 // JS_SMALL_BRANCH means the range on a branch instruction
 // is smaller than the whole address space
 #    define JS_SMALL_BRANCH
 #endif
 namespace js {
 namespace jit {
 
 enum Scale {
@@ -680,17 +680,17 @@ enum AsmJSImmKind
     AsmJSImm_InvokeFromAsmJS_Ignore,
     AsmJSImm_InvokeFromAsmJS_ToInt32,
     AsmJSImm_InvokeFromAsmJS_ToNumber,
     AsmJSImm_CoerceInPlace_ToInt32,
     AsmJSImm_CoerceInPlace_ToNumber,
     AsmJSImm_ToInt32,
     AsmJSImm_EnableActivationFromAsmJS,
     AsmJSImm_DisableActivationFromAsmJS,
-#if defined(JS_CPU_ARM)
+#if defined(JS_CODEGEN_ARM)
     AsmJSImm_aeabi_idivmod,
     AsmJSImm_aeabi_uidivmod,
 #endif
     AsmJSImm_ModD,
     AsmJSImm_SinD,
     AsmJSImm_SinF,
     AsmJSImm_CosD,
     AsmJSImm_CosF,
--- a/js/src/jit/shared/Assembler-x86-shared.cpp
+++ b/js/src/jit/shared/Assembler-x86-shared.cpp
@@ -1,21 +1,21 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 "gc/Marking.h"
 #include "jit/JitCompartment.h"
-#if defined(JS_CPU_X86)
+#if defined(JS_CODEGEN_X86)
 # include "jit/x86/MacroAssembler-x86.h"
-#elif defined(JS_CPU_X64)
+#elif defined(JS_CODEGEN_X64)
 # include "jit/x64/MacroAssembler-x64.h"
-#elif defined(JS_CPU_ARM)
+#elif defined(JS_CODEGEN_ARM)
 # include "jit/arm/MacroAssembler-arm.h"
 #endif
 
 using namespace js;
 using namespace js::jit;
 
 void
 AssemblerX86Shared::copyJumpRelocationTable(uint8_t *dest)
--- a/js/src/jit/shared/Assembler-x86-shared.h
+++ b/js/src/jit/shared/Assembler-x86-shared.h
@@ -1160,17 +1160,17 @@ class AssemblerX86Shared
 
     void pushFlags() {
         masm.push_flags();
     }
     void popFlags() {
         masm.pop_flags();
     }
 
-#ifdef JS_CPU_X86
+#ifdef JS_CODEGEN_X86
     void pushAllRegs() {
         masm.pusha();
     }
     void popAllRegs() {
         masm.popa();
     }
 #endif
 
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -59,17 +59,17 @@ CodeGeneratorShared::CodeGeneratorShared
     // argument stack depth separately.
     if (gen->compilingAsmJS()) {
         JS_ASSERT(graph->argumentSlotCount() == 0);
         frameDepth_ += gen->maxAsmJSStackArgBytes();
 
         // An MAsmJSCall does not align the stack pointer at calls sites but instead
         // relies on the a priori stack adjustment (in the prologue) on platforms
         // (like x64) which require the stack to be aligned.
-#ifdef JS_CPU_ARM
+#ifdef JS_CODEGEN_ARM
         bool forceAlign = true;
 #else
         bool forceAlign = false;
 #endif
         if (gen->performsAsmJSCall() || forceAlign) {
             unsigned alignmentAtCall = AlignmentMidPrologue + frameDepth_;
             if (unsigned rem = alignmentAtCall % StackAlignment)
                 frameDepth_ += StackAlignment - rem;
--- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp
@@ -150,17 +150,17 @@ CodeGeneratorX86Shared::visitBitAndAndBr
         masm.testl(ToRegister(baab->left()), ToRegister(baab->right()));
     emitBranch(Assembler::NonZero, baab->ifTrue(), baab->ifFalse());
     return true;
 }
 
 void
 CodeGeneratorX86Shared::emitCompare(MCompare::CompareType type, const LAllocation *left, const LAllocation *right)
 {
-#ifdef JS_CPU_X64
+#ifdef JS_CODEGEN_X64
     if (type == MCompare::Compare_Object) {
         masm.cmpq(ToRegister(left), ToOperand(right));
         return;
     }
 #endif
 
     if (right->isConstant())
         masm.cmpl(ToRegister(left), Imm32(ToInt32(right)));
@@ -334,33 +334,33 @@ CodeGeneratorX86Shared::generateOutOfLin
 }
 
 class BailoutJump {
     Assembler::Condition cond_;
 
   public:
     BailoutJump(Assembler::Condition cond) : cond_(cond)
     { }
-#ifdef JS_CPU_X86
+#ifdef JS_CODEGEN_X86
     void operator()(MacroAssembler &masm, uint8_t *code) const {
         masm.j(cond_, ImmPtr(code), Relocation::HARDCODED);
     }
 #endif
     void operator()(MacroAssembler &masm, Label *label) const {
         masm.j(cond_, label);
     }
 };
 
 class BailoutLabel {
     Label *label_;
 
   public:
     BailoutLabel(Label *label) : label_(label)
     { }
-#ifdef JS_CPU_X86
+#ifdef JS_CODEGEN_X86
     void operator()(MacroAssembler &masm, uint8_t *code) const {
         masm.retarget(label_, ImmPtr(code), Relocation::HARDCODED);
     }
 #endif
     void operator()(MacroAssembler &masm, Label *label) const {
         masm.retarget(label_, label);
     }
 };
@@ -388,17 +388,17 @@ CodeGeneratorX86Shared::bailout(const T 
         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() && deoptTable_,
                  frameClass_.frameSize() == masm.framePushed());
 
-#ifdef JS_CPU_X86
+#ifdef JS_CODEGEN_X86
     // On x64, bailout tables are pointless, because 16 extra bytes are
     // reserved per external jump, whereas it takes only 10 bytes to encode a
     // a non-table based bailout.
     if (assignBailoutId(snapshot)) {
         binder(masm, deoptTable_->raw() + snapshot->bailoutId() * BAILOUT_TABLE_ENTRY_SIZE);
         return true;
     }
 #endif
--- a/js/src/jit/shared/Lowering-shared-inl.h
+++ b/js/src/jit/shared/Lowering-shared-inl.h
@@ -319,17 +319,17 @@ LIRGeneratorShared::useRegisterOrNonNega
 LAllocation
 LIRGeneratorShared::useRegisterOrNonDoubleConstant(MDefinition *mir)
 {
     if (mir->isConstant() && mir->type() != MIRType_Double && mir->type() != MIRType_Float32)
         return LAllocation(mir->toConstant()->vp());
     return useRegister(mir);
 }
 
-#if defined(JS_CPU_ARM)
+#if defined(JS_CODEGEN_ARM)
 LAllocation
 LIRGeneratorShared::useAnyOrConstant(MDefinition *mir)
 {
     return useRegisterOrConstant(mir);
 }
 LAllocation
 LIRGeneratorShared::useStorable(MDefinition *mir)
 {
--- a/js/src/jit/shared/Lowering-x86-shared.cpp
+++ b/js/src/jit/shared/Lowering-x86-shared.cpp
@@ -283,17 +283,17 @@ LIRGeneratorX86Shared::lowerUrshD(MUrsh 
 {
     MDefinition *lhs = mir->lhs();
     MDefinition *rhs = mir->rhs();
 
     JS_ASSERT(lhs->type() == MIRType_Int32);
     JS_ASSERT(rhs->type() == MIRType_Int32);
     JS_ASSERT(mir->type() == MIRType_Double);
 
-#ifdef JS_CPU_X64
+#ifdef JS_CODEGEN_X64
     JS_ASSERT(ecx == rcx);
 #endif
 
     LUse lhsUse = useRegisterAtStart(lhs);
     LAllocation rhsAlloc = rhs->isConstant() ? useOrConstant(rhs) : useFixed(rhs, ecx);
 
     LUrshD *lir = new(alloc()) LUrshD(lhsUse, rhsAlloc, tempCopy(lhs, 0));
     return define(lir, mir);
--- a/js/src/jit/shared/MacroAssembler-x86-shared.h
+++ b/js/src/jit/shared/MacroAssembler-x86-shared.h
@@ -5,19 +5,19 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jit_shared_MacroAssembler_x86_shared_h
 #define jit_shared_MacroAssembler_x86_shared_h
 
 #include "mozilla/Casting.h"
 #include "mozilla/DebugOnly.h"
 
-#if defined(JS_CPU_X86)
+#if defined(JS_CODEGEN_X86)
 # include "jit/x86/Assembler-x86.h"
-#elif defined(JS_CPU_X64)
+#elif defined(JS_CODEGEN_X64)
 # include "jit/x64/Assembler-x64.h"
 #endif
 
 namespace js {
 namespace jit {
 
 class MacroAssemblerX86Shared : public Assembler
 {
--- a/js/src/jit/shared/MoveEmitter-x86-shared.cpp
+++ b/js/src/jit/shared/MoveEmitter-x86-shared.cpp
@@ -236,28 +236,28 @@ MoveEmitterX86::breakCycle(const MoveOpe
       case MoveOp::DOUBLE:
         if (to.isMemory()) {
             masm.loadDouble(toAddress(to), ScratchFloatReg);
             masm.storeDouble(ScratchFloatReg, cycleSlot());
         } else {
             masm.storeDouble(to.floatReg(), cycleSlot());
         }
         break;
-#ifdef JS_CPU_X64
+#ifdef JS_CODEGEN_X64
       case MoveOp::INT32:
         // x64 can't pop to a 32-bit destination, so don't push.
         if (to.isMemory()) {
             masm.load32(toAddress(to), ScratchReg);
             masm.store32(ScratchReg, cycleSlot());
         } else {
             masm.store32(to.reg(), cycleSlot());
         }
         break;
 #endif
-#ifndef JS_CPU_X64
+#ifndef JS_CODEGEN_X64
       case MoveOp::INT32:
 #endif
       case MoveOp::GENERAL:
         masm.Push(toOperand(to));
         break;
       default:
         MOZ_ASSUME_UNREACHABLE("Unexpected move type");
     }
@@ -288,30 +288,30 @@ MoveEmitterX86::completeCycle(const Move
         JS_ASSERT(pushedAtCycle_ - pushedAtStart_ >= sizeof(double));
         if (to.isMemory()) {
             masm.loadDouble(cycleSlot(), ScratchFloatReg);
             masm.storeDouble(ScratchFloatReg, toAddress(to));
         } else {
             masm.loadDouble(cycleSlot(), to.floatReg());
         }
         break;
-#ifdef JS_CPU_X64
+#ifdef JS_CODEGEN_X64
       case MoveOp::INT32:
         JS_ASSERT(pushedAtCycle_ != -1);
         JS_ASSERT(pushedAtCycle_ - pushedAtStart_ >= sizeof(int32_t));
         // x64 can't pop to a 32-bit destination.
         if (to.isMemory()) {
             masm.load32(cycleSlot(), ScratchReg);
             masm.store32(ScratchReg, toAddress(to));
         } else {
             masm.load32(cycleSlot(), to.reg());
         }
         break;
 #endif
-#ifndef JS_CPU_X64
+#ifndef JS_CODEGEN_X64
       case MoveOp::INT32:
 #endif
       case MoveOp::GENERAL:
         JS_ASSERT(masm.framePushed() - pushedAtStart_ >= sizeof(intptr_t));
         masm.Pop(toPopOperand(to));
         break;
       default:
         MOZ_ASSUME_UNREACHABLE("Unexpected move type");
@@ -324,17 +324,17 @@ MoveEmitterX86::emitInt32Move(const Move
     if (from.isGeneralReg()) {
         masm.move32(from.reg(), toOperand(to));
     } else if (to.isGeneralReg()) {
         JS_ASSERT(from.isMemory());
         masm.load32(toAddress(from), to.reg());
     } else {
         // Memory to memory gpr move.
         JS_ASSERT(from.isMemory());
-#ifdef JS_CPU_X64
+#ifdef JS_CODEGEN_X64
         // x64 has a ScratchReg. Use it.
         masm.load32(toAddress(from), ScratchReg);
         masm.move32(ScratchReg, toOperand(to));
 #else
         // No ScratchReg; bounce it off the stack.
         masm.Push(toOperand(from));
         masm.Pop(toPopOperand(to));
 #endif
@@ -349,29 +349,29 @@ MoveEmitterX86::emitGeneralMove(const Mo
     } else if (to.isGeneralReg()) {
         JS_ASSERT(from.isMemoryOrEffectiveAddress());
         if (from.isMemory())
             masm.loadPtr(toAddress(from), to.reg());
         else
             masm.lea(toOperand(from), to.reg());
     } else if (from.isMemory()) {
         // Memory to memory gpr move.
-#ifdef JS_CPU_X64
+#ifdef JS_CODEGEN_X64
         // x64 has a ScratchReg. Use it.
         masm.loadPtr(toAddress(from), ScratchReg);
         masm.mov(ScratchReg, toOperand(to));
 #else
         // No ScratchReg; bounce it off the stack.
         masm.Push(toOperand(from));
         masm.Pop(toPopOperand(to));
 #endif
     } else {
         // Effective address to memory move.
         JS_ASSERT(from.isEffectiveAddress());
-#ifdef JS_CPU_X64
+#ifdef JS_CODEGEN_X64
         // x64 has a ScratchReg. Use it.
         masm.lea(toOperand(from), ScratchReg);
         masm.mov(ScratchReg, toOperand(to));
 #else
         // This is tricky without a ScratchReg. We can't do an lea. Bounce the
         // base register off the stack, then add the offset in place. Note that
         // this clobbers FLAGS!
         masm.Push(from.base());
--- a/js/src/jit/shared/MoveEmitter-x86-shared.h
+++ b/js/src/jit/shared/MoveEmitter-x86-shared.h
@@ -2,21 +2,21 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 jit_MoveEmitter_x86_shared_h
 #define jit_MoveEmitter_x86_shared_h
 
-#if defined(JS_CPU_X86)
+#if defined(JS_CODEGEN_X86)
 # include "jit/x86/MacroAssembler-x86.h"
-#elif defined(JS_CPU_X64)
+#elif defined(JS_CODEGEN_X64)
 # include "jit/x64/MacroAssembler-x64.h"
-#elif defined(JS_CPU_ARM)
+#elif defined(JS_CODEGEN_ARM)
 # include "jit/arm/MacroAssembler-arm.h"
 #endif
 #include "jit/MoveResolver.h"
 
 namespace js {
 namespace jit {
 
 class CodeGenerator;
--- a/js/src/jit/x86/Trampoline-x86.cpp
+++ b/js/src/jit/x86/Trampoline-x86.cpp
@@ -359,17 +359,17 @@ JitRuntime::generateArgumentsRectifier(J
     // Copy the number of actual arguments.
     masm.loadPtr(Address(esp, IonRectifierFrameLayout::offsetOfNumActualArgs()), edx);
 
     masm.moveValue(UndefinedValue(), ebx, edi);
 
     // NOTE: The fact that x86 ArgumentsRectifier saves the FramePointer is relied upon
     // by the baseline bailout code.  If this changes, fix that code!  See
     // BaselineJIT.cpp/BaselineStackBuilder::calculatePrevFramePtr, and
-    // BaselineJIT.cpp/InitFromBailout.  Check for the |#if defined(JS_CPU_X86)| portions.
+    // BaselineJIT.cpp/InitFromBailout.  Check for the |#if defined(JS_CODEGEN_X86)| portions.
     masm.push(FramePointer);
     masm.movl(esp, FramePointer); // Save %esp.
 
     // Push undefined.
     {
         Label undefLoopTop;
         masm.bind(&undefLoopTop);
 
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3489,27 +3489,31 @@ JS_SetElement(JSContext *cx, HandleObjec
     RootedValue value(cx, NumberValue(v));
     return SetElement(cx, obj, index, &value);
 }
 
 JS_PUBLIC_API(bool)
 JS_SetProperty(JSContext *cx, HandleObject obj, const char *name, HandleValue v)
 {
     JSAtom *atom = Atomize(cx, name, strlen(name));
+    if (!atom)
+        return false;
     RootedId id(cx, AtomToId(atom));
-    return atom && JS_SetPropertyById(cx, obj, id, v);
+    return JS_SetPropertyById(cx, obj, id, v);
 }
 
 JS_PUBLIC_API(bool)
 JS_SetUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen,
                  HandleValue v)
 {
     JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
+    if (!atom)
+        return false;
     RootedId id(cx, AtomToId(atom));
-    return atom && JS_SetPropertyById(cx, obj, id, v);
+    return JS_SetPropertyById(cx, obj, id, v);
 }
 
 JS_PUBLIC_API(bool)
 JS_DeletePropertyById2(JSContext *cx, HandleObject obj, HandleId id, bool *result)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -4450,16 +4450,25 @@ struct JSErrorReport {
 #define JSREPORT_IS_STRICT_MODE_ERROR(flags) (((flags) &                      \
                                               JSREPORT_STRICT_MODE_ERROR) != 0)
 extern JS_PUBLIC_API(JSErrorReporter)
 JS_GetErrorReporter(JSContext *cx);
 
 extern JS_PUBLIC_API(JSErrorReporter)
 JS_SetErrorReporter(JSContext *cx, JSErrorReporter er);
 
+namespace JS {
+
+extern JS_PUBLIC_API(bool)
+CreateTypeError(JSContext *cx, HandleString stack, HandleString fileName,
+                uint32_t lineNumber, uint32_t columnNumber, JSErrorReport *report,
+                HandleString message, MutableHandleValue rval);
+
+} /* namespace JS */
+
 /************************************************************************/
 
 /*
  * Dates.
  */
 
 extern JS_PUBLIC_API(JSObject *)
 JS_NewDateObject(JSContext *cx, int year, int mon, int mday, int hour, int min, int sec);
@@ -4716,17 +4725,17 @@ class AutoHideScriptedCaller
         UnhideScriptedCaller(mContext);
     }
 
   protected:
     JSContext *mContext;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
-} /* namepsace JS */
+} /* namespace JS */
 
 /*
  * Encode/Decode interpreted scripts and functions to/from memory.
  */
 
 extern JS_PUBLIC_API(void *)
 JS_EncodeScript(JSContext *cx, JS::HandleScript script, uint32_t *lengthp);
 
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -863,8 +863,28 @@ js_CopyErrorObject(JSContext *cx, Handle
     uint32_t lineNumber = err->lineNumber();
     uint32_t columnNumber = err->columnNumber();
     JSExnType errorType = err->type();
 
     // Create the Error object.
     return ErrorObject::create(cx, errorType, stack, fileName,
                                lineNumber, columnNumber, &copyReport, message);
 }
+
+JS_PUBLIC_API(bool)
+JS::CreateTypeError(JSContext *cx, HandleString stack, HandleString fileName,
+                    uint32_t lineNumber, uint32_t columnNumber, JSErrorReport *report,
+                    HandleString message, MutableHandleValue rval)
+{
+    assertSameCompartment(cx, stack, fileName, message);
+    js::ScopedJSFreePtr<JSErrorReport> rep;
+    if (report)
+        rep = CopyErrorReport(cx, report);
+
+    RootedObject obj(cx,
+        js::ErrorObject::create(cx, JSEXN_TYPEERR, stack, fileName,
+                                lineNumber, columnNumber, &rep, message));
+    if (!obj)
+        return false;
+
+    rval.setObject(*obj);
+    return true;
+}
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -276,26 +276,26 @@ if CONFIG['ENABLE_ION']:
         'jit/Snapshots.cpp',
         'jit/StupidAllocator.cpp',
         'jit/TypePolicy.cpp',
         'jit/TypeRepresentationSet.cpp',
         'jit/UnreachableCodeElimination.cpp',
         'jit/ValueNumbering.cpp',
         'jit/VMFunctions.cpp',
     ]
-    if CONFIG['TARGET_CPU'].find('86') != -1:
+    if CONFIG['JS_CODEGEN_X86'] or CONFIG['JS_CODEGEN_X64']:
         UNIFIED_SOURCES += [
             'jit/shared/Assembler-x86-shared.cpp',
             'jit/shared/BaselineCompiler-x86-shared.cpp',
             'jit/shared/BaselineIC-x86-shared.cpp',
             'jit/shared/CodeGenerator-x86-shared.cpp',
             'jit/shared/Lowering-x86-shared.cpp',
             'jit/shared/MoveEmitter-x86-shared.cpp',
         ]
-        if CONFIG['TARGET_CPU'] == 'x86_64':
+        if CONFIG['JS_CODEGEN_X64']:
             UNIFIED_SOURCES += [
                 'jit/x64/Assembler-x64.cpp',
                 'jit/x64/Bailouts-x64.cpp',
                 'jit/x64/BaselineCompiler-x64.cpp',
                 'jit/x64/BaselineIC-x64.cpp',
                 'jit/x64/CodeGenerator-x64.cpp',
                 'jit/x64/Lowering-x64.cpp',
                 'jit/x64/MacroAssembler-x64.cpp',
@@ -307,29 +307,33 @@ if CONFIG['ENABLE_ION']:
                 'jit/x86/Bailouts-x86.cpp',
                 'jit/x86/BaselineCompiler-x86.cpp',
                 'jit/x86/BaselineIC-x86.cpp',
                 'jit/x86/CodeGenerator-x86.cpp',
                 'jit/x86/Lowering-x86.cpp',
                 'jit/x86/MacroAssembler-x86.cpp',
                 'jit/x86/Trampoline-x86.cpp',
             ]
-    elif CONFIG['TARGET_CPU'].find('arm') != -1:
+    elif CONFIG['JS_CODEGEN_ARM']:
         UNIFIED_SOURCES += [
             'jit/arm/Architecture-arm.cpp',
             'jit/arm/Assembler-arm.cpp',
             'jit/arm/Bailouts-arm.cpp',
             'jit/arm/BaselineCompiler-arm.cpp',
             'jit/arm/BaselineIC-arm.cpp',
             'jit/arm/CodeGenerator-arm.cpp',
             'jit/arm/Lowering-arm.cpp',
             'jit/arm/MacroAssembler-arm.cpp',
             'jit/arm/MoveEmitter-arm.cpp',
             'jit/arm/Trampoline-arm.cpp',
         ]
+        if CONFIG['JS_ARM_SIMULATOR']:
+            UNIFIED_SOURCES += [
+                'jit/arm/Simulator-arm.cpp'
+            ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     SOURCES += [
         'assembler/jit/ExecutableAllocatorWin.cpp',
         'yarr/OSAllocatorWin.cpp',
     ]
 elif CONFIG['OS_ARCH'] == 'OS2':
     SOURCES += [
@@ -338,21 +342,21 @@ elif CONFIG['OS_ARCH'] == 'OS2':
     ]
 else:
     SOURCES += [
         'assembler/jit/ExecutableAllocatorPosix.cpp',
         'yarr/OSAllocatorPosix.cpp',
     ]
 
 if CONFIG['ENABLE_ION'] or CONFIG['ENABLE_YARR_JIT']:
-    if '86' in CONFIG['TARGET_CPU']:
+    if CONFIG['JS_CODEGEN_X86'] or CONFIG['JS_CODEGEN_X64']:
         SOURCES += [
             'assembler/assembler/MacroAssemblerX86Common.cpp',
         ]
-    elif CONFIG['CPU_ARCH'] == 'arm':
+    elif CONFIG['JS_CODEGEN_ARM']:
         SOURCES += [
             'assembler/assembler/ARMAssembler.cpp',
             'assembler/assembler/MacroAssemblerARM.cpp',
         ]
 
 if CONFIG['ENABLE_YARR_JIT']:
     SOURCES += [
         'yarr/YarrJIT.cpp'
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -5896,22 +5896,22 @@ main(int argc, char **argv, char **envp)
 #ifdef DEBUG
     /*
      * Process OOM options as early as possible so that we can observe as many
      * allocations as possible.
      */
     if (op.getBoolOption('O'))
         OOM_printAllocationCount = true;
 
-#if defined(JS_CPU_X86) && defined(JS_ION)
+#if defined(JS_CODEGEN_X86) && defined(JS_ION)
     if (op.getBoolOption("no-fpu"))
         JSC::MacroAssembler::SetFloatingPointDisabled();
 #endif
 
-#if (defined(JS_CPU_X86) || defined(JS_CPU_X64)) && defined(JS_ION)
+#if (defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)) && defined(JS_ION)
     if (op.getBoolOption("no-sse3")) {
         JSC::MacroAssembler::SetSSE3Disabled();
         PropagateFlagToNestedShells("--no-sse3");
     }
     if (op.getBoolOption("no-sse4")) {
         JSC::MacroAssembler::SetSSE4Disabled();
         PropagateFlagToNestedShells("--no-sse4");
     }
--- a/js/src/vm/Probes-inl.h
+++ b/js/src/vm/Probes-inl.h
@@ -49,17 +49,17 @@ probes::EnterScript(JSContext *cx, JSScr
         DTraceEnterJSFun(cx, maybeFun, script);
 #endif
 #ifdef MOZ_TRACE_JSCALLS
     cx->doFunctionCallback(maybeFun, script, 1);
 #endif
 
     JSRuntime *rt = cx->runtime();
     if (rt->spsProfiler.enabled()) {
-        rt->spsProfiler.enter(cx, script, maybeFun);
+        rt->spsProfiler.enter(script, maybeFun);
         JS_ASSERT_IF(!fp->isGeneratorFrame(), !fp->hasPushedSPSFrame());
         fp->setPushedSPSFrame();
     }
 
     return ok;
 }
 
 inline bool
@@ -71,17 +71,17 @@ probes::ExitScript(JSContext *cx, JSScri
     if (JAVASCRIPT_FUNCTION_RETURN_ENABLED())
         DTraceExitJSFun(cx, maybeFun, script);
 #endif
 #ifdef MOZ_TRACE_JSCALLS
     cx->doFunctionCallback(maybeFun, script, 0);
 #endif
 
     if (popSPSFrame)
-        cx->runtime()->spsProfiler.exit(cx, script, maybeFun);
+        cx->runtime()->spsProfiler.exit(script, maybeFun);
 
     return ok;
 }
 
 inline bool
 probes::StartExecution(JSScript *script)
 {
     bool ok = true;
--- a/js/src/vm/SPSProfiler.cpp
+++ b/js/src/vm/SPSProfiler.cpp
@@ -4,16 +4,17 @@
  * 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 "vm/SPSProfiler.h"
 
 #include "mozilla/DebugOnly.h"
 
 #include "jsnum.h"
+#include "jsprf.h"
 #include "jsscript.h"
 
 #include "jit/BaselineJIT.h"
 #include "vm/StringBuffer.h"
 
 using namespace js;
 
 using mozilla::DebugOnly;
@@ -22,29 +23,38 @@ SPSProfiler::SPSProfiler(JSRuntime *rt)
   : rt(rt),
     stack_(nullptr),
     size_(nullptr),
     max_(0),
     slowAssertions(false),
     enabled_(false)
 {
     JS_ASSERT(rt != nullptr);
+#ifdef JS_THREADSAFE
+    lock_ = PR_NewLock();
+    if (lock_ == nullptr)
+        MOZ_CRASH("Couldn't allocate lock!");
+#endif
 }
 
 SPSProfiler::~SPSProfiler()
 {
     if (strings.initialized()) {
         for (ProfileStringMap::Enum e(strings); !e.empty(); e.popFront())
             js_free(const_cast<char *>(e.front().value()));
     }
+#ifdef JS_THREADSAFE
+    PR_DestroyLock(lock_);
+#endif
 }
 
 void
 SPSProfiler::setProfilingStack(ProfileEntry *stack, uint32_t *size, uint32_t max)
 {
+    AutoSPSLock lock(lock_);
     JS_ASSERT_IF(size_ && *size_ != 0, !enabled());
     if (!strings.initialized())
         strings.init();
     stack_ = stack;
     size_  = size;
     max_   = max;
 }
 
@@ -71,23 +81,24 @@ SPSProfiler::enable(bool enabled)
      * their profiler state toggled so they behave properly.
      */
     jit::ToggleBaselineSPS(rt, enabled);
 #endif
 }
 
 /* Lookup the string for the function/script, creating one if necessary */
 const char*
-SPSProfiler::profileString(JSContext *cx, JSScript *script, JSFunction *maybeFun)
+SPSProfiler::profileString(JSScript *script, JSFunction *maybeFun)
 {
+    AutoSPSLock lock(lock_);
     JS_ASSERT(strings.initialized());
     ProfileStringMap::AddPtr s = strings.lookupForAdd(script);
     if (s)
         return s->value();
-    const char *str = allocProfileString(cx, script, maybeFun);
+    const char *str = allocProfileString(script, maybeFun);
     if (str == nullptr)
         return nullptr;
     if (!strings.add(s, script, str)) {
         js_free(const_cast<char *>(str));
         return nullptr;
     }
     return str;
 }
@@ -97,47 +108,48 @@ SPSProfiler::onScriptFinalized(JSScript 
 {
     /*
      * This function is called whenever a script is destroyed, regardless of
      * whether profiling has been turned on, so don't invoke a function on an
      * invalid hash set. Also, even if profiling was enabled but then turned
      * off, we still want to remove the string, so no check of enabled() is
      * done.
      */
+    AutoSPSLock lock(lock_);
     if (!strings.initialized())
         return;
     if (ProfileStringMap::Ptr entry = strings.lookup(script)) {
         const char *tofree = entry->value();
         strings.remove(entry);
         js_free(const_cast<char *>(tofree));
     }
 }
 
 bool
-SPSProfiler::enter(JSContext *cx, JSScript *script, JSFunction *maybeFun)
+SPSProfiler::enter(JSScript *script, JSFunction *maybeFun)
 {
-    const char *str = profileString(cx, script, maybeFun);
+    const char *str = profileString(script, maybeFun);
     if (str == nullptr)
         return false;
 
     JS_ASSERT_IF(*size_ > 0 && *size_ - 1 < max_ && stack_[*size_ - 1].js(),
                  stack_[*size_ - 1].pc() != nullptr);
     push(str, nullptr, script, script->code());
     return true;
 }
 
 void
-SPSProfiler::exit(JSContext *cx, JSScript *script, JSFunction *maybeFun)
+SPSProfiler::exit(JSScript *script, JSFunction *maybeFun)
 {
     pop();
 
 #ifdef DEBUG
     /* Sanity check to make sure push/pop balanced */
     if (*size_ < max_) {
-        const char *str = profileString(cx, script, maybeFun);
+        const char *str = profileString(script, maybeFun);
         /* Can't fail lookup because we should already be in the set */
         JS_ASSERT(str != nullptr);
 
         // Bug 822041
         if (!stack_[*size_].js()) {
             fprintf(stderr, "--- ABOUT TO FAIL ASSERTION ---\n");
             fprintf(stderr, " stack=%p size=%d/%d\n", (void*) stack_, *size_, max_);
             for (int32_t i = *size_; i >= 0; i--) {
@@ -202,54 +214,63 @@ SPSProfiler::pop()
 }
 
 /*
  * Serializes the script/function pair into a "descriptive string" which is
  * allowed to fail. This function cannot trigger a GC because it could finalize
  * some scripts, resize the hash table of profile strings, and invalidate the
  * AddPtr held while invoking allocProfileString.
  */
-const char*
-SPSProfiler::allocProfileString(JSContext *cx, JSScript *script, JSFunction *maybeFun)
+const char *
+SPSProfiler::allocProfileString(JSScript *script, JSFunction *maybeFun)
 {
     // Note: this profiler string is regexp-matched by
     // browser/devtools/profiler/cleopatra/js/parserWorker.js.
-    DebugOnly<uint64_t> gcBefore = cx->runtime()->gcNumber;
-    StringBuffer buf(cx);
-    bool hasAtom = maybeFun != nullptr && maybeFun->displayAtom() != nullptr;
+
+    // Determine if the function (if any) has an explicit or guessed name.
+    bool hasAtom = maybeFun && maybeFun->displayAtom();
+
+    // Get the function name, if any, and its length.
+    const jschar *atom = nullptr;
+    size_t lenAtom = 0;
     if (hasAtom) {
-        if (!buf.append(maybeFun->displayAtom()))
-            return nullptr;
-        if (!buf.append(" ("))
-            return nullptr;
+        atom = maybeFun->displayAtom()->charsZ();
+        lenAtom = maybeFun->displayAtom()->length();
     }
-    if (script->filename()) {
-        if (!buf.appendInflated(script->filename(), strlen(script->filename())))
-            return nullptr;
-    } else if (!buf.append("<unknown>")) {
-        return nullptr;
-    }
-    if (!buf.append(":"))
-        return nullptr;
-    if (!NumberValueToStringBuffer(cx, NumberValue(script->lineno()), buf))
-        return nullptr;
-    if (hasAtom && !buf.append(")"))
-        return nullptr;
+
+    // Get the script filename, if any, and its length.
+    const char *filename = script->filename();
+    if (filename == nullptr)
+        filename = "<unknown>";
+    size_t lenFilename = strlen(filename);
 
-    size_t len = buf.length();
+    // Get the line number and its length as a string.
+    uint64_t lineno = script->lineno();
+    size_t lenLineno = 1;
+    for (uint64_t i = lineno; i /= 10; lenLineno++);
+
+    // Determine the required buffer size.
+    size_t len = lenFilename + lenLineno + 1; // +1 for the ":" separating them.
+    if (hasAtom)
+        len += lenAtom + 3; // +3 for the " (" and ")" it adds.
+
+    // Allocate the buffer.
     char *cstr = js_pod_malloc<char>(len + 1);
     if (cstr == nullptr)
         return nullptr;
 
-    const jschar *ptr = buf.begin();
-    for (size_t i = 0; i < len; i++)
-        cstr[i] = ptr[i];
-    cstr[len] = 0;
+    // Construct the descriptive string.
+    size_t ret;
+    if (hasAtom)
+        ret = JS_snprintf(cstr, len + 1, "%hs (%s:%llu)", atom, filename, lineno);
+    else
+        ret = JS_snprintf(cstr, len + 1, "%s:%llu", filename, lineno);
 
-    JS_ASSERT(gcBefore == cx->runtime()->gcNumber);
+    MOZ_ASSERT(ret == len, "Computed length should match actual length!");
+
     return cstr;
 }
 
 SPSEntryMarker::SPSEntryMarker(JSRuntime *rt
                                MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
     : profiler(&rt->spsProfiler)
 {
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
--- a/js/src/vm/SPSProfiler.h
+++ b/js/src/vm/SPSProfiler.h
@@ -7,16 +7,17 @@
 #ifndef vm_SPSProfiler_h
 #define vm_SPSProfiler_h
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/GuardObjects.h"
 
 #include <stddef.h>
 
+#include "jslock.h"
 #include "jsscript.h"
 
 #include "js/ProfilingStack.h"
 
 /*
  * SPS Profiler integration with the JS Engine
  * https://developer.mozilla.org/en/Performance/Profiling_with_the_Built-in_Profiler
  *
@@ -118,19 +119,19 @@ class SPSProfiler
 
     JSRuntime            *rt;
     ProfileStringMap     strings;
     ProfileEntry         *stack_;
     uint32_t             *size_;
     uint32_t             max_;
     bool                 slowAssertions;
     uint32_t             enabled_;
+    PRLock               *lock_;
 
-    const char *allocProfileString(JSContext *cx, JSScript *script,
-                                   JSFunction *function);
+    const char *allocProfileString(JSScript *script, JSFunction *function);
     void push(const char *string, void *sp, JSScript *script, jsbytecode *pc);
     void pop();
 
   public:
     SPSProfiler(JSRuntime *rt);
     ~SPSProfiler();
 
     uint32_t **addressOfSizePointer() {
@@ -160,46 +161,83 @@ class SPSProfiler
      * Functions which are the actual instrumentation to track run information
      *
      *   - enter: a function has started to execute
      *   - updatePC: updates the pc information about where a function
      *               is currently executing
      *   - exit: this function has ceased execution, and no further
      *           entries/exits will be made
      */
-    bool enter(JSContext *cx, JSScript *script, JSFunction *maybeFun);
-    void exit(JSContext *cx, JSScript *script, JSFunction *maybeFun);
+    bool enter(JSScript *script, JSFunction *maybeFun);
+    void exit(JSScript *script, JSFunction *maybeFun);
     void updatePC(JSScript *script, jsbytecode *pc) {
         if (enabled() && *size_ - 1 < max_) {
             JS_ASSERT(*size_ > 0);
             JS_ASSERT(stack_[*size_ - 1].script() == script);
             stack_[*size_ - 1].setPC(pc);
         }
     }
 
     /* Enter a C++ function. */
     void enterNative(const char *string, void *sp);
     void exitNative() { pop(); }
 
     jsbytecode *ipToPC(JSScript *script, size_t ip) { return nullptr; }
 
     void setProfilingStack(ProfileEntry *stack, uint32_t *size, uint32_t max);
-    const char *profileString(JSContext *cx, JSScript *script, JSFunction *maybeFun);
+    const char *profileString(JSScript *script, JSFunction *maybeFun);
     void onScriptFinalized(JSScript *script);
 
     /* meant to be used for testing, not recommended to call in normal code */
-    size_t stringsCount() { return strings.count(); }
-    void stringsReset() { strings.clear(); }
+    size_t stringsCount();
+    void stringsReset();
 
     uint32_t *addressOfEnabled() {
         return &enabled_;
     }
 };
 
 /*
+ * This class is used to make sure the strings table
+ * is only accessed on one thread at a time.
+ */
+class AutoSPSLock
+{
+  public:
+#ifdef JS_THREADSAFE
+    AutoSPSLock(PRLock *lock)
+    {
+        MOZ_ASSERT(lock, "Parameter should not be null!");
+        lock_ = lock;
+        PR_Lock(lock);
+    }
+    ~AutoSPSLock() { PR_Unlock(lock_); }
+#else
+    AutoSPSLock(PRLock *) {}
+#endif
+
+  private:
+    PRLock *lock_;
+};
+
+inline size_t
+SPSProfiler::stringsCount()
+{
+    AutoSPSLock lock(lock_);
+    return strings.count();
+}
+
+inline void
+SPSProfiler::stringsReset()
+{
+    AutoSPSLock lock(lock_);
+    strings.clear();
+}
+
+/*
  * This class is used in RunScript() to push the marker onto the sampling stack
  * that we're about to enter JS function calls. This is the only time in which a
  * valid stack pointer is pushed to the sampling stack.
  */
 class SPSEntryMarker
 {
   public:
     SPSEntryMarker(JSRuntime *rt
@@ -249,17 +287,16 @@ class SPSInstrumentation
       : profiler_(profiler), frame(nullptr)
     {
         enterInlineFrame();
     }
 
     /* Small proxies around SPSProfiler */
     bool enabled() { return profiler_ && profiler_->enabled(); }
     SPSProfiler *profiler() { JS_ASSERT(enabled()); return profiler_; }
-    bool slowAssertions() { return enabled() && profiler_->slowAssertionsEnabled(); }
 
     /* Signals an inline function returned, reverting to the previous state */
     void leaveInlineFrame() {
         if (!enabled())
             return;
         JS_ASSERT(frame->left == 0);
         JS_ASSERT(frame->script != nullptr);
         frames.shrinkBy(1);
@@ -315,21 +352,20 @@ class SPSInstrumentation
         JS_ASSERT(frame->left == 0);
         frame->script = script;
     }
 
     /*
      * Flags entry into a JS function for the first time. Before this is called,
      * no instrumentation is emitted, but after this instrumentation is emitted.
      */
-    bool push(JSContext *cx, JSScript *script, Assembler &masm, Register scratch) {
+    bool push(JSScript *script, Assembler &masm, Register scratch) {
         if (!enabled())
             return true;
-        const char *string = profiler_->profileString(cx, script,
-                                                      script->functionNonDelazifying());
+        const char *string = profiler_->profileString(script, script->functionNonDelazifying());
         if (string == nullptr)
             return false;
         masm.spsPushFrame(profiler_, string, script, scratch);
         setPushed(script);
         return true;
     }
 
     /*
--- a/js/src/vm/Shape.cpp
+++ b/js/src/vm/Shape.cpp
@@ -1616,17 +1616,18 @@ class InitialShapeSetRef : public Buffer
     {}
 
     void mark(JSTracer *trc) {
         TaggedProto priorProto = proto;
         JSObject *priorParent = parent;
         JSObject *priorMetadata = metadata;
         if (proto.isObject())
             Mark(trc, reinterpret_cast<JSObject**>(&proto), "initialShapes set proto");
-        Mark(trc, &parent, "initialShapes set parent");
+        if (parent)
+            Mark(trc, &parent, "initialShapes set parent");
         if (metadata)
             Mark(trc, &metadata, "initialShapes set metadata");
         if (proto == priorProto && parent == priorParent && metadata == priorMetadata)
             return;
 
         /* Find the original entry, which must still be present. */
         InitialShapeEntry::Lookup lookup(clasp, priorProto,
                                          priorParent, parent,
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -2,16 +2,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/. */
 
 /* rendering object for list-item bullets */
 
 #include "nsBulletFrame.h"
 
+#include "mozilla/MathAlgorithms.h"
 #include "nsCOMPtr.h"
 #include "nsGkAtoms.h"
 #include "nsGenericHTMLElement.h"
 #include "nsAttrValueInlines.h"
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "nsIDocument.h"
 #include "nsRenderingContext.h"
@@ -892,28 +893,26 @@ static const CJKIdeographicData gDataTra
     0x4f0d, 0x9678, 0x67d2, 0x634c, 0x7396
   },
   { 0x62fe, 0x4f70, 0x4edf }, // unit
   { 0x842c, 0x5104 },         // unit10K
   CHINESE,                    // lang
   false                       // informal
 };
 
-static const bool CJKIdeographicToText(int32_t ordinal, nsString& result,
+static const bool CJKIdeographicToText(int32_t aOrdinal, nsString& result,
                                        const CJKIdeographicData& data)
 {
   char16_t buf[NUM_BUF_SIZE];
   int32_t idx = NUM_BUF_SIZE;
   int32_t pos = 0;
-  bool isNegative = (ordinal < 0);
-  bool needZero = (ordinal == 0);
+  bool isNegative = (aOrdinal < 0);
+  bool needZero = (aOrdinal == 0);
   int32_t unitidx = 0, unit10Kidx = 0;
-  if (isNegative) {
-    ordinal = -ordinal;
-  }
+  uint32_t ordinal = mozilla::Abs(aOrdinal);
   do {
     unitidx = pos % 4;
     if (unitidx == 0) {
       unit10Kidx = pos / 4;
     }
     int32_t cur = ordinal % 10;
     if (cur == 0) {
       if (needZero) {
--- a/layout/mathml/nsMathMLmmultiscriptsFrame.cpp
+++ b/layout/mathml/nsMathMLmmultiscriptsFrame.cpp
@@ -352,18 +352,17 @@ nsMathMLmmultiscriptsFrame::PlaceMultiSc
         // If italics correction is applied, we always add "a little to spare"
         // (see TeXbook Ch.11, p.64), as we estimate the italic creation
         // ourselves and it isn't the same as TeX.
         italicCorrection += onePixel;
       }
 
       // we update boundingMetrics.{ascent,descent} with that
       // of the baseFrame only after processing all the sup/sub pairs
-      // XXX need italic correction only *if* there are postscripts ?
-      boundingMetrics.width = bmBase.width + italicCorrection;
+      boundingMetrics.width = bmBase.width;
       boundingMetrics.rightBearing = bmBase.rightBearing;
       boundingMetrics.leftBearing = bmBase.leftBearing; // until overwritten
     } else {
       // super/subscript block
       if ( childTag == nsGkAtoms::none) {
         foundNoneTag = true;
       }
 
@@ -420,19 +419,20 @@ nsMathMLmmultiscriptsFrame::PlaceMultiSc
         bmMultiSup.ascent = std::max(bmMultiSup.ascent, bmSupScript.ascent);
         bmMultiSup.descent = std::max(bmMultiSup.descent, bmSupScript.descent);
         multiSupSize.Height() = 
           std::max(multiSupSize.Height(),
                    supScriptSize.Height() - supScriptSize.TopAscent());
 
         if (bmSupScript.width)
           width = std::max(width, bmSupScript.width + aScriptSpace);
-        rightBearing = std::max(rightBearing, bmSupScript.rightBearing);
 
         if (!prescriptsFrame) { // we are still looping over base & postscripts
+          rightBearing = std::max(rightBearing,
+                                  italicCorrection + bmSupScript.rightBearing);
           boundingMetrics.rightBearing = boundingMetrics.width + rightBearing;
           boundingMetrics.width += width;
         } else {
           prescriptsWidth += width;
           if (firstPrescriptsPair) {
             firstPrescriptsPair = false;
             boundingMetrics.leftBearing =
               std::min(bmSubScript.leftBearing, bmSupScript.leftBearing);
@@ -565,17 +565,17 @@ nsMathMLmmultiscriptsFrame::PlaceMultiSc
         // place the base ...
         childFrame = baseFrame;
         dy = aDesiredSize.TopAscent() - baseSize.TopAscent();
         FinishReflowChild (baseFrame, aPresContext, baseSize, nullptr,
                            aFrame->MirrorIfRTL(aDesiredSize.Width(),
                                                baseSize.Width(),
                                                dx),
                            dy, 0);
-        dx += bmBase.width + italicCorrection;
+        dx += bmBase.width;
       } else if (prescriptsFrame != childFrame) {
         // process each sup/sub pair
         if (0 == count) {
           subScriptFrame = childFrame;
           count = 1;
         } else if (1 == count) {
           if (tag != nsGkAtoms::msub_)
             supScriptFrame = childFrame;
@@ -603,18 +603,22 @@ nsMathMLmmultiscriptsFrame::PlaceMultiSc
                                aFrame->MirrorIfRTL(aDesiredSize.Width(),
                                                    subScriptSize.Width(),
                                                    x),
                                dy, 0);
           }
 
           if (supScriptFrame) {
             nscoord x = dx;
-            if (isPreScript)
+            if (isPreScript) {
               x += width - supScriptSize.Width();
+            } else {
+              // post superscripts are shifted by the italic correction value
+              x += italicCorrection;
+            }
             dy = aDesiredSize.TopAscent() - supScriptSize.TopAscent() -
               maxSupScriptShift;
             FinishReflowChild (supScriptFrame, aPresContext, supScriptSize,
                                nullptr,
                                aFrame->MirrorIfRTL(aDesiredSize.Width(),
                                                    supScriptSize.Width(),
                                                    x),
                                dy, 0);
--- a/layout/reftests/mathml/multiscripts-1-ref.html
+++ b/layout/reftests/mathml/multiscripts-1-ref.html
@@ -53,23 +53,17 @@
     <math>
       <mrow style="background: red;">
         <mtext style="background-color: rgba(0, 0, 255, 0.4);">AAA</mtext>
       </mrow>
     </math>
 
     <br><br>
 
-    msup / msupsub:
-    <math>
-      <mmultiscripts style="background: red;">
-        <mtext style="background-color: rgba(0, 0, 255, 0.4);">AAA</mtext>
-      </mmultiscripts>
-    </math>
-
+    msupsub:
     <math>
       <mmultiscripts style="background: red;">
         <mtext style="background-color: rgba(0, 0, 255, 0.4);">AAA</mtext>
         <none />
         <none />
       </mmultiscripts>
     </math>
 
--- a/layout/reftests/mathml/multiscripts-1.html
+++ b/layout/reftests/mathml/multiscripts-1.html
@@ -53,24 +53,17 @@
       <msub style="background: red;">
         <mtext style="background-color: rgba(0, 0, 255, 0.4);">AAA</mtext>
         <mrow></mrow>
       </msub>
     </math>
 
     <br><br>
 
-    msup / msupsub:
-    <math>
-      <msup style="background: red;">
-        <mtext style="background-color: rgba(0, 0, 255, 0.4);">AAA</mtext>
-        <mrow></mrow>
-      </msup>
-    </math>
-
+    msupsub:
     <math>
       <msubsup style="background: red;">
         <mtext style="background-color: rgba(0, 0, 255, 0.4);">AAA</mtext>
         <mrow></mrow>
         <mrow></mrow>
       </msubsup>
     </math>
 
--- a/layout/reftests/mathml/reftest.list
+++ b/layout/reftests/mathml/reftest.list
@@ -150,16 +150,17 @@ fails == whitespace-trim-4.html whitespa
 == operator-1.xhtml operator-1-ref.xhtml
 == scriptshift-1.xhtml scriptshift-1-ref.xhtml
 == number-size-1.xhtml number-size-1-ref.xhtml
 == multiscripts-1.html multiscripts-1-ref.html
 == mathml-mmultiscript-base.html mathml-mmultiscript-base-ref.html
 == mathml-mmultiscript-mprescript.html mathml-mmultiscript-mprescript-ref.html
 != menclose-1.html menclose-1-ref.html
 == mmultiscript-align.html mmultiscript-align-ref.html
+== subscript-italic-correction.html subscript-italic-correction-ref.html
 == mathvariant-1a.html mathvariant-1a-ref.html
 == mathvariant-1b.html mathvariant-1b-ref.html
 == mathvariant-1c.html mathvariant-1c-ref.html
 == mathvariant-1d.html mathvariant-1d-ref.html
 == mathvariant-2.html mathvariant-2-ref.html
 == mathvariant-3.html mathvariant-3-ref.html
 == mathvariant-4.html mathvariant-4-ref.html
 == mathvariant-5.html mathvariant-5-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/mathml/subscript-italic-correction-ref.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<html>
+  <head>
+    <title>subscript</title>
+    <meta charset="utf-8"/>
+  </head>
+  <body style="background: #5f5; font-size: 50px;">
+
+    <div>
+      <math>
+        <msubsup>
+          <mi>f</mi>
+          <mspace id="s0" width="50px" height="50px" mathbackground="blue"/>
+          <mspace id="s1" width="50px" height="50px" mathbackground="blue"/>
+        </msubsup>
+      </math>
+    </div>
+
+    <br/>
+
+    <div>
+      <math>
+        <mmultiscripts>
+          <mi>f</mi>
+          <mspace id="s2" width="50px" height="50px" mathbackground="blue"/>
+          <mspace id="s3" width="50px" height="50px" mathbackground="blue"/>
+          <mspace id="s4" width="50px" height="50px" mathbackground="blue"/>
+          <mspace id="s5" width="50px" height="50px" mathbackground="blue"/>
+          <mspace id="s6" width="50px" height="50px" mathbackground="blue"/>
+          <mspace id="s7" width="50px" height="50px" mathbackground="blue"/>
+        </mmultiscripts>
+      </math>
+    </div>
+
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/mathml/subscript-italic-correction.html
@@ -0,0 +1,61 @@
+<!doctype html>
+<html class="reftest-wait">
+  <head>
+    <title>subscript</title>
+    <meta charset="utf-8"/>
+    <script type="text/javascript">
+      function verifyItalicCorrections()
+      {
+        var epsilon = 5;
+        for (var i = 0; i < 8; i += 2) {
+          var sub = document.getElementById("s" + i);
+          var sup = document.getElementById("s" + (i+1));
+          var italicCorrection =
+           sup.getBoundingClientRect().left - sub.getBoundingClientRect().left;
+           if (italicCorrection < epsilon) {
+             return false;
+           }
+        }
+        return true;
+      }
+
+      function doTest()
+      {
+        if (verifyItalicCorrections()) {
+          document.body.style.background = "#5f5";
+        }
+        document.documentElement.removeAttribute("class");
+      }
+      window.addEventListener("MozReftestInvalidate", doTest, false);
+    </script>
+  </head>
+  <body style="background: #f00; font-size: 50px;">
+
+    <div>
+      <math>
+        <msubsup>
+          <mi>f</mi>
+          <mspace id="s0" width="50px" height="50px" mathbackground="blue"/>
+          <mspace id="s1" width="50px" height="50px" mathbackground="blue"/>
+        </msubsup>
+      </math>
+    </div>
+
+    <br/>
+
+    <div>
+      <math>
+        <mmultiscripts>
+          <mi>f</mi>
+          <mspace id="s2" width="50px" height="50px" mathbackground="blue"/>
+          <mspace id="s3" width="50px" height="50px" mathbackground="blue"/>
+          <mspace id="s4" width="50px" height="50px" mathbackground="blue"/>
+          <mspace id="s5" width="50px" height="50px" mathbackground="blue"/>
+          <mspace id="s6" width="50px" height="50px" mathbackground="blue"/>
+          <mspace id="s7" width="50px" height="50px" mathbackground="blue"/>
+        </mmultiscripts>
+      </math>
+    </div>
+
+  </body>
+</html>
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -3842,16 +3842,22 @@ pref("print.postscript.print_command", "
 // 2. The parent of non-topmost panel is not activated when the panel is hidden.
 // So, we have no reasons we should use non-toplevel window for popup.
 pref("ui.panel.default_level_parent", true);
 
 pref("mousewheel.system_scroll_override_on_root_content.enabled", false);
 
 pref("ui.key.menuAccessKeyFocuses", true);
 
+#if MOZ_WIDGET_GTK == 2
+pref("intl.ime.use_simple_context_on_password_field", true);
+#else
+pref("intl.ime.use_simple_context_on_password_field", false);
+#endif
+
 # XP_UNIX
 #endif
 #endif
 #endif
 
 #if OS_ARCH==AIX
 
 // Override default Japanese fonts
--- a/testing/marionette/client/setup.py
+++ b/testing/marionette/client/setup.py
@@ -1,12 +1,12 @@
 import os
 from setuptools import setup, find_packages
 
-version = '0.7.2'
+version = '0.7.3'
 
 # get documentation from the README
 try:
     here = os.path.dirname(os.path.abspath(__file__))
     description = file(os.path.join(here, 'README.md')).read()
 except (OSError, IOError):
     description = ''
 
--- a/toolkit/components/places/mozIAsyncLivemarks.idl
+++ b/toolkit/components/places/mozIAsyncLivemarks.idl
@@ -7,65 +7,67 @@
 interface nsIURI;
 
 interface mozILivemarkCallback;
 interface mozILivemarkInfo;
 interface mozILivemark;
 
 interface nsINavHistoryResultObserver;
 
-[scriptable, uuid(1dbf174c-696e-4d9b-af0f-350da50d2249)]
+[scriptable, uuid(5B48E5A2-F07A-4E64-A935-C722A3D60B65)]
 interface mozIAsyncLivemarks : nsISupports
 {
   /**
    * Creates a new livemark
    *
    * @param aLivemarkInfo
    *        mozILivemarkInfo object containing at least title, parentId,
    *        index and feedURI of the livemark to create.
    * @param [optional] aCallback
    *        Invoked when the creation process is done.  In case of failure will
    *        receive an error code.
-   *
+   * @return {Promise}
    * @throws NS_ERROR_INVALID_ARG if the supplied information is insufficient
    *         for the creation.
    */
-  void addLivemark(in jsval aLivemarkInfo,
-                   [optional]in mozILivemarkCallback aCallback);
+  jsval addLivemark(in jsval aLivemarkInfo,
+                    [optional] in mozILivemarkCallback aCallback);
 
   /**
    * Removes an existing livemark.
    *
    * @param aLivemarkInfo
    *        mozILivemarkInfo object containing either an id or a guid of the
    *        livemark to remove.
    * @param [optional] aCallback
    *        Invoked when the removal process is done.  In case of failure will
    *        receive an error code.
    *
+   * @return {Promise}
    * @throws NS_ERROR_INVALID_ARG if the id/guid is invalid.
    */
-  void removeLivemark(in jsval aLivemarkInfo,
-                      [optional]in mozILivemarkCallback aCallback);
+  jsval removeLivemark(in jsval aLivemarkInfo,
+                       [optional] in mozILivemarkCallback aCallback);
 
   /**
    * Gets an existing livemark.
    *
    * @param aLivemarkInfo
    *        mozILivemarkInfo object containing either an id or a guid of the
    *        livemark to retrieve.
-   * @param aCallback
+   * @param [optional] aCallback
    *        Invoked when the fetching process is done.  In case of failure will
    *        receive an error code.
    *
+   * @return {Promise}
    * @throws NS_ERROR_INVALID_ARG if the id/guid is invalid or an invalid
    *         callback is provided.
    */
-  void getLivemark(in jsval aLivemarkInfo,
-                   in mozILivemarkCallback aCallback);
+  jsval getLivemark(in jsval aLivemarkInfo,
+                    [optional] in mozILivemarkCallback aCallback);
 
   /**
    * Reloads all livemarks if they are expired or if forced to do so.
    *
    * @param [optional]aForceUpdate
    *        If set to true forces a reload even if contents are still valid.
    *
    * @note The update process is asynchronous, observers registered through
--- a/toolkit/components/places/nsLivemarkService.js
+++ b/toolkit/components/places/nsLivemarkService.js
@@ -11,16 +11,18 @@ const Cu = Components.utils;
 //// Modules
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
                                   "resource://gre/modules/PlacesUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Promise",
+                                  "resource://gre/modules/Promise.jsm");
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Services
 
 XPCOMUtils.defineLazyServiceGetter(this, "secMan",
                                    "@mozilla.org/scriptsecuritymanager;1",
                                    "nsIScriptSecurityManager");
 XPCOMUtils.defineLazyGetter(this, "asyncHistory", function () {
@@ -44,17 +46,17 @@ const ONERROR_EXPIRE_TIME_MS = 300000; /
 
 ////////////////////////////////////////////////////////////////////////////////
 //// LivemarkService
 
 function LivemarkService()
 {
   // Cleanup on shutdown.
   Services.obs.addObserver(this, PlacesUtils.TOPIC_SHUTDOWN, true);
- 
+
   // Observe bookmarks and history, but don't init the services just for that.
   PlacesUtils.addLazyBookmarkObserver(this, true);
 
   // Asynchronously build the livemarks cache.
   this._ensureAsynchronousCache();
 }
 
 LivemarkService.prototype = {
@@ -97,17 +99,17 @@ LivemarkService.prototype = {
       handleResult: function LS_handleResult(aResults)
       {
         for (let row = aResults.getNextRow(); row; row = aResults.getNextRow()) {
           let id = row.getResultByName("id");
           let siteURL = row.getResultByName("siteURI");
           let guid = row.getResultByName("guid");
           livemarkSvc._livemarks[id] =
             new Livemark({ id: id,
-                           guid: guid,             
+                           guid: guid,
                            title: row.getResultByName("title"),
                            parentId: row.getResultByName("parent"),
                            index: row.getResultByName("position"),
                            lastModified: row.getResultByName("lastModified"),
                            feedURI: NetUtil.newURI(row.getResultByName("feedURI")),
                            siteURI: siteURL ? NetUtil.newURI(siteURL) : null,
             });
           livemarkSvc._guids[guid] = id;
@@ -208,17 +210,18 @@ LivemarkService.prototype = {
         (aLivemarkInfo.siteURI && !(aLivemarkInfo.siteURI instanceof Ci.nsIURI)) ||
         (aLivemarkInfo.guid && !/^[a-zA-Z0-9\-_]{12}$/.test(aLivemarkInfo.guid))) {
       throw Cr.NS_ERROR_INVALID_ARG;
     }
 
     // The addition is done synchronously due to the fact importExport service
     // and JSON backups require that.  The notification is async though.
     // Once bookmarks are async, this may be properly fixed.
-    let result = Cr.NS_OK;
+    let deferred = Promise.defer();
+    let addLivemarkEx = null;
     let livemark = null;
     try {
       // Disallow adding a livemark inside another livemark.
       if (aLivemarkInfo.parentId in this._livemarks) {
         throw new Components.Exception("", Cr.NS_ERROR_INVALID_ARG);
       }
 
       // Don't pass unexpected input data to the livemark constructor.
@@ -241,28 +244,43 @@ LivemarkService.prototype = {
       }
 
       // Updating the cache even if it has not yet been populated doesn't
       // matter since it will just be overwritten.
       this._livemarks[livemark.id] = livemark;
       this._guids[aLivemarkInfo.guid] = livemark.id;
     }
     catch (ex) {
-      result = ex.result;
+      addLivemarkEx = ex;
       livemark = null;
     }
     finally {
-      if (aLivemarkCallback) {
-        this._onCacheReady(function LS_addLivemark_ETAT() {
-          try {
-            aLivemarkCallback.onCompletion(result, livemark);
-          } catch(ex2) {}
-        }, true);
-      }
+      this._onCacheReady( () => {
+        if (addLivemarkEx) {
+          if (aLivemarkCallback) {
+            try {
+              aLivemarkCallback.onCompletion(addLivemarkEx.result, livemark);
+            }
+            catch(ex2) { }
+          }
+          deferred.reject(ad