Merge m-i to m-c, a=merge
authorPhil Ringnalda <philringnalda@gmail.com>
Sat, 28 Jun 2014 17:39:03 -0700
changeset 213272 afa67a2f790564db49e3ccd9ad9d2d91c9524302
parent 213200 6ee5583b0fa6b4d6326205450370fea6bcbeea50 (current diff)
parent 213271 5c88c5b4fe0791233b30ba503739894aaea7ebf5 (diff)
child 213282 613ac64b87fe14560a7ecd21f501c6f44356f974
child 213323 5a63232687d10d0774032472ad8b0f5ee06885f4
child 213336 60468194f3d8b94df5c644b982621ba2948974e4
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone33.0a1
first release with
nightly linux32
afa67a2f7905 / 33.0a1 / 20140629030206 / files
nightly linux64
afa67a2f7905 / 33.0a1 / 20140629030206 / files
nightly mac
afa67a2f7905 / 33.0a1 / 20140629030206 / files
nightly win32
afa67a2f7905 / 33.0a1 / 20140629030206 / files
nightly win64
afa67a2f7905 / 33.0a1 / 20140629030206 / 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 m-i to m-c, a=merge
dom/interfaces/xpath/nsIDOMNSXPathExpression.idl
dom/interfaces/xpath/nsIDOMXPathExpression.idl
dom/xslt/xpath/nsXPathExpression.cpp
dom/xslt/xpath/nsXPathExpression.h
--- a/.hgignore
+++ b/.hgignore
@@ -66,8 +66,12 @@
 # git checkout of libstagefright
 ^media/libstagefright/android$
 
 # Tag files generated by GNU Global
 GTAGS
 GRTAGS
 GSYMS
 GPATH
+
+# Unit tests for Loop
+^browser/components/loop/standalone/content/config\.js$
+^browser/components/loop/standalone/node_modules/
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -46,17 +46,16 @@ class nsIDocShell;
 class nsIDocumentEncoder;
 class nsIDocumentObserver;
 class nsIDOMDocument;
 class nsIDOMDocumentFragment;
 class nsIDOMDocumentType;
 class nsIDOMElement;
 class nsIDOMNodeFilter;
 class nsIDOMNodeList;
-class nsIDOMXPathExpression;
 class nsIDOMXPathNSResolver;
 class nsIHTMLCollection;
 class nsILayoutHistoryState;
 class nsILoadContext;
 class nsIObjectLoadingContent;
 class nsIObserver;
 class nsIPresShell;
 class nsIPrincipal;
@@ -117,16 +116,17 @@ class NodeIterator;
 class ProcessingInstruction;
 class StyleSheetList;
 class SVGDocument;
 class Touch;
 class TouchList;
 class TreeWalker;
 class UndoManager;
 class XPathEvaluator;
+class XPathExpression;
 class XPathResult;
 template<typename> class OwningNonNull;
 template<typename> class Sequence;
 
 template<typename, typename> class CallbackObjectHolder;
 typedef CallbackObjectHolder<NodeFilter, nsIDOMNodeFilter> NodeFilterHolder;
 } // namespace dom
 } // namespace mozilla
@@ -2264,17 +2264,17 @@ public:
 
   // QuerySelector and QuerySelectorAll already defined on nsINode
   nsINodeList* GetAnonymousNodes(Element& aElement);
   Element* GetAnonymousElementByAttribute(Element& aElement,
                                           const nsAString& aAttrName,
                                           const nsAString& aAttrValue);
   Element* GetBindingParent(nsINode& aNode);
   void LoadBindingDocument(const nsAString& aURI, mozilla::ErrorResult& rv);
-  already_AddRefed<nsIDOMXPathExpression>
+  mozilla::dom::XPathExpression*
     CreateExpression(const nsAString& aExpression,
                      nsIDOMXPathNSResolver* aResolver,
                      mozilla::ErrorResult& rv);
   already_AddRefed<nsIDOMXPathNSResolver>
     CreateNSResolver(nsINode* aNodeResolver, mozilla::ErrorResult& rv);
   already_AddRefed<mozilla::dom::XPathResult>
     Evaluate(JSContext* aCx, const nsAString& aExpression, nsINode* aContextNode,
              nsIDOMXPathNSResolver* aResolver, uint16_t aType,
--- a/content/base/src/nsCSPParser.cpp
+++ b/content/base/src/nsCSPParser.cpp
@@ -325,17 +325,17 @@ nsCSPParser::subHost()
   uint32_t charCounter = 0;
 
   while (!atEnd() && !peek(COLON) && !peek(SLASH)) {
     ++charCounter;
     while (hostChar()) {
       /* consume */
       ++charCounter;
     }
-    if (accept(DOT) && !accept(isCharacterToken)) {
+    if (accept(DOT) && !hostChar()) {
       return false;
     }
     if (charCounter > kSubHostPathCharacterCutoff) {
       return false;
     }
   }
   return true;
 }
@@ -361,18 +361,18 @@ nsCSPParser::host()
     if (!accept(DOT)) {
       const char16_t* params[] = { mCurToken.get() };
       logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidHost",
                                params, ArrayLength(params));
       return nullptr;
     }
   }
 
-  // Expecting at least one Character
-  if (!accept(isCharacterToken)) {
+  // Expecting at least one host-char
+  if (!hostChar()) {
     const char16_t* params[] = { mCurToken.get() };
     logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidHost",
                              params, ArrayLength(params));
     return nullptr;
   }
 
   // There might be several sub hosts defined.
   if (!subHost()) {
@@ -679,16 +679,17 @@ nsCSPParser::sourceList(nsTArray<nsCSPBa
 {
   bool isNone = false;
 
   // remember, srcs start at index 1
   for (uint32_t i = 1; i < mCurDir.Length(); i++) {
     // mCurToken is only set here and remains the current token
     // to be processed, which avoid passing arguments between functions.
     mCurToken = mCurDir[i];
+    resetCurValue();
 
     CSPPARSERLOG(("nsCSPParser::sourceList, mCurToken: %s, mCurValue: %s",
                  NS_ConvertUTF16toUTF8(mCurToken).get(),
                  NS_ConvertUTF16toUTF8(mCurValue).get()));
 
     // Special case handling for none:
     // Ignore 'none' if any other src is available.
     // (See http://www.w3.org/TR/CSP11/#parsing)
--- a/content/base/src/nsCSPUtils.cpp
+++ b/content/base/src/nsCSPUtils.cpp
@@ -766,18 +766,19 @@ nsCSPPolicy::permits(nsContentPolicyType
   if (defaultDir) {
     if (!defaultDir->permits(aUri, aNonce)) {
       defaultDir->toString(outViolatedDirective);
       return false;
     }
     return true;
   }
 
-  // Didn't find a directive, load is not allowed.
-  return false;
+  // unspecified default-src should default to no restrictions
+  // see bug 764937
+  return true;
 }
 
 bool
 nsCSPPolicy::allows(nsContentPolicyType aContentType,
                     enum CSPKeyword aKeyword,
                     const nsAString& aHashOrNonce) const
 {
   CSPUTILSLOG(("nsCSPPolicy::allows, aKeyWord: %s, a HashOrNonce: %s",
--- a/content/base/src/nsDOMCaretPosition.cpp
+++ b/content/base/src/nsDOMCaretPosition.cpp
@@ -46,17 +46,17 @@ nsDOMCaretPosition::GetClientRect() cons
                                              mOffset,
                                              getter_AddRefs<nsRange>(domRange));
   if (!NS_SUCCEEDED(creationRv)) {
     return nullptr;
   }
 
   NS_ASSERTION(domRange, "unable to retrieve valid dom range from CaretPosition");
 
-  rect = domRange->GetBoundingClientRect();
+  rect = domRange->GetBoundingClientRect(false);
 
   return rect.forget();
 }
 
 JSObject*
 nsDOMCaretPosition::WrapObject(JSContext *aCx)
 {
   return mozilla::dom::CaretPositionBinding::Wrap(aCx, this);
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -97,17 +97,16 @@
 // for radio group stuff
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIRadioVisitor.h"
 #include "nsIFormControl.h"
 
 #include "nsBidiUtils.h"
 
 #include "nsIDOMUserDataHandler.h"
-#include "nsIDOMXPathExpression.h"
 #include "nsIDOMXPathNSResolver.h"
 #include "nsIParserService.h"
 #include "nsContentCreatorFunctions.h"
 
 #include "nsIScriptContext.h"
 #include "nsBindingManager.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsHTMLDocument.h"
@@ -12036,17 +12035,17 @@ nsIDocument::Constructor(const GlobalObj
   }
 
   nsCOMPtr<nsIDocument> doc = do_QueryInterface(document);
   doc->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE);
 
   return doc.forget();
 }
 
-already_AddRefed<nsIDOMXPathExpression>
+XPathExpression*
 nsIDocument::CreateExpression(const nsAString& aExpression,
                               nsIDOMXPathNSResolver* aResolver,
                               ErrorResult& rv)
 {
   return XPathEvaluator()->CreateExpression(aExpression, aResolver, rv);
 }
 
 already_AddRefed<nsIDOMXPathNSResolver>
@@ -12062,24 +12061,16 @@ nsIDocument::Evaluate(JSContext* aCx, co
                       uint16_t aType, JS::Handle<JSObject*> aResult,
                       ErrorResult& rv)
 {
   return XPathEvaluator()->Evaluate(aCx, aExpression, aContextNode, aResolver,
                                     aType, aResult, rv);
 }
 
 NS_IMETHODIMP
-nsDocument::CreateExpression(const nsAString& aExpression,
-                             nsIDOMXPathNSResolver* aResolver,
-                             nsIDOMXPathExpression** aResult)
-{
-  return XPathEvaluator()->CreateExpression(aExpression, aResolver, aResult);
-}
-
-NS_IMETHODIMP
 nsDocument::CreateNSResolver(nsIDOMNode* aNodeResolver,
                              nsIDOMXPathNSResolver** aResult)
 {
   return XPathEvaluator()->CreateNSResolver(aNodeResolver, aResult);
 }
 
 NS_IMETHODIMP
 nsDocument::Evaluate(const nsAString& aExpression, nsIDOMNode* aContextNode,
--- a/content/base/src/nsRange.cpp
+++ b/content/base/src/nsRange.cpp
@@ -2720,27 +2720,33 @@ nsRange::CreateContextualFragment(const 
   }
 
   return nsContentUtils::CreateContextualFragment(mStartParent, aFragment,
                                                   false, aRv);
 }
 
 static void ExtractRectFromOffset(nsIFrame* aFrame,
                                   const nsIFrame* aRelativeTo, 
-                                  const int32_t aOffset, nsRect* aR, bool aKeepLeft)
+                                  const int32_t aOffset, nsRect* aR, bool aKeepLeft,
+                                  bool aClampToEdge)
 {
   nsPoint point;
   aFrame->GetPointFromOffset(aOffset, &point);
 
   point += aFrame->GetOffsetTo(aRelativeTo);
 
-  //given a point.x, extract left or right portion of rect aR
-  //point.x has to be within this rect
-  NS_ASSERTION(aR->x <= point.x && point.x <= aR->XMost(),
-                   "point.x should not be outside of rect r");
+  if (!aClampToEdge && !aR->Contains(point)) {
+    aR->width = 0;
+    aR->x = point.x;
+    return;
+  }
+
+  if (aClampToEdge) {
+    point = aR->ClampPoint(point);
+  }
 
   if (aKeepLeft) {
     aR->width = point.x - aR->x;
   } else {
     aR->width = aR->XMost() - point.x;
     aR->x = point.x;
   }
 }
@@ -2757,50 +2763,52 @@ GetTextFrameForContent(nsIContent* aCont
     if (frame && frame->GetType() == nsGkAtoms::textFrame) {
       return static_cast<nsTextFrame*>(frame);
     }
   }
   return nullptr;
 }
 
 static nsresult GetPartialTextRect(nsLayoutUtils::RectCallback* aCallback,
-                                   nsIContent* aContent, int32_t aStartOffset, int32_t aEndOffset)
+                                   nsIContent* aContent, int32_t aStartOffset,
+                                   int32_t aEndOffset, bool aClampToEdge)
 {
   nsTextFrame* textFrame = GetTextFrameForContent(aContent);
   if (textFrame) {
     nsIFrame* relativeTo = nsLayoutUtils::GetContainingBlockForClientRect(textFrame);
     for (nsTextFrame* f = textFrame; f; f = static_cast<nsTextFrame*>(f->GetNextContinuation())) {
       int32_t fstart = f->GetContentOffset(), fend = f->GetContentEnd();
       if (fend <= aStartOffset || fstart >= aEndOffset)
         continue;
 
       // overlapping with the offset we want
       f->EnsureTextRun(nsTextFrame::eInflated);
       NS_ENSURE_TRUE(f->GetTextRun(nsTextFrame::eInflated), NS_ERROR_OUT_OF_MEMORY);
       bool rtl = f->GetTextRun(nsTextFrame::eInflated)->IsRightToLeft();
       nsRect r(f->GetOffsetTo(relativeTo), f->GetSize());
       if (fstart < aStartOffset) {
         // aStartOffset is within this frame
-        ExtractRectFromOffset(f, relativeTo, aStartOffset, &r, rtl);
+        ExtractRectFromOffset(f, relativeTo, aStartOffset, &r, rtl, aClampToEdge);
       }
       if (fend > aEndOffset) {
         // aEndOffset is in the middle of this frame
-        ExtractRectFromOffset(f, relativeTo, aEndOffset, &r, !rtl);
+        ExtractRectFromOffset(f, relativeTo, aEndOffset, &r, !rtl, aClampToEdge);
       }
       aCallback->AddRect(r);
     }
   }
   return NS_OK;
 }
 
 /* static */ void
 nsRange::CollectClientRects(nsLayoutUtils::RectCallback* aCollector,
                             nsRange* aRange,
                             nsINode* aStartParent, int32_t aStartOffset,
-                            nsINode* aEndParent, int32_t aEndOffset)
+                            nsINode* aEndParent, int32_t aEndOffset,
+                            bool aClampToEdge)
 {
   // Hold strong pointers across the flush
   nsCOMPtr<nsINode> startContainer = aStartParent;
   nsCOMPtr<nsINode> endContainer = aEndParent;
 
   // Flush out layout so our frames are up to date.
   if (!aStartParent->IsInDoc()) {
     return;
@@ -2827,17 +2835,17 @@ nsRange::CollectClientRects(nsLayoutUtil
         int32_t outOffset;
         nsIFrame* outFrame;
         textFrame->GetChildFrameContainingOffset(aStartOffset, false,
           &outOffset, &outFrame);
         if (outFrame) {
            nsIFrame* relativeTo =
              nsLayoutUtils::GetContainingBlockForClientRect(outFrame);
            nsRect r(outFrame->GetOffsetTo(relativeTo), outFrame->GetSize());
-           ExtractRectFromOffset(outFrame, relativeTo, aStartOffset, &r, false);
+           ExtractRectFromOffset(outFrame, relativeTo, aStartOffset, &r, false, aClampToEdge);
            r.width = 0;
            aCollector->AddRect(r);
         }
       }
     }
     return;
   }
 
@@ -2846,78 +2854,78 @@ nsRange::CollectClientRects(nsLayoutUtil
     iter.Next();
     nsCOMPtr<nsIContent> content = do_QueryInterface(node);
     if (!content)
       continue;
     if (content->IsNodeOfType(nsINode::eTEXT)) {
        if (node == startContainer) {
          int32_t offset = startContainer == endContainer ?
            aEndOffset : content->GetText()->GetLength();
-         GetPartialTextRect(aCollector, content, aStartOffset, offset);
+         GetPartialTextRect(aCollector, content, aStartOffset, offset, aClampToEdge);
          continue;
        } else if (node == endContainer) {
-         GetPartialTextRect(aCollector, content, 0, aEndOffset);
+         GetPartialTextRect(aCollector, content, 0, aEndOffset, aClampToEdge);
          continue;
        }
     }
 
     nsIFrame* frame = content->GetPrimaryFrame();
     if (frame) {
       nsLayoutUtils::GetAllInFlowRects(frame,
         nsLayoutUtils::GetContainingBlockForClientRect(frame), aCollector);
     }
   } while (!iter.IsDone());
 }
 
 NS_IMETHODIMP
 nsRange::GetBoundingClientRect(nsIDOMClientRect** aResult)
 {
-  *aResult = GetBoundingClientRect().take();
+  *aResult = GetBoundingClientRect(true).take();
   return NS_OK;
 }
 
 already_AddRefed<DOMRect>
-nsRange::GetBoundingClientRect()
+nsRange::GetBoundingClientRect(bool aClampToEdge)
 {
   nsRefPtr<DOMRect> rect = new DOMRect(ToSupports(this));
   if (!mStartParent) {
     return rect.forget();
   }
 
   nsLayoutUtils::RectAccumulator accumulator;
   CollectClientRects(&accumulator, this, mStartParent, mStartOffset, 
-    mEndParent, mEndOffset);
+    mEndParent, mEndOffset, aClampToEdge);
 
   nsRect r = accumulator.mResultRect.IsEmpty() ? accumulator.mFirstRect : 
     accumulator.mResultRect;
   rect->SetLayoutRect(r);
   return rect.forget();
 }
 
 NS_IMETHODIMP
 nsRange::GetClientRects(nsIDOMClientRectList** aResult)
 {
-  *aResult = GetClientRects().take();
+  *aResult = GetClientRects(true).take();
   return NS_OK;
 }
 
 already_AddRefed<DOMRectList>
-nsRange::GetClientRects()
+nsRange::GetClientRects(bool aClampToEdge)
 {
   if (!mStartParent) {
     return nullptr;
   }
 
   nsRefPtr<DOMRectList> rectList =
     new DOMRectList(static_cast<nsIDOMRange*>(this));
 
   nsLayoutUtils::RectListBuilder builder(rectList);
 
   CollectClientRects(&builder, this, mStartParent, mStartOffset, 
-    mEndParent, mEndOffset);
+    mEndParent, mEndOffset, aClampToEdge);
   return rectList.forget();
 }
 
 NS_IMETHODIMP
 nsRange::GetUsedFontFaces(nsIDOMFontFaceList** aResult)
 {
   *aResult = nullptr;
 
--- a/content/base/src/nsRange.h
+++ b/content/base/src/nsRange.h
@@ -212,18 +212,18 @@ public:
   void SelectNodeContents(nsINode& aNode, ErrorResult& aErr);
   void SetEnd(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr);
   void SetEndAfter(nsINode& aNode, ErrorResult& aErr);
   void SetEndBefore(nsINode& aNode, ErrorResult& aErr);
   void SetStart(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr);
   void SetStartAfter(nsINode& aNode, ErrorResult& aErr);
   void SetStartBefore(nsINode& aNode, ErrorResult& aErr);
   void SurroundContents(nsINode& aNode, ErrorResult& aErr);
-  already_AddRefed<DOMRect> GetBoundingClientRect();
-  already_AddRefed<DOMRectList> GetClientRects();
+  already_AddRefed<DOMRect> GetBoundingClientRect(bool aClampToEdge = true);
+  already_AddRefed<DOMRectList> GetClientRects(bool aClampToEdge = true);
 
   nsINode* GetParentObject() const { return mOwner; }
   virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE MOZ_FINAL;
 
 private:
   // no copy's or assigns
   nsRange(const nsRange&);
   nsRange& operator=(const nsRange&);
@@ -254,17 +254,18 @@ public:
                                      bool *outNodeAfter);
 
   static bool IsNodeSelected(nsINode* aNode, uint32_t aStartOffset,
                              uint32_t aEndOffset);
 
   static void CollectClientRects(nsLayoutUtils::RectCallback* aCollector,
                                  nsRange* aRange,
                                  nsINode* aStartParent, int32_t aStartOffset,
-                                 nsINode* aEndParent, int32_t aEndOffset);
+                                 nsINode* aEndParent, int32_t aEndOffset,
+                                 bool aClampToEdge);
 
   typedef nsTHashtable<nsPtrHashKey<nsRange> > RangeHashTable;
 protected:
   void RegisterCommonAncestor(nsINode* aNode);
   void UnregisterCommonAncestor(nsINode* aNode);
   nsINode* IsValidBoundary(nsINode* aNode);
 
   // CharacterDataChanged set aNotInsertedYet to true to disable an assertion
--- a/content/base/test/TestCSPParser.cpp
+++ b/content/base/test/TestCSPParser.cpp
@@ -390,16 +390,24 @@ nsresult TestSimplePolicies() {
     { " ; ; ; ;     default-src            abc    ; ; ; ;",
       "default-src http://abc" },
     { "script-src 'none' 'none' 'none';",
       "script-src 'none'" },
     { "script-src http://www.example.com/path-1//",
       "script-src http://www.example.com" },
     { "script-src http://www.example.com/path-1//path_2",
       "script-src http://www.example.com" },
+    { "default-src 127.0.0.1",
+      "default-src http://127.0.0.1" },
+    { "default-src 127.0.0.1:*",
+      "default-src http://127.0.0.1:*" },
+    { "default-src -; ",
+      "default-src http://-" },
+    { "script-src 1",
+      "script-src http://1" }
   };
 
   uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
   return runTestSuite(policies, policyCount, 1);
 }
 
 // ============================= TestPoliciesThatLogWarning ========================
 
@@ -427,18 +435,16 @@ nsresult TestBadPolicies() {
     { "default-src 'self", "" },
     { "script-sr 'self", "" },
     { "default-src 'unsafe-inlin' ", "" },
     { "default-src */", "" },
     { "default-src", "" },
     { "", "" },
     { "; ; ; ; ; ; ;", "" },
     { "defaut-src asdf", "" },
-    { "default-src -; ", "" },
-    { "script-src 1", "" },
     { "default-src: aaa", "" },
     { "default-src 'unsafe-inlin' ", "" },
     { "default-src :88", "" },
     { "script-src abc::::::88", "" },
     { "asdf http://test.com", ""},
     { "script-src *.*:*", "" },
     { "img-src *::88", "" },
     { "object-src http://localhost:", "" },
--- a/content/base/test/mochitest.ini
+++ b/content/base/test/mochitest.ini
@@ -533,16 +533,17 @@ skip-if = (buildapp == 'b2g' && toolkit 
 [test_bug811701.xhtml]
 [test_bug813919.html]
 [test_bug814576.html]
 [test_bug819051.html]
 [test_bug820909.html]
 [test_bug827160.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #needs plugin support # b2g(needs plugin support) b2g-debug(debug-only failure) b2g-desktop(needs plugin support)
 [test_bug840098.html]
+[test_bug864595.html]
 [test_bug868999.html]
 [test_bug869000.html]
 [test_bug869002.html]
 [test_bug869006.html]
 [test_bug876282.html]
 [test_bug890580.html]
 [test_bug891952.html]
 [test_bug894874.html]
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug864595.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=864595
+-->
+<head>
+  <title>Test for Bug 864595</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=864595">Mozilla Bug 864595</a>
+<div id='editable' style='display:inline-block;'>abcd  </div>
+<script type="application/javascript">
+/** Test for Bug 864595 **/
+var range = document.createRange();
+var elt = document.getElementById('editable');
+var eltRect = elt.getBoundingClientRect();
+
+var txtNode = elt.childNodes[0];
+range.setStart(txtNode, 0);
+range.setEnd(txtNode, 5);
+var rect = range.getBoundingClientRect();
+ok(rect.left >= eltRect.left && rect.right <= eltRect.right, "rect.left >= eltRect.left && rect.right <= eltRect.right");
+
+/* Put caret in the space */
+var caretPosX = rect.right + 10;
+var caretPosY = (rect.top + rect.bottom ) / 2;
+var caretRect = document.caretPositionFromPoint(caretPosX, caretPosY).getClientRect();
+ok(caretRect.right >= rect.right, "caretRect.right >= rect.right");
+
+</script>
+</body>
+</html>
--- a/content/media/fmp4/wmf/WMFMediaDataDecoder.h
+++ b/content/media/fmp4/wmf/WMFMediaDataDecoder.h
@@ -8,17 +8,19 @@
 #define WMFMediaDataDecoder_h_
 
 
 #include "WMF.h"
 #include "MP4Reader.h"
 #include "MFTDecoder.h"
 #include "mozilla/RefPtr.h"
 
-class mp4_demuxer::MP4Sample;
+namespace mp4_demuxer {
+class MP4Sample;
+}
 
 namespace mozilla {
 
 // Encapsulates the initialization of the MFTDecoder appropriate for decoding
 // a given stream, and the process of converting the IMFSample produced
 // by the MFT into a MediaData object.
 class WMFOutputSource {
 public:
--- a/content/xul/templates/src/nsXMLBinding.cpp
+++ b/content/xul/templates/src/nsXMLBinding.cpp
@@ -7,73 +7,45 @@
 #include "nsXULTemplateResultXML.h"
 #include "nsXMLBinding.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/XPathResult.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(nsXMLBindingSet)
-NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE(nsXMLBindingSet)
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLBindingSet)
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXMLBindingSet)
-  nsXMLBinding* binding = tmp->mFirst;
-  while (binding) {
-    binding->mExpr = nullptr;
-    binding = binding->mNext;
-  }
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXMLBindingSet)
-  nsXMLBinding* binding = tmp->mFirst;
-  while (binding) {
-    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "nsXMLBinding::mExpr"); 
-    cb.NoteXPCOMChild(binding->mExpr);
-    binding = binding->mNext;
-  }
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsXMLBindingSet, AddRef)
-NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsXMLBindingSet, Release)
-
 nsXMLBindingSet::~nsXMLBindingSet()
 {}
 
-nsresult
-nsXMLBindingSet::AddBinding(nsIAtom* aVar, nsIDOMXPathExpression* aExpr)
+void
+nsXMLBindingSet::AddBinding(nsIAtom* aVar, nsAutoPtr<XPathExpression>&& aExpr)
 {
-  nsAutoPtr<nsXMLBinding> newbinding(new nsXMLBinding(aVar, aExpr));
-  NS_ENSURE_TRUE(newbinding, NS_ERROR_OUT_OF_MEMORY);
+  nsAutoPtr<nsXMLBinding> newbinding(new nsXMLBinding(aVar, Move(aExpr)));
 
   if (mFirst) {
     nsXMLBinding* binding = mFirst;
 
     while (binding) {
       // if the target variable is already used in a binding, ignore it
       // since it won't be useful for anything
       if (binding->mVar == aVar)
-        return NS_OK;
+        return;
 
       // add the binding at the end of the list
       if (!binding->mNext) {
         binding->mNext = newbinding;
-        break;
+        return;
       }
 
       binding = binding->mNext;
     }
   }
   else {
     mFirst = newbinding;
   }
-
-  return NS_OK;
 }
 
 int32_t
 nsXMLBindingSet::LookupTargetIndex(nsIAtom* aTargetVariable,
                                    nsXMLBinding** aBinding)
 {
   int32_t idx = 0;
   nsXMLBinding* binding = mFirst;
@@ -97,49 +69,40 @@ nsXMLBindingValues::GetAssignmentFor(nsX
                                      int32_t aIndex,
                                      uint16_t aType)
 {
   XPathResult* value = mValues.SafeElementAt(aIndex);
   if (value) {
     return value;
   }
 
-  nsCOMPtr<nsIDOMNode> contextNode;
-  aResult->GetNode(getter_AddRefs(contextNode));
+  nsINode* contextNode = aResult->Node();
   if (!contextNode) {
     return nullptr;
   }
 
   mValues.EnsureLengthAtLeast(aIndex + 1);
 
-  nsCOMPtr<nsISupports> resultsupports;
-  aBinding->mExpr->Evaluate(contextNode, aType,
-                            nullptr, getter_AddRefs(resultsupports));
-
-  mValues.ReplaceElementAt(aIndex, XPathResult::FromSupports(resultsupports));
+  ErrorResult ignored;
+  mValues[aIndex] = aBinding->mExpr->Evaluate(*contextNode, aType, nullptr,
+                                              ignored);
 
   return mValues[aIndex];
 }
 
-void
+nsINode*
 nsXMLBindingValues::GetNodeAssignmentFor(nsXULTemplateResultXML* aResult,
                                          nsXMLBinding* aBinding,
-                                         int32_t aIndex,
-                                         nsIDOMNode** aNode)
+                                         int32_t aIndex)
 {
   XPathResult* result = GetAssignmentFor(aResult, aBinding, aIndex,
                                          XPathResult::FIRST_ORDERED_NODE_TYPE);
 
-  nsINode* node;
   ErrorResult rv;
-  if (result && (node = result->GetSingleNodeValue(rv))) {
-    CallQueryInterface(node, aNode);
-  } else {
-    *aNode = nullptr;
-  }
+  return result ? result->GetSingleNodeValue(rv) : nullptr;
 }
 
 void
 nsXMLBindingValues::GetStringAssignmentFor(nsXULTemplateResultXML* aResult,
                                            nsXMLBinding* aBinding,
                                            int32_t aIndex,
                                            nsAString& aValue)
 {
--- a/content/xul/templates/src/nsXMLBinding.h
+++ b/content/xul/templates/src/nsXMLBinding.h
@@ -3,19 +3,20 @@
  * 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 nsXMLBinding_h__
 #define nsXMLBinding_h__
 
 #include "nsAutoPtr.h"
 #include "nsIAtom.h"
-#include "nsCycleCollectionParticipant.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/dom/XPathExpression.h"
 
+class nsINode;
 class nsXULTemplateResultXML;
 class nsXMLBindingValues;
 namespace mozilla {
 namespace dom {
 class XPathResult;
 }
 }
 
@@ -23,21 +24,21 @@ class XPathResult;
  * Classes related to storing bindings for XML handling.
  */
 
 /**
  * a <binding> description
  */
 struct nsXMLBinding {
   nsCOMPtr<nsIAtom> mVar;
-  nsCOMPtr<nsIDOMXPathExpression> mExpr;
+  nsAutoPtr<mozilla::dom::XPathExpression> mExpr;
 
   nsAutoPtr<nsXMLBinding> mNext;
 
-  nsXMLBinding(nsIAtom* aVar, nsIDOMXPathExpression* aExpr)
+  nsXMLBinding(nsIAtom* aVar, nsAutoPtr<mozilla::dom::XPathExpression>&& aExpr)
     : mVar(aVar), mExpr(aExpr), mNext(nullptr)
   {
     MOZ_COUNT_CTOR(nsXMLBinding);
   }
 
   ~nsXMLBinding()
   {
     MOZ_COUNT_DTOR(nsXMLBinding);
@@ -48,36 +49,26 @@ struct nsXMLBinding {
  * a collection of <binding> descriptors. This object is refcounted by
  * nsXMLBindingValues objects and the query processor.
  */
 class nsXMLBindingSet MOZ_FINAL
 {
   ~nsXMLBindingSet();
 
 public:
-
-  // results hold a reference to a binding set in their
-  // nsXMLBindingValues fields
-  nsCycleCollectingAutoRefCnt mRefCnt;
-
   // pointer to the first binding in a linked list
   nsAutoPtr<nsXMLBinding> mFirst;
 
-public:
-
-  NS_METHOD_(MozExternalRefCountType) AddRef();
-  NS_METHOD_(MozExternalRefCountType) Release();
-  NS_DECL_OWNINGTHREAD
-  NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsXMLBindingSet)
+  NS_INLINE_DECL_REFCOUNTING(nsXMLBindingSet);
 
   /**
    * Add a binding to the set
    */
-  nsresult
-  AddBinding(nsIAtom* aVar, nsIDOMXPathExpression* aExpr);
+  void
+  AddBinding(nsIAtom* aVar, nsAutoPtr<mozilla::dom::XPathExpression>&& aExpr);
 
   /**
    * The nsXMLBindingValues class stores an array of values, one for each
    * target symbol that could be set by the bindings in the set.
    * LookupTargetIndex determines the index into the array for a given
    * target symbol.
    */
   int32_t
@@ -126,21 +117,20 @@ public:
    * aType the type of result expected
    */
   mozilla::dom::XPathResult*
   GetAssignmentFor(nsXULTemplateResultXML* aResult,
                    nsXMLBinding* aBinding,
                    int32_t idx,
                    uint16_t type);
 
-  void
+  nsINode*
   GetNodeAssignmentFor(nsXULTemplateResultXML* aResult,
                        nsXMLBinding* aBinding,
-                       int32_t idx,
-                       nsIDOMNode** aValue);
+                       int32_t idx);
 
   void
   GetStringAssignmentFor(nsXULTemplateResultXML* aResult,
                          nsXMLBinding* aBinding,
                          int32_t idx,
                          nsAString& aValue);
 };
 
--- a/content/xul/templates/src/nsXULTemplateQueryProcessorXML.cpp
+++ b/content/xul/templates/src/nsXULTemplateQueryProcessorXML.cpp
@@ -16,20 +16,21 @@
 #include "nsGkAtoms.h"
 #include "nsIURI.h"
 #include "nsIArray.h"
 #include "nsIScriptContext.h"
 #include "nsArrayUtils.h"
 #include "nsPIDOMWindow.h"
 #include "nsXULContentUtils.h"
 #include "nsXMLHttpRequest.h"
-
+#include "mozilla/dom/XPathEvaluator.h"
 #include "nsXULTemplateQueryProcessorXML.h"
 #include "nsXULTemplateResultXML.h"
 #include "nsXULSortService.h"
+#include "mozilla/dom/Element.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_IMPL_ISUPPORTS(nsXMLQuery, nsXMLQuery)
 
 //----------------------------------------------------------------------
 //
@@ -48,25 +49,23 @@ nsXULTemplateResultSetXML::HasMoreElemen
     *aResult = !rv.Failed() && mPosition < length;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXULTemplateResultSetXML::GetNext(nsISupports **aResult)
 {
     ErrorResult rv;
-    nsCOMPtr<nsIDOMNode> node =
-        do_QueryInterface(mResults->SnapshotItem(mPosition, rv));
+    nsINode* node = mResults->SnapshotItem(mPosition, rv);
     if (rv.Failed()) {
         return rv.ErrorCode();
     }
 
     nsXULTemplateResultXML* result =
-        new nsXULTemplateResultXML(mQuery, node, mBindingSet);
-    NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
+        new nsXULTemplateResultXML(mQuery, node->AsContent(), mBindingSet);
 
     ++mPosition;
     *aResult = result;
     NS_ADDREF(result);
     return NS_OK;
 }
 
 
@@ -77,18 +76,16 @@ nsXULTemplateResultSetXML::GetNext(nsISu
 
 static PLDHashOperator
 TraverseRuleToBindingsMap(nsISupports* aKey, nsXMLBindingSet* aMatch, void* aContext)
 {
     nsCycleCollectionTraversalCallback *cb =
         static_cast<nsCycleCollectionTraversalCallback*>(aContext);
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mRuleToBindingsMap key");
     cb->NoteXPCOMChild(aKey);
-    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mRuleToBindingsMap value");
-    cb->NoteNativeChild(aMatch, NS_CYCLE_COLLECTION_PARTICIPANT(nsXMLBindingSet));
     return PL_DHASH_NEXT;
 }
   
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULTemplateQueryProcessorXML)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXULTemplateQueryProcessorXML)
     tmp->mRuleToBindingsMap.Clear();
     NS_IMPL_CYCLE_COLLECTION_UNLINK(mRoot)
@@ -205,25 +202,24 @@ NS_IMETHODIMP
 nsXULTemplateQueryProcessorXML::InitializeForBuilding(nsISupports* aDatasource,
                                                       nsIXULTemplateBuilder* aBuilder,
                                                       nsIDOMNode* aRootNode)
 {
     if (mGenerationStarted)
         return NS_ERROR_UNEXPECTED;
 
     // the datasource is either a document or a DOM element
-    nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aDatasource);
+    nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDatasource);
     if (doc)
-        doc->GetDocumentElement(getter_AddRefs(mRoot));
+        mRoot = doc->GetDocumentElement();
     else
       mRoot = do_QueryInterface(aDatasource);
     NS_ENSURE_STATE(mRoot);
 
-    mEvaluator = do_CreateInstance("@mozilla.org/dom/xpath-evaluator;1");
-    NS_ENSURE_TRUE(mEvaluator, NS_ERROR_OUT_OF_MEMORY);
+    mEvaluator = new XPathEvaluator();
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXULTemplateQueryProcessorXML::Done()
 {
     mGenerationStarted = false;
@@ -235,76 +231,70 @@ nsXULTemplateQueryProcessorXML::Done()
 
 NS_IMETHODIMP
 nsXULTemplateQueryProcessorXML::CompileQuery(nsIXULTemplateBuilder* aBuilder,
                                              nsIDOMNode* aQueryNode,
                                              nsIAtom* aRefVariable,
                                              nsIAtom* aMemberVariable,
                                              nsISupports** _retval)
 {
-    nsresult rv = NS_OK;
-
     *_retval = nullptr;
 
     nsCOMPtr<nsIContent> content = do_QueryInterface(aQueryNode);
 
     nsAutoString expr;
     content->GetAttr(kNameSpaceID_None, nsGkAtoms::expr, expr);
 
     // if an expression is not specified, then the default is to
     // just take all of the children
     if (expr.IsEmpty())
         expr.Assign('*');
 
-    nsCOMPtr<nsIDOMXPathExpression> compiledexpr;
-    rv = CreateExpression(expr, aQueryNode, getter_AddRefs(compiledexpr));
-    if (NS_FAILED(rv)) {
+    ErrorResult rv;
+    nsAutoPtr<XPathExpression> compiledexpr;
+    compiledexpr = CreateExpression(expr, content, rv);
+    if (rv.Failed()) {
         nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_BAD_XPATH);
-        return rv;
+        return rv.ErrorCode();
     }
 
     nsRefPtr<nsXMLQuery> query =
-        new nsXMLQuery(this, aMemberVariable, compiledexpr);
-    NS_ENSURE_TRUE(query, NS_ERROR_OUT_OF_MEMORY);
+        new nsXMLQuery(this, aMemberVariable, Move(compiledexpr));
 
     for (nsIContent* condition = content->GetFirstChild();
          condition;
          condition = condition->GetNextSibling()) {
 
         if (condition->NodeInfo()->Equals(nsGkAtoms::assign,
                                           kNameSpaceID_XUL)) {
             nsAutoString var;
             condition->GetAttr(kNameSpaceID_None, nsGkAtoms::var, var);
 
             nsAutoString expr;
             condition->GetAttr(kNameSpaceID_None, nsGkAtoms::expr, expr);
 
             // ignore assignments without a variable or an expression
             if (!var.IsEmpty() && !expr.IsEmpty()) {
-                nsCOMPtr<nsIDOMNode> conditionNode =
-                    do_QueryInterface(condition);
-                rv = CreateExpression(expr, conditionNode,
-                                      getter_AddRefs(compiledexpr));
-                if (NS_FAILED(rv)) {
+                compiledexpr = CreateExpression(expr, condition, rv);
+                if (rv.Failed()) {
                     nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_BAD_ASSIGN_XPATH);
-                    return rv;
+                    return rv.ErrorCode();
                 }
 
                 nsCOMPtr<nsIAtom> varatom = do_GetAtom(var);
 
-                rv = query->AddBinding(varatom, compiledexpr);
-                NS_ENSURE_SUCCESS(rv, rv);
+                query->AddBinding(varatom, Move(compiledexpr));
             }
         }
     }
 
     *_retval = query;
     NS_ADDREF(*_retval);
 
-    return rv;
+    return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXULTemplateQueryProcessorXML::GenerateResults(nsISupports* aDatasource,
                                                 nsIXULTemplateResult* aRef,
                                                 nsISupports* aQuery,
                                                 nsISimpleEnumerator** aResults)
 {
@@ -313,39 +303,39 @@ nsXULTemplateQueryProcessorXML::Generate
 
     mGenerationStarted = true;
 
     nsCOMPtr<nsXMLQuery> xmlquery = do_QueryInterface(aQuery);
     if (!xmlquery)
         return NS_ERROR_INVALID_ARG;
 
     nsCOMPtr<nsISupports> supports;
-    nsCOMPtr<nsIDOMNode> context;
+    nsCOMPtr<nsINode> context;
     if (aRef)
       aRef->GetBindingObjectFor(xmlquery->GetMemberVariable(),
                                 getter_AddRefs(supports));
     context = do_QueryInterface(supports);
     if (!context)
         context = mRoot;
 
-    nsIDOMXPathExpression* expr = xmlquery->GetResultsExpression();
+    XPathExpression* expr = xmlquery->GetResultsExpression();
     if (!expr)
         return NS_ERROR_FAILURE;
 
-    nsCOMPtr<nsISupports> exprsupportsresults;
-    nsresult rv = expr->Evaluate(context,
-                                 XPathResult::ORDERED_NODE_SNAPSHOT_TYPE,
-                                 nullptr, getter_AddRefs(exprsupportsresults));
-    NS_ENSURE_SUCCESS(rv, rv);
+    ErrorResult rv;
+    nsRefPtr<XPathResult> exprresults =
+        expr->Evaluate(*context, XPathResult::ORDERED_NODE_SNAPSHOT_TYPE,
+                       nullptr, rv);
+    if (rv.Failed()) {
+        return rv.ErrorCode();
+    }
 
-    XPathResult* exprresults = XPathResult::FromSupports(exprsupportsresults);
     nsXULTemplateResultSetXML* results =
-        new nsXULTemplateResultSetXML(xmlquery, exprresults,
+        new nsXULTemplateResultSetXML(xmlquery, exprresults.forget(),
                                       xmlquery->GetBindingSet());
-    NS_ENSURE_TRUE(results, NS_ERROR_OUT_OF_MEMORY);
 
     *aResults = results;
     NS_ADDREF(*aResults);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -358,52 +348,51 @@ nsXULTemplateQueryProcessorXML::AddBindi
         return NS_ERROR_FAILURE;
 
     nsRefPtr<nsXMLBindingSet> bindings = mRuleToBindingsMap.GetWeak(aRuleNode);
     if (!bindings) {
         bindings = new nsXMLBindingSet();
         mRuleToBindingsMap.Put(aRuleNode, bindings);
     }
 
-    nsCOMPtr<nsIDOMXPathExpression> compiledexpr;
-    nsresult rv =
-        CreateExpression(aExpr, aRuleNode, getter_AddRefs(compiledexpr));
-    if (NS_FAILED(rv)) {
+    nsCOMPtr<nsINode> ruleNode = do_QueryInterface(aRuleNode);
+
+    ErrorResult rv;
+    nsAutoPtr<XPathExpression> compiledexpr;
+    compiledexpr = CreateExpression(aExpr, ruleNode, rv);
+    if (rv.Failed()) {
         nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_BAD_BINDING_XPATH);
         return NS_OK;
     }
 
     // aRef isn't currently used for XML query processors
-    return bindings->AddBinding(aVar, compiledexpr);
+    bindings->AddBinding(aVar, Move(compiledexpr));
+    return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXULTemplateQueryProcessorXML::TranslateRef(nsISupports* aDatasource,
                                              const nsAString& aRefString,
                                              nsIXULTemplateResult** aRef)
 {
     *aRef = nullptr;
 
     // the datasource is either a document or a DOM element
-    nsCOMPtr<nsIDOMElement> rootElement;
-    nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aDatasource);
+    nsCOMPtr<Element> rootElement;
+    nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDatasource);
     if (doc)
-        doc->GetDocumentElement(getter_AddRefs(rootElement));
+        rootElement = doc->GetRootElement();
     else
         rootElement = do_QueryInterface(aDatasource);
 
     // if no root element, just return. The document may not have loaded yet
     if (!rootElement)
         return NS_OK;
     
-    nsXULTemplateResultXML* result =
-        new nsXULTemplateResultXML(nullptr, rootElement, nullptr);
-    NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
-
-    *aRef = result;
+    *aRef = new nsXULTemplateResultXML(nullptr, rootElement, nullptr);
     NS_ADDREF(*aRef);
 
     return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsXULTemplateQueryProcessorXML::CompareResults(nsIXULTemplateResult* aLeft,
@@ -429,34 +418,28 @@ nsXULTemplateQueryProcessorXML::CompareR
 }
 
 nsXMLBindingSet*
 nsXULTemplateQueryProcessorXML::GetOptionalBindingsForRule(nsIDOMNode* aRuleNode)
 {
     return mRuleToBindingsMap.GetWeak(aRuleNode);
 }
 
-nsresult
+XPathExpression*
 nsXULTemplateQueryProcessorXML::CreateExpression(const nsAString& aExpr,
-                                                 nsIDOMNode* aNode,
-                                                 nsIDOMXPathExpression** aCompiledExpr)
+                                                 nsINode* aNode,
+                                                 ErrorResult& aRv)
 {
-    nsCOMPtr<nsIDOMXPathNSResolver> nsResolver;
-
-    nsCOMPtr<nsIDOMDocument> doc;
-    aNode->GetOwnerDocument(getter_AddRefs(doc));
-
-    nsCOMPtr<nsIDOMXPathEvaluator> eval = do_QueryInterface(doc);
-    if (eval) {
-        nsresult rv =
-             eval->CreateNSResolver(aNode, getter_AddRefs(nsResolver));
-        NS_ENSURE_SUCCESS(rv, rv);
+    nsCOMPtr<nsIDOMXPathNSResolver> nsResolver =
+        aNode->OwnerDoc()->CreateNSResolver(aNode, aRv);
+    if (aRv.Failed()) {
+        return nullptr;
     }
 
-    return mEvaluator->CreateExpression(aExpr, nsResolver, aCompiledExpr);
+    return mEvaluator->CreateExpression(aExpr, nsResolver, aRv);
 }
 
 NS_IMETHODIMP
 nsXULTemplateQueryProcessorXML::HandleEvent(nsIDOMEvent* aEvent)
 {
     NS_PRECONDITION(aEvent, "aEvent null");
     nsAutoString eventType;
     aEvent->GetType(eventType);
--- a/content/xul/templates/src/nsXULTemplateQueryProcessorXML.h
+++ b/content/xul/templates/src/nsXULTemplateQueryProcessorXML.h
@@ -8,24 +8,24 @@
 
 #include "nsIXULTemplateBuilder.h"
 #include "nsIXULTemplateQueryProcessor.h"
 
 #include "nsISimpleEnumerator.h"
 #include "nsString.h"
 #include "nsCOMArray.h"
 #include "nsRefPtrHashtable.h"
-#include "nsIDOMElement.h"
 #include "nsIDOMEventListener.h"
-#include "nsIDOMXPathExpression.h"
 #include "nsIDOMXPathEvaluator.h"
 #include "nsXMLBinding.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIXMLHttpRequest.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/dom/Element.h"
+#include "mozilla/dom/XPathEvaluator.h"
 #include "mozilla/dom/XPathResult.h"
 
 class nsXULTemplateQueryProcessorXML;
 
 #define NS_IXMLQUERY_IID \
   {0x0358d692, 0xccce, 0x4a97, \
     { 0xb2, 0x51, 0xba, 0x8f, 0x17, 0x0f, 0x3b, 0x6f }}
  
@@ -38,49 +38,49 @@ class nsXMLQuery MOZ_FINAL : public nsIS
 
     // return a weak reference to the processor the query was created from
     nsXULTemplateQueryProcessorXML* Processor() { return mProcessor; }
 
     // return a weak reference t the member variable for the query
     nsIAtom* GetMemberVariable() { return mMemberVariable; }
 
     // return a weak reference to the expression used to generate results
-    nsIDOMXPathExpression* GetResultsExpression() { return mResultsExpr; }
+    mozilla::dom::XPathExpression* GetResultsExpression()
+      { return mResultsExpr; }
 
     // return a weak reference to the additional required bindings
     nsXMLBindingSet* GetBindingSet() { return mRequiredBindings; }
 
     // add a required binding for the query
-    nsresult
-    AddBinding(nsIAtom* aVar, nsIDOMXPathExpression* aExpr)
+    void
+    AddBinding(nsIAtom* aVar, nsAutoPtr<mozilla::dom::XPathExpression>&& aExpr)
     {
         if (!mRequiredBindings) {
             mRequiredBindings = new nsXMLBindingSet();
-            NS_ENSURE_TRUE(mRequiredBindings, NS_ERROR_OUT_OF_MEMORY);
         }
 
-        return mRequiredBindings->AddBinding(aVar, aExpr);
+        mRequiredBindings->AddBinding(aVar, mozilla::Move(aExpr));
     }
 
     nsXMLQuery(nsXULTemplateQueryProcessorXML* aProcessor,
-                        nsIAtom* aMemberVariable,
-                        nsIDOMXPathExpression* aResultsExpr)
+               nsIAtom* aMemberVariable,
+               nsAutoPtr<mozilla::dom::XPathExpression>&& aResultsExpr)
         : mProcessor(aProcessor),
           mMemberVariable(aMemberVariable),
           mResultsExpr(aResultsExpr)
     { }
 
   protected:
     ~nsXMLQuery() {}
 
     nsXULTemplateQueryProcessorXML* mProcessor;
 
     nsCOMPtr<nsIAtom> mMemberVariable;
 
-    nsCOMPtr<nsIDOMXPathExpression> mResultsExpr;
+    nsAutoPtr<mozilla::dom::XPathExpression> mResultsExpr;
 
     nsRefPtr<nsXMLBindingSet> mRequiredBindings;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsXMLQuery, NS_IXMLQUERY_IID)
 
 class nsXULTemplateResultSetXML MOZ_FINAL : public nsISimpleEnumerator
 {
@@ -104,17 +104,17 @@ public:
 
     // nsISupports interface
     NS_DECL_ISUPPORTS
 
     // nsISimpleEnumerator interface
     NS_DECL_NSISIMPLEENUMERATOR
 
     nsXULTemplateResultSetXML(nsXMLQuery* aQuery,
-                              mozilla::dom::XPathResult* aResults,
+                              already_AddRefed<mozilla::dom::XPathResult> aResults,
                               nsXMLBindingSet* aBindingSet)
         : mQuery(aQuery),
           mBindingSet(aBindingSet),
           mResults(aResults),
           mPosition(0)
     {}
 };
 
@@ -138,32 +138,32 @@ public:
     // nsIDOMEventListener interface
     NS_DECL_NSIDOMEVENTLISTENER
 
     nsXMLBindingSet*
     GetOptionalBindingsForRule(nsIDOMNode* aRuleNode);
 
     // create an XPath expression from aExpr, using aNode for
     // resolving namespaces
-    nsresult
+    mozilla::dom::XPathExpression*
     CreateExpression(const nsAString& aExpr,
-                     nsIDOMNode* aNode,
-                     nsIDOMXPathExpression** aCompiledExpr);
+                     nsINode* aNode,
+                     mozilla::ErrorResult& aRv);
 
 private:
 
     ~nsXULTemplateQueryProcessorXML() {}
 
     bool mGenerationStarted;
 
     nsRefPtrHashtable<nsISupportsHashKey, nsXMLBindingSet> mRuleToBindingsMap;
 
-    nsCOMPtr<nsIDOMElement> mRoot;
+    nsCOMPtr<mozilla::dom::Element> mRoot;
 
-    nsCOMPtr<nsIDOMXPathEvaluator> mEvaluator;
+    nsRefPtr<mozilla::dom::XPathEvaluator> mEvaluator;
 
     nsCOMPtr<nsIXULTemplateBuilder> mTemplateBuilder;
 
     nsCOMPtr<nsIXMLHttpRequest> mRequest;
 };
 
 
 #endif // nsXULTemplateQueryProcessorXML_h__
--- a/content/xul/templates/src/nsXULTemplateResultXML.cpp
+++ b/content/xul/templates/src/nsXULTemplateResultXML.cpp
@@ -13,27 +13,25 @@
 #include "nsXULTemplateResultXML.h"
 #include "nsXMLBinding.h"
 
 static uint32_t sTemplateId = 0;
 
 NS_IMPL_ISUPPORTS(nsXULTemplateResultXML, nsIXULTemplateResult)
 
 nsXULTemplateResultXML::nsXULTemplateResultXML(nsXMLQuery* aQuery,
-                                               nsIDOMNode* aNode,
+                                               nsIContent* aNode,
                                                nsXMLBindingSet* aBindings)
     : mQuery(aQuery), mNode(aNode)
 {
-    nsCOMPtr<nsIContent> content = do_QueryInterface(mNode);
-
     // If the node has an id, create the uri from it. Otherwise, there isn't
     // anything to identify the node with so just use a somewhat random number.
-    nsCOMPtr<nsIAtom> id = content->GetID();
+    nsCOMPtr<nsIAtom> id = mNode->GetID();
     if (id) {
-      nsCOMPtr<nsIURI> uri = content->GetBaseURI();
+      nsCOMPtr<nsIURI> uri = mNode->GetBaseURI();
       nsAutoCString spec;
       uri->GetSpec(spec);
 
       mId = NS_ConvertUTF8toUTF16(spec);
 
       nsAutoString idstr;
       id->ToString(idstr);
       mId += NS_LITERAL_STRING("#") + idstr;
@@ -47,20 +45,17 @@ nsXULTemplateResultXML::nsXULTemplateRes
     if (aBindings)
         mRequiredValues.SetBindingSet(aBindings);
 }
 
 NS_IMETHODIMP
 nsXULTemplateResultXML::GetIsContainer(bool* aIsContainer)
 {
     // a node is considered a container if it has children
-    if (mNode)
-        mNode->HasChildNodes(aIsContainer);
-    else
-        *aIsContainer = false;
+    *aIsContainer = mNode && mNode->HasChildNodes();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXULTemplateResultXML::GetIsEmpty(bool* aIsEmpty)
 {
     // a node is considered empty if it has no elements as children
     nsCOMPtr<nsIContent> content = do_QueryInterface(mNode);
@@ -143,38 +138,35 @@ nsXULTemplateResultXML::GetBindingFor(ns
 }
 
 NS_IMETHODIMP
 nsXULTemplateResultXML::GetBindingObjectFor(nsIAtom* aVar, nsISupports** aValue)
 {
     NS_ENSURE_ARG_POINTER(aVar);
 
     nsXMLBinding* binding;
-    nsCOMPtr<nsIDOMNode> node;
+    nsCOMPtr<nsISupports> node;
 
     if (mQuery && aVar == mQuery->GetMemberVariable()) {
         node = mNode;
     }
     else {
         int32_t idx = mRequiredValues.LookupTargetIndex(aVar, &binding);
         if (idx > 0) {
-            mRequiredValues.GetNodeAssignmentFor(this, binding, idx,
-                                                 getter_AddRefs(node));
+            node = mRequiredValues.GetNodeAssignmentFor(this, binding, idx);
         }
         else {
             idx = mOptionalValues.LookupTargetIndex(aVar, &binding);
             if (idx > 0) {
-                mOptionalValues.GetNodeAssignmentFor(this, binding, idx,
-                                                     getter_AddRefs(node));
+                node = mOptionalValues.GetNodeAssignmentFor(this, binding, idx);
             }
         }
     }
 
-    *aValue = node;
-    NS_IF_ADDREF(*aValue);
+    node.forget(aValue);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXULTemplateResultXML::RuleMatched(nsISupports* aQueryNode,
                                     nsIDOMNode* aRuleNode)
 {
     // when a rule matches, set the bindings that must be used.
@@ -190,15 +182,8 @@ nsXULTemplateResultXML::RuleMatched(nsIS
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXULTemplateResultXML::HasBeenRemoved()
 {
     return NS_OK;
 }
-
-void
-nsXULTemplateResultXML::GetNode(nsIDOMNode** aNode)
-{
-    *aNode = mNode;
-    NS_IF_ADDREF(*aNode);
-}
--- a/content/xul/templates/src/nsXULTemplateResultXML.h
+++ b/content/xul/templates/src/nsXULTemplateResultXML.h
@@ -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/. */
 
 #ifndef nsXULTemplateResultXML_h__
 #define nsXULTemplateResultXML_h__
 
 #include "nsCOMPtr.h"
+#include "nsIContent.h"
 #include "nsIURI.h"
 #include "nsIRDFResource.h"
 #include "nsXULTemplateQueryProcessorXML.h"
 #include "nsIXULTemplateResult.h"
 #include "mozilla/Attributes.h"
 
 /**
  * An single result of an query
@@ -19,36 +20,39 @@
 class nsXULTemplateResultXML MOZ_FINAL : public nsIXULTemplateResult
 {
 public:
     NS_DECL_ISUPPORTS
 
     NS_DECL_NSIXULTEMPLATERESULT
 
     nsXULTemplateResultXML(nsXMLQuery* aQuery,
-                           nsIDOMNode* aNode,
+                           nsIContent* aNode,
                            nsXMLBindingSet* aBindings);
 
-    void GetNode(nsIDOMNode** aNode);
+    nsIContent* Node()
+    {
+        return mNode;
+    }
 
 protected:
 
     ~nsXULTemplateResultXML() {}
 
     // ID used for persisting data. It is constructed using the mNode's
     // base uri plus the node's id to form 'baseuri#id'. If the node has no
     // id, then an id of the form 'row<some number>' is generated. In the
     // latter case, persistence will not work as there won't be a unique id.
     nsAutoString mId;
 
     // query that generated the result
     nsCOMPtr<nsXMLQuery> mQuery;
 
     // context node in datasource
-    nsCOMPtr<nsIDOMNode> mNode;
+    nsCOMPtr<nsIContent> mNode;
 
     // assignments in query
     nsXMLBindingValues mRequiredValues;
 
     // extra assignments made by rules (<binding> tags)
     nsXMLBindingValues mOptionalValues;
 };
 
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -106,18 +106,16 @@
 #include "nsIBoxObject.h"
 #ifdef MOZ_XUL
 #include "nsITreeSelection.h"
 #include "nsITreeContentView.h"
 #include "nsITreeView.h"
 #include "nsIXULTemplateBuilder.h"
 #include "nsITreeColumns.h"
 #endif
-#include "nsIDOMXPathExpression.h"
-#include "nsIDOMNSXPathExpression.h"
 #include "nsIDOMXPathNSResolver.h"
 
 // Storage includes
 #include "nsIDOMStorage.h"
 #include "nsPIDOMStorage.h"
 
 // Drag and drop
 #include "nsIDOMFile.h"
@@ -339,18 +337,16 @@ static nsDOMClassInfoData sClassInfoData
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(CSSSupportsRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(XSLTProcessor, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
-  NS_DEFINE_CLASSINFO_DATA(XPathExpression, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(XPathNSResolver, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   // WhatWG Storage
 
   // mrbkap says we don't need WANT_ADDPROPERTY on Storage objects
   // since a call to addProperty() is always followed by a call to
   // setProperty(), except in the case when a getter or setter is set
@@ -937,21 +933,16 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSSupportsRule)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(XSLTProcessor, nsIXSLTProcessor)
     DOM_CLASSINFO_MAP_ENTRY(nsIXSLTProcessor)
     DOM_CLASSINFO_MAP_ENTRY(nsIXSLTProcessorPrivate)
   DOM_CLASSINFO_MAP_END
 
-  DOM_CLASSINFO_MAP_BEGIN(XPathExpression, nsIDOMXPathExpression)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMXPathExpression)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSXPathExpression)
-  DOM_CLASSINFO_MAP_END
-
   DOM_CLASSINFO_MAP_BEGIN(XPathNSResolver, nsIDOMXPathNSResolver)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMXPathNSResolver)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(Storage, nsIDOMStorage)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorage)
   DOM_CLASSINFO_MAP_END
 
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -41,17 +41,16 @@ DOMCI_CLASS(TreeColumn)
 
 DOMCI_CLASS(CSSMozDocumentRule)
 DOMCI_CLASS(CSSSupportsRule)
 
 // XSLTProcessor
 DOMCI_CLASS(XSLTProcessor)
 
 // DOM Level 3 XPath objects
-DOMCI_CLASS(XPathExpression)
 DOMCI_CLASS(XPathNSResolver)
 
 // WhatWG WebApps Objects
 DOMCI_CLASS(Storage)
 
 DOMCI_CLASS(Blob)
 DOMCI_CLASS(File)
 
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1667,16 +1667,21 @@ DOMInterfaces = {
 'XPathEvaluator': {
     'wrapperCache': False
 },
 
 'XPathResult': {
     'resultNotAddRefed': ['singleNodeValue', 'iterateNext', 'snapshotItem']
 },
 
+'XPathExpression': {
+    'wrapperCache': False,
+    'nativeOwnership': 'owned',
+},
+
 'XULDocument': {
     'headerFile': 'XULDocument.h'
 },
 
 'XULElement': {
     'nativeType': 'nsXULElement',
     'resultNotAddRefed': [ 'controllers', 'style' ]
 },
@@ -2006,11 +2011,10 @@ addExternalIface('OutputStream', nativeT
                  notflattened=True)
 addExternalIface('Principal', nativeType='nsIPrincipal',
                  headerFile='nsIPrincipal.h', notflattened=True)
 addExternalIface('StackFrame', nativeType='nsIStackFrame',
                  headerFile='nsIException.h', notflattened=True)
 addExternalIface('URI', nativeType='nsIURI', headerFile='nsIURI.h',
                  notflattened=True)
 addExternalIface('UserDataHandler')
-addExternalIface('XPathExpression')
 addExternalIface('XPathNSResolver')
 addExternalIface('XULCommandDispatcher')
--- a/dom/interfaces/xpath/moz.build
+++ b/dom/interfaces/xpath/moz.build
@@ -1,16 +1,14 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
-    'nsIDOMNSXPathExpression.idl',
     'nsIDOMXPathEvaluator.idl',
-    'nsIDOMXPathExpression.idl',
     'nsIDOMXPathNSResolver.idl',
     'nsIDOMXPathResult.idl',
 ]
 
 XPIDL_MODULE = 'dom_xpath'
 
deleted file mode 100644
--- a/dom/interfaces/xpath/nsIDOMNSXPathExpression.idl
+++ /dev/null
@@ -1,34 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "domstubs.idl"
-
-interface XPathException;
-
-/**
- * Interface for Mozilla specific XPathExpression functions.
- */
-[scriptable, uuid(ce600ca8-e98a-4419-ad61-2f6d0cb0ecc8)]
-interface nsIDOMNSXPathExpression : nsISupports
-{
-  /**
-   * Evaluate the expression with the given context. Similar to
-   * nsIDOMXPathExpression::evaluate(), except that this takes the context
-   * position and size too.
-   *
-   * @param contextNode       The context node
-   * @param contextPosition   The context position
-   * @param contextSize       The context size
-   * @param type              The needed result type
-   * @param result            The result
-   */
-  nsISupports evaluateWithContext(in nsIDOMNode contextNode,
-                                  in unsigned long contextPosition,
-                                  in unsigned long contextSize,
-                                  in unsigned short type,
-                                  in nsISupports result)
-                                    raises(XPathException,
-                                           DOMException);
-};
--- a/dom/interfaces/xpath/nsIDOMXPathEvaluator.idl
+++ b/dom/interfaces/xpath/nsIDOMXPathEvaluator.idl
@@ -5,26 +5,21 @@
 
 /**
  * Corresponds to http://www.w3.org/TR/2002/WD-DOM-Level-3-XPath-20020208
  */
 
 #include "domstubs.idl"
 
 interface nsIDOMXPathNSResolver;
-interface nsIDOMXPathExpression;
 interface XPathException;
 
-[uuid(75506f8a-b504-11d5-a7f2-ca108ab8b6fc)]
+[uuid(89a0fe71-c1d9-46bd-b76b-47f51fd935ff)]
 interface nsIDOMXPathEvaluator : nsISupports
 {
-  nsIDOMXPathExpression    createExpression(in DOMString expression, 
-                                            in nsIDOMXPathNSResolver resolver)
-                                      raises(XPathException,
-                                             DOMException);
   nsIDOMXPathNSResolver    createNSResolver(in nsIDOMNode nodeResolver);
   nsISupports              evaluate(in DOMString expression, 
                                     in nsIDOMNode contextNode, 
                                     in nsIDOMXPathNSResolver resolver, 
                                     in unsigned short type, 
                                     in nsISupports result)
                                       raises(XPathException,
                                              DOMException);
deleted file mode 100644
--- a/dom/interfaces/xpath/nsIDOMXPathExpression.idl
+++ /dev/null
@@ -1,22 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * Corresponds to http://www.w3.org/TR/2002/WD-DOM-Level-3-XPath-20020208
- */
-
-#include "domstubs.idl"
-
-interface XPathException;
-
-[scriptable, uuid(75506f82-b504-11d5-a7f2-ca108ab8b6fc)]
-interface nsIDOMXPathExpression : nsISupports
-{
-  nsISupports              evaluate(in nsIDOMNode contextNode, 
-                                    in unsigned short type, 
-                                    in nsISupports result)
-                                      raises(XPathException,
-                                             DOMException);
-};
--- a/dom/webidl/XPathEvaluator.webidl
+++ b/dom/webidl/XPathEvaluator.webidl
@@ -1,15 +1,14 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-interface XPathExpression;
 interface XPathNSResolver;
 
 [Constructor]
 interface XPathEvaluator {
   // Based on nsIDOMXPathEvaluator
   [NewObject, Throws]
   XPathExpression createExpression(DOMString expression,
                                    XPathNSResolver? resolver);
new file mode 100644
--- /dev/null
+++ b/dom/webidl/XPathExpression.webidl
@@ -0,0 +1,22 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+interface XPathExpression {
+  // The result specifies a specific result object which may be reused and
+  // returned by this method. If this is specified as null or it's not an
+  // XPathResult object, a new result object will be constructed and returned.
+  [Throws]
+  XPathResult evaluate(Node contextNode, unsigned short type, object? result);
+
+  // The result specifies a specific result object which may be reused and
+  // returned by this method. If this is specified as null or it's not an
+  // XPathResult object, a new result object will be constructed and returned.
+  [Throws, ChromeOnly]
+  XPathResult evaluateWithContext(Node contextNode,
+                                  unsigned long contextPosition,
+                                  unsigned long contextSize,
+                                  unsigned short type, object? result);
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -476,16 +476,17 @@ WEBIDL_FILES = [
     'WorkerNavigator.webidl',
     'XMLDocument.webidl',
     'XMLHttpRequest.webidl',
     'XMLHttpRequestEventTarget.webidl',
     'XMLHttpRequestUpload.webidl',
     'XMLSerializer.webidl',
     'XMLStylesheetProcessingInstruction.webidl',
     'XPathEvaluator.webidl',
+    'XPathExpression.webidl',
     'XPathResult.webidl',
     'XULCommandEvent.webidl',
     'XULDocument.webidl',
     'XULElement.webidl',
 ]
 
 if CONFIG['MOZ_AUDIO_CHANNEL_MANAGER']:
     WEBIDL_FILES += [
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -16,16 +16,17 @@
 #include "nsIScriptContext.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsISupportsPriority.h"
 #include "nsITimer.h"
 #include "nsIURI.h"
 #include "nsPIDOMWindow.h"
 
 #include <algorithm>
+#include "BackgroundChild.h"
 #include "GeckoProfiler.h"
 #include "js/OldDebugAPI.h"
 #include "jsfriendapi.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/AtomList.h"
 #include "mozilla/dom/BindingUtils.h"
@@ -34,16 +35,17 @@
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/Navigator.h"
 #include "nsContentUtils.h"
 #include "nsCycleCollector.h"
 #include "nsDOMJSUtils.h"
+#include "nsIIPCBackgroundChildCreateCallback.h"
 #include "nsISupportsImpl.h"
 #include "nsLayoutStatics.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThread.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOM.h"
 #include "nsXPCOMPrivate.h"
@@ -58,16 +60,22 @@
 #include "nsThreadManager.h"
 #endif
 
 #include "ServiceWorker.h"
 #include "SharedWorker.h"
 #include "WorkerPrivate.h"
 #include "WorkerRunnable.h"
 
+#ifdef ENABLE_TESTS
+#include "BackgroundChildImpl.h"
+#include "mozilla/ipc/PBackgroundChild.h"
+#include "prrng.h"
+#endif
+
 using namespace mozilla;
 using namespace mozilla::dom;
 
 USING_WORKERS_NAMESPACE
 
 using mozilla::MutexAutoLock;
 using mozilla::MutexAutoUnlock;
 using mozilla::Preferences;
@@ -155,16 +163,20 @@ const JS::ContextOptions kRequiredContex
 uint32_t gMaxWorkersPerDomain = MAX_WORKERS_PER_DOMAIN;
 
 // Does not hold an owning reference.
 RuntimeService* gRuntimeService = nullptr;
 
 // Only non-null during the call to Init.
 RuntimeService* gRuntimeServiceDuringInit = nullptr;
 
+#ifdef ENABLE_TESTS
+bool gTestPBackground = false;
+#endif // ENABLE_TESTS
+
 enum {
   ID_Worker = 0,
   ID_ChromeWorker,
   ID_Event,
   ID_MessageEvent,
   ID_ErrorEvent,
 
   ID_COUNT
@@ -899,16 +911,47 @@ public:
       nsCycleCollector_collect(nullptr);
     }
   }
 
 private:
   WorkerPrivate* mWorkerPrivate;
 };
 
+class WorkerBackgroundChildCallback MOZ_FINAL :
+  public nsIIPCBackgroundChildCreateCallback
+{
+  bool* mDone;
+
+public:
+  WorkerBackgroundChildCallback(bool* aDone)
+  : mDone(aDone)
+  {
+    MOZ_ASSERT(mDone);
+  }
+
+  NS_DECL_ISUPPORTS
+
+private:
+  ~WorkerBackgroundChildCallback()
+  { }
+
+  virtual void
+  ActorCreated(PBackgroundChild* aActor) MOZ_OVERRIDE
+  {
+    *mDone = true;
+  }
+
+  virtual void
+  ActorFailed() MOZ_OVERRIDE
+  {
+    *mDone = true;
+  }
+};
+
 class WorkerThreadPrimaryRunnable MOZ_FINAL : public nsRunnable
 {
   WorkerPrivate* mWorkerPrivate;
   nsRefPtr<RuntimeService::WorkerThread> mThread;
   JSRuntime* mParentRuntime;
 
   class FinishedRunnable MOZ_FINAL : public nsRunnable
   {
@@ -941,16 +984,19 @@ public:
   }
 
   NS_DECL_ISUPPORTS_INHERITED
 
 private:
   ~WorkerThreadPrimaryRunnable()
   { }
 
+  nsresult
+  SynchronouslyCreatePBackground();
+
   NS_DECL_NSIRUNNABLE
 };
 
 class WorkerTaskRunnable MOZ_FINAL : public WorkerRunnable
 {
   nsRefPtr<WorkerTask> mTask;
 
 public:
@@ -1040,16 +1086,38 @@ public:
   void
   SetAcceptingNonWorkerRunnables(bool aAcceptingNonWorkerRunnables)
   {
     MutexAutoLock lock(mLock);
     mAcceptingNonWorkerRunnables = aAcceptingNonWorkerRunnables;
   }
 #endif
 
+#ifdef ENABLE_TESTS
+  void
+  TestPBackground()
+  {
+    using namespace mozilla::ipc;
+    if (gTestPBackground) {
+      // Randomize value to validate workers are not cross-posting messages.
+      uint32_t testValue;
+      PRSize randomSize = PR_GetRandomNoise(&testValue, sizeof(testValue));
+      MOZ_RELEASE_ASSERT(randomSize == sizeof(testValue));
+      nsCString testStr;
+      testStr.AppendInt(testValue);
+      testStr.AppendInt(reinterpret_cast<int64_t>(PR_GetCurrentThread()));
+      PBackgroundChild* existingBackgroundChild =
+        BackgroundChild::GetForCurrentThread();
+      MOZ_RELEASE_ASSERT(existingBackgroundChild);
+      bool ok = existingBackgroundChild->SendPBackgroundTestConstructor(testStr);
+      MOZ_RELEASE_ASSERT(ok);
+    }
+  }
+#endif // #ENABLE_TESTS
+
 private:
   WorkerThread()
   : nsThread(nsThread::NOT_MAIN_THREAD, WORKER_STACK_SIZE),
     mWorkerPrivate(nullptr)
 #ifdef DEBUG
     , mAcceptingNonWorkerRunnables(true)
 #endif
   { }
@@ -1243,16 +1311,20 @@ RuntimeService::GetOrCreateService()
   if (!gRuntimeService) {
     nsRefPtr<RuntimeService> service = new RuntimeService();
     if (NS_FAILED(service->Init())) {
       NS_WARNING("Failed to initialize!");
       service->Cleanup();
       return nullptr;
     }
 
+#ifdef ENABLE_TESTS
+    gTestPBackground = mozilla::Preferences::GetBool("pbackground.testing", false);
+#endif // ENABLE_TESTS
+
     // The observer service now owns us until shutdown.
     gRuntimeService = service;
   }
 
   return gRuntimeService;
 }
 
 // static
@@ -1532,20 +1604,16 @@ RuntimeService::ScheduleWorker(JSContext
   nsCOMPtr<nsIRunnable> runnable =
     new WorkerThreadPrimaryRunnable(aWorkerPrivate, thread, JS_GetParentRuntime(aCx));
   if (NS_FAILED(thread->Dispatch(runnable, NS_DISPATCH_NORMAL))) {
     UnregisterWorker(aCx, aWorkerPrivate);
     JS_ReportError(aCx, "Could not dispatch to thread!");
     return false;
   }
 
-#ifdef DEBUG
-  thread->SetAcceptingNonWorkerRunnables(false);
-#endif
-
   return true;
 }
 
 // static
 void
 RuntimeService::ShutdownIdleThreads(nsITimer* aTimer, void* /* aClosure */)
 {
   AssertIsOnMainThread();
@@ -2487,18 +2555,30 @@ RuntimeService::WorkerThread::Observer::
 }
 
 NS_IMETHODIMP
 RuntimeService::WorkerThread::Observer::OnProcessNextEvent(
                                                nsIThreadInternal* /* aThread */,
                                                bool aMayWait,
                                                uint32_t aRecursionDepth)
 {
+  using mozilla::ipc::BackgroundChild;
+
   mWorkerPrivate->AssertIsOnWorkerThread();
-  MOZ_ASSERT(!aMayWait);
+
+  // If the PBackground child is not created yet, then we must permit
+  // blocking event processing to support SynchronouslyCreatePBackground().
+  // If this occurs then we are spinning on the event queue at the start of
+  // PrimaryWorkerRunnable::Run() and don't want to process the event in
+  // mWorkerPrivate yet.
+  if (aMayWait) {
+    MOZ_ASSERT(aRecursionDepth == 2);
+    MOZ_ASSERT(!BackgroundChild::GetForCurrentThread());
+    return NS_OK;
+  }
 
   mWorkerPrivate->OnProcessNextEvent(aRecursionDepth);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 RuntimeService::WorkerThread::Observer::AfterProcessNextEvent(
                                                nsIThreadInternal* /* aThread */,
@@ -2532,21 +2612,25 @@ LogViolationDetailsRunnable::Run()
   nsRefPtr<MainThreadStopSyncLoopRunnable> response =
     new MainThreadStopSyncLoopRunnable(mWorkerPrivate, mSyncLoopTarget.forget(),
                                        true);
   MOZ_ALWAYS_TRUE(response->Dispatch(nullptr));
 
   return NS_OK;
 }
 
+NS_IMPL_ISUPPORTS(WorkerBackgroundChildCallback, nsIIPCBackgroundChildCreateCallback)
+
 NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadPrimaryRunnable, nsRunnable)
 
 NS_IMETHODIMP
 WorkerThreadPrimaryRunnable::Run()
 {
+  using mozilla::ipc::BackgroundChild;
+
 #ifdef MOZ_NUWA_PROCESS
   if (IsNuwaProcess()) {
     NS_ASSERTION(NuwaMarkCurrentThread != nullptr,
                   "NuwaMarkCurrentThread is undefined!");
     NuwaMarkCurrentThread(nullptr, nullptr);
     NuwaFreezeCurrentThread();
   }
 #endif
@@ -2555,16 +2639,29 @@ WorkerThreadPrimaryRunnable::Run()
 
   nsAutoCString threadName;
   threadName.AssignLiteral("WebWorker '");
   threadName.Append(NS_LossyConvertUTF16toASCII(mWorkerPrivate->ScriptURL()));
   threadName.Append('\'');
 
   profiler_register_thread(threadName.get(), &stackBaseGuess);
 
+  // Note: SynchronouslyCreatePBackground() must be called prior to
+  //       mThread->SetWorker() in order to avoid accidentally consuming
+  //       worker messages here.
+  nsresult rv = SynchronouslyCreatePBackground();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    // XXX need to fire an error at parent.
+    return rv;
+  }
+
+#ifdef ENABLE_TESTS
+  mThread->TestPBackground();
+#endif
+
   mThread->SetWorker(mWorkerPrivate);
 
   mWorkerPrivate->AssertIsOnWorkerThread();
 
   {
     nsCycleCollector_startup();
 
     WorkerJSRuntime runtime(mParentRuntime, mWorkerPrivate);
@@ -2588,16 +2685,22 @@ WorkerThreadPrimaryRunnable::Run()
       {
         JSAutoRequest ar(cx);
 
         mWorkerPrivate->DoRunLoop(cx);
 
         JS_ReportPendingException(cx);
       }
 
+#ifdef ENABLE_TESTS
+      mThread->TestPBackground();
+#endif
+
+      BackgroundChild::CloseForCurrentThread();
+
 #ifdef MOZ_ENABLE_PROFILER_SPS
       if (stack) {
         stack->sampleRuntime(nullptr);
       }
 #endif
     }
 
     // Destroy the main context.  This will unroot the main worker global and
@@ -2626,16 +2729,48 @@ WorkerThreadPrimaryRunnable::Run()
     new FinishedRunnable(mThread.forget());
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mainThread->Dispatch(finishedRunnable,
                                                     NS_DISPATCH_NORMAL)));
 
   profiler_unregister_thread();
   return NS_OK;
 }
 
+nsresult
+WorkerThreadPrimaryRunnable::SynchronouslyCreatePBackground()
+{
+  using mozilla::ipc::BackgroundChild;
+
+  MOZ_ASSERT(!BackgroundChild::GetForCurrentThread());
+
+  bool done = false;
+  nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback =
+    new WorkerBackgroundChildCallback(&done);
+
+  if (NS_WARN_IF(!BackgroundChild::GetOrCreateForCurrentThread(callback))) {
+    return NS_ERROR_FAILURE;
+  }
+
+  while (!done) {
+    if (NS_WARN_IF(!NS_ProcessNextEvent(mThread, true /* aMayWay */))) {
+      return NS_ERROR_FAILURE;
+    }
+  }
+
+  if (NS_WARN_IF(!BackgroundChild::GetForCurrentThread())) {
+    return NS_ERROR_FAILURE;
+  }
+
+#ifdef DEBUG
+  mThread->SetAcceptingNonWorkerRunnables(false);
+#endif
+
+  return NS_OK;
+}
+
 NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadPrimaryRunnable::FinishedRunnable,
                              nsRunnable)
 
 NS_IMETHODIMP
 WorkerThreadPrimaryRunnable::FinishedRunnable::Run()
 {
   AssertIsOnMainThread();
 
--- a/dom/xslt/xpath/XPathEvaluator.cpp
+++ b/dom/xslt/xpath/XPathEvaluator.cpp
@@ -2,29 +2,30 @@
 /* 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/XPathEvaluator.h"
 #include "mozilla/Move.h"
 #include "nsCOMPtr.h"
 #include "nsIAtom.h"
-#include "nsXPathExpression.h"
+#include "mozilla/dom/XPathExpression.h"
 #include "nsXPathNSResolver.h"
 #include "XPathResult.h"
 #include "nsContentCID.h"
 #include "txExpr.h"
 #include "txExprParser.h"
 #include "nsError.h"
 #include "txURIUtils.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsDOMString.h"
 #include "nsNameSpaceManager.h"
 #include "nsContentUtils.h"
+#include "txIXPathContext.h"
 #include "mozilla/dom/XPathEvaluatorBinding.h"
 #include "mozilla/dom/BindingUtils.h"
 
 extern nsresult
 TX_ResolveFunctionCallXPCOM(const nsCString &aContractID, int32_t aNamespaceID,
                             nsIAtom *aName, nsISupports *aState,
                             FunctionCall **aFunction);
 
@@ -89,64 +90,66 @@ XPathEvaluator::CreateNSResolver(nsIDOMN
 NS_IMETHODIMP
 XPathEvaluator::Evaluate(const nsAString & aExpression,
                          nsIDOMNode *aContextNode,
                          nsIDOMXPathNSResolver *aResolver,
                          uint16_t aType,
                          nsISupports *aInResult,
                          nsISupports **aResult)
 {
-    nsCOMPtr<nsIDOMXPathExpression> expression;
-    nsresult rv = CreateExpression(aExpression, aResolver,
-                                   getter_AddRefs(expression));
-    NS_ENSURE_SUCCESS(rv, rv);
+    ErrorResult rv;
+    nsAutoPtr<XPathExpression> expression(CreateExpression(aExpression,
+                                                           aResolver, rv));
+    if (rv.Failed()) {
+        return rv.ErrorCode();
+    }
+
+    nsCOMPtr<nsINode> node = do_QueryInterface(aContextNode);
+    if (!node) {
+        return NS_ERROR_FAILURE;
+    }
 
-    return expression->Evaluate(aContextNode, aType, aInResult, aResult);
+    nsCOMPtr<nsIXPathResult> inResult = do_QueryInterface(aInResult);
+    nsRefPtr<XPathResult> result =
+        expression->Evaluate(*node, aType,
+                             static_cast<XPathResult*>(inResult.get()), rv);
+    if (rv.Failed()) {
+        return rv.ErrorCode();
+    }
+
+    *aResult = ToSupports(result.forget().take());
+
+    return NS_OK;
 }
 
 
-NS_IMETHODIMP
+XPathExpression*
 XPathEvaluator::CreateExpression(const nsAString & aExpression,
                                  nsIDOMXPathNSResolver *aResolver,
-                                 nsIDOMXPathExpression **aResult)
+                                 ErrorResult& aRv)
 {
-    nsresult rv;
     if (!mRecycler) {
-        nsRefPtr<txResultRecycler> recycler = new txResultRecycler;
-        NS_ENSURE_TRUE(recycler, NS_ERROR_OUT_OF_MEMORY);
-        
-        rv = recycler->init();
-        NS_ENSURE_SUCCESS(rv, rv);
-        
-        mRecycler = recycler;
+        mRecycler = new txResultRecycler;
     }
 
     nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
     XPathEvaluatorParseContext pContext(aResolver, !(doc && doc->IsHTML()));
 
     nsAutoPtr<Expr> expression;
-    rv = txExprParser::createExpr(PromiseFlatString(aExpression), &pContext,
-                                  getter_Transfers(expression));
-    if (NS_FAILED(rv)) {
-        if (rv == NS_ERROR_DOM_NAMESPACE_ERR) {
-            return NS_ERROR_DOM_NAMESPACE_ERR;
+    aRv = txExprParser::createExpr(PromiseFlatString(aExpression), &pContext,
+                                   getter_Transfers(expression));
+    if (aRv.Failed()) {
+        if (aRv.ErrorCode() != NS_ERROR_DOM_NAMESPACE_ERR) {
+            aRv.Throw(NS_ERROR_DOM_INVALID_EXPRESSION_ERR);
         }
 
-        return NS_ERROR_DOM_INVALID_EXPRESSION_ERR;
+        return nullptr;
     }
 
-    nsCOMPtr<nsIDOMDocument> document = do_QueryReferent(mDocument);
-
-    *aResult = new nsXPathExpression(Move(expression), mRecycler, document);
-    if (!*aResult) {
-        return NS_ERROR_OUT_OF_MEMORY;
-    }
-
-    NS_ADDREF(*aResult);
-    return NS_OK;
+    return new XPathExpression(Move(expression), mRecycler, doc);
 }
 
 JSObject*
 XPathEvaluator::WrapObject(JSContext* aCx)
 {
     return dom::XPathEvaluatorBinding::Wrap(aCx, this);
 }
 
@@ -154,26 +157,16 @@ XPathEvaluator::WrapObject(JSContext* aC
 already_AddRefed<XPathEvaluator>
 XPathEvaluator::Constructor(const GlobalObject& aGlobal,
                             ErrorResult& rv)
 {
     nsRefPtr<XPathEvaluator> newObj = new XPathEvaluator(nullptr);
     return newObj.forget();
 }
 
-already_AddRefed<nsIDOMXPathExpression>
-XPathEvaluator::CreateExpression(const nsAString& aExpression,
-                                 nsIDOMXPathNSResolver* aResolver,
-                                 ErrorResult& rv)
-{
-  nsCOMPtr<nsIDOMXPathExpression> expr;
-  rv = CreateExpression(aExpression, aResolver, getter_AddRefs(expr));
-  return expr.forget();
-}
-
 already_AddRefed<nsIDOMXPathNSResolver>
 XPathEvaluator::CreateNSResolver(nsINode* aNodeResolver,
                                  ErrorResult& rv)
 {
   nsCOMPtr<nsIDOMNode> nodeResolver = do_QueryInterface(aNodeResolver);
   nsCOMPtr<nsIDOMXPathNSResolver> res;
   rv = CreateNSResolver(nodeResolver, getter_AddRefs(res));
   return res.forget();
--- a/dom/xslt/xpath/XPathEvaluator.h
+++ b/dom/xslt/xpath/XPathEvaluator.h
@@ -16,16 +16,17 @@
 
 class nsINode;
 class txResultRecycler;
 
 namespace mozilla {
 namespace dom {
 
 class GlobalObject;
+class XPathExpression;
 class XPathResult;
 
 /**
  * A class for evaluating an XPath expression string
  */
 class XPathEvaluator MOZ_FINAL : public nsIDOMXPathEvaluator
 {
     ~XPathEvaluator();
@@ -42,17 +43,17 @@ public:
     JSObject* WrapObject(JSContext* aCx);
     nsIDocument* GetParentObject()
     {
         nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
         return doc;
     }
     static already_AddRefed<XPathEvaluator>
         Constructor(const GlobalObject& aGlobal, ErrorResult& rv);
-    already_AddRefed<nsIDOMXPathExpression>
+    XPathExpression*
         CreateExpression(const nsAString& aExpression,
                          nsIDOMXPathNSResolver* aResolver,
                          ErrorResult& rv);
     already_AddRefed<nsIDOMXPathNSResolver>
         CreateNSResolver(nsINode* aNodeResolver, ErrorResult& rv);
     already_AddRefed<XPathResult>
         Evaluate(JSContext* aCx, const nsAString& aExpression,
                  nsINode* aContextNode, nsIDOMXPathNSResolver* aResolver,
rename from dom/xslt/xpath/nsXPathExpression.cpp
rename to dom/xslt/xpath/XPathExpression.cpp
--- a/dom/xslt/xpath/nsXPathExpression.cpp
+++ b/dom/xslt/xpath/XPathExpression.cpp
@@ -1,124 +1,162 @@
 /* -*- 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/Move.h"
-#include "nsXPathExpression.h"
+#include "XPathExpression.h"
 #include "txExpr.h"
 #include "txExprResult.h"
+#include "txIXPathContext.h"
 #include "nsError.h"
 #include "nsIDOMCharacterData.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIDOMDocument.h"
 #include "XPathResult.h"
 #include "txURIUtils.h"
 #include "txXPathTreeWalker.h"
+#include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/XPathResultBinding.h"
 
-using namespace mozilla::dom;
 using mozilla::Move;
 
-NS_IMPL_CYCLE_COLLECTION(nsXPathExpression, mDocument)
+namespace mozilla {
+namespace dom {
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXPathExpression)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXPathExpression)
-
-DOMCI_DATA(XPathExpression, nsXPathExpression)
+class EvalContextImpl : public txIEvalContext
+{
+public:
+    EvalContextImpl(const txXPathNode& aContextNode,
+                    uint32_t aContextPosition, uint32_t aContextSize,
+                    txResultRecycler* aRecycler)
+        : mContextNode(aContextNode),
+          mContextPosition(aContextPosition),
+          mContextSize(aContextSize),
+          mLastError(NS_OK),
+          mRecycler(aRecycler)
+    {
+    }
 
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXPathExpression)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMXPathExpression)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMNSXPathExpression)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMXPathExpression)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(XPathExpression)
-NS_INTERFACE_MAP_END
+    nsresult getError()
+    {
+        return mLastError;
+    }
+
+    TX_DECL_EVAL_CONTEXT;
 
-nsXPathExpression::nsXPathExpression(nsAutoPtr<Expr>&& aExpression,
-                                     txResultRecycler* aRecycler,
-                                     nsIDOMDocument *aDocument)
+private:
+    const txXPathNode& mContextNode;
+    uint32_t mContextPosition;
+    uint32_t mContextSize;
+    nsresult mLastError;
+    nsRefPtr<txResultRecycler> mRecycler;
+};
+
+XPathExpression::XPathExpression(nsAutoPtr<Expr>&& aExpression,
+                                 txResultRecycler* aRecycler,
+                                 nsIDocument *aDocument)
     : mExpression(Move(aExpression)),
       mRecycler(aRecycler),
-      mDocument(aDocument)
+      mDocument(do_GetWeakReference(aDocument)),
+      mCheckDocument(aDocument != nullptr)
+{
+}
+
+XPathExpression::~XPathExpression()
 {
 }
 
-NS_IMETHODIMP
-nsXPathExpression::Evaluate(nsIDOMNode *aContextNode,
-                            uint16_t aType,
-                            nsISupports *aInResult,
-                            nsISupports **aResult)
+already_AddRefed<XPathResult>
+XPathExpression::EvaluateWithContext(JSContext* aCx,
+                                     nsINode& aContextNode,
+                                     uint32_t aContextPosition,
+                                     uint32_t aContextSize,
+                                     uint16_t aType,
+                                     JS::Handle<JSObject*> aInResult,
+                                     ErrorResult& aRv)
 {
-    return EvaluateWithContext(aContextNode, 1, 1, aType, aInResult, aResult);
-}
-
-NS_IMETHODIMP
-nsXPathExpression::EvaluateWithContext(nsIDOMNode *aContextNode,
-                                       uint32_t aContextPosition,
-                                       uint32_t aContextSize,
-                                       uint16_t aType,
-                                       nsISupports *aInResult,
-                                       nsISupports **aResult)
-{
-    nsCOMPtr<nsINode> context = do_QueryInterface(aContextNode);
-    NS_ENSURE_ARG(context);
-
-    if (aContextPosition > aContextSize)
-        return NS_ERROR_FAILURE;
-
-    if (!nsContentUtils::CanCallerAccess(aContextNode))
-        return NS_ERROR_DOM_SECURITY_ERR;
-
-    if (mDocument && mDocument != aContextNode) {
-        nsCOMPtr<nsIDOMDocument> contextDocument;
-        aContextNode->GetOwnerDocument(getter_AddRefs(contextDocument));
-
-        if (mDocument != contextDocument) {
-            return NS_ERROR_DOM_WRONG_DOCUMENT_ERR;
+    XPathResult* inResult = nullptr;
+    if (aInResult) {
+        nsresult rv = UNWRAP_OBJECT(XPathResult, aInResult, inResult);
+        if (NS_FAILED(rv) && rv != NS_ERROR_XPC_BAD_CONVERT_JS) {
+            aRv.Throw(rv);
+            return nullptr;
         }
     }
 
-    uint16_t nodeType = context->NodeType();
+    return EvaluateWithContext(aContextNode, aContextPosition, aContextSize,
+                               aType, inResult, aRv);
+}
+
+already_AddRefed<XPathResult>
+XPathExpression::EvaluateWithContext(nsINode& aContextNode,
+                                     uint32_t aContextPosition,
+                                     uint32_t aContextSize,
+                                     uint16_t aType,
+                                     XPathResult* aInResult,
+                                     ErrorResult& aRv)
+{
+    if (aContextPosition > aContextSize) {
+        aRv.Throw(NS_ERROR_FAILURE);
+        return nullptr;
+    }
+
+    if (!nsContentUtils::CanCallerAccess(&aContextNode)) {
+        aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+        return nullptr;
+    }
+
+    if (mCheckDocument) {
+        nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
+        if (doc != aContextNode.OwnerDoc()) {
+            aRv.Throw(NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
+            return nullptr;
+        }
+    }
+
+    uint16_t nodeType = aContextNode.NodeType();
 
     if (nodeType == nsIDOMNode::TEXT_NODE ||
         nodeType == nsIDOMNode::CDATA_SECTION_NODE) {
-        nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(aContextNode);
-        NS_ENSURE_TRUE(textNode, NS_ERROR_FAILURE);
+        nsCOMPtr<nsIDOMCharacterData> textNode =
+            do_QueryInterface(&aContextNode);
+        if (!textNode) {
+            aRv.Throw(NS_ERROR_FAILURE);
+            return nullptr;
+        }
 
-        if (textNode) {
-            uint32_t textLength;
-            textNode->GetLength(&textLength);
-            if (textLength == 0)
-                return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
+        uint32_t textLength;
+        textNode->GetLength(&textLength);
+        if (textLength == 0) {
+            aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+            return nullptr;
         }
 
         // XXX Need to get logical XPath text node for CDATASection
         //     and Text nodes.
     }
     else if (nodeType != nsIDOMNode::DOCUMENT_NODE &&
              nodeType != nsIDOMNode::ELEMENT_NODE &&
              nodeType != nsIDOMNode::ATTRIBUTE_NODE &&
              nodeType != nsIDOMNode::COMMENT_NODE &&
              nodeType != nsIDOMNode::PROCESSING_INSTRUCTION_NODE) {
-        return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
+        aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+        return nullptr;
     }
 
-    NS_ENSURE_ARG(aResult);
-    *aResult = nullptr;
-
-    nsAutoPtr<txXPathNode> contextNode(txXPathNativeNode::createXPathNode(aContextNode));
-    if (!contextNode) {
-        return NS_ERROR_OUT_OF_MEMORY;
-    }
-
+    nsAutoPtr<txXPathNode> contextNode(txXPathNativeNode::createXPathNode(&aContextNode));
     EvalContextImpl eContext(*contextNode, aContextPosition, aContextSize,
                              mRecycler);
     nsRefPtr<txAExprResult> exprResult;
-    nsresult rv = mExpression->evaluate(&eContext, getter_AddRefs(exprResult));
-    NS_ENSURE_SUCCESS(rv, rv);
+    aRv = mExpression->evaluate(&eContext, getter_AddRefs(exprResult));
+    if (aRv.Failed()) {
+        return nullptr;
+    }
 
     uint16_t resultType = aType;
     if (aType == XPathResult::ANY_TYPE) {
         short exprResultType = exprResult->getResultType();
         switch (exprResultType) {
             case txAExprResult::NUMBER:
                 resultType = XPathResult::NUMBER_TYPE;
                 break;
@@ -127,76 +165,83 @@ nsXPathExpression::EvaluateWithContext(n
                 break;
             case txAExprResult::BOOLEAN:
                 resultType = XPathResult::BOOLEAN_TYPE;
                 break;
             case txAExprResult::NODESET:
                 resultType = XPathResult::UNORDERED_NODE_ITERATOR_TYPE;
                 break;
             case txAExprResult::RESULT_TREE_FRAGMENT:
-                NS_ERROR("Can't return a tree fragment!");
-                return NS_ERROR_FAILURE;
+                aRv.Throw(NS_ERROR_FAILURE);
+                return nullptr;
         }
     }
 
-    // We need a result object and it must be our implementation.
-    nsCOMPtr<nsIXPathResult> xpathResult = do_QueryInterface(aInResult);
+    nsRefPtr<XPathResult> xpathResult = aInResult;
     if (!xpathResult) {
-        // Either no aInResult or not one of ours.
-        xpathResult = new XPathResult(context);
+        xpathResult = new XPathResult(&aContextNode);
     }
-    rv = xpathResult->SetExprResult(exprResult, resultType, context);
-    NS_ENSURE_SUCCESS(rv, rv);
 
-    return CallQueryInterface(xpathResult, aResult);
+    aRv = xpathResult->SetExprResult(exprResult, resultType, &aContextNode);
+
+    return xpathResult.forget();
 }
 
 /*
- * Implementation of the txIEvalContext private to nsXPathExpression
+ * Implementation of the txIEvalContext private to XPathExpression
  * EvalContextImpl bases on only one context node and no variables
  */
 
 nsresult
-nsXPathExpression::EvalContextImpl::getVariable(int32_t aNamespace,
-                                                nsIAtom* aLName,
-                                                txAExprResult*& aResult)
+EvalContextImpl::getVariable(int32_t aNamespace,
+                             nsIAtom* aLName,
+                             txAExprResult*& aResult)
 {
     aResult = 0;
     return NS_ERROR_INVALID_ARG;
 }
 
-bool nsXPathExpression::EvalContextImpl::isStripSpaceAllowed(const txXPathNode& aNode)
+bool
+EvalContextImpl::isStripSpaceAllowed(const txXPathNode& aNode)
 {
     return false;
 }
 
-void* nsXPathExpression::EvalContextImpl::getPrivateContext()
+void*
+EvalContextImpl::getPrivateContext()
 {
     // we don't have a private context here.
     return nullptr;
 }
 
-txResultRecycler* nsXPathExpression::EvalContextImpl::recycler()
+txResultRecycler*
+EvalContextImpl::recycler()
 {
     return mRecycler;
 }
 
-void nsXPathExpression::EvalContextImpl::receiveError(const nsAString& aMsg,
-                                                      nsresult aRes)
+void
+EvalContextImpl::receiveError(const nsAString& aMsg, nsresult aRes)
 {
     mLastError = aRes;
     // forward aMsg to console service?
 }
 
-const txXPathNode& nsXPathExpression::EvalContextImpl::getContextNode()
+const txXPathNode&
+EvalContextImpl::getContextNode()
 {
     return mContextNode;
 }
 
-uint32_t nsXPathExpression::EvalContextImpl::size()
+uint32_t
+EvalContextImpl::size()
 {
     return mContextSize;
 }
 
-uint32_t nsXPathExpression::EvalContextImpl::position()
+uint32_t
+EvalContextImpl::position()
 {
     return mContextPosition;
 }
+
+} // namespace dom
+} // namespace mozilla
rename from dom/xslt/xpath/nsXPathExpression.h
rename to dom/xslt/xpath/XPathExpression.h
--- a/dom/xslt/xpath/nsXPathExpression.h
+++ b/dom/xslt/xpath/XPathExpression.h
@@ -1,78 +1,75 @@
 /* -*- 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 nsXPathExpression_h__
-#define nsXPathExpression_h__
+#ifndef mozilla_dom_XPathExpression_h
+#define mozilla_dom_XPathExpression_h
 
-#include "nsIDOMXPathExpression.h"
-#include "nsIDOMNSXPathExpression.h"
-#include "txIXPathContext.h"
-#include "txResultRecycler.h"
 #include "nsAutoPtr.h"
 #include "nsCycleCollectionParticipant.h"
+#include "nsIWeakReferenceUtils.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/dom/NonRefcountedDOMObject.h"
+#include "mozilla/dom/XPathExpressionBinding.h"
 
 class Expr;
+class nsIDocument;
+class nsINode;
+class txResultRecycler;
 class txXPathNode;
 
+namespace mozilla {
+namespace dom {
+
+class XPathResult;
+
 /**
  * A class for evaluating an XPath expression string
  */
-class nsXPathExpression MOZ_FINAL : public nsIDOMXPathExpression,
-                                    public nsIDOMNSXPathExpression
+class XPathExpression MOZ_FINAL : public NonRefcountedDOMObject
 {
 public:
-    nsXPathExpression(nsAutoPtr<Expr>&& aExpression, txResultRecycler* aRecycler,
-                      nsIDOMDocument *aDocument);
+    XPathExpression(nsAutoPtr<Expr>&& aExpression, txResultRecycler* aRecycler,
+                    nsIDocument *aDocument);
+    ~XPathExpression();
+
+    JSObject* WrapObject(JSContext* aCx, bool* aTookOwnership)
+    {
+        return XPathExpressionBinding::Wrap(aCx, this, aTookOwnership);
+    }
 
-    // nsISupports interface
-    NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-    NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXPathExpression,
-                                             nsIDOMXPathExpression)
-
-    // nsIDOMXPathExpression interface
-    NS_DECL_NSIDOMXPATHEXPRESSION
-
-    // nsIDOMNSXPathExpression interface
-    NS_DECL_NSIDOMNSXPATHEXPRESSION
+    already_AddRefed<XPathResult>
+        Evaluate(JSContext* aCx, nsINode& aContextNode, uint16_t aType,
+                 JS::Handle<JSObject*> aInResult, ErrorResult& aRv)
+    {
+        return EvaluateWithContext(aCx, aContextNode, 1, 1, aType, aInResult,
+                                   aRv);
+    }
+    already_AddRefed<XPathResult>
+        EvaluateWithContext(JSContext* aCx, nsINode& aContextNode,
+                            uint32_t aContextPosition, uint32_t aContextSize,
+                            uint16_t aType, JS::Handle<JSObject*> aInResult,
+                            ErrorResult& aRv);
+    already_AddRefed<XPathResult>
+        Evaluate(nsINode& aContextNode, uint16_t aType, XPathResult* aInResult,
+                 ErrorResult& aRv)
+    {
+        return EvaluateWithContext(aContextNode, 1, 1, aType, aInResult, aRv);
+    }
+    already_AddRefed<XPathResult>
+        EvaluateWithContext(nsINode& aContextNode, uint32_t aContextPosition,
+                            uint32_t aContextSize, uint16_t aType,
+                            XPathResult* aInResult, ErrorResult& aRv);
 
 private:
-    ~nsXPathExpression() {}
-
     nsAutoPtr<Expr> mExpression;
     nsRefPtr<txResultRecycler> mRecycler;
-    nsCOMPtr<nsIDOMDocument> mDocument;
-
-    class EvalContextImpl : public txIEvalContext
-    {
-    public:
-        EvalContextImpl(const txXPathNode& aContextNode,
-                        uint32_t aContextPosition, uint32_t aContextSize,
-                        txResultRecycler* aRecycler)
-            : mContextNode(aContextNode),
-              mContextPosition(aContextPosition),
-              mContextSize(aContextSize),
-              mLastError(NS_OK),
-              mRecycler(aRecycler)
-        {
-        }
-
-        nsresult getError()
-        {
-            return mLastError;
-        }
-
-        TX_DECL_EVAL_CONTEXT;
-
-    private:
-        const txXPathNode& mContextNode;
-        uint32_t mContextPosition;
-        uint32_t mContextSize;
-        nsresult mLastError;
-        nsRefPtr<txResultRecycler> mRecycler;
-    };
+    nsWeakPtr mDocument;
+    bool mCheckDocument;
 };
 
-#endif
+} // namespace dom
+} // namespace mozilla
+
+#endif /* mozilla_dom_XPathExpression_h */
--- a/dom/xslt/xpath/moz.build
+++ b/dom/xslt/xpath/moz.build
@@ -1,21 +1,21 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 EXPORTS.mozilla.dom += [
     'XPathEvaluator.h',
+    'XPathExpression.h',
     'XPathResult.h',
 ]
 
 UNIFIED_SOURCES += [
-    'nsXPathExpression.cpp',
     'nsXPathNSResolver.cpp',
     'txBooleanExpr.cpp',
     'txBooleanResult.cpp',
     'txCoreFunctionCall.cpp',
     'txErrorExpr.cpp',
     'txExpr.cpp',
     'txExprLexer.cpp',
     'txExprParser.cpp',
@@ -42,16 +42,17 @@ UNIFIED_SOURCES += [
     'txStringResult.cpp',
     'txUnaryExpr.cpp',
     'txUnionExpr.cpp',
     'txUnionNodeTest.cpp',
     'txVariableRefExpr.cpp',
     'txXPathOptimizer.cpp',
     'txXPCOMExtensionFunction.cpp',
     'XPathEvaluator.cpp',
+    'XPathExpression.cpp',
     'XPathResult.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
 LOCAL_INCLUDES += [
     '../base',
     '../xml',
--- a/dom/xslt/xpath/txResultRecycler.cpp
+++ b/dom/xslt/xpath/txResultRecycler.cpp
@@ -3,19 +3,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/. */
 
 #include "txResultRecycler.h"
 #include "txExprResult.h"
 #include "txNodeSet.h"
 
 txResultRecycler::txResultRecycler()
-    : mEmptyStringResult(nullptr),
-      mTrueResult(nullptr),
-      mFalseResult(nullptr)
+    : mEmptyStringResult(new StringResult(nullptr)),
+      mTrueResult(new BooleanResult(true)),
+      mFalseResult(new BooleanResult(false))
 {
 }
 
 txResultRecycler::~txResultRecycler()
 {
     txStackIterator stringIter(&mStringResults);
     while (stringIter.hasNext()) {
         delete static_cast<StringResult*>(stringIter.next());
@@ -23,44 +23,16 @@ txResultRecycler::~txResultRecycler()
     txStackIterator nodesetIter(&mNodeSetResults);
     while (nodesetIter.hasNext()) {
         delete static_cast<txNodeSet*>(nodesetIter.next());
     }
     txStackIterator numberIter(&mNumberResults);
     while (numberIter.hasNext()) {
         delete static_cast<NumberResult*>(numberIter.next());
     }
-
-    NS_IF_RELEASE(mEmptyStringResult);
-    NS_IF_RELEASE(mTrueResult);
-    NS_IF_RELEASE(mFalseResult);
-}
-
-
-nsresult
-txResultRecycler::init()
-{
-    NS_ASSERTION(!mEmptyStringResult && !mTrueResult && !mFalseResult,
-                 "Already inited");
-    mEmptyStringResult = new StringResult(nullptr);
-    NS_ENSURE_TRUE(mEmptyStringResult, NS_ERROR_OUT_OF_MEMORY);
-
-    NS_ADDREF(mEmptyStringResult);
-
-    mTrueResult = new BooleanResult(true);
-    NS_ENSURE_TRUE(mTrueResult, NS_ERROR_OUT_OF_MEMORY);
-
-    NS_ADDREF(mTrueResult);
-
-    mFalseResult = new BooleanResult(false);
-    NS_ENSURE_TRUE(mFalseResult, NS_ERROR_OUT_OF_MEMORY);
-
-    NS_ADDREF(mFalseResult);
-
-    return NS_OK;
 }
 
 
 void
 txResultRecycler::recycle(txAExprResult* aResult)
 {
     NS_ASSERTION(aResult->mRefCnt == 0, "In-use txAExprResult recycled");
     nsRefPtr<txResultRecycler> kungFuDeathGrip;
--- a/dom/xslt/xpath/txResultRecycler.h
+++ b/dom/xslt/xpath/txResultRecycler.h
@@ -2,31 +2,31 @@
 /* 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 txResultRecycler_h__
 #define txResultRecycler_h__
 
 #include "nsCOMPtr.h"
+#include "nsAutoPtr.h"
 #include "txStack.h"
 
 class txAExprResult;
 class StringResult;
 class txNodeSet;
 class txXPathNode;
 class NumberResult;
 class BooleanResult;
 
 class txResultRecycler
 {
 public:
     txResultRecycler();
     ~txResultRecycler();
-    nsresult init();
 
     void AddRef()
     {
         ++mRefCnt;
         NS_LOG_ADDREF(this, mRefCnt, "txResultRecycler", sizeof(*this));
     }
     void Release()
     {
@@ -67,14 +67,14 @@ public:
      */
     nsresult getNonSharedNodeSet(txNodeSet* aNodeSet, txNodeSet** aResult);
 
 private:
     nsAutoRefCnt mRefCnt;
     txStack mStringResults;
     txStack mNodeSetResults;
     txStack mNumberResults;
-    StringResult* mEmptyStringResult;
-    BooleanResult* mTrueResult;
-    BooleanResult* mFalseResult;
+    nsRefPtr<StringResult> mEmptyStringResult;
+    nsRefPtr<BooleanResult> mTrueResult;
+    nsRefPtr<BooleanResult> mFalseResult;
 };
 
 #endif //txResultRecycler_h__
--- a/dom/xslt/xpath/txXPathOptimizer.cpp
+++ b/dom/xslt/xpath/txXPathOptimizer.cpp
@@ -75,21 +75,16 @@ txXPathOptimizer::optimize(Expr* aInExpr
     nsresult rv = NS_OK;
 
     // First check if the expression will produce the same result
     // under any context.
     Expr::ExprType exprType = aInExpr->getType();
     if (exprType != Expr::LITERAL_EXPR &&
         !aInExpr->isSensitiveTo(Expr::ANY_CONTEXT)) {
         nsRefPtr<txResultRecycler> recycler = new txResultRecycler;
-        NS_ENSURE_TRUE(recycler, NS_ERROR_OUT_OF_MEMORY);
-
-        rv = recycler->init();
-        NS_ENSURE_SUCCESS(rv, rv);
-
         txEarlyEvalContext context(recycler);
         nsRefPtr<txAExprResult> exprRes;
 
         // Don't throw if this fails since it could be that the expression
         // is or contains an error-expression.
         rv = aInExpr->evaluate(&context, getter_AddRefs(exprRes));
         if (NS_SUCCEEDED(rv)) {
             *aOutExpr = new txLiteralExpr(exprRes);
--- a/dom/xslt/xslt/txExecutionState.cpp
+++ b/dom/xslt/xslt/txExecutionState.cpp
@@ -120,20 +120,16 @@ txExecutionState::init(const txXPathNode
     // Set up loaded-documents-hash
     mLoadedDocuments.init(txXPathNodeUtils::getOwnerDocument(aNode));
 
     // Init members
     rv = mKeyHash.init();
     NS_ENSURE_SUCCESS(rv, rv);
     
     mRecycler = new txResultRecycler;
-    NS_ENSURE_TRUE(mRecycler, NS_ERROR_OUT_OF_MEMORY);
-    
-    rv = mRecycler->init();
-    NS_ENSURE_SUCCESS(rv, rv);
     
     // The actual value here doesn't really matter since noone should use this
     // value. But lets put something errorlike in just in case
     mGlobalVarPlaceholderValue = new StringResult(NS_LITERAL_STRING("Error"), nullptr);
     NS_ENSURE_TRUE(mGlobalVarPlaceholderValue, NS_ERROR_OUT_OF_MEMORY);
 
     // Initiate first instruction. This has to be done last since findTemplate
     // might use us.
--- a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp
+++ b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp
@@ -465,20 +465,16 @@ txMozillaXSLTProcessor::AddXSLTParam(con
 
         // Set up context
         nsAutoPtr<txXPathNode> contextNode(
           txXPathNativeNode::createXPathNode(aContext));
         NS_ENSURE_TRUE(contextNode, NS_ERROR_OUT_OF_MEMORY);
 
         if (!mRecycler) {
             mRecycler = new txResultRecycler;
-            NS_ENSURE_TRUE(mRecycler, NS_ERROR_OUT_OF_MEMORY);
-
-            rv = mRecycler->init();
-            NS_ENSURE_SUCCESS(rv, rv);
         }
 
         txXSLTParamContext paramContext(&mParamNamespaceMap, *contextNode,
                                         mRecycler);
 
         // Parse
         nsAutoPtr<Expr> expr;
         rv = txExprParser::createExpr(aSelect, &paramContext,
--- a/gfx/layers/ipc/ISurfaceAllocator.cpp
+++ b/gfx/layers/ipc/ISurfaceAllocator.cpp
@@ -173,17 +173,20 @@ ISurfaceAllocator::DestroySharedSurface(
       NS_RUNTIMEABORT("surface type not implemented!");
   }
   *aSurface = SurfaceDescriptor();
 }
 
 // XXX - We should actually figure out the minimum shmem allocation size on
 // a certain platform and use that.
 const uint32_t sShmemPageSize = 4096;
+
+#ifdef DEBUG
 const uint32_t sSupportedBlockSize = 4;
+#endif
 
 enum AllocationStatus
 {
   STATUS_ALLOCATED,
   STATUS_FREED
 };
 
 struct ShmemSectionHeapHeader
@@ -319,10 +322,10 @@ ISurfaceAllocator::AllocGrallocBuffer(co
 }
 
 void
 ISurfaceAllocator::DeallocGrallocBuffer(MaybeMagicGrallocBufferHandle* aHandle)
 {
   SharedBufferManagerChild::GetSingleton()->DeallocGrallocBuffer(*aHandle);
 }
 
-} // namespace
-} // namespace
+} // namespace layers
+} // namespace mozilla
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -54,18 +54,16 @@
 
 #include "GeckoProfiler.h"
 
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
 #include "libdisplay/GonkDisplay.h"     // for GonkDisplay
 #include <ui/Fence.h>
 #endif
 
-#define BUFFER_OFFSET(i) ((char *)nullptr + (i))
-
 namespace mozilla {
 
 using namespace std;
 using namespace gfx;
 
 namespace layers {
 
 using namespace mozilla::gl;
@@ -401,21 +399,23 @@ SetRects(int n,
 {
   if (flip_y) {
     std::swap(ty0, ty1);
   }
   aLayerRects[n] = Rect(x0, y0, x1 - x0, y1 - y0);
   aTextureRects[n] = Rect(tx0, ty0, tx1 - tx0, ty1 - ty0);
 }
 
+#ifdef DEBUG
 static inline bool
 FuzzyEqual(float a, float b)
 {
   return fabs(a - b) < 0.0001f;
 }
+#endif
 
 static int
 DecomposeIntoNoRepeatRects(const Rect& aRect,
                            const Rect& aTexCoordRect,
                            Rect* aLayerRects,
                            Rect* aTextureRects)
 {
   Rect texCoordRect = aTexCoordRect;
--- a/gfx/src/nsFontMetrics.cpp
+++ b/gfx/src/nsFontMetrics.cpp
@@ -157,23 +157,25 @@ nscoord
 nsFontMetrics::XHeight()
 {
     return ROUND_TO_TWIPS(GetMetrics().xHeight);
 }
 
 nscoord
 nsFontMetrics::SuperscriptOffset()
 {
-    return ROUND_TO_TWIPS(GetMetrics().superscriptOffset);
+    return ROUND_TO_TWIPS(GetMetrics().emHeight *
+                          NS_FONT_SUPERSCRIPT_OFFSET_RATIO);
 }
 
 nscoord
 nsFontMetrics::SubscriptOffset()
 {
-    return ROUND_TO_TWIPS(GetMetrics().subscriptOffset);
+    return ROUND_TO_TWIPS(GetMetrics().emHeight *
+                          NS_FONT_SUBSCRIPT_OFFSET_RATIO);
 }
 
 void
 nsFontMetrics::GetStrikeout(nscoord& aOffset, nscoord& aSize)
 {
     aOffset = ROUND_TO_TWIPS(GetMetrics().strikeoutOffset);
     aSize = ROUND_TO_TWIPS(GetMetrics().strikeoutSize);
 }
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -8,16 +8,17 @@
 
 #include "mozilla/Attributes.h"
 #include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform
 #include "mozilla/layers/AsyncPanZoomController.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/GeckoContentController.h"
 #include "mozilla/layers/CompositorParent.h"
 #include "mozilla/layers/APZCTreeManager.h"
+#include "mozilla/Preferences.h"
 #include "base/task.h"
 #include "Layers.h"
 #include "TestLayers.h"
 #include "gfxPrefs.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
@@ -53,16 +54,34 @@ public:
   MOCK_METHOD3(HandleDoubleTap, void(const CSSPoint&, int32_t, const ScrollableLayerGuid&));
   MOCK_METHOD3(HandleSingleTap, void(const CSSPoint&, int32_t, const ScrollableLayerGuid&));
   MOCK_METHOD3(HandleLongTap, void(const CSSPoint&, int32_t, const ScrollableLayerGuid&));
   MOCK_METHOD3(HandleLongTapUp, void(const CSSPoint&, int32_t, const ScrollableLayerGuid&));
   MOCK_METHOD3(SendAsyncScrollDOMEvent, void(bool aIsRoot, const CSSRect &aContentRect, const CSSSize &aScrollableSize));
   MOCK_METHOD2(PostDelayedTask, void(Task* aTask, int aDelayMs));
 };
 
+class TestScopedBoolPref {
+public:
+  TestScopedBoolPref(const char* aPref, bool aVal)
+    : mPref(aPref)
+  {
+    mOldVal = Preferences::GetBool(aPref);
+    Preferences::SetBool(aPref, aVal);
+  }
+
+  ~TestScopedBoolPref() {
+    Preferences::SetBool(mPref, mOldVal);
+  }
+
+private:
+  const char* mPref;
+  bool mOldVal;
+};
+
 class MockContentControllerDelayed : public MockContentController {
 public:
   MockContentControllerDelayed()
   {
   }
 
   void PostDelayedTask(Task* aTask, int aDelayMs) {
     mTaskQueue.AppendElement(aTask);
@@ -879,40 +898,100 @@ TEST_F(AsyncPanZoomControllerTester, Fli
   DoFlingStopTest(false);
 }
 
 TEST_F(AsyncPanZoomControllerTester, FlingStopTap) {
   DoFlingStopTest(true);
 }
 
 TEST_F(AsyncPanZoomControllerTester, OverScrollPanning) {
+  TestScopedBoolPref overscrollEnabledPref("apz.overscroll.enabled", true);
+
   TimeStamp testStartTime = TimeStamp::Now();
   AsyncPanZoomController::SetFrameTime(testStartTime);
 
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc, tm);
 
   apzc->SetFrameMetrics(TestFrameMetrics());
   apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
 
-  EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
-  EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
+  // Pan sufficiently to hit overscroll behavior
+  int time = 0;
+  int touchStart = 500;
+  int touchEnd = 10;
+  ApzcPan(apzc, tm, time, touchStart, touchEnd);
+  EXPECT_TRUE(apzc->IsOverscrolled());
+
+  // Note that in the calls to SampleContentTransformForFrame below, the time
+  // increment used is sufficiently large for the animation to have completed. However,
+  // any single call to SampleContentTransformForFrame will not finish an animation
+  // *and* also proceed through the following animation, if there is one.
+  // Therefore the minimum number of calls to go from an overscroll-inducing pan
+  // to a reset state is 3; these are documented further below.
+
+  ScreenPoint pointOut;
+  ViewTransform viewTransformOut;
+
+  // This sample will run to the end of the non-overscrolling fling animation
+  // and will schedule the overscrolling fling animation.
+  apzc->SampleContentTransformForFrame(testStartTime + TimeDuration::FromMilliseconds(10000), &viewTransformOut, pointOut);
+  EXPECT_EQ(ScreenPoint(0, 90), pointOut);
+  EXPECT_TRUE(apzc->IsOverscrolled());
+
+  // This sample will run to the end of the overscrolling fling animation and
+  // will schedule the snapback animation.
+  apzc->SampleContentTransformForFrame(testStartTime + TimeDuration::FromMilliseconds(20000), &viewTransformOut, pointOut);
+  EXPECT_EQ(ScreenPoint(0, 90), pointOut);
+  EXPECT_TRUE(apzc->IsOverscrolled());
+
+  // This sample will run to the end of the snapback animation and reset the state.
+  apzc->SampleContentTransformForFrame(testStartTime + TimeDuration::FromMilliseconds(30000), &viewTransformOut, pointOut);
+  EXPECT_EQ(ScreenPoint(0, 90), pointOut);
+  EXPECT_FALSE(apzc->IsOverscrolled());
+
+  apzc->AssertStateIsReset();
+  apzc->Destroy();
+}
+
+TEST_F(AsyncPanZoomControllerTester, OverScrollAbort) {
+  TestScopedBoolPref overscrollEnabledPref("apz.overscroll.enabled", true);
+
+  TimeStamp testStartTime = TimeStamp::Now();
+  AsyncPanZoomController::SetFrameTime(testStartTime);
+
+  nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
+  nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
+  nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc, tm);
+
+  apzc->SetFrameMetrics(TestFrameMetrics());
+  apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
 
   // Pan sufficiently to hit overscroll behavior
   int time = 0;
   int touchStart = 500;
   int touchEnd = 10;
+  ApzcPan(apzc, tm, time, touchStart, touchEnd);
+  EXPECT_TRUE(apzc->IsOverscrolled());
+
   ScreenPoint pointOut;
   ViewTransform viewTransformOut;
 
-  // Pan down
-  ApzcPan(apzc, tm, time, touchStart, touchEnd);
-  apzc->SampleContentTransformForFrame(testStartTime+TimeDuration::FromMilliseconds(1000), &viewTransformOut, pointOut);
-  EXPECT_EQ(ScreenPoint(0, 90), pointOut);
+  // This sample call will run to the end of the non-overscrolling fling animation
+  // and will schedule the overscrolling fling animation (see comment in OverScrollPanning
+  // above for more explanation).
+  apzc->SampleContentTransformForFrame(testStartTime + TimeDuration::FromMilliseconds(10000), &viewTransformOut, pointOut);
+  EXPECT_TRUE(apzc->IsOverscrolled());
+
+  // At this point, we have an active overscrolling fling animation.
+  // Check that cancelling the animation clears the overscroll.
+  apzc->CancelAnimation();
+  EXPECT_FALSE(apzc->IsOverscrolled());
+  apzc->AssertStateIsReset();
 
   apzc->Destroy();
 }
 
 TEST_F(AsyncPanZoomControllerTester, ShortPress) {
   nsRefPtr<MockContentControllerDelayed> mcc = new NiceMock<MockContentControllerDelayed>();
   nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(
--- a/gfx/thebes/gfxDWriteFonts.cpp
+++ b/gfx/thebes/gfxDWriteFonts.cpp
@@ -2,19 +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/. */
 
 #include "gfxDWriteFonts.h"
 
 #include "mozilla/MemoryReporting.h"
 
-#include "gfxHarfBuzzShaper.h"
 #include <algorithm>
-#include "gfxGraphiteShaper.h"
 #include "gfxDWriteFontList.h"
 #include "gfxContext.h"
 #include <dwrite.h>
 
 #include "harfbuzz/hb.h"
 
 // Chosen this as to resemble DWrite's own oblique face style.
 #define OBLIQUE_SKEW_FACTOR 0.3
@@ -101,24 +99,16 @@ gfxDWriteFont::gfxDWriteFont(gfxFontEntr
     rv = fe->CreateFontFace(getter_AddRefs(mFontFace), sims);
 
     if (NS_FAILED(rv)) {
         mIsValid = false;
         return;
     }
 
     ComputeMetrics(anAAOption);
-
-    if (FontCanSupportGraphite()) {
-        mGraphiteShaper = new gfxGraphiteShaper(this);
-    }
-
-    if (FontCanSupportHarfBuzz()) {
-        mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
-    }
 }
 
 gfxDWriteFont::~gfxDWriteFont()
 {
     if (mCairoFontFace) {
         cairo_font_face_destroy(mCairoFontFace);
     }
     if (mScaledFont) {
@@ -129,42 +119,16 @@ gfxDWriteFont::~gfxDWriteFont()
 
 gfxFont*
 gfxDWriteFont::CopyWithAntialiasOption(AntialiasOption anAAOption)
 {
     return new gfxDWriteFont(static_cast<gfxDWriteFontEntry*>(mFontEntry.get()),
                              &mStyle, mNeedsBold, anAAOption);
 }
 
-bool
-gfxDWriteFont::ShapeText(gfxContext      *aContext,
-                         const char16_t *aText,
-                         uint32_t         aOffset,
-                         uint32_t         aLength,
-                         int32_t          aScript,
-                         gfxShapedText   *aShapedText,
-                         bool             aPreferPlatformShaping)
-{
-    bool ok = false;
-
-    if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
-        ok = mGraphiteShaper->ShapeText(aContext, aText, aOffset, aLength,
-                                        aScript, aShapedText);
-    }
-
-    if (!ok && mHarfBuzzShaper) {
-        ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength,
-                                        aScript, aShapedText);
-    }
-
-    PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
-
-    return ok;
-}
-
 const gfxFont::Metrics&
 gfxDWriteFont::GetMetrics()
 {
     return *mMetrics;
 }
 
 bool
 gfxDWriteFont::GetFakeMetricsForArialBlack(DWRITE_FONT_METRICS *aFontMetrics)
@@ -311,32 +275,29 @@ gfxDWriteFont::ComputeMetrics(AntialiasO
     mMetrics->underlineOffset =
         fontMetrics.underlinePosition * mFUnitsConvFactor;
     mMetrics->underlineSize = 
         fontMetrics.underlineThickness * mFUnitsConvFactor;
     mMetrics->strikeoutOffset =
         fontMetrics.strikethroughPosition * mFUnitsConvFactor;
     mMetrics->strikeoutSize =
         fontMetrics.strikethroughThickness * mFUnitsConvFactor;
-    mMetrics->superscriptOffset = 0;
-    mMetrics->subscriptOffset = 0;
 
     SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont);
 
 #if 0
     printf("Font: %p (%s) size: %f\n", this,
            NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size);
     printf("    emHeight: %f emAscent: %f emDescent: %f\n", mMetrics->emHeight, mMetrics->emAscent, mMetrics->emDescent);
     printf("    maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics->maxAscent, mMetrics->maxDescent, mMetrics->maxAdvance);
     printf("    internalLeading: %f externalLeading: %f\n", mMetrics->internalLeading, mMetrics->externalLeading);
     printf("    spaceWidth: %f aveCharWidth: %f zeroOrAve: %f xHeight: %f\n",
            mMetrics->spaceWidth, mMetrics->aveCharWidth, mMetrics->zeroOrAveCharWidth, mMetrics->xHeight);
-    printf("    uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n",
-           mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize,
-           mMetrics->superscriptOffset, mMetrics->subscriptOffset);
+    printf("    uOff: %f uSize: %f stOff: %f stSize: %f\n",
+           mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize);
 #endif
 }
 
 using namespace mozilla; // for AutoSwap_* types
 
 struct EBLCHeader {
     AutoSwap_PRUint32 version;
     AutoSwap_PRUint32 numSizes;
--- a/gfx/thebes/gfxDWriteFonts.h
+++ b/gfx/thebes/gfxDWriteFonts.h
@@ -66,24 +66,16 @@ public:
 
     virtual FontType GetType() const { return FONT_TYPE_DWRITE; }
 
     virtual mozilla::TemporaryRef<mozilla::gfx::ScaledFont> GetScaledFont(mozilla::gfx::DrawTarget *aTarget);
 
     virtual cairo_scaled_font_t *GetCairoScaledFont();
 
 protected:
-    virtual bool ShapeText(gfxContext     *aContext,
-                           const char16_t *aText,
-                           uint32_t        aOffset,
-                           uint32_t        aLength,
-                           int32_t         aScript,
-                           gfxShapedText  *aShapedText,
-                           bool            aPreferPlatformShaping = false);
-
     bool GetFakeMetricsForArialBlack(DWRITE_FONT_METRICS *aFontMetrics);
 
     void ComputeMetrics(AntialiasOption anAAOption);
 
     bool HasBitmapStrikeForSize(uint32_t aSize);
 
     cairo_font_face_t *CairoFontFace();
 
--- a/gfx/thebes/gfxFT2FontBase.cpp
+++ b/gfx/thebes/gfxFT2FontBase.cpp
@@ -128,17 +128,17 @@ gfxFT2FontBase::GetMetrics()
     //    printf("font name: %s %f\n", NS_ConvertUTF16toUTF8(GetName()).get(), GetStyle()->size);
     //    printf ("pango font %s\n", pango_font_description_to_string (pango_font_describe (font)));
 
     fprintf (stderr, "Font: %s\n", NS_ConvertUTF16toUTF8(GetName()).get());
     fprintf (stderr, "    emHeight: %f emAscent: %f emDescent: %f\n", mMetrics.emHeight, mMetrics.emAscent, mMetrics.emDescent);
     fprintf (stderr, "    maxAscent: %f maxDescent: %f\n", mMetrics.maxAscent, mMetrics.maxDescent);
     fprintf (stderr, "    internalLeading: %f externalLeading: %f\n", mMetrics.externalLeading, mMetrics.internalLeading);
     fprintf (stderr, "    spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.xHeight);
-    fprintf (stderr, "    uOff: %f uSize: %f stOff: %f stSize: %f suOff: %f suSize: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize, mMetrics.superscriptOffset, mMetrics.subscriptOffset);
+    fprintf (stderr, "    uOff: %f uSize: %f stOff: %f stSize: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize);
 #endif
 
     mHasMetrics = true;
     return mMetrics;
 }
 
 // Get the glyphID of a space
 uint32_t
--- a/gfx/thebes/gfxFT2Fonts.cpp
+++ b/gfx/thebes/gfxFT2Fonts.cpp
@@ -19,18 +19,16 @@
 #endif
 
 #include "gfxTypes.h"
 #include "gfxFT2Fonts.h"
 #include "gfxFT2FontBase.h"
 #include "gfxFT2Utils.h"
 #include "gfxFT2FontList.h"
 #include <locale.h>
-#include "gfxHarfBuzzShaper.h"
-#include "gfxGraphiteShaper.h"
 #include "nsGkAtoms.h"
 #include "nsTArray.h"
 #include "nsUnicodeRange.h"
 #include "nsCRT.h"
 #include "nsXULAppAPI.h"
 
 #include "prlog.h"
 #include "prinit.h"
@@ -39,52 +37,30 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/gfx/2D.h"
 
 /**
  * gfxFT2Font
  */
 
 bool
-gfxFT2Font::ShapeText(gfxContext      *aContext,
+gfxFT2Font::ShapeText(gfxContext     *aContext,
                       const char16_t *aText,
-                      uint32_t         aOffset,
-                      uint32_t         aLength,
-                      int32_t          aScript,
-                      gfxShapedText   *aShapedText,
-                      bool             aPreferPlatformShaping)
+                      uint32_t        aOffset,
+                      uint32_t        aLength,
+                      int32_t         aScript,
+                      gfxShapedText  *aShapedText)
 {
-    bool ok = false;
-
-    if (FontCanSupportGraphite()) {
-        if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
-            if (!mGraphiteShaper) {
-                mGraphiteShaper = new gfxGraphiteShaper(this);
-            }
-            ok = mGraphiteShaper->ShapeText(aContext, aText,
-                                            aOffset, aLength,
-                                            aScript, aShapedText);
-        }
+    if (!gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript,
+                            aShapedText)) {
+        // harfbuzz must have failed(?!), just render raw glyphs
+        AddRange(aText, aOffset, aLength, aShapedText);
+        PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
     }
 
-    if (!ok && gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aScript)) {
-        if (!mHarfBuzzShaper) {
-            mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
-        }
-        ok = mHarfBuzzShaper->ShapeText(aContext, aText,
-                                        aOffset, aLength,
-                                        aScript, aShapedText);
-    }
-
-    if (!ok) {
-        AddRange(aText, aOffset, aLength, aShapedText);
-    }
-
-    PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
-
     return true;
 }
 
 void
 gfxFT2Font::AddRange(const char16_t *aText, uint32_t aOffset,
                      uint32_t aLength, gfxShapedText *aShapedText)
 {
     const uint32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit();
--- a/gfx/thebes/gfxFT2Fonts.h
+++ b/gfx/thebes/gfxFT2Fonts.h
@@ -72,18 +72,17 @@ public: // new functions
 #endif
 
 protected:
     virtual bool ShapeText(gfxContext      *aContext,
                            const char16_t *aText,
                            uint32_t         aOffset,
                            uint32_t         aLength,
                            int32_t          aScript,
-                           gfxShapedText   *aShapedText,
-                           bool             aPreferPlatformShaping);
+                           gfxShapedText   *aShapedText);
 
     void FillGlyphDataForChar(uint32_t ch, CachedGlyphData *gd);
 
     void AddRange(const char16_t *aText,
                   uint32_t         aOffset,
                   uint32_t         aLength,
                   gfxShapedText   *aShapedText);
 
--- a/gfx/thebes/gfxFT2Utils.cpp
+++ b/gfx/thebes/gfxFT2Utils.cpp
@@ -62,18 +62,16 @@ gfxFT2LockedFace::GetMetrics(gfxFont::Me
         aMetrics->externalLeading = 0.2 * emHeight;
         const gfxFloat spaceWidth = 0.5 * emHeight;
         aMetrics->spaceWidth = spaceWidth;
         aMetrics->maxAdvance = spaceWidth;
         aMetrics->aveCharWidth = spaceWidth;
         aMetrics->zeroOrAveCharWidth = spaceWidth;
         const gfxFloat xHeight = 0.5 * emHeight;
         aMetrics->xHeight = xHeight;
-        aMetrics->superscriptOffset = xHeight;
-        aMetrics->subscriptOffset = xHeight;
         const gfxFloat underlineSize = emHeight / 14.0;
         aMetrics->underlineSize = underlineSize;
         aMetrics->underlineOffset = -underlineSize;
         aMetrics->strikeoutOffset = 0.25 * emHeight;
         aMetrics->strikeoutSize = underlineSize;
 
         *aSpaceGlyph = 0;
         return;
@@ -238,34 +236,16 @@ gfxFT2LockedFace::GetMetrics(gfxFont::Me
     } else { // No strikeout info.
         aMetrics->strikeoutSize = aMetrics->underlineSize;
         // Use OpenType spec's suggested position for Roman font.
         aMetrics->strikeoutOffset = emHeight * 409.0 / 2048.0
             + 0.5 * aMetrics->strikeoutSize;
     }
     SnapLineToPixels(aMetrics->strikeoutOffset, aMetrics->strikeoutSize);
 
-    if (os2 && os2->ySuperscriptYOffset) {
-        gfxFloat val = ScaleRoundDesignUnits(os2->ySuperscriptYOffset,
-                                             ftMetrics.y_scale);
-        aMetrics->superscriptOffset = std::max(1.0, val);
-    } else {
-        aMetrics->superscriptOffset = aMetrics->xHeight;
-    }
-    
-    if (os2 && os2->ySubscriptYOffset) {
-        gfxFloat val = ScaleRoundDesignUnits(os2->ySubscriptYOffset,
-                                             ftMetrics.y_scale);
-        // some fonts have the incorrect sign. 
-        val = fabs(val);
-        aMetrics->subscriptOffset = std::max(1.0, val);
-    } else {
-        aMetrics->subscriptOffset = aMetrics->xHeight;
-    }
-
     aMetrics->maxHeight = aMetrics->maxAscent + aMetrics->maxDescent;
 
     // Make the line height an integer number of pixels so that lines will be
     // equally spaced (rather than just being snapped to pixels, some up and
     // some down).  Layout calculates line height from the emHeight +
     // internalLeading + externalLeading, but first each of these is rounded
     // to layout units.  To ensure that the result is an integer number of
     // pixels, round each of the components to pixels.
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -18,16 +18,17 @@
 
 #include "gfxFont.h"
 #include "gfxPlatform.h"
 #include "nsGkAtoms.h"
 
 #include "gfxTypes.h"
 #include "gfxContext.h"
 #include "gfxFontMissingGlyphs.h"
+#include "gfxGraphiteShaper.h"
 #include "gfxHarfBuzzShaper.h"
 #include "gfxUserFontSet.h"
 #include "gfxPlatformFontList.h"
 #include "gfxScriptItemizer.h"
 #include "nsSpecialCasingData.h"
 #include "nsTextRunTransformations.h"
 #include "nsUnicodeProperties.h"
 #include "nsMathUtils.h"
@@ -4069,61 +4070,57 @@ gfxFont::CacheHashEntry::KeyEquals(const
 }
 
 bool
 gfxFont::ShapeText(gfxContext    *aContext,
                    const uint8_t *aText,
                    uint32_t       aOffset,
                    uint32_t       aLength,
                    int32_t        aScript,
-                   gfxShapedText *aShapedText,
-                   bool           aPreferPlatformShaping)
+                   gfxShapedText *aShapedText)
 {
     nsDependentCSubstring ascii((const char*)aText, aLength);
     nsAutoString utf16;
     AppendASCIItoUTF16(ascii, utf16);
     if (utf16.Length() != aLength) {
         return false;
     }
     return ShapeText(aContext, utf16.BeginReading(), aOffset, aLength,
-                     aScript, aShapedText, aPreferPlatformShaping);
+                     aScript, aShapedText);
 }
 
 bool
 gfxFont::ShapeText(gfxContext      *aContext,
                    const char16_t *aText,
                    uint32_t         aOffset,
                    uint32_t         aLength,
                    int32_t          aScript,
-                   gfxShapedText   *aShapedText,
-                   bool             aPreferPlatformShaping)
+                   gfxShapedText   *aShapedText)
 {
     bool ok = false;
 
-    if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
-        ok = mGraphiteShaper->ShapeText(aContext, aText, aOffset, aLength,
-                                        aScript, aShapedText);
-    }
-
-    if (!ok && mHarfBuzzShaper && !aPreferPlatformShaping) {
-        if (gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aScript)) {
-            ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength,
+    if (FontCanSupportGraphite()) {
+        if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
+            if (!mGraphiteShaper) {
+                mGraphiteShaper = new gfxGraphiteShaper(this);
+            }
+            ok = mGraphiteShaper->ShapeText(aContext, aText, aOffset, aLength,
                                             aScript, aShapedText);
         }
     }
 
     if (!ok) {
-        if (!mPlatformShaper) {
-            CreatePlatformShaper();
-        }
-        if (mPlatformShaper) {
-            ok = mPlatformShaper->ShapeText(aContext, aText, aOffset, aLength,
-                                            aScript, aShapedText);
-        }
-    }
+        if (!mHarfBuzzShaper) {
+            mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
+        }
+        ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength,
+                                        aScript, aShapedText);
+    }
+
+    NS_WARN_IF_FALSE(ok, "shaper failed, expect scrambled or missing text");
 
     PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
 
     return ok;
 }
 
 void
 gfxFont::PostShapingFixup(gfxContext      *aContext,
@@ -4592,18 +4589,16 @@ gfxFont::InitMetricsFromSfntTables(Metri
             // version 2 and later includes the x-height field
             SET_SIGNED(xHeight, os2->sxHeight);
             // Abs because of negative xHeight seen in Kokonor (Tibetan) font
             aMetrics.xHeight = Abs(aMetrics.xHeight);
         }
         // this should always be present in any valid OS/2 of any version
         if (len >= offsetof(OS2Table, sTypoLineGap) + sizeof(int16_t)) {
             SET_SIGNED(aveCharWidth, os2->xAvgCharWidth);
-            SET_SIGNED(subscriptOffset, os2->ySubscriptYOffset);
-            SET_SIGNED(superscriptOffset, os2->ySuperscriptYOffset);
             SET_SIGNED(strikeoutSize, os2->yStrikeoutSize);
             SET_SIGNED(strikeoutOffset, os2->yStrikeoutPosition);
 
             // for fonts with USE_TYPO_METRICS set in the fsSelection field,
             // and for all OpenType math fonts (having a 'MATH' table),
             // let the OS/2 sTypo* metrics override those from the hhea table
             // (see http://www.microsoft.com/typography/otspec/os2.htm#fss)
             const uint16_t kUseTypoMetricsMask = 1 << 7;
@@ -4655,23 +4650,16 @@ void gfxFont::CalculateDerivedMetrics(Me
 
     if (GetFontEntry()->IsFixedPitch()) {
         // Some Quartz fonts are fixed pitch, but there's some glyph with a bigger
         // advance than the average character width... this forces
         // those fonts to be recognized like fixed pitch fonts by layout.
         aMetrics.maxAdvance = aMetrics.aveCharWidth;
     }
 
-    if (!aMetrics.subscriptOffset) {
-        aMetrics.subscriptOffset = aMetrics.xHeight;
-    }
-    if (!aMetrics.superscriptOffset) {
-        aMetrics.superscriptOffset = aMetrics.xHeight;
-    }
-
     if (!aMetrics.strikeoutOffset) {
         aMetrics.strikeoutOffset = aMetrics.xHeight * 0.5;
     }
     if (!aMetrics.strikeoutSize) {
         aMetrics.strikeoutSize = aMetrics.underlineSize;
     }
 }
 
@@ -4680,29 +4668,16 @@ gfxFont::SanitizeMetrics(gfxFont::Metric
 {
     // Even if this font size is zero, this font is created with non-zero size.
     // However, for layout and others, we should return the metrics of zero size font.
     if (mStyle.size == 0.0) {
         memset(aMetrics, 0, sizeof(gfxFont::Metrics));
         return;
     }
 
-    // MS (P)Gothic and MS (P)Mincho are not having suitable values in their super script offset.
-    // If the values are not suitable, we should use x-height instead of them.
-    // See https://bugzilla.mozilla.org/show_bug.cgi?id=353632
-    if (aMetrics->superscriptOffset <= 0 ||
-        aMetrics->superscriptOffset >= aMetrics->maxAscent) {
-        aMetrics->superscriptOffset = aMetrics->xHeight;
-    }
-    // And also checking the case of sub script offset. The old gfx for win has checked this too.
-    if (aMetrics->subscriptOffset <= 0 ||
-        aMetrics->subscriptOffset >= aMetrics->maxAscent) {
-        aMetrics->subscriptOffset = aMetrics->xHeight;
-    }
-
     aMetrics->underlineSize = std::max(1.0, aMetrics->underlineSize);
     aMetrics->strikeoutSize = std::max(1.0, aMetrics->strikeoutSize);
 
     aMetrics->underlineOffset = std::min(aMetrics->underlineOffset, -1.0);
 
     if (aMetrics->maxAscent < 1.0) {
         // We cannot draw strikeout line and overline in the ascent...
         aMetrics->underlineSize = 0;
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -1474,22 +1474,22 @@ public:
         NS_ASSERTION(aFont, "shaper requires a valid font!");
     }
 
     virtual ~gfxFontShaper() { }
 
     // Shape a piece of text and store the resulting glyph data into
     // aShapedText. Parameters aOffset/aLength indicate the range of
     // aShapedText to be updated; aLength is also the length of aText.
-    virtual bool ShapeText(gfxContext      *aContext,
+    virtual bool ShapeText(gfxContext     *aContext,
                            const char16_t *aText,
-                           uint32_t         aOffset,
-                           uint32_t         aLength,
-                           int32_t          aScript,
-                           gfxShapedText   *aShapedText) = 0;
+                           uint32_t        aOffset,
+                           uint32_t        aLength,
+                           int32_t         aScript,
+                           gfxShapedText  *aShapedText) = 0;
 
     gfxFont *GetFont() const { return mFont; }
 
     // returns true if features exist in output, false otherwise
     static bool
     MergeFontFeatures(const gfxFontStyle *aStyle,
                       const nsTArray<gfxFontFeature>& aFontFeatures,
                       bool aDisableLigatures,
@@ -1653,18 +1653,16 @@ public:
     virtual mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions>
       GetGlyphRenderingOptions() { return nullptr; }
 
     gfxFloat SynthesizeSpaceWidth(uint32_t aCh);
 
     // Font metrics
     struct Metrics {
         gfxFloat xHeight;
-        gfxFloat superscriptOffset;
-        gfxFloat subscriptOffset;
         gfxFloat strikeoutSize;
         gfxFloat strikeoutOffset;
         gfxFloat underlineSize;
         gfxFloat underlineOffset;
 
         gfxFloat internalLeading;
         gfxFloat externalLeading;
 
@@ -1993,28 +1991,26 @@ protected:
     bool SpaceMayParticipateInShaping(int32_t aRunScript);
 
     // For 8-bit text, expand to 16-bit and then call the following method.
     bool ShapeText(gfxContext    *aContext,
                    const uint8_t *aText,
                    uint32_t       aOffset, // dest offset in gfxShapedText
                    uint32_t       aLength,
                    int32_t        aScript,
-                   gfxShapedText *aShapedText, // where to store the result
-                   bool           aPreferPlatformShaping = false);
+                   gfxShapedText *aShapedText); // where to store the result
 
     // Call the appropriate shaper to generate glyphs for aText and store
     // them into aShapedText.
     virtual bool ShapeText(gfxContext      *aContext,
                            const char16_t *aText,
                            uint32_t         aOffset,
                            uint32_t         aLength,
                            int32_t          aScript,
-                           gfxShapedText   *aShapedText,
-                           bool             aPreferPlatformShaping = false);
+                           gfxShapedText   *aShapedText);
 
     // Helper to adjust for synthetic bold and set character-type flags
     // in the shaped text; implementations of ShapeText should call this
     // after glyph shaping has been completed.
     void PostShapingFixup(gfxContext      *aContext,
                           const char16_t *aText,
                           uint32_t         aOffset, // position within aShapedText
                           uint32_t         aLength,
@@ -2163,29 +2159,24 @@ protected:
 
     // the AA setting requested for this font - may affect glyph bounds
     AntialiasOption            mAntialiasOption;
 
     // a copy of the font without antialiasing, if needed for separate
     // measurement by mathml code
     nsAutoPtr<gfxFont>         mNonAAFont;
 
-    // we may switch between these shapers on the fly, based on the script
-    // of the text run being shaped
-    nsAutoPtr<gfxFontShaper>   mPlatformShaper;
+    // we create either or both of these shapers when needed, depending
+    // whether the font has graphite tables, and whether graphite shaping
+    // is actually enabled
     nsAutoPtr<gfxFontShaper>   mHarfBuzzShaper;
     nsAutoPtr<gfxFontShaper>   mGraphiteShaper;
 
     mozilla::RefPtr<mozilla::gfx::ScaledFont> mAzureScaledFont;
 
-    // Create a default platform text shaper for this font.
-    // (TODO: This should become pure virtual once all font backends have
-    // been updated.)
-    virtual void CreatePlatformShaper() { }
-
     // Helper for subclasses that want to initialize standard metrics from the
     // tables of sfnt (TrueType/OpenType) fonts.
     // This will use mFUnitsConvFactor if it is already set, else compute it
     // from mAdjustedSize and the unitsPerEm in the font's 'head' table.
     // Returns TRUE and sets mIsValid=TRUE if successful;
     // Returns TRUE but leaves mIsValid=FALSE if the font seems to be broken.
     // Returns FALSE if the font does not appear to be an sfnt at all,
     // and should be handled (if possible) using other APIs.
--- a/gfx/thebes/gfxFontConstants.h
+++ b/gfx/thebes/gfxFontConstants.h
@@ -191,9 +191,13 @@ enum {
 #define NS_FONT_VARIANT_NUMERIC_FRACTION_MASK \
     NS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS | \
     NS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS
 
 #define NS_FONT_VARIANT_POSITION_NORMAL             0
 #define NS_FONT_VARIANT_POSITION_SUPER              1
 #define NS_FONT_VARIANT_POSITION_SUB                2
 
+// based on fixed offset values used within WebKit
+#define NS_FONT_SUBSCRIPT_OFFSET_RATIO     (0.20)
+#define NS_FONT_SUPERSCRIPT_OFFSET_RATIO   (0.34)
+
 #endif
--- a/gfx/thebes/gfxGDIFont.cpp
+++ b/gfx/thebes/gfxGDIFont.cpp
@@ -3,19 +3,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 "gfxGDIFont.h"
 
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/WindowsVersion.h"
 
-#include "gfxHarfBuzzShaper.h"
 #include <algorithm>
-#include "gfxGraphiteShaper.h"
 #include "gfxWindowsPlatform.h"
 #include "gfxContext.h"
 #include "mozilla/Preferences.h"
 #include "nsUnicodeProperties.h"
 #include "gfxFontConstants.h"
 
 #include "cairo-win32.h"
 
@@ -47,20 +45,16 @@ gfxGDIFont::gfxGDIFont(GDIFontEntry *aFo
     : gfxFont(aFontEntry, aFontStyle, anAAOption),
       mFont(nullptr),
       mFontFace(nullptr),
       mMetrics(nullptr),
       mSpaceGlyph(0),
       mNeedsBold(aNeedsBold),
       mScriptCache(nullptr)
 {
-    if (FontCanSupportGraphite()) {
-        mGraphiteShaper = new gfxGraphiteShaper(this);
-    }
-    mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
 }
 
 gfxGDIFont::~gfxGDIFont()
 {
     if (mScaledFont) {
         cairo_scaled_font_destroy(mScaledFont);
     }
     if (mFontFace) {
@@ -78,23 +72,22 @@ gfxGDIFont::~gfxGDIFont()
 gfxFont*
 gfxGDIFont::CopyWithAntialiasOption(AntialiasOption anAAOption)
 {
     return new gfxGDIFont(static_cast<GDIFontEntry*>(mFontEntry.get()),
                           &mStyle, mNeedsBold, anAAOption);
 }
 
 bool
-gfxGDIFont::ShapeText(gfxContext      *aContext,
+gfxGDIFont::ShapeText(gfxContext     *aContext,
                       const char16_t *aText,
-                      uint32_t         aOffset,
-                      uint32_t         aLength,
-                      int32_t          aScript,
-                      gfxShapedText   *aShapedText,
-                      bool             aPreferPlatformShaping)
+                      uint32_t        aOffset,
+                      uint32_t        aLength,
+                      int32_t         aScript,
+                      gfxShapedText  *aShapedText)
 {
     if (!mMetrics) {
         Initialize();
     }
     if (!mIsValid) {
         NS_WARNING("invalid font! expect incorrect text rendering");
         return false;
     }
@@ -103,17 +96,17 @@ gfxGDIFont::ShapeText(gfxContext      *a
     // creating a "toy" font internally (see bug 544617).
     // We must check that this succeeded, otherwise we risk cairo creating the
     // wrong kind of font internally as a fallback (bug 744480).
     if (!SetupCairoFont(aContext)) {
         return false;
     }
 
     return gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript,
-                              aShapedText, aPreferPlatformShaping);
+                              aShapedText);
 }
 
 const gfxFont::Metrics&
 gfxGDIFont::GetMetrics()
 {
     if (!mMetrics) {
         Initialize();
     }
@@ -242,19 +235,16 @@ gfxGDIFont::Initialize()
 
     // Get font metrics if size > 0
     if (mAdjustedSize > 0.0) {
 
         OUTLINETEXTMETRIC oMetrics;
         TEXTMETRIC& metrics = oMetrics.otmTextMetrics;
 
         if (0 < GetOutlineTextMetrics(dc.GetDC(), sizeof(oMetrics), &oMetrics)) {
-            mMetrics->superscriptOffset = (double)oMetrics.otmptSuperscriptOffset.y;
-            // Some fonts have wrong sign on their subscript offset, bug 410917.
-            mMetrics->subscriptOffset = fabs((double)oMetrics.otmptSubscriptOffset.y);
             mMetrics->strikeoutSize = (double)oMetrics.otmsStrikeoutSize;
             mMetrics->strikeoutOffset = (double)oMetrics.otmsStrikeoutPosition;
             mMetrics->underlineSize = (double)oMetrics.otmsUnderscoreSize;
             mMetrics->underlineOffset = (double)oMetrics.otmsUnderscorePosition;
 
             const MAT2 kIdentityMatrix = { {0, 1}, {0, 0}, {0, 0}, {0, 1} };
             GLYPHMETRICS gm;
             DWORD len = GetGlyphOutlineW(dc.GetDC(), char16_t('x'), GGO_METRICS, &gm, 0, nullptr, &kIdentityMatrix);
@@ -283,18 +273,16 @@ gfxGDIFont::Initialize()
                 NS_WARNING("Missing or corrupt font data, fasten your seatbelt");
                 mIsValid = false;
                 memset(mMetrics, 0, sizeof(*mMetrics));
                 return;
             }
 
             mMetrics->xHeight =
                 ROUND((float)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR);
-            mMetrics->superscriptOffset = mMetrics->xHeight;
-            mMetrics->subscriptOffset = mMetrics->xHeight;
             mMetrics->strikeoutSize = 1;
             mMetrics->strikeoutOffset = ROUND(mMetrics->xHeight * 0.5f); // 50% of xHeight
             mMetrics->underlineSize = 1;
             mMetrics->underlineOffset = -ROUND((float)metrics.tmDescent * 0.30f); // 30% of descent
             mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading;
             mMetrics->emAscent = metrics.tmAscent - metrics.tmInternalLeading;
             mMetrics->emDescent = metrics.tmDescent;
         }
@@ -389,19 +377,18 @@ gfxGDIFont::Initialize()
 
 #if 0
     printf("Font: %p (%s) size: %f adjusted size: %f valid: %s\n", this,
            NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size, mAdjustedSize, (mIsValid ? "yes" : "no"));
     printf("    emHeight: %f emAscent: %f emDescent: %f\n", mMetrics->emHeight, mMetrics->emAscent, mMetrics->emDescent);
     printf("    maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics->maxAscent, mMetrics->maxDescent, mMetrics->maxAdvance);
     printf("    internalLeading: %f externalLeading: %f\n", mMetrics->internalLeading, mMetrics->externalLeading);
     printf("    spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics->spaceWidth, mMetrics->aveCharWidth, mMetrics->xHeight);
-    printf("    uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n",
-           mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize,
-           mMetrics->superscriptOffset, mMetrics->subscriptOffset);
+    printf("    uOff: %f uSize: %f stOff: %f stSize: %f\n",
+           mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize);
 #endif
 }
 
 void
 gfxGDIFont::FillLogFont(LOGFONTW& aLogFont, gfxFloat aSize,
                         bool aUseGDIFakeItalic)
 {
     GDIFontEntry *fe = static_cast<GDIFontEntry*>(GetFontEntry());
--- a/gfx/thebes/gfxGDIFont.h
+++ b/gfx/thebes/gfxGDIFont.h
@@ -67,23 +67,22 @@ public:
                                         FontCacheSizes* aSizes) const;
     virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                         FontCacheSizes* aSizes) const;
 
     virtual FontType GetType() const { return FONT_TYPE_GDI; }
 
 protected:
     /* override to ensure the cairo font is set up properly */
-    virtual bool ShapeText(gfxContext      *aContext,
+    virtual bool ShapeText(gfxContext     *aContext,
                            const char16_t *aText,
-                           uint32_t         aOffset,
-                           uint32_t         aLength,
-                           int32_t          aScript,
-                           gfxShapedText   *aShapedText,
-                           bool             aPreferPlatformShaping);
+                           uint32_t        aOffset,
+                           uint32_t        aLength,
+                           int32_t         aScript,
+                           gfxShapedText  *aShapedText);
 
     void Initialize(); // creates metrics and Cairo fonts
 
     // Fill the given LOGFONT record according to our style, but don't adjust
     // the lfItalic field if we're going to use a cairo transform for fake
     // italics.
     void FillLogFont(LOGFONTW& aLogFont, gfxFloat aSize, bool aUseGDIFakeItalic);
 
--- a/gfx/thebes/gfxMacFont.cpp
+++ b/gfx/thebes/gfxMacFont.cpp
@@ -3,19 +3,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 "gfxMacFont.h"
 
 #include "mozilla/MemoryReporting.h"
 
 #include "gfxCoreTextShaper.h"
-#include "gfxHarfBuzzShaper.h"
 #include <algorithm>
-#include "gfxGraphiteShaper.h"
 #include "gfxPlatformMac.h"
 #include "gfxContext.h"
 #include "gfxFontUtils.h"
 #include "gfxMacPlatformFontList.h"
 #include "gfxFontConstants.h"
 
 #include "cairo-quartz.h"
 
@@ -102,59 +100,54 @@ gfxMacFont::gfxMacFont(MacOSFontEntry *a
         mIsValid = false;
 #ifdef DEBUG
         char warnBuf[1024];
         sprintf(warnBuf, "Failed to create scaled font: %s status: %d",
                 NS_ConvertUTF16toUTF8(GetName()).get(), cairoerr);
         NS_WARNING(warnBuf);
 #endif
     }
-
-    if (FontCanSupportGraphite()) {
-        mGraphiteShaper = new gfxGraphiteShaper(this);
-    }
-    if (FontCanSupportHarfBuzz()) {
-        mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
-    }
 }
 
 gfxMacFont::~gfxMacFont()
 {
     if (mScaledFont) {
         cairo_scaled_font_destroy(mScaledFont);
     }
     if (mFontFace) {
         cairo_font_face_destroy(mFontFace);
     }
 }
 
 bool
-gfxMacFont::ShapeText(gfxContext      *aContext,
+gfxMacFont::ShapeText(gfxContext     *aContext,
                       const char16_t *aText,
-                      uint32_t         aOffset,
-                      uint32_t         aLength,
-                      int32_t          aScript,
-                      gfxShapedText   *aShapedText,
-                      bool             aPreferPlatformShaping)
+                      uint32_t        aOffset,
+                      uint32_t        aLength,
+                      int32_t         aScript,
+                      gfxShapedText  *aShapedText)
 {
     if (!mIsValid) {
         NS_WARNING("invalid font! expect incorrect text rendering");
         return false;
     }
 
-    bool requiresAAT =
-        static_cast<MacOSFontEntry*>(GetFontEntry())->RequiresAATLayout();
-    return gfxFont::ShapeText(aContext, aText, aOffset, aLength,
-                              aScript, aShapedText, requiresAAT);
-}
+    if (static_cast<MacOSFontEntry*>(GetFontEntry())->RequiresAATLayout()) {
+        if (!mCoreTextShaper) {
+            mCoreTextShaper = new gfxCoreTextShaper(this);
+        }
+        if (mCoreTextShaper->ShapeText(aContext, aText, aOffset, aLength,
+                                       aScript, aShapedText)) {
+            PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
+            return true;
+        }
+    }
 
-void
-gfxMacFont::CreatePlatformShaper()
-{
-    mPlatformShaper = new gfxCoreTextShaper(this);
+    return gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript,
+                              aShapedText);
 }
 
 bool
 gfxMacFont::SetupCairoFont(gfxContext *aContext)
 {
     if (cairo_scaled_font_status(mScaledFont) != CAIRO_STATUS_SUCCESS) {
         // Don't cairo_set_scaled_font as that would propagate the error to
         // the cairo_t, precluding any further drawing.
@@ -327,17 +320,17 @@ gfxMacFont::InitMetrics()
 #if 0
     fprintf (stderr, "Font: %p (%s) size: %f\n", this,
              NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size);
 //    fprintf (stderr, "    fbounds.origin.x %f y %f size.width %f height %f\n", fbounds.origin.x, fbounds.origin.y, fbounds.size.width, fbounds.size.height);
     fprintf (stderr, "    emHeight: %f emAscent: %f emDescent: %f\n", mMetrics.emHeight, mMetrics.emAscent, mMetrics.emDescent);
     fprintf (stderr, "    maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics.maxAscent, mMetrics.maxDescent, mMetrics.maxAdvance);
     fprintf (stderr, "    internalLeading: %f externalLeading: %f\n", mMetrics.internalLeading, mMetrics.externalLeading);
     fprintf (stderr, "    spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.xHeight);
-    fprintf (stderr, "    uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize, mMetrics.superscriptOffset, mMetrics.subscriptOffset);
+    fprintf (stderr, "    uOff: %f uSize: %f stOff: %f stSize: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize);
 #endif
 }
 
 gfxFloat
 gfxMacFont::GetCharWidth(CFDataRef aCmap, char16_t aUniChar,
                          uint32_t *aGlyphID, gfxFloat aConvFactor)
 {
     CGGlyph glyph = 0;
--- a/gfx/thebes/gfxMacFont.h
+++ b/gfx/thebes/gfxMacFont.h
@@ -46,38 +46,37 @@ public:
     virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                         FontCacheSizes* aSizes) const;
     virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                         FontCacheSizes* aSizes) const;
 
     virtual FontType GetType() const { return FONT_TYPE_MAC; }
 
 protected:
-    virtual void CreatePlatformShaper();
-
     // override to prefer CoreText shaping with fonts that depend on AAT
-    virtual bool ShapeText(gfxContext      *aContext,
+    virtual bool ShapeText(gfxContext     *aContext,
                            const char16_t *aText,
-                           uint32_t         aOffset,
-                           uint32_t         aLength,
-                           int32_t          aScript,
-                           gfxShapedText   *aShapedText,
-                           bool             aPreferPlatformShaping = false);
+                           uint32_t        aOffset,
+                           uint32_t        aLength,
+                           int32_t         aScript,
+                           gfxShapedText  *aShapedText);
 
     void InitMetrics();
     void InitMetricsFromPlatform();
 
     // Get width and glyph ID for a character; uses aConvFactor
     // to convert font units as returned by CG to actual dimensions
     gfxFloat GetCharWidth(CFDataRef aCmap, char16_t aUniChar,
                           uint32_t *aGlyphID, gfxFloat aConvFactor);
 
     // a weak reference to the CoreGraphics font: this is owned by the
     // MacOSFontEntry, it is not retained or released by gfxMacFont
     CGFontRef             mCGFont;
 
     cairo_font_face_t    *mFontFace;
 
+    nsAutoPtr<gfxFontShaper> mCoreTextShaper;
+
     Metrics               mMetrics;
     uint32_t              mSpaceGlyph;
 };
 
 #endif /* GFX_MACFONT_H */
--- a/gfx/thebes/gfxPangoFonts.cpp
+++ b/gfx/thebes/gfxPangoFonts.cpp
@@ -15,18 +15,16 @@
 #ifdef MOZ_WIDGET_QT
 #include "gfxQtPlatform.h"
 #endif
 #include "gfxPangoFonts.h"
 #include "gfxFT2FontBase.h"
 #include "gfxFT2Utils.h"
 #include "harfbuzz/hb.h"
 #include "harfbuzz/hb-ot.h"
-#include "gfxHarfBuzzShaper.h"
-#include "gfxGraphiteShaper.h"
 #include "nsUnicodeProperties.h"
 #include "nsUnicodeScriptCodes.h"
 #include "gfxFontconfigUtils.h"
 #include "gfxUserFontSet.h"
 #include "gfxFontConstants.h"
 
 #include <cairo.h>
 #include <cairo-ft.h>
@@ -658,24 +656,16 @@ public:
 
 #ifdef USE_SKIA
     virtual mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions> GetGlyphRenderingOptions();
 #endif
 
 protected:
     virtual already_AddRefed<gfxFont> GetSmallCapsFont();
 
-    virtual bool ShapeText(gfxContext      *aContext,
-                           const char16_t *aText,
-                           uint32_t         aOffset,
-                           uint32_t         aLength,
-                           int32_t          aScript,
-                           gfxShapedText   *aShapedText,
-                           bool             aPreferPlatformShaping);
-
 private:
     gfxFcFont(cairo_scaled_font_t *aCairoFont, gfxFcFontEntry *aFontEntry,
               const gfxFontStyle *aFontStyle);
 
     // key for locating a gfxFcFont corresponding to a cairo_scaled_font
     static cairo_user_data_key_t sGfxFontKey;
 };
 
@@ -1559,52 +1549,16 @@ gfxFcFont::GetSmallCapsFont()
 
     font = new gfxFcFont(smallFont, fe, &style);
     gfxFontCache::GetCache()->AddNew(font);
     cairo_scaled_font_destroy(smallFont);
 
     return font.forget();
 }
 
-bool
-gfxFcFont::ShapeText(gfxContext      *aContext,
-                     const char16_t *aText,
-                     uint32_t         aOffset,
-                     uint32_t         aLength,
-                     int32_t          aScript,
-                     gfxShapedText   *aShapedText,
-                     bool             aPreferPlatformShaping)
-{
-    bool ok = false;
-
-    if (FontCanSupportGraphite()) {
-        if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
-            if (!mGraphiteShaper) {
-                mGraphiteShaper = new gfxGraphiteShaper(this);
-            }
-            ok = mGraphiteShaper->ShapeText(aContext, aText, aOffset, aLength,
-                                            aScript, aShapedText);
-        }
-    }
-
-    if (!ok) {
-        if (!mHarfBuzzShaper) {
-            mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
-        }
-        ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength,
-                                        aScript, aShapedText);
-    }
-
-    NS_WARN_IF_FALSE(ok, "shaper failed, expect scrambled or missing text");
-
-    PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
-
-    return ok;
-}
-
 /* static */ void
 gfxPangoFontGroup::Shutdown()
 {
     // Resetting gFTLibrary in case this is wanted again after a
     // cairo_debug_reset_static_data.
     gFTLibrary = nullptr;
 }
 
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -140,18 +140,16 @@ public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIOBSERVER
 };
 
 NS_IMPL_ISUPPORTS(SRGBOverrideObserver, nsIObserver, nsISupportsWeakReference)
 
 #define GFX_DOWNLOADABLE_FONTS_ENABLED "gfx.downloadable_fonts.enabled"
 
-#define GFX_PREF_HARFBUZZ_SCRIPTS "gfx.font_rendering.harfbuzz.scripts"
-#define HARFBUZZ_SCRIPTS_DEFAULT  mozilla::unicode::SHAPING_DEFAULT
 #define GFX_PREF_FALLBACK_USE_CMAPS  "gfx.font_rendering.fallback.always_use_cmaps"
 
 #define GFX_PREF_OPENTYPE_SVG "gfx.font_rendering.opentype_svg.enabled"
 
 #define GFX_PREF_WORD_CACHE_CHARLIMIT "gfx.font_rendering.wordcache.charlimit"
 #define GFX_PREF_WORD_CACHE_MAXENTRIES "gfx.font_rendering.wordcache.maxentries"
 
 #define GFX_PREF_GRAPHITE_SHAPING "gfx.font_rendering.graphite.enabled"
@@ -261,17 +259,16 @@ static const char *gPrefLangNames[] = {
     "x-tibt",
     "x-unicode",
 };
 
 gfxPlatform::gfxPlatform()
   : mAzureCanvasBackendCollector(MOZ_THIS_IN_INITIALIZER_LIST(),
                                  &gfxPlatform::GetAzureBackendInfo)
 {
-    mUseHarfBuzzScripts = UNINITIALIZED_VALUE;
     mAllowDownloadableFonts = UNINITIALIZED_VALUE;
     mFallbackUsesCmaps = UNINITIALIZED_VALUE;
 
     mWordCacheCharLimit = UNINITIALIZED_VALUE;
     mWordCacheMaxEntries = UNINITIALIZED_VALUE;
     mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
     mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
     mBidiNumeralOption = UNINITIALIZED_VALUE;
@@ -1129,28 +1126,16 @@ gfxPlatform::UseGraphiteShaping()
     if (mGraphiteShapingEnabled == UNINITIALIZED_VALUE) {
         mGraphiteShapingEnabled =
             Preferences::GetBool(GFX_PREF_GRAPHITE_SHAPING, false);
     }
 
     return mGraphiteShapingEnabled;
 }
 
-bool
-gfxPlatform::UseHarfBuzzForScript(int32_t aScriptCode)
-{
-    if (mUseHarfBuzzScripts == UNINITIALIZED_VALUE) {
-        mUseHarfBuzzScripts = Preferences::GetInt(GFX_PREF_HARFBUZZ_SCRIPTS, HARFBUZZ_SCRIPTS_DEFAULT);
-    }
-
-    int32_t shapingType = mozilla::unicode::ScriptShapingType(aScriptCode);
-
-    return (mUseHarfBuzzScripts & shapingType) != 0;
-}
-
 gfxFontEntry*
 gfxPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
                               const uint8_t *aFontData,
                               uint32_t aLength)
 {
     // Default implementation does not handle activating downloaded fonts;
     // just free the data and return.
     // Platforms that support @font-face must override this,
@@ -1875,19 +1860,16 @@ gfxPlatform::FontsPrefsChanged(const cha
         mWordCacheCharLimit = UNINITIALIZED_VALUE;
         FlushFontAndWordCaches();
     } else if (!strcmp(GFX_PREF_WORD_CACHE_MAXENTRIES, aPref)) {
         mWordCacheMaxEntries = UNINITIALIZED_VALUE;
         FlushFontAndWordCaches();
     } else if (!strcmp(GFX_PREF_GRAPHITE_SHAPING, aPref)) {
         mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
         FlushFontAndWordCaches();
-    } else if (!strcmp(GFX_PREF_HARFBUZZ_SCRIPTS, aPref)) {
-        mUseHarfBuzzScripts = UNINITIALIZED_VALUE;
-        FlushFontAndWordCaches();
     } else if (!strcmp(BIDI_NUMERAL_PREF, aPref)) {
         mBidiNumeralOption = UNINITIALIZED_VALUE;
     } else if (!strcmp(GFX_PREF_OPENTYPE_SVG, aPref)) {
         mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
         gfxFontCache::GetCache()->AgeAllGenerations();
     }
 }
 
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -384,23 +384,16 @@ public:
     uint32_t WordCacheMaxEntries();
 
     /**
      * Whether to use the SIL Graphite rendering engine
      * (for fonts that include Graphite tables)
      */
     bool UseGraphiteShaping();
 
-    /**
-     * Whether to use the harfbuzz shaper (depending on script complexity).
-     *
-     * This allows harfbuzz to be enabled selectively via the preferences.
-     */
-    bool UseHarfBuzzForScript(int32_t aScriptCode);
-
     // check whether format is supported on a platform or not (if unclear, returns true)
     virtual bool IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags) { return false; }
 
     void GetPrefFonts(nsIAtom *aLanguage, nsString& array, bool aAppendUnicode = true);
 
     // in some situations, need to make decisions about ambiguous characters, may need to look at multiple pref langs
     void GetLangPrefs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang);
     
@@ -605,19 +598,16 @@ protected:
     int8_t  mOpenTypeSVGEnabled;
 
     int8_t  mBidiNumeralOption;
 
     // whether to always search font cmaps globally 
     // when doing system font fallback
     int8_t  mFallbackUsesCmaps;
 
-    // which scripts should be shaped with harfbuzz
-    int32_t mUseHarfBuzzScripts;
-
     // max character limit for words in word cache
     int32_t mWordCacheCharLimit;
 
     // max number of entries in word cache
     int32_t mWordCacheMaxEntries;
 
 private:
     /**
--- a/image/public/imgIContainer.idl
+++ b/image/public/imgIContainer.idl
@@ -39,35 +39,37 @@ struct Orientation;
 
 %}
 
 [ptr] native gfxContext(gfxContext);
 [ref] native gfxMatrix(gfxMatrix);
 [ref] native gfxRect(gfxRect);
 native gfxGraphicsFilter(GraphicsFilter);
 [ref] native nsIntRect(nsIntRect);
+native nsIntRectByVal(nsIntRect);
 [ref] native nsIntSize(nsIntSize);
 native nsSize(nsSize);
 [ptr] native nsIFrame(nsIFrame);
 [ptr] native ImageContainer(mozilla::layers::ImageContainer);
 [ptr] native LayerManager(mozilla::layers::LayerManager);
 native Orientation(mozilla::image::Orientation);
 [ref] native TimeStamp(mozilla::TimeStamp);
 [ptr] native SVGImageContext(mozilla::SVGImageContext);
 native TempRefSourceSurface(mozilla::TemporaryRef<mozilla::gfx::SourceSurface>);
+native TempRefImgIContainer(already_AddRefed<imgIContainer>);
 
 
 /**
  * imgIContainer is the interface that represents an image. It allows
  * access to frames as Thebes surfaces. It also allows drawing of images
  * onto Thebes contexts.
  *
  * Internally, imgIContainer also manages animation of images.
  */
-[scriptable, builtinclass, uuid(503a830c-734d-4362-91f6-73f83ac59646)]
+[scriptable, builtinclass, uuid(c9bd1257-45fb-4ea6-a669-6da212479191)]
 interface imgIContainer : nsISupports
 {
   /**
    * The width of the container rectangle.  In the case of any error,
    * zero is returned, and an exception will be thrown.
    */
   readonly attribute int32_t width;
 
@@ -343,9 +345,24 @@ interface imgIContainer : nsISupports
    * This has no effect if the image isn't animated or it has started animating
    * already; it also has no effect if the image format doesn't care about
    * animation start time.
    *
    * In all cases, animation does not actually begin until startAnimation(),
    * resetAnimation(), or requestRefresh() is called for the first time.
    */
   [notxpcom] void setAnimationStartTime([const] in TimeStamp aTime);
+
+  /*
+   * Given an invalidation rect in the coordinate system used by the decoder,
+   * returns an invalidation rect in image space.
+   *
+   * This is the identity transformation in most cases, but the result can
+   * differ if the image is wrapped by an ImageWrapper that changes its size
+   * or orientation.
+   */
+  [notxpcom] nsIntRectByVal getImageSpaceInvalidationRect([const] in nsIntRect aRect);
+
+  /*
+   * Removes any ImageWrappers and returns the unwrapped base image.
+   */
+  [notxpcom, nostdcall] TempRefImgIContainer unwrap();
 };
--- a/image/src/ClippedImage.cpp
+++ b/image/src/ClippedImage.cpp
@@ -419,10 +419,23 @@ ClippedImage::RequestDiscard()
 NS_IMETHODIMP_(Orientation)
 ClippedImage::GetOrientation()
 {
   // XXX(seth): This should not actually be here; this is just to work around a
   // what appears to be a bug in MSVC's linker.
   return InnerImage()->GetOrientation();
 }
 
+NS_IMETHODIMP_(nsIntRect)
+ClippedImage::GetImageSpaceInvalidationRect(const nsIntRect& aRect)
+{
+  if (!ShouldClip()) {
+    return InnerImage()->GetImageSpaceInvalidationRect(aRect);
+  }
+
+  nsIntRect rect(InnerImage()->GetImageSpaceInvalidationRect(aRect));
+  rect = rect.Intersect(mClip);
+  rect.MoveBy(-mClip.x, -mClip.y);
+  return rect;
+}
+
 } // namespace image
 } // namespace mozilla
--- a/image/src/ClippedImage.h
+++ b/image/src/ClippedImage.h
@@ -47,16 +47,17 @@ public:
                   const gfxRect& aFill,
                   const nsIntRect& aSubimage,
                   const nsIntSize& aViewportSize,
                   const SVGImageContext* aSVGContext,
                   uint32_t aWhichFrame,
                   uint32_t aFlags) MOZ_OVERRIDE;
   NS_IMETHOD RequestDiscard() MOZ_OVERRIDE;
   NS_IMETHOD_(Orientation) GetOrientation() MOZ_OVERRIDE;
+  NS_IMETHOD_(nsIntRect) GetImageSpaceInvalidationRect(const nsIntRect& aRect) MOZ_OVERRIDE;
 
 protected:
   ClippedImage(Image* aImage, nsIntRect aClip);
 
   virtual ~ClippedImage();
 
 private:
   mozilla::TemporaryRef<SourceSurface>
--- a/image/src/ImageWrapper.cpp
+++ b/image/src/ImageWrapper.cpp
@@ -312,10 +312,22 @@ ImageWrapper::GetFirstFrameDelay()
 }
 
 NS_IMETHODIMP_(void)
 ImageWrapper::SetAnimationStartTime(const mozilla::TimeStamp& aTime)
 {
   mInnerImage->SetAnimationStartTime(aTime);
 }
 
+NS_IMETHODIMP_(nsIntRect)
+ImageWrapper::GetImageSpaceInvalidationRect(const nsIntRect& aRect)
+{
+  return mInnerImage->GetImageSpaceInvalidationRect(aRect);
+}
+
+already_AddRefed<imgIContainer>
+ImageWrapper::Unwrap()
+{
+  return mInnerImage->Unwrap();
+}
+
 } // namespace image
 } // namespace mozilla
--- a/image/src/OrientedImage.cpp
+++ b/image/src/OrientedImage.cpp
@@ -245,10 +245,37 @@ OrientedImage::Draw(gfxContext* aContext
     swap(viewportSize.width, viewportSize.height);
   }
 
   return InnerImage()->Draw(aContext, aFilter, userSpaceToImageSpace,
                             aFill, subimage, viewportSize, aSVGContext,
                             aWhichFrame, aFlags);
 }
 
+NS_IMETHODIMP_(nsIntRect)
+OrientedImage::GetImageSpaceInvalidationRect(const nsIntRect& aRect)
+{
+  nsIntRect rect(InnerImage()->GetImageSpaceInvalidationRect(aRect));
+
+  if (mOrientation.IsIdentity()) {
+    return rect;
+  }
+
+  int32_t width, height;
+  nsresult rv = InnerImage()->GetWidth(&width);
+  rv = NS_FAILED(rv) ? rv : InnerImage()->GetHeight(&height);
+  if (NS_FAILED(rv)) {
+    // Fall back to identity if the width and height aren't available.
+    return rect;
+  }
+
+  // Transform the invalidation rect into the correct orientation.
+  gfxMatrix matrix(OrientationMatrix(nsIntSize(width, height)).Invert());
+  gfxRect invalidRect(matrix.TransformBounds(gfxRect(rect.x, rect.y,
+                                                     rect.width, rect.height)));
+  invalidRect.RoundOut();
+
+  return nsIntRect(invalidRect.x, invalidRect.y,
+                   invalidRect.width, invalidRect.height);
+}
+
 } // namespace image
 } // namespace mozilla
--- a/image/src/OrientedImage.h
+++ b/image/src/OrientedImage.h
@@ -42,16 +42,17 @@ public:
                   GraphicsFilter aFilter,
                   const gfxMatrix& aUserSpaceToImageSpace,
                   const gfxRect& aFill,
                   const nsIntRect& aSubimage,
                   const nsIntSize& aViewportSize,
                   const SVGImageContext* aSVGContext,
                   uint32_t aWhichFrame,
                   uint32_t aFlags) MOZ_OVERRIDE;
+  NS_IMETHOD_(nsIntRect) GetImageSpaceInvalidationRect(const nsIntRect& aRect) MOZ_OVERRIDE;
  
 protected:
   OrientedImage(Image* aImage, Orientation aOrientation)
     : ImageWrapper(aImage)
     , mOrientation(aOrientation)
   { }
 
   virtual ~OrientedImage() { }
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -1596,16 +1596,22 @@ RasterImage::SetLoopCount(int32_t aLoopC
     return;
 
   if (mAnim) {
     // No need to set this if we're not an animation
     mFrameBlender.SetLoopCount(aLoopCount);
   }
 }
 
+NS_IMETHODIMP_(nsIntRect)
+RasterImage::GetImageSpaceInvalidationRect(const nsIntRect& aRect)
+{
+  return aRect;
+}
+
 nsresult
 RasterImage::AddSourceData(const char *aBuffer, uint32_t aCount)
 {
   ReentrantMonitorAutoEnter lock(mDecodingMonitor);
 
   if (mError)
     return NS_ERROR_FAILURE;
 
@@ -3155,16 +3161,23 @@ RasterImage::FinishedSomeDecoding(eShutd
       diff = mStatusDiff;
       mStatusDiff = ImageStatusDiff::NoChange();
     }
   }
 
   return RequestDecodeIfNeeded(rv, aIntent, done, wasSize);
 }
 
+already_AddRefed<imgIContainer>
+RasterImage::Unwrap()
+{
+  nsCOMPtr<imgIContainer> self(this);
+  return self.forget();
+}
+
 NS_IMPL_ISUPPORTS(RasterImage::DecodePool,
                   nsIObserver)
 
 /* static */ RasterImage::DecodePool*
 RasterImage::DecodePool::Singleton()
 {
   if (!sSingleton) {
     MOZ_ASSERT(NS_IsMainThread());
--- a/image/src/VectorImage.cpp
+++ b/image/src/VectorImage.cpp
@@ -565,16 +565,22 @@ VectorImage::SendInvalidationNotificatio
 
   if (mStatusTracker) {
     SurfaceCache::Discard(this);
     mStatusTracker->FrameChanged(&nsIntRect::GetMaxSizedIntRect());
     mStatusTracker->OnStopFrame();
   }
 }
 
+NS_IMETHODIMP_(nsIntRect)
+VectorImage::GetImageSpaceInvalidationRect(const nsIntRect& aRect)
+{
+  return aRect;
+}
+
 //******************************************************************************
 /* readonly attribute int32_t height; */
 NS_IMETHODIMP
 VectorImage::GetHeight(int32_t* aHeight)
 {
   if (mError || !mIsFullyLoaded) {
     *aHeight = 0;
     return NS_ERROR_FAILURE;
@@ -1203,10 +1209,17 @@ VectorImage::InvalidateObserversOnNextRe
 {
   if (mHaveAnimations) {
     mHasPendingInvalidation = true;
   } else {
     SendInvalidationNotifications();
   }
 }
 
+already_AddRefed<imgIContainer>
+VectorImage::Unwrap()
+{
+  nsCOMPtr<imgIContainer> self(this);
+  return self.forget();
+}
+
 } // namespace image
 } // namespace mozilla
--- a/image/src/imgLoader.cpp
+++ b/image/src/imgLoader.cpp
@@ -594,16 +594,17 @@ static nsresult NewImageChannel(nsIChann
   }
 
   // Pass in a nullptr loadgroup because this is the underlying network
   // request. This request may be referenced by several proxy image requests
   // (possibly in different documents).
   // If all of the proxy requests are canceled then this request should be
   // canceled too.
   //
+  aLoadFlags |= nsIChannel::LOAD_CLASSIFY_URI;
   rv = NS_NewChannel(aResult,
                      aURI,        // URI
                      nullptr,      // Cached IOService
                      nullptr,      // LoadGroup
                      callbacks,   // Notification Callbacks
                      aLoadFlags,
                      aPolicy);
   if (NS_FAILED(rv))
--- a/image/test/unit/image_load_helpers.js
+++ b/image/test/unit/image_load_helpers.js
@@ -11,16 +11,19 @@ const DATA_AVAILABLE = 0x04;
 // One bit per callback that imageListener below implements. Stored in
 // ImageListener.state.
 const SIZE_AVAILABLE = 0x01;
 const FRAME_UPDATE = 0x02;
 const FRAME_COMPLETE = 0x04;
 const LOAD_COMPLETE = 0x08;
 const DECODE_COMPLETE = 0x10;
 
+// Safebrowsing requires that the profile dir is set.
+do_get_profile();
+
 // An implementation of imgIScriptedNotificationObserver with the ability to
 // call specified functions on onStartRequest and onStopRequest.
 function ImageListener(start_callback, stop_callback)
 {
   this.sizeAvailable = function onSizeAvailable(aRequest)
   {
     do_check_false(this.synchronous);
 
--- a/intl/unicharutil/util/nsUnicodeProperties.cpp
+++ b/intl/unicharutil/util/nsUnicodeProperties.cpp
@@ -244,74 +244,16 @@ bool
 IsClusterExtender(uint32_t aCh, uint8_t aCategory)
 {
     return ((aCategory >= HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK &&
              aCategory <= HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) ||
             (aCh >= 0x200c && aCh <= 0x200d) || // ZWJ, ZWNJ
             (aCh >= 0xff9e && aCh <= 0xff9f));  // katakana sound marks
 }
 
-// TODO: replace this with a properties file or similar;
-// expect this to evolve as harfbuzz shaping support matures.
-//
-// The "shaping type" of each script run, as returned by this
-// function, is compared to the bits set in the
-// gfx.font_rendering.harfbuzz.scripts
-// preference to decide whether to use the harfbuzz shaper.
-//
-int32_t
-ScriptShapingType(int32_t aScriptCode)
-{
-    switch (aScriptCode) {
-    default:
-        return SHAPING_DEFAULT; // scripts not explicitly listed here are
-                                // assumed to just use default shaping
-
-    case MOZ_SCRIPT_ARABIC:
-    case MOZ_SCRIPT_SYRIAC:
-    case MOZ_SCRIPT_NKO:
-    case MOZ_SCRIPT_MANDAIC:
-        return SHAPING_ARABIC; // bidi scripts with Arabic-style shaping
-
-    case MOZ_SCRIPT_HEBREW:
-        return SHAPING_HEBREW;
-
-    case MOZ_SCRIPT_HANGUL:
-        return SHAPING_HANGUL;
-
-    case MOZ_SCRIPT_MONGOLIAN: // to be supported by the Arabic shaper?
-        return SHAPING_MONGOLIAN;
-
-    case MOZ_SCRIPT_THAI: // no complex OT features, but MS engines like to do
-                          // sequence checking
-        return SHAPING_THAI;
-
-    case MOZ_SCRIPT_BENGALI:
-    case MOZ_SCRIPT_DEVANAGARI:
-    case MOZ_SCRIPT_GUJARATI:
-    case MOZ_SCRIPT_GURMUKHI:
-    case MOZ_SCRIPT_KANNADA:
-    case MOZ_SCRIPT_MALAYALAM:
-    case MOZ_SCRIPT_ORIYA:
-    case MOZ_SCRIPT_SINHALA:
-    case MOZ_SCRIPT_TAMIL:
-    case MOZ_SCRIPT_TELUGU:
-    case MOZ_SCRIPT_KHMER:
-    case MOZ_SCRIPT_LAO:
-    case MOZ_SCRIPT_TIBETAN:
-    case MOZ_SCRIPT_NEW_TAI_LUE:
-    case MOZ_SCRIPT_TAI_LE:
-    case MOZ_SCRIPT_MYANMAR:
-    case MOZ_SCRIPT_PHAGS_PA:
-    case MOZ_SCRIPT_BATAK:
-    case MOZ_SCRIPT_BRAHMI:
-        return SHAPING_INDIC; // scripts that require Indic or other "special" shaping
-    }
-}
-
 void
 ClusterIterator::Next()
 {
     if (AtEnd()) {
         NS_WARNING("ClusterIterator has already reached the end");
         return;
     }
 
--- a/intl/unicharutil/util/nsUnicodeProperties.h
+++ b/intl/unicharutil/util/nsUnicodeProperties.h
@@ -114,28 +114,16 @@ inline HSType GetHangulSyllableType(uint
 // Case mappings for the full Unicode range;
 // note that it may be worth testing for ASCII chars and taking
 // a separate fast-path before calling these, in perf-critical places
 uint32_t GetUppercase(uint32_t aCh);
 uint32_t GetLowercase(uint32_t aCh);
 uint32_t GetTitlecaseForLower(uint32_t aCh); // maps LC to titlecase, UC unchanged
 uint32_t GetTitlecaseForAll(uint32_t aCh); // maps both UC and LC to titlecase
 
-enum ShapingType {
-  SHAPING_DEFAULT   = 0x0001,
-  SHAPING_ARABIC    = 0x0002,
-  SHAPING_HEBREW    = 0x0004,
-  SHAPING_HANGUL    = 0x0008,
-  SHAPING_MONGOLIAN = 0x0010,
-  SHAPING_INDIC     = 0x0020,
-  SHAPING_THAI      = 0x0040
-};
-
-int32_t ScriptShapingType(int32_t aScriptCode);
-
 // A simple iterator for a string of char16_t codepoints that advances
 // by Unicode grapheme clusters
 class ClusterIterator
 {
 public:
     ClusterIterator(const char16_t* aText, uint32_t aLength)
         : mPos(aText), mLimit(aText + aLength)
 #ifdef DEBUG
--- a/ipc/glue/BackgroundChild.h
+++ b/ipc/glue/BackgroundChild.h
@@ -32,16 +32,21 @@ class PBackgroundChild;
 //
 // Creation of PBackground is asynchronous. GetForCurrentThread() will return
 // null until the sequence is complete. GetOrCreateForCurrentThread() will start
 // the creation sequence and will call back via the
 // nsIIPCBackgroundChildCreateCallback interface when completed. Thereafter
 // (assuming success) GetForCurrentThread() will return the same actor every
 // time.
 //
+// CloseForCurrentThread() will close the current PBackground actor.  Subsequent
+// calls to GetForCurrentThread will return null.  CloseForCurrentThread() may
+// only be called exactly once per thread.  Currently it is illegal to call this
+// before the PBackground actor has been created.
+//
 // The PBackgroundChild actor and all its sub-protocol actors will be
 // automatically destroyed when its designated thread completes.
 class BackgroundChild MOZ_FINAL
 {
   friend class mozilla::dom::ContentChild;
   friend class mozilla::dom::ContentParent;
 
   typedef base::ProcessId ProcessId;
@@ -51,16 +56,20 @@ public:
   // See above.
   static PBackgroundChild*
   GetForCurrentThread();
 
   // See above.
   static bool
   GetOrCreateForCurrentThread(nsIIPCBackgroundChildCreateCallback* aCallback);
 
+  // See above.
+  static void
+  CloseForCurrentThread();
+
 private:
   // Only called by ContentChild or ContentParent.
   static void
   Startup();
 
   // Only called by ContentChild.
   static PBackgroundChild*
   Alloc(Transport* aTransport, ProcessId aOtherProcess);
--- a/ipc/glue/BackgroundImpl.cpp
+++ b/ipc/glue/BackgroundImpl.cpp
@@ -345,16 +345,18 @@ class ChildImpl MOZ_FINAL : public Backg
   static bool sShutdownHasStarted;
 
 #ifdef RELEASE_BUILD
   DebugOnly<nsIThread*> mBoundThread;
 #else
   nsIThread* mBoundThread;
 #endif
 
+  DebugOnly<bool> mActorDestroyed;
+
 public:
   static bool
   OpenProtocolOnMainThread(nsIEventTarget* aEventTarget);
 
   static void
   Shutdown();
 
   void
@@ -367,18 +369,25 @@ public:
 #else
     bool current;
 #endif
     THREADSAFETY_ASSERT(
       NS_SUCCEEDED(mBoundThread->IsOnCurrentThread(&current)));
     THREADSAFETY_ASSERT(current);
   }
 
+  void
+  AssertActorDestroyed()
+  {
+    MOZ_ASSERT(mActorDestroyed, "ChildImpl::ActorDestroy not called in time");
+  }
+
   ChildImpl()
   : mBoundThread(nullptr)
+  , mActorDestroyed(false)
   {
     AssertIsOnMainThread();
   }
 
   NS_INLINE_DECL_REFCOUNTING(ChildImpl)
 
 private:
   // Forwarded from BackgroundChild.
@@ -392,39 +401,56 @@ private:
   // Forwarded from BackgroundChild.
   static PBackgroundChild*
   GetForCurrentThread();
 
   // Forwarded from BackgroundChild.
   static bool
   GetOrCreateForCurrentThread(nsIIPCBackgroundChildCreateCallback* aCallback);
 
+  // Forwarded from BackgroundChild.
+  static void
+  CloseForCurrentThread();
+
   // Forwarded from BackgroundChildImpl.
   static BackgroundChildImpl::ThreadLocal*
   GetThreadLocalForCurrentThread();
 
   static void
   ThreadLocalDestructor(void* aThreadLocal)
   {
     auto threadLocalInfo = static_cast<ThreadLocalInfo*>(aThreadLocal);
 
     if (threadLocalInfo) {
       if (threadLocalInfo->mActor) {
         threadLocalInfo->mActor->Close();
+        threadLocalInfo->mActor->AssertActorDestroyed();
+        // Since the actor is created on the main thread it must only
+        // be released on the main thread as well.
+        if (!NS_IsMainThread()) {
+          ChildImpl* actor;
+          threadLocalInfo->mActor.forget(&actor);
+
+          nsCOMPtr<nsIRunnable> releaser =
+            NS_NewNonOwningRunnableMethod(actor, &ChildImpl::Release);
+          MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(releaser)));
+        }
       }
       delete threadLocalInfo;
     }
   }
 
   static void
   DispatchFailureCallback(nsIEventTarget* aEventTarget);
 
   // This class is reference counted.
   ~ChildImpl()
-  { }
+  {
+    AssertActorDestroyed();
+  }
 
   void
   SetBoundThread()
   {
     THREADSAFETY_ASSERT(!mBoundThread);
 
 #if defined(DEBUG) || !defined(RELEASE_BUILD)
     mBoundThread = NS_GetCurrentThread();
@@ -830,16 +856,23 @@ BackgroundChild::GetForCurrentThread()
 // static
 bool
 BackgroundChild::GetOrCreateForCurrentThread(
                                  nsIIPCBackgroundChildCreateCallback* aCallback)
 {
   return ChildImpl::GetOrCreateForCurrentThread(aCallback);
 }
 
+// static
+void
+BackgroundChild::CloseForCurrentThread()
+{
+  ChildImpl::CloseForCurrentThread();
+}
+
 // -----------------------------------------------------------------------------
 // BackgroundChildImpl Public Methods
 // -----------------------------------------------------------------------------
 
 // static
 BackgroundChildImpl::ThreadLocal*
 BackgroundChildImpl::GetThreadLocalForCurrentThread()
 {
@@ -1573,17 +1606,21 @@ ChildImpl::Alloc(Transport* aTransport, 
 PBackgroundChild*
 ChildImpl::GetForCurrentThread()
 {
   MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex);
 
   auto threadLocalInfo =
     static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
 
-  return threadLocalInfo ? threadLocalInfo->mActor : nullptr;
+  if (!threadLocalInfo) {
+    return nullptr;
+  }
+
+  return threadLocalInfo->mActor;
 }
 
 // static
 bool
 ChildImpl::GetOrCreateForCurrentThread(
                                  nsIIPCBackgroundChildCreateCallback* aCallback)
 {
   MOZ_ASSERT(aCallback);
@@ -1638,16 +1675,41 @@ ChildImpl::GetOrCreateForCurrentThread(
     CRASH_IN_CHILD_PROCESS("Failed to dispatch to main thread!");
     return false;
   }
 
   return true;
 }
 
 // static
+void
+ChildImpl::CloseForCurrentThread()
+{
+  MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex,
+             "BackgroundChild::Startup() was never called!");
+  auto threadLocalInfo =
+    static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
+
+  // If we don't have a thread local we are in one of these conditions:
+  //   1) Startup has not completed and we are racing
+  //   2) We were called again after a previous close or shutdown
+  // For now, these should not happen, so crash.  We can add extra complexity
+  // in the future if it turns out we need to support these cases.
+  if (!threadLocalInfo) {
+    MOZ_CRASH("Attempting to close a non-existent PBackground actor!");
+  }
+
+  if (threadLocalInfo->mActor) {
+    threadLocalInfo->mActor->FlushPendingInterruptQueue();
+  }
+  DebugOnly<PRStatus> status = PR_SetThreadPrivate(sThreadLocalIndex, nullptr);
+  MOZ_ASSERT(status == PR_SUCCESS);
+}
+
+// static
 BackgroundChildImpl::ThreadLocal*
 ChildImpl::GetThreadLocalForCurrentThread()
 {
   MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex,
              "BackgroundChild::Startup() was never called!");
 
   auto threadLocalInfo =
     static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
@@ -1941,16 +2003,17 @@ ChildImpl::DispatchFailureCallback(nsIEv
   }
 }
 
 void
 ChildImpl::ActorDestroy(ActorDestroyReason aWhy)
 {
   AssertIsOnBoundThread();
 
+  mActorDestroyed = true;
   BackgroundChildImpl::ActorDestroy(aWhy);
 }
 
 NS_IMPL_ISUPPORTS(ChildImpl::ShutdownObserver, nsIObserver)
 
 NS_IMETHODIMP
 ChildImpl::ShutdownObserver::Observe(nsISupports* aSubject,
                                      const char* aTopic,
--- a/ipc/glue/MessagePump.cpp
+++ b/ipc/glue/MessagePump.cpp
@@ -2,21 +2,23 @@
  * 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 "MessagePump.h"
 
 #include "nsIRunnable.h"
 #include "nsIThread.h"
 #include "nsITimer.h"
+#include "nsICancelableRunnable.h"
 
 #include "base/basictypes.h"
 #include "base/logging.h"
 #include "base/scoped_nsautorelease_pool.h"
 #include "mozilla/Assertions.h"
+#include "mozilla/AutoRestore.h"
 #include "mozilla/DebugOnly.h"
 #include "nsComponentManagerUtils.h"
 #include "nsDebug.h"
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 #include "nsThreadUtils.h"
 #include "nsTimerImpl.h"
 #include "nsXULAppAPI.h"
@@ -35,35 +37,40 @@ using namespace mozilla::ipc;
 
 NS_DEFINE_NAMED_CID(NS_TIMER_CID);
 
 static mozilla::DebugOnly<MessagePump::Delegate*> gFirstDelegate;
 
 namespace mozilla {
 namespace ipc {
 
-class DoWorkRunnable MOZ_FINAL : public nsIRunnable,
+class DoWorkRunnable MOZ_FINAL : public nsICancelableRunnable,
                                  public nsITimerCallback
 {
 public:
   DoWorkRunnable(MessagePump* aPump)
   : mPump(aPump)
+  , mCanceled(false)
+  , mCallingRunWhileCanceled(false)
   {
     MOZ_ASSERT(aPump);
   }
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIRUNNABLE
   NS_DECL_NSITIMERCALLBACK
+  NS_DECL_NSICANCELABLERUNNABLE
 
 private:
   ~DoWorkRunnable()
   { }
 
   MessagePump* mPump;
+  bool mCanceled;
+  bool mCallingRunWhileCanceled;
 };
 
 } /* namespace ipc */
 } /* namespace mozilla */
 
 MessagePump::MessagePump()
 : mThread(nullptr)
 {
@@ -206,21 +213,27 @@ void
 MessagePump::DoDelayedWork(base::MessagePump::Delegate* aDelegate)
 {
   aDelegate->DoDelayedWork(&delayed_work_time_);
   if (!delayed_work_time_.is_null()) {
     ScheduleDelayedWork(delayed_work_time_);
   }
 }
 
-NS_IMPL_ISUPPORTS(DoWorkRunnable, nsIRunnable, nsITimerCallback)
+NS_IMPL_ISUPPORTS(DoWorkRunnable, nsIRunnable, nsITimerCallback,
+                                  nsICancelableRunnable)
 
 NS_IMETHODIMP
 DoWorkRunnable::Run()
 {
+  MOZ_ASSERT(!mCanceled || mCallingRunWhileCanceled);
+  if (mCanceled && !mCallingRunWhileCanceled) {
+    return NS_OK;
+  }
+
   MessageLoop* loop = MessageLoop::current();
   MOZ_ASSERT(loop);
 
   bool nestableTasksAllowed = loop->NestableTasksAllowed();
 
   // MessageLoop::RunTask() disallows nesting, but our Frankenventloop will
   // always dispatch DoWork() below from what looks to MessageLoop like a nested
   // context.  So we unconditionally allow nesting here.
@@ -237,16 +250,33 @@ DoWorkRunnable::Notify(nsITimer* aTimer)
   MessageLoop* loop = MessageLoop::current();
   MOZ_ASSERT(loop);
 
   mPump->DoDelayedWork(loop);
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+DoWorkRunnable::Cancel()
+{
+  MOZ_ASSERT(!mCanceled);
+  MOZ_ASSERT(!mCallingRunWhileCanceled);
+
+  // Workers require cancelable runnables, but we can't really cancel cleanly
+  // here.  If we don't process all of these then we will leave something
+  // unprocessed in the chromium queue.  Therefore, eagerly complete our work
+  // instead by immediately calling Run().
+  mCanceled = true;
+  mozilla::AutoRestore<bool> guard(mCallingRunWhileCanceled);
+  mCallingRunWhileCanceled = true;
+  Run();
+  return NS_OK;
+}
+
 void
 MessagePumpForChildProcess::Run(base::MessagePump::Delegate* aDelegate)
 {
   if (mFirstRun) {
     MOZ_ASSERT(aDelegate && !gFirstDelegate);
     gFirstDelegate = aDelegate;
 
     mFirstRun = false;
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -2712,21 +2712,29 @@ Parser<ParseHandler>::matchLabel(Mutable
     } else {
         label.set(nullptr);
     }
     return true;
 }
 
 template <typename ParseHandler>
 bool
-Parser<ParseHandler>::reportRedeclaration(Node pn, bool isConst, JSAtom *atom)
-{
-    JSAutoByteString name;
-    if (AtomToPrintableString(context, atom, &name))
-        report(ParseError, false, pn, JSMSG_REDECLARED_VAR, isConst ? "const" : "variable", name.ptr());
+Parser<ParseHandler>::reportRedeclaration(Node pn, bool isConst, HandlePropertyName name)
+{
+    JSAutoByteString printable;
+    if (!AtomToPrintableString(context, name, &printable))
+        return false;
+
+    StmtInfoPC *stmt = LexicalLookup(pc, name, nullptr, (StmtInfoPC *)nullptr);
+    if (stmt && stmt->type == STMT_CATCH) {
+        report(ParseError, false, pn, JSMSG_REDECLARED_CATCH_IDENTIFIER, printable.ptr());
+    } else {
+        report(ParseError, false, pn, JSMSG_REDECLARED_VAR, isConst ? "const" : "variable",
+               printable.ptr());
+    }
     return false;
 }
 
 /*
  * Define a let-variable in a block, let-expression, or comprehension scope. pc
  * must already be in such a scope.
  *
  * Throw a SyntaxError if 'atom' is an invalid name. Otherwise create a
@@ -2995,30 +3003,36 @@ Parser<ParseHandler>::bindVarOrConst(Bin
 
         if (isConstDecl) {
             parser->report(ParseError, false, pn, JSMSG_REDECLARED_PARAM, bytes.ptr());
             return false;
         }
         if (!parser->report(ParseExtraWarning, false, pn, JSMSG_VAR_HIDES_ARG, bytes.ptr()))
             return false;
     } else {
+        bool inCatchBody = (stmt && stmt->type == STMT_CATCH);
         bool error = (isConstDecl ||
                       dn_kind == Definition::CONST ||
                       (dn_kind == Definition::LET &&
-                       (stmt->type != STMT_CATCH || OuterLet(pc, stmt, name))));
+                       (!inCatchBody || OuterLet(pc, stmt, name))));
 
         if (parser->options().extraWarningsOption
             ? data->op != JSOP_DEFVAR || dn_kind != Definition::VAR
             : error)
         {
             JSAutoByteString bytes;
+            if (!AtomToPrintableString(cx, name, &bytes))
+                return false;
+
             ParseReportKind reporter = error ? ParseError : ParseExtraWarning;
-            if (!AtomToPrintableString(cx, name, &bytes) ||
-                !parser->report(reporter, false, pn, JSMSG_REDECLARED_VAR,
-                                Definition::kindString(dn_kind), bytes.ptr()))
+            if (!(inCatchBody
+                  ? parser->report(reporter, false, pn,
+                                   JSMSG_REDECLARED_CATCH_IDENTIFIER, bytes.ptr())
+                  : parser->report(reporter, false, pn, JSMSG_REDECLARED_VAR,
+                                   Definition::kindString(dn_kind), bytes.ptr())))
             {
                 return false;
             }
         }
     }
 
     parser->handler.linkUseToDef(pn, dn);
     return true;
@@ -3604,16 +3618,35 @@ Parser<FullParseHandler>::letDeclaration
             return null();
         }
 
         if (stmt && stmt->isBlockScope) {
             JS_ASSERT(pc->staticScope == stmt->staticScope);
         } else {
             if (pc->atBodyLevel()) {
                 /*
+                 * When bug 589199 is fixed, let variables will be stored in
+                 * the slots of a new scope chain object, encountered just
+                 * before the global object in the overall chain.  This extra
+                 * object is present in the scope chain for all code in that
+                 * global, including self-hosted code.  But self-hosted code
+                 * must be usable against *any* global object, including ones
+                 * with other let variables -- variables possibly placed in
+                 * conflicting slots.  Forbid top-level let declarations to
+                 * prevent such conflicts from ever occurring.
+                 */
+                if (options().selfHostingMode &&
+                    !pc->sc->isFunctionBox() &&
+                    stmt == pc->topScopeStmt)
+                {
+                    report(ParseError, false, null(), JSMSG_SELFHOSTED_TOP_LEVEL_LET);
+                    return null();
+                }
+
+                /*
                  * ES4 specifies that let at top level and at body-block scope
                  * does not shadow var, so convert back to var.
                  */
                 pn = variables(PNK_VAR);
                 if (!pn)
                     return null();
                 pn->pn_xflags |= PNX_POPVAR;
                 break;
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -637,17 +637,17 @@ class Parser : private JS::AutoGCRooter,
             HandlePropertyName name, Parser<ParseHandler> *parser);
 
     static bool
     bindVarOrConst(BindData<ParseHandler> *data,
                    HandlePropertyName name, Parser<ParseHandler> *parser);
 
     static Node null() { return ParseHandler::null(); }
 
-    bool reportRedeclaration(Node pn, bool isConst, JSAtom *atom);
+    bool reportRedeclaration(Node pn, bool isConst, HandlePropertyName name);
     bool reportBadReturn(Node pn, ParseReportKind kind, unsigned errnum, unsigned anonerrnum);
     bool checkFinalReturn(Node pn);
     DefinitionNode getOrCreateLexicalDependency(ParseContext<ParseHandler> *pc, JSAtom *atom);
 
     bool leaveFunction(Node fn, ParseContext<ParseHandler> *outerpc,
                        FunctionSyntaxKind kind = Expression);
 
     TokenPos pos() const { return tokenStream.currentToken().pos; }
--- a/js/src/jit-test/tests/asm.js/testFFI.js
+++ b/js/src/jit-test/tests/asm.js/testFFI.js
@@ -93,53 +93,55 @@ var recurse = function(i,j) { if (i == 0
 var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function g(i,j,k) { i=i|0;j=+j;k=k|0; if (!(k|0)) ffi(i|0,j)|0; else g(i, j+1.0, (k-1)|0) } function f(i,j) { i=i|0;j=+j; g(i,j,4) } return f'), null, {ffi:recurse});
 assertThrowsValue(function() { f(0,2.4) }, 2.4+4);
 assertThrowsValue(function() { f(1,2.4) }, 2.4+8);
 assertThrowsValue(function() { f(8,2.4) }, 2.4+36);
 
 assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + 'var identity=imp.identity; function g(x) { x=+x; return +identity(x) } return g'), null, imp)(13.37), 13.37);
 
 // Test asm.js => ion paths
-setJitCompilerOption("ion.usecount.trigger", 20);
+setJitCompilerOption("ion.usecount.trigger", 10);
+setJitCompilerOption("baseline.usecount.trigger", 0);
+setJitCompilerOption("offthread-compilation.enable", 0);
 
 // In registers on x64 and ARM, on the stack for x86
 function ffiIntFew(a,b,c,d) { return d+1 }
 var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=i|0; return ffi(i|0,(i+1)|0,(i+2)|0,(i+3)|0)|0 } return f'), null, {ffi:ffiIntFew});
 for (var i = 0; i < 40; i++)
     assertEq(f(i), i+4);
 
 // Stack and registers for x64 and ARM, stack for x86
 function ffiIntMany(a,b,c,d,e,f,g,h,i,j) { return j+1 }
 var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=i|0; return ffi(i|0,(i+1)|0,(i+2)|0,(i+3)|0,(i+4)|0,(i+5)|0,(i+6)|0,(i+7)|0,(i+8)|0,(i+9)|0)|0 } return f'), null, {ffi:ffiIntMany});
-for (var i = 0; i < 40; i++)
+for (var i = 0; i < 15; i++)
     assertEq(f(i), i+10);
 
 // In registers on x64 and ARM, on the stack for x86
 function ffiDoubleFew(a,b,c,d) { return d+1 }
 var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=+i; return +ffi(i,i+1.0,i+2.0,i+3.0) } return f'), null, {ffi:ffiDoubleFew});
-for (var i = 0; i < 40; i++)
+for (var i = 0; i < 15; i++)
     assertEq(f(i), i+4);
 
 // Stack and registers for x64 and ARM, stack for x86
 function ffiDoubleMany(a,b,c,d,e,f,g,h,i,j) { return j+1 }
 var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=+i; return +ffi(i,i+1.0,i+2.0,i+3.0,i+4.0,i+5.0,i+6.0,i+7.0,i+8.0,i+9.0) } return f'), null, {ffi:ffiDoubleMany});
-for (var i = 0; i < 40; i++)
+for (var i = 0; i < 15; i++)
     assertEq(f(i), i+10);
 
 // Test the throw path
-function ffiThrow(n) { if (n == 38) throw 'yolo'; }
+function ffiThrow(n) { if (n == 14) throw 'yolo'; }
 var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=i|0; ffi(i >> 0); } return f'), null, {ffi:ffiThrow});
 var i = 0;
 try {
-    for (; i < 40; i++)
+    for (; i < 15; i++)
         f(i);
     throw 'assume unreachable';
 } catch (e) {
     assertEq(e, 'yolo');
-    assertEq(i, 38);
+    assertEq(i, 14);
 }
 
 // OOL conversion paths
 var INT32_MAX = Math.pow(2, 31) - 1;
 function ffiOOLConvertInt(n) { if (n == 40) return INT32_MAX + 1; return 42; }
 var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=i|0; return ffi(i >> 0) | 0; } return f'), null, {ffi:ffiOOLConvertInt});
 for (var i = 0; i < 40; i++)
     assertEq(f(i), 42);
--- a/js/src/jit-test/tests/asm.js/testStackWalking.js
+++ b/js/src/jit-test/tests/asm.js/testStackWalking.js
@@ -12,20 +12,24 @@ function matchStack(stackString, stackAr
 }
 
 var stack;
 function dumpStack()
 {
     stack = new Error().stack
 }
 
+setJitCompilerOption("ion.usecount.trigger", 10);
+setJitCompilerOption("baseline.usecount.trigger", 0);
+setJitCompilerOption("offthread-compilation.enable", 0);
+
 var callFFI = asmCompile('global', 'ffis', USE_ASM + "var ffi=ffis.ffi; function f() { return ffi()|0 } return f");
 
 var f = asmLink(callFFI, null, {ffi:dumpStack});
-for (var i = 0; i < 5000; i++) {
+for (var i = 0; i < 15; i++) {
     stack = null;
     f();
     matchStack(stack, ['dumpStack', 'f']);
 }
 
 if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
     var callFFI = asmCompile('global', 'ffis', USE_ASM + "var ffi=ffis.ffi; function f() { return ffi()|0 } return f");
     assertEq(isAsmJSModuleLoadedFromCache(callFFI), true);
@@ -37,17 +41,17 @@ if (isAsmJSCompilationAvailable() && isC
 var f1 = asmLink(callFFI, null, {ffi:dumpStack});
 var f2 = asmLink(callFFI, null, {ffi:function middle() { f1() }});
 stack = null;
 (function outer() { f2() })();
 matchStack(stack, ["dumpStack", "f", "middle", "f"]);
 
 function returnStackDumper() { return { valueOf:function() { stack = new Error().stack } } }
 var f = asmLink(callFFI, null, {ffi:returnStackDumper});
-for (var i = 0; i < 5000; i++) {
+for (var i = 0; i < 15; i++) {
     stack = null;
     f();
     matchStack(stack, ['valueOf', 'f']);
 }
 
 var caught = false;
 try {
     stack = null;
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -11,17 +11,16 @@
 #ifdef MOZ_VTUNE
 # include "vtune/VTuneWrapper.h"
 #endif
 
 #include "jsmath.h"
 #include "jsprf.h"
 #include "prmjtime.h"
 
-#include "assembler/assembler/MacroAssembler.h"
 #include "frontend/Parser.h"
 #include "jit/AsmJSLink.h"
 #include "jit/AsmJSModule.h"
 #include "jit/AsmJSSignalHandlers.h"
 #include "jit/CodeGenerator.h"
 #include "jit/CompileWrappers.h"
 #include "jit/MIR.h"
 #include "jit/MIRGraph.h"
@@ -1404,19 +1403,16 @@ class MOZ_STACK_CLASS ModuleCompiler
         if (p) {
             *exitIndex = p->value();
             return true;
         }
         if (!module_->addExit(ffiIndex, exitIndex))
             return false;
         return exits_.add(p, Move(exitDescriptor), *exitIndex);
     }
-    bool addFunctionName(PropertyName *name, uint32_t *index) {
-        return module_->addFunctionName(name, index);
-    }
 
     // Note a constraint on the minimum size of the heap.  The heap size is
     // constrained when linking to be at least the maximum of all such constraints.
     void requireHeapLengthToBeAtLeast(uint32_t len) {
         module_->requireHeapLengthToBeAtLeast(len);
     }
     uint32_t minHeapLength() const {
         return module_->minHeapLength();
@@ -1438,16 +1434,21 @@ class MOZ_STACK_CLASS ModuleCompiler
         masm_.resetForNewCodeGenerator(mir.alloc());
         masm_.align(CodeAlignment);
         masm_.bind(func.code());
     }
 
     bool finishGeneratingFunction(Func &func, MIRGenerator &mir, CodeGenerator &codegen) {
         JS_ASSERT(func.defined() && func.code()->bound());
 
+        uint32_t beginOffset = func.code()->offset();
+        uint32_t endOffset = masm_.currentOffset();
+        if (!module_->addFunctionCodeRange(func.name(), beginOffset, endOffset))
+            return false;
+
         jit::IonScriptCounts *counts = codegen.extractScriptCounts();
         if (counts && !module_->addFunctionCounts(counts)) {
             js_delete(counts);
             return false;
         }
 
 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
         unsigned line = 0, column = 0;
@@ -1475,25 +1476,29 @@ class MOZ_STACK_CLASS ModuleCompiler
 
     void finishFunctionBodies() {
         JS_ASSERT(!finishedFunctionBodies_);
         masm_.align(AsmJSPageSize);
         finishedFunctionBodies_ = true;
         module_->finishFunctionBodies(masm_.currentOffset());
     }
 
+    void startGeneratingEntry(unsigned exportIndex) {
+        module_->exportedFunction(exportIndex).initCodeOffset(masm_.currentOffset());
+    }
+    bool finishGeneratingEntry(unsigned exportIndex) {
+        return module_->addEntryCodeRange(exportIndex, masm_.currentOffset());
+    }
+
     void setInterpExitOffset(unsigned exitIndex) {
         module_->exit(exitIndex).initInterpOffset(masm_.currentOffset());
     }
     void setIonExitOffset(unsigned exitIndex) {
         module_->exit(exitIndex).initIonOffset(masm_.currentOffset());
     }
-    void setEntryOffset(unsigned exportIndex) {
-        module_->exportedFunction(exportIndex).initCodeOffset(masm_.currentOffset());
-    }
 
     void buildCompilationTimeReport(bool storedInCache, ScopedJSFreePtr<char> *out) {
         ScopedJSFreePtr<char> slowFuns;
 #ifndef JS_MORE_DETERMINISTIC
         int64_t usecAfter = PRMJ_Now();
         int msTotal = (usecAfter - usecBefore_) / PRMJ_USEC_PER_MSEC;
         if (!slowFunctions_.empty()) {
             slowFuns.reset(JS_smprintf("; %d functions compiled slowly: ", slowFunctions_.length()));
@@ -1803,17 +1808,16 @@ class FunctionCompiler
     typedef Vector<TypedValue> VarInitializerVector;
     typedef HashMap<PropertyName*, BlockVector> LabeledBlockMap;
     typedef HashMap<ParseNode*, BlockVector> UnlabeledBlockMap;
     typedef Vector<ParseNode*, 4> NodeStack;
 
     ModuleCompiler &       m_;
     LifoAlloc &            lifo_;
     ParseNode *            fn_;
-    uint32_t               functionNameIndex_;
 
     LocalMap               locals_;
     VarInitializerVector   varInitializers_;
     Maybe<RetType>         alreadyReturned_;
 
     TempAllocator *        alloc_;
     MIRGraph *             graph_;
     CompileInfo *          info_;
@@ -1824,25 +1828,21 @@ class FunctionCompiler
 
     NodeStack              loopStack_;
     NodeStack              breakableStack_;
     UnlabeledBlockMap      unlabeledBreaks_;
     UnlabeledBlockMap      unlabeledContinues_;
     LabeledBlockMap        labeledBreaks_;
     LabeledBlockMap        labeledContinues_;
 
-    static const uint32_t NO_FUNCTION_NAME_INDEX = UINT32_MAX;
-    JS_STATIC_ASSERT(NO_FUNCTION_NAME_INDEX > CallSiteDesc::FUNCTION_NAME_INDEX_MAX);
-
   public:
     FunctionCompiler(ModuleCompiler &m, ParseNode *fn, LifoAlloc &lifo)
       : m_(m),
         lifo_(lifo),
         fn_(fn),
-        functionNameIndex_(NO_FUNCTION_NAME_INDEX),
         locals_(m.cx()),
         varInitializers_(m.cx()),
         alloc_(nullptr),
         graph_(nullptr),
         info_(nullptr),
         mirGen_(nullptr),
         curBlock_(nullptr),
         loopStack_(m.cx()),
@@ -2274,22 +2274,17 @@ class FunctionCompiler
         if (inDeadCode()) {
             *def = nullptr;
             return true;
         }
 
         uint32_t line, column;
         m_.tokenStream().srcCoords.lineNumAndColumnIndex(call.node_->pn_pos.begin, &line, &column);
 
-        if (functionNameIndex_ == NO_FUNCTION_NAME_INDEX) {
-            if (!m_.addFunctionName(FunctionName(fn_), &functionNameIndex_))
-                return false;
-        }
-
-        CallSiteDesc desc(line, column, functionNameIndex_);
+        CallSiteDesc desc(line, column);
         MAsmJSCall *ins = MAsmJSCall::New(alloc(), desc, callee, call.regArgs_, returnType,
                                           call.spIncrement_);
         if (!ins)
             return false;
 
         curBlock_->add(ins);
         *def = ins;
         return true;
@@ -5950,17 +5945,17 @@ GenerateEntry(ModuleCompiler &m, const A
     // In constrast to the system ABI, the Ion convention is that all registers
     // are clobbered by calls. Thus, we must save the caller's non-volatile
     // registers.
     //
     // NB: GenerateExits assumes that masm.framePushed() == 0 before
     // PushRegsInMask(NonVolatileRegs).
     masm.setFramePushed(0);
 
-    // See AsmJSFrameSize comment in Assembler-*.h.
+    // See AsmJSFrameSize comment in Assembler-shared.h.
 #if defined(JS_CODEGEN_ARM)
     masm.push(lr);
 #endif // JS_CODEGEN_ARM
 #if defined(JS_CODEGEN_MIPS)
     masm.push(ra);
 #endif
 
     masm.PushRegsInMask(NonVolatileRegs);
@@ -6025,17 +6020,17 @@ GenerateEntry(ModuleCompiler &m, const A
                 masm.storeDouble(ScratchDoubleReg, Address(StackPointer, iter->offsetFromArgBase()));
             }
             break;
         }
     }
 
     // Call into the real function.
     AssertStackAlignment(masm);
-    masm.call(CallSiteDesc::Entry(), func.code());
+    masm.call(func.code());
 
     // Pop the stack and recover the original 'argv' argument passed to the
     // trampoline (which was pushed on the stack).
     masm.freeStack(stackDec);
     masm.Pop(argv);
 
     // Store the return value in argv[0]
     switch (func.sig().retType().which()) {
@@ -6209,24 +6204,28 @@ 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);
 
-    // See AsmJSFrameSize comment in Assembler-*.h.
+    // See AsmJSFrameSize comment in Assembler-shared.h.
 #if defined(JS_CODEGEN_ARM)
     masm.push(lr);
-#endif
-#if defined(JS_CODEGEN_MIPS)
+#elif defined(JS_CODEGEN_MIPS)
     masm.push(ra);
 #endif
 
+    // Store the frame pointer in AsmJSActivation::exitFP for stack unwinding.
+    Register activation = ABIArgGenerator::NonArgReturnVolatileReg0;
+    LoadAsmJSActivationIntoRegister(masm, activation);
+    masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitFP()));
+
     MIRType typeArray[] = { MIRType_Pointer,   // cx
                             MIRType_Pointer,   // exitDatum
                             MIRType_Int32,     // argc
                             MIRType_Pointer }; // argv
     MIRTypeVector invokeArgTypes(m.cx());
     invokeArgTypes.infallibleAppend(typeArray, ArrayLength(typeArray));
 
     // At the point of the call, the stack layout shall be (sp grows to the left):
@@ -6235,26 +6234,21 @@ GenerateFFIInterpreterExit(ModuleCompile
     // sp is aligned.
     unsigned offsetToArgv = AlignBytes(StackArgBytes(invokeArgTypes) + MaybeRetAddr, StackAlignment);
     unsigned argvBytes = Max<size_t>(1, exit.sig().args().length()) * sizeof(Value);
     unsigned stackDec = StackDecrementForCall(masm, offsetToArgv + argvBytes);
     masm.reserveStack(stackDec);
 
     // Fill the argument array.
     unsigned offsetToCallerStackArgs = AsmJSFrameSize + masm.framePushed();
-    Register scratch = ABIArgGenerator::NonArgReturnVolatileReg0;
+    Register scratch = ABIArgGenerator::NonArgReturnVolatileReg1;
     FillArgumentArray(m, exit.sig().args(), offsetToArgv, offsetToCallerStackArgs, scratch);
 
     // Prepare the arguments for the call to InvokeFromAsmJS_*.
     ABIArgMIRTypeIter i(invokeArgTypes);
-    Register activation = ABIArgGenerator::NonArgReturnVolatileReg1;
-    LoadAsmJSActivationIntoRegister(masm, activation);
-
-    // Record sp in the AsmJSActivation for stack-walking.
-    masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitSP()));
 
     // argument 0: cx
     if (i->kind() == ABIArg::GPR) {
         LoadJSContextFromActivation(masm, activation, i->gpr());
     } else {
         LoadJSContextFromActivation(masm, activation, scratch);
         masm.storePtr(scratch, Address(StackPointer, i->offsetFromArgBase()));
     }
@@ -6285,37 +6279,42 @@ GenerateFFIInterpreterExit(ModuleCompile
     }
     i++;
     JS_ASSERT(i.done());
 
     // Make the call, test whether it succeeded, and extract the return value.
     AssertStackAlignment(masm);
     switch (exit.sig().retType().which()) {
       case RetType::Void:
-        masm.callExit(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_Ignore), i.stackBytesConsumedSoFar());
+        masm.call(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_Ignore));
         masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
         break;
       case RetType::Signed:
-        masm.callExit(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_ToInt32), i.stackBytesConsumedSoFar());
+        masm.call(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_ToInt32));
         masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
         masm.unboxInt32(argv, ReturnReg);
         break;
       case RetType::Double:
-        masm.callExit(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_ToNumber), i.stackBytesConsumedSoFar());
+        masm.call(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_ToNumber));
         masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
         masm.loadDouble(argv, ReturnDoubleReg);
         break;
       case RetType::Float:
         MOZ_ASSUME_UNREACHABLE("Float32 shouldn't be returned from a FFI");
         break;
     }
 
     // Note: the caller is IonMonkey code which means there are no non-volatile
     // registers to restore.
     masm.freeStack(stackDec);
+
+    // Clear exitFP before the frame is destroyed.
+    LoadAsmJSActivationIntoRegister(masm, activation);
+    masm.storePtr(ImmWord(0), Address(activation, AsmJSActivation::offsetOfExitFP()));
+
     masm.ret();
 }
 
 static void
 GenerateOOLConvert(ModuleCompiler &m, RetType retType, Label *throwLabel)
 {
     MacroAssembler &masm = m.masm();
 
@@ -6330,19 +6329,16 @@ GenerateOOLConvert(ModuleCompiler &m, Re
     // Store value
     unsigned offsetToArgv = StackArgBytes(callArgTypes) + MaybeRetAddr;
     masm.storeValue(JSReturnOperand, Address(StackPointer, offsetToArgv));
 
     Register scratch = ABIArgGenerator::NonArgReturnVolatileReg0;
     Register activation = ABIArgGenerator::NonArgReturnVolatileReg1;
     LoadAsmJSActivationIntoRegister(masm, activation);
 
-    // Record sp in the AsmJSActivation for stack-walking.
-    masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitSP()));
-
     // Store real arguments
     ABIArgMIRTypeIter i(callArgTypes);
 
     // argument 0: cx
     if (i->kind() == ABIArg::GPR) {
         LoadJSContextFromActivation(masm, activation, i->gpr());
     } else {
         LoadJSContextFromActivation(masm, activation, scratch);
@@ -6360,22 +6356,22 @@ GenerateOOLConvert(ModuleCompiler &m, Re
     }
     i++;
     JS_ASSERT(i.done());
 
     // Call
     AssertStackAlignment(masm);
     switch (retType.which()) {
       case RetType::Signed:
-        masm.callExit(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToInt32), i.stackBytesConsumedSoFar());
+        masm.call(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToInt32));
         masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
         masm.unboxInt32(Address(StackPointer, offsetToArgv), ReturnReg);
         break;
       case RetType::Double:
-        masm.callExit(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToNumber), i.stackBytesConsumedSoFar());
+        masm.call(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToNumber));
         masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
         masm.loadDouble(Address(StackPointer, offsetToArgv), ReturnDoubleReg);
         break;
       default:
         MOZ_ASSUME_UNREACHABLE("Unsupported convert type");
     }
 }
 
@@ -6383,29 +6379,32 @@ static void
 GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit,
                          unsigned exitIndex, Label *throwLabel)
 {
     MacroAssembler &masm = m.masm();
     masm.align(CodeAlignment);
     m.setIonExitOffset(exitIndex);
     masm.setFramePushed(0);
 
-    // See AsmJSFrameSize comment in Assembler-*.h.
+    // See AsmJSFrameSize comment in Assembler-shared.h.
+#if defined(JS_CODEGEN_ARM)
+    masm.push(lr);
+#elif defined(JS_CODEGEN_MIPS)
+    masm.push(ra);
+#endif
+
+    // Store the frame pointer in AsmJSActivation::exitFP for stack unwinding.
+    Register activation = ABIArgGenerator::NonArgReturnVolatileReg0;
+    LoadAsmJSActivationIntoRegister(masm, activation);
+    masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitFP()));
+
+    // Ion does not preserve nonvolatile registers, so we have to preserve them.
 #if defined(JS_CODEGEN_X64)
     masm.Push(HeapReg);
-#elif defined(JS_CODEGEN_ARM)
-    masm.push(lr);
-
-    // The GlobalReg (r10) and HeapReg (r11) also need to be restored before
-    // returning to asm.js code.
-    // The NANReg also needs to be restored, but is a constant and is reloaded before
-    // returning to asm.js code.
-    masm.PushRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code())));
-#elif defined(JS_CODEGEN_MIPS)
-    masm.push(ra);
+#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
     masm.PushRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code())));
 #endif
 
     // The stack frame is used for the call into Ion and also for calls into C for OOL
     // conversion of the result.  A frame large enough for both is allocated.
     //
     // Arguments to the Ion function are in the following order on the stack:
     // | return address | descriptor | callee | argc | this | arg1 | arg2 | ...
@@ -6493,42 +6492,30 @@ GenerateFFIIonExit(ModuleCompiler &m, co
         // This sequence requires four registers, and needs to preserve the 'callee'
         // register, so there are five live registers.
         JS_ASSERT(callee == AsmJSIonExitRegCallee);
         Register reg0 = AsmJSIonExitRegE0;
         Register reg1 = AsmJSIonExitRegE1;
         Register reg2 = AsmJSIonExitRegE2;
         Register reg3 = AsmJSIonExitRegE3;
 
-        LoadAsmJSActivationIntoRegister(masm, reg0);
-
-        // Record sp in the AsmJSActivation for stack-walking.
-#if defined(JS_CODEGEN_MIPS)
-        // Add a flag to indicate to AsmJSFrameIterator that we are calling
-        // into Ion, since the offset from SP to the return address is
-        // different when calling Ion vs. the native ABI.
-        masm.ma_or(reg1, StackPointer, Imm32(0x1));
-        masm.storePtr(reg1, Address(reg0, AsmJSActivation::offsetOfExitSP()));
-#else
-        masm.storePtr(StackPointer, Address(reg0, AsmJSActivation::offsetOfExitSP()));
-#endif
-
         // The following is inlined:
         //   JSContext *cx = activation->cx();
         //   Activation *act = cx->mainThread().activation();
         //   act.active_ = true;
         //   act.prevJitTop_ = cx->mainThread().jitTop;
         //   act.prevJitJSContext_ = cx->mainThread().jitJSContext;
         //   cx->mainThread().jitJSContext = cx;
         // On the ARM store8() uses the secondScratchReg (lr) as a temp.
         size_t offsetOfActivation = offsetof(JSRuntime, mainThread) +
                                     PerThreadData::offsetOfActivation();
         size_t offsetOfJitTop = offsetof(JSRuntime, mainThread) + offsetof(PerThreadData, jitTop);
         size_t offsetOfJitJSContext = offsetof(JSRuntime, mainThread) +
                                       offsetof(PerThreadData, jitJSContext);
+        LoadAsmJSActivationIntoRegister(masm, reg0);
         masm.loadPtr(Address(reg0, AsmJSActivation::offsetOfContext()), reg3);
         masm.loadPtr(Address(reg3, JSContext::offsetOfRuntime()), reg0);
         masm.loadPtr(Address(reg0, offsetOfActivation), reg1);
         masm.store8(Imm32(1), Address(reg1, JitActivation::offsetOfActiveUint8()));
         masm.loadPtr(Address(reg0, offsetOfJitTop), reg2);
         masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevJitTop()));
         masm.loadPtr(Address(reg0, offsetOfJitJSContext), reg2);
         masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevJitJSContext()));
@@ -6590,23 +6577,29 @@ GenerateFFIIonExit(ModuleCompiler &m, co
         break;
       case RetType::Float:
         MOZ_ASSUME_UNREACHABLE("Float shouldn't be returned from a FFI");
         break;
     }
 
     masm.bind(&done);
     masm.freeStack(stackDec);
+
+    // Restore non-volatile registers saved in the prologue.
 #if defined(JS_CODEGEN_X64)
     masm.Pop(HeapReg);
-#endif
-#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
+#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
     masm.loadConstantDouble(GenericNaN(), NANReg);
     masm.PopRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code())));
 #endif
+
+    // Clear exitFP before the frame is destroyed.
+    LoadAsmJSActivationIntoRegister(masm, activation);
+    masm.storePtr(ImmWord(0), Address(activation, AsmJSActivation::offsetOfExitFP()));
+
     masm.ret();
     JS_ASSERT(masm.framePushed() == 0);
 
     // oolConvert
     if (oolConvert.used()) {
         masm.bind(&oolConvert);
         masm.setFramePushed(oolConvertFramePushed);
         GenerateOOLConvert(m, exit.sig().retType(), throwLabel);
@@ -6637,43 +6630,49 @@ 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());
 
+    // The stack-overflow is checked before bumping the stack.
+    masm.setFramePushed(0);
+
+    // Store the frame pointer in AsmJSActivation::exitFP for stack unwinding.
+    Register activation = ABIArgGenerator::NonArgReturnVolatileReg0;
+    LoadAsmJSActivationIntoRegister(masm, activation);
+    masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitFP()));
+
     MIRTypeVector argTypes(m.cx());
     argTypes.infallibleAppend(MIRType_Pointer); // cx
 
     unsigned stackDec = StackDecrementForCall(masm, argTypes, MaybeRetAddr);
     masm.reserveStack(stackDec);
 
-    Register activation = ABIArgGenerator::NonArgReturnVolatileReg0;
-    LoadAsmJSActivationIntoRegister(masm, activation);
-
-    // Record sp in the AsmJSActivation for stack-walking.
-    masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitSP()));
-
     ABIArgMIRTypeIter i(argTypes);
 
     // argument 0: cx
     if (i->kind() == ABIArg::GPR) {
         LoadJSContextFromActivation(masm, activation, i->gpr());
     } else {
         LoadJSContextFromActivation(masm, activation, activation);
         masm.storePtr(activation, Address(StackPointer, i->offsetFromArgBase()));
     }
     i++;
 
     JS_ASSERT(i.done());
 
     AssertStackAlignment(masm);
-    masm.callExit(AsmJSImmPtr(AsmJSImm_ReportOverRecursed), i.stackBytesConsumedSoFar());
+    masm.call(AsmJSImmPtr(AsmJSImm_ReportOverRecursed));
+
+    // Clear exitFP before the frame is destroyed.
+    LoadAsmJSActivationIntoRegister(masm, activation);
+    masm.storePtr(ImmWord(0), Address(activation, AsmJSActivation::offsetOfExitFP()));
 
     // Don't worry about restoring the stack; throwLabel will pop everything.
     masm.jump(throwLabel);
     return !masm.oom();
 }
 
 static const RegisterSet AllRegsExceptSP =
     RegisterSet(GeneralRegisterSet(Registers::AllMask &
@@ -6862,20 +6861,20 @@ GenerateThrowExit(ModuleCompiler &m, Lab
 
     return !masm.oom();
 }
 
 static bool
 GenerateStubs(ModuleCompiler &m)
 {
     for (unsigned i = 0; i < m.module().numExportedFunctions(); i++) {
-        m.setEntryOffset(i);
+        m.startGeneratingEntry(i);
         if (!GenerateEntry(m, m.module().exportedFunction(i)))
             return false;
-        if (m.masm().oom())
+        if (m.masm().oom() || !m.finishGeneratingEntry(i))
             return false;
     }
 
     Label throwLabel;
 
     // The order of the iterations here is non-deterministic, since
     // m.allExits() is a hash keyed by pointer values!
     for (ModuleCompiler::ExitMap::Range r = m.allExits(); !r.empty(); r.popFront()) {
new file mode 100644
--- /dev/null
+++ b/js/src/jit/AsmJSFrameIterator.cpp
@@ -0,0 +1,75 @@
+/* -*- 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 "jit/AsmJSFrameIterator.h"
+
+#include "jit/AsmJS.h"
+#include "jit/AsmJSModule.h"
+
+using namespace js;
+using namespace js::jit;
+
+static void *
+ReturnAddressFromFP(uint8_t *fp)
+{
+    // In asm.js code, the "frame" consists of a single word: the saved
+    // return address of the caller.
+    static_assert(AsmJSFrameSize == sizeof(void*), "Frame size mismatch");
+    return *(uint8_t**)fp;
+}
+
+AsmJSFrameIterator::AsmJSFrameIterator(const AsmJSActivation &activation)
+  : module_(&activation.module()),
+    fp_(activation.exitFP())
+{
+    if (!fp_)
+        return;
+    settle(ReturnAddressFromFP(fp_));
+}
+
+void
+AsmJSFrameIterator::operator++()
+{
+    JS_ASSERT(!done());
+    fp_ += callsite_->stackDepth();
+    settle(ReturnAddressFromFP(fp_));
+}
+
+void
+AsmJSFrameIterator::settle(void *returnAddress)
+{
+    const AsmJSModule::CodeRange *codeRange = module_->lookupCodeRange(ReturnAddressFromFP(fp_));
+    JS_ASSERT(codeRange);
+    codeRange_ = codeRange;
+
+    switch (codeRange->kind()) {
+      case AsmJSModule::CodeRange::Entry:
+        fp_ = nullptr;
+        JS_ASSERT(done());
+        return;
+      case AsmJSModule::CodeRange::Function:
+        callsite_ = module_->lookupCallSite(returnAddress);
+        JS_ASSERT(callsite_);
+        break;
+    }
+}
+
+JSAtom *
+AsmJSFrameIterator::functionDisplayAtom() const
+{
+    JS_ASSERT(!done());
+    return reinterpret_cast<const AsmJSModule::CodeRange*>(codeRange_)->functionName(*module_);
+}
+
+unsigned
+AsmJSFrameIterator::computeLine(uint32_t *column) const
+{
+    JS_ASSERT(!done());
+    if (column)
+        *column = callsite_->column();
+    return callsite_->line();
+}
+
new file mode 100644
--- /dev/null
+++ b/js/src/jit/AsmJSFrameIterator.h
@@ -0,0 +1,46 @@
+/* -*- 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/. */
+
+#ifndef jit_AsmJSFrameIterator_h
+#define jit_AsmJSFrameIterator_h
+
+#include "mozilla/NullPtr.h"
+
+#include <stdint.h>
+
+class JSAtom;
+
+namespace js {
+
+class AsmJSActivation;
+class AsmJSModule;
+namespace jit { struct CallSite; }
+
+// Iterates over the frames of a single AsmJSActivation.
+class AsmJSFrameIterator
+{
+    const AsmJSModule *module_;
+    const jit::CallSite *callsite_;
+    uint8_t *fp_;
+
+    // Really, a const AsmJSModule::CodeRange*, but no forward declarations of
+    // nested classes, so use void* to avoid pulling in all of AsmJSModule.h.
+    const void *codeRange_;
+
+    void settle(void *returnAddress);
+
+  public:
+    explicit AsmJSFrameIterator() : module_(nullptr) {}
+    explicit AsmJSFrameIterator(const AsmJSActivation &activation);
+    void operator++();
+    bool done() const { return !fp_; }
+    JSAtom *functionDisplayAtom() const;
+    unsigned computeLine(uint32_t *column) const;
+};
+
+} // namespace js
+
+#endif // jit_AsmJSFrameIterator_h
--- a/js/src/jit/AsmJSLink.cpp
+++ b/js/src/jit/AsmJSLink.cpp
@@ -29,111 +29,16 @@
 #include "jsobjinlines.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::IsNaN;
 using mozilla::PodZero;
 
-static uint8_t *
-ReturnAddressForExitCall(uint8_t **psp)
-{
-    uint8_t *sp = *psp;
-#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
-    // For calls to Ion/C++ on x86/x64, the exitSP is the SP right before the call
-    // to C++. Since the call instruction pushes the return address, we know
-    // that the return address is 1 word below exitSP.
-    return *(uint8_t**)(sp - sizeof(void*));
-#elif defined(JS_CODEGEN_ARM)
-    // For calls to Ion/C++ on ARM, the *caller* pushes the return address on
-    // the stack. For Ion, this is just part of the ABI. For C++, the return
-    // address is explicitly pushed before the call since we cannot expect the
-    // callee to immediately push lr. This means that exitSP points to the
-    // return address.
-    return *(uint8_t**)sp;
-#elif defined(JS_CODEGEN_MIPS)
-    // On MIPS we have two cases: an exit to C++ will store the return address
-    // at ShadowStackSpace above sp; an exit to Ion will store the return
-    // address at sp. To distinguish the two cases, the low bit of sp (which is
-    // aligned and therefore zero) is set for Ion exits.
-    if (uintptr_t(sp) & 0x1) {
-        sp = *psp -= 0x1;  // Clear the low bit
-        return *(uint8_t**)sp;
-    }
-    return *(uint8_t**)(sp + ShadowStackSpace);
-#else
-# error "Unknown architecture!"
-#endif
-}
-
-static uint8_t *
-ReturnAddressForJitCall(uint8_t *sp)
-{
-    // Once inside JIT code, sp always points to the word before the return
-    // address.
-    return *(uint8_t**)(sp - sizeof(void*));
-}
-
-AsmJSFrameIterator::AsmJSFrameIterator(const AsmJSActivation *activation)
-  : module_(nullptr)
-{
-    if (!activation || activation->isInterruptedSP())
-        return;
-
-    module_ = &activation->module();
-    sp_ = activation->exitSP();
-
-    settle(ReturnAddressForExitCall(&sp_));
-}
-
-void
-AsmJSFrameIterator::operator++()
-{
-    settle(ReturnAddressForJitCall(sp_));
-}
-
-void
-AsmJSFrameIterator::settle(uint8_t *returnAddress)
-{
-    callsite_ = module_->lookupCallSite(returnAddress);
-    if (!callsite_ || callsite_->isEntry()) {
-        module_ = nullptr;
-        return;
-    }
-
-    if (callsite_->isEntry()) {
-        module_ = nullptr;
-        return;
-    }
-
-    sp_ += callsite_->stackDepth();
-
-    if (callsite_->isExit())
-        return settle(ReturnAddressForJitCall(sp_));
-
-    JS_ASSERT(callsite_->isNormal());
-}
-
-JSAtom *
-AsmJSFrameIterator::functionDisplayAtom() const
-{
-    JS_ASSERT(!done());
-    return module_->functionName(callsite_->functionNameIndex());
-}
-
-unsigned
-AsmJSFrameIterator::computeLine(uint32_t *column) const
-{
-    JS_ASSERT(!done());
-    if (column)
-        *column = callsite_->column();
-    return callsite_->line();
-}
-
 static bool
 CloneModule(JSContext *cx, MutableHandle<AsmJSModuleObject*> moduleObj)
 {
     ScopedJSDeletePtr<AsmJSModule> module;
     if (!moduleObj->module().clone(cx, &module))
         return false;
 
     module->staticallyLink(cx);
--- a/js/src/jit/AsmJSLink.h
+++ b/js/src/jit/AsmJSLink.h
@@ -4,41 +4,18 @@
  * 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_AsmJSLink_h
 #define jit_AsmJSLink_h
 
 #include "NamespaceImports.h"
 
-class JSAtom;
-
 namespace js {
 
-class AsmJSActivation;
-class AsmJSModule;
-namespace jit { struct CallSite; }
-
-// Iterates over the frames of a single AsmJSActivation.
-class AsmJSFrameIterator
-{
-    const AsmJSModule *module_;
-    const jit::CallSite *callsite_;
-    uint8_t *sp_;
-
-    void settle(uint8_t *returnAddress);
-
-  public:
-    explicit AsmJSFrameIterator(const AsmJSActivation *activation);
-    void operator++();
-    bool done() const { return !module_; }
-    JSAtom *functionDisplayAtom() const;
-    unsigned computeLine(uint32_t *column) const;
-};
-
 #ifdef JS_ION
 
 // Create a new JSFunction to replace originalFun as the representation of the
 // function defining the succesfully-validated module 'moduleObj'.
 extern JSFunction *
 NewAsmJSModuleFunction(ExclusiveContext *cx, JSFunction *originalFun, HandleObject moduleObj);
 
 // Return whether this is the js::Native returned by NewAsmJSModuleFunction.
--- a/js/src/jit/AsmJSModule.cpp
+++ b/js/src/jit/AsmJSModule.cpp
@@ -162,16 +162,17 @@ AsmJSModule::addSizeOfMisc(mozilla::Mall
                            size_t *asmJSModuleData)
 {
     *asmJSModuleCode += pod.totalBytes_;
     *asmJSModuleData += mallocSizeOf(this) +
                         globals_.sizeOfExcludingThis(mallocSizeOf) +
                         exits_.sizeOfExcludingThis(mallocSizeOf) +
                         exports_.sizeOfExcludingThis(mallocSizeOf) +
                         callSites_.sizeOfExcludingThis(mallocSizeOf) +
+                        codeRanges_.sizeOfExcludingThis(mallocSizeOf) +
                         functionNames_.sizeOfExcludingThis(mallocSizeOf) +
                         heapAccesses_.sizeOfExcludingThis(mallocSizeOf) +
                         functionCounts_.sizeOfExcludingThis(mallocSizeOf) +
 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
                         profiledFunctions_.sizeOfExcludingThis(mallocSizeOf) +
 #endif
 #if defined(JS_ION_PERF)
                         perfProfiledBlocksFunctions_.sizeOfExcludingThis(mallocSizeOf) +
@@ -184,47 +185,86 @@ struct CallSiteRetAddrOffset
     const CallSiteVector &callSites;
     explicit CallSiteRetAddrOffset(const CallSiteVector &callSites) : callSites(callSites) {}
     uint32_t operator[](size_t index) const {
         return callSites[index].returnAddressOffset();
     }
 };
 
 const CallSite *
-AsmJSModule::lookupCallSite(uint8_t *returnAddress) const
+AsmJSModule::lookupCallSite(void *returnAddress) const
 {
     JS_ASSERT(isFinished());
 
-    uint32_t target = returnAddress - code_;
+    uint32_t target = ((uint8_t*)returnAddress) - code_;
     size_t lowerBound = 0;
     size_t upperBound = callSites_.length();
 
     size_t match;
     if (!BinarySearch(CallSiteRetAddrOffset(callSites_), lowerBound, upperBound, target, &match))
         return nullptr;
 
     return &callSites_[match];
 }
 
+namespace js {
+
+// Create an ordering on CodeRange and pc offsets suitable for BinarySearch.
+// Stick these in the same namespace as AsmJSModule so that argument-dependent
+// lookup will find it.
+bool
+operator==(size_t pcOffset, const AsmJSModule::CodeRange &rhs)
+{
+    return pcOffset >= rhs.beginOffset() && pcOffset < rhs.endOffset();
+}
+bool
+operator<=(const AsmJSModule::CodeRange &lhs, const AsmJSModule::CodeRange &rhs)
+{
+    return lhs.beginOffset() <= rhs.beginOffset();
+}
+bool
+operator<(size_t pcOffset, const AsmJSModule::CodeRange &rhs)
+{
+    return pcOffset < rhs.beginOffset();
+}
+
+} // namespace js
+
+const AsmJSModule::CodeRange *
+AsmJSModule::lookupCodeRange(void *pc) const
+{
+    JS_ASSERT(isFinished());
+
+    uint32_t target = ((uint8_t*)pc) - code_;
+    size_t lowerBound = 0;
+    size_t upperBound = codeRanges_.length();
+
+    size_t match;
+    if (!BinarySearch(codeRanges_, lowerBound, upperBound, target, &match))
+        return nullptr;
+
+    return &codeRanges_[match];
+}
+
 struct HeapAccessOffset
 {
     const AsmJSHeapAccessVector &accesses;
     explicit HeapAccessOffset(const AsmJSHeapAccessVector &accesses) : accesses(accesses) {}
     uintptr_t operator[](size_t index) const {
         return accesses[index].offset();
     }
 };
 
 const AsmJSHeapAccess *
-AsmJSModule::lookupHeapAccess(uint8_t *pc) const
+AsmJSModule::lookupHeapAccess(void *pc) const
 {
     JS_ASSERT(isFinished());
     JS_ASSERT(containsPC(pc));
 
-    uint32_t target = pc - code_;
+    uint32_t target = ((uint8_t*)pc) - code_;
     size_t lowerBound = 0;
     size_t upperBound = heapAccesses_.length();
 
     size_t match;
     if (!BinarySearch(HeapAccessOffset(heapAccesses_), lowerBound, upperBound, target, &match))
         return nullptr;
 
     return &heapAccesses_[match];
@@ -288,16 +328,21 @@ AsmJSModule::finish(ExclusiveContext *cx
     for (unsigned i = 0; i < numExportedFunctions(); i++)
         exportedFunction(i).updateCodeOffset(masm);
     for (unsigned i = 0; i < numExits(); i++)
         exit(i).updateOffsets(masm);
     for (size_t i = 0; i < callSites_.length(); i++) {
         CallSite &c = callSites_[i];
         c.setReturnAddressOffset(masm.actualOffset(c.returnAddressOffset()));
     }
+    for (size_t i = 0; i < codeRanges_.length(); i++) {
+        CodeRange &c = codeRanges_[i];
+        c.beginOffset_ = masm.actualOffset(c.beginOffset_);
+        c.endOffset_ = masm.actualOffset(c.endOffset_);
+    }
 #endif
     JS_ASSERT(pod.functionBytes_ % AsmJSPageSize == 0);
 
     // Absolute link metadata: absolute addresses that refer to some fixed
     // address in the address space.
     for (size_t i = 0; i < masm.numAsmJSAbsoluteLinks(); i++) {
         AsmJSAbsoluteLink src = masm.asmJSAbsoluteLink(i);
         AbsoluteLink link;
@@ -1079,16 +1124,17 @@ AsmJSModule::serializedSize() const
            pod.codeBytes_ +
            SerializedNameSize(globalArgumentName_) +
            SerializedNameSize(importArgumentName_) +
            SerializedNameSize(bufferArgumentName_) +
            SerializedVectorSize(globals_) +
            SerializedVectorSize(exits_) +
            SerializedVectorSize(exports_) +
            SerializedPodVectorSize(callSites_) +
+           SerializedPodVectorSize(codeRanges_) +
            SerializedVectorSize(functionNames_) +
            SerializedPodVectorSize(heapAccesses_) +
 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
            SerializedVectorSize(profiledFunctions_) +
 #endif
            staticLinkData_.serializedSize();
 }
 
@@ -1099,16 +1145,17 @@ AsmJSModule::serialize(uint8_t *cursor) 
     cursor = WriteBytes(cursor, code_, pod.codeBytes_);
     cursor = SerializeName(cursor, globalArgumentName_);
     cursor = SerializeName(cursor, importArgumentName_);
     cursor = SerializeName(cursor, bufferArgumentName_);
     cursor = SerializeVector(cursor, globals_);
     cursor = SerializeVector(cursor, exits_);
     cursor = SerializeVector(cursor, exports_);
     cursor = SerializePodVector(cursor, callSites_);
+    cursor = SerializePodVector(cursor, codeRanges_);
     cursor = SerializeVector(cursor, functionNames_);
     cursor = SerializePodVector(cursor, heapAccesses_);
 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
     cursor = SerializeVector(cursor, profiledFunctions_);
 #endif
     cursor = staticLinkData_.serialize(cursor);
     return cursor;
 }
@@ -1125,16 +1172,17 @@ AsmJSModule::deserialize(ExclusiveContex
     (cursor = ReadBytes(cursor, code_, pod.codeBytes_)) &&
     (cursor = DeserializeName(cx, cursor, &globalArgumentName_)) &&
     (cursor = DeserializeName(cx, cursor, &importArgumentName_)) &&
     (cursor = DeserializeName(cx, cursor, &bufferArgumentName_)) &&
     (cursor = DeserializeVector(cx, cursor, &globals_)) &&
     (cursor = DeserializeVector(cx, cursor, &exits_)) &&
     (cursor = DeserializeVector(cx, cursor, &exports_)) &&
     (cursor = DeserializePodVector(cx, cursor, &callSites_)) &&
+    (cursor = DeserializePodVector(cx, cursor, &codeRanges_)) &&
     (cursor = DeserializeVector(cx, cursor, &functionNames_)) &&
     (cursor = DeserializePodVector(cx, cursor, &heapAccesses_)) &&
 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
     (cursor = DeserializeVector(cx, cursor, &profiledFunctions_)) &&
 #endif
     (cursor = staticLinkData_.deserialize(cx, cursor));
 
     loadedFromCache_ = true;
@@ -1195,16 +1243,17 @@ AsmJSModule::clone(JSContext *cx, Scoped
     out.globalArgumentName_ = globalArgumentName_;
     out.importArgumentName_ = importArgumentName_;
     out.bufferArgumentName_ = bufferArgumentName_;
 
     if (!CloneVector(cx, globals_, &out.globals_) ||
         !CloneVector(cx, exits_, &out.exits_) ||
         !CloneVector(cx, exports_, &out.exports_) ||
         !ClonePodVector(cx, callSites_, &out.callSites_) ||
+        !ClonePodVector(cx, codeRanges_, &out.codeRanges_) ||
         !CloneVector(cx, functionNames_, &out.functionNames_) ||
         !ClonePodVector(cx, heapAccesses_, &out.heapAccesses_) ||
         !staticLinkData_.clone(cx, &out.staticLinkData_))
     {
         return false;
     }
 
     out.loadedFromCache_ = loadedFromCache_;
--- a/js/src/jit/AsmJSModule.h
+++ b/js/src/jit/AsmJSModule.h
@@ -308,16 +308,43 @@ class AsmJSModule
         }
 
         size_t serializedSize() const;
         uint8_t *serialize(uint8_t *cursor) const;
         const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor);
         bool clone(ExclusiveContext *cx, ExportedFunction *out) const;
     };
 
+    class CodeRange
+    {
+      public:
+        enum Kind { Entry, Function };
+
+      private:
+        Kind kind_;
+        uint32_t beginOffset_;
+        uint32_t endOffset_;
+        uint32_t functionNameIndex_;
+
+        friend class AsmJSModule;
+        CodeRange(Kind kind, uint32_t beginOffset, uint32_t endOffset)
+          : kind_(kind), beginOffset_(beginOffset), endOffset_(endOffset)
+        {}
+
+      public:
+        CodeRange() {}
+        Kind kind() const { return kind_; }
+        uint32_t beginOffset() const { return beginOffset_; }
+        uint32_t endOffset() const { return endOffset_; }
+        PropertyName *functionName(const AsmJSModule &module) const {
+            JS_ASSERT(kind_ == Function);
+            return module.functionNames_[functionNameIndex_].name();
+        }
+    };
+
     class Name
     {
         PropertyName *name_;
       public:
         Name() : name_(nullptr) {}
         MOZ_IMPLICIT Name(PropertyName *name) : name_(name) {}
         PropertyName *name() const { return name_; }
         PropertyName *&name() { return name_; }
@@ -474,16 +501,17 @@ class AsmJSModule
     // respect to caching.
     const uint32_t                        funcStart_;
     const uint32_t                        offsetToEndOfUseAsm_;
 
     Vector<Global,                 0, SystemAllocPolicy> globals_;
     Vector<Exit,                   0, SystemAllocPolicy> exits_;
     Vector<ExportedFunction,       0, SystemAllocPolicy> exports_;
     Vector<jit::CallSite,          0, SystemAllocPolicy> callSites_;
+    Vector<CodeRange,              0, SystemAllocPolicy> codeRanges_;
     Vector<Name,                   0, SystemAllocPolicy> functionNames_;
     Vector<jit::AsmJSHeapAccess,   0, SystemAllocPolicy> heapAccesses_;
     Vector<jit::IonScriptCounts*,  0, SystemAllocPolicy> functionCounts_;
 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
     Vector<ProfiledFunction,       0, SystemAllocPolicy> profiledFunctions_;
 #endif
 #if defined(JS_ION_PERF)
     Vector<ProfiledBlocksFunction, 0, SystemAllocPolicy> perfProfiledBlocksFunctions_;
@@ -661,27 +689,31 @@ class AsmJSModule
     /*************************************************************************/
     // These functions are called while parsing/compiling function bodies:
 
     void requireHeapLengthToBeAtLeast(uint32_t len) {
         JS_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
         if (len > pod.minHeapLength_)
             pod.minHeapLength_ = len;
     }
-    bool addFunctionName(PropertyName *name, uint32_t *nameIndex) {
+    bool addFunctionCodeRange(PropertyName *name, uint32_t beginOffset, uint32_t endOffset) {
         JS_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
         JS_ASSERT(name->isTenured());
-        if (functionNames_.length() > jit::CallSiteDesc::FUNCTION_NAME_INDEX_MAX)
+        JS_ASSERT(beginOffset <= endOffset);
+        JS_ASSERT_IF(!codeRanges_.empty(), codeRanges_.back().endOffset() <= beginOffset);
+        if (functionNames_.length() >= UINT32_MAX)
             return false;
-        *nameIndex = functionNames_.length();
-        return functionNames_.append(name);
+        CodeRange codeRange(CodeRange::Function, beginOffset, endOffset);
+        codeRange.functionNameIndex_ = functionNames_.length();
+        return functionNames_.append(name) && codeRanges_.append(codeRange);
     }
-    PropertyName *functionName(uint32_t i) const {
-        JS_ASSERT(isFinished());
-        return functionNames_[i].name();
+    bool addEntryCodeRange(unsigned exportIndex, uint32_t endOffset) {
+        uint32_t beginOffset = exports_[exportIndex].pod.codeOffset_;
+        CodeRange codeRange(CodeRange::Entry, beginOffset, endOffset);
+        return codeRanges_.append(codeRange);
     }
     bool addExit(unsigned ffiIndex, unsigned *exitIndex) {
         JS_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
         if (SIZE_MAX - pod.funcPtrTableAndExitBytes_ < sizeof(ExitDatum))
             return false;
         uint32_t globalDataOffset = globalDataBytes();
         JS_STATIC_ASSERT(sizeof(ExitDatum) % sizeof(void*) == 0);
         pod.funcPtrTableAndExitBytes_ += sizeof(ExitDatum);
@@ -847,21 +879,25 @@ class AsmJSModule
     uint8_t *ionExitTrampoline(const Exit &exit) const {
         JS_ASSERT(isFinished());
         JS_ASSERT(exit.ionCodeOffset_);
         return code_ + exit.ionCodeOffset_;
     }
 
     // Lookup a callsite by the return pc (from the callee to the caller).
     // Return null if no callsite was found.
-    const jit::CallSite *lookupCallSite(uint8_t *returnAddress) const;
+    const jit::CallSite *lookupCallSite(void *returnAddress) const;
+
+    // Lookup the name the code range containing the given pc. Return null if no
+    // code range was found.
+    const CodeRange *lookupCodeRange(void *pc) const;
 
     // Lookup a heap access site by the pc which performs the access. Return
     // null if no heap access was found.
-    const jit::AsmJSHeapAccess *lookupHeapAccess(uint8_t *pc) const;
+    const jit::AsmJSHeapAccess *lookupHeapAccess(void *pc) const;
 
     // The global data section is placed after the executable code (i.e., at
     // offset codeBytes_) in the module's linear allocation. The global data
     // are laid out in this order:
     //   0. a pointer (padded up to 8 bytes to ensure double-alignment of
     //      globals) for the heap that was linked to the module.
     //   1. global variable state (elements are sizeof(uint64_t))
     //   2. interleaved function-pointer tables and exits. These are allocated
--- a/js/src/jit/AsmJSSignalHandlers.cpp
+++ b/js/src/jit/AsmJSSignalHandlers.cpp
@@ -351,17 +351,17 @@ HandleSimulatorInterrupt(JSRuntime *rt, 
     // simulator could be in the middle of an instruction. On ARM, the signal
     // handlers are currently only used for Odin code, see bug 964258.
 
 #if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     const AsmJSModule &module = activation->module();
     if (module.containsPC((void *)rt->mainThread.simulator()->get_pc()) &&
         module.containsPC(faultingAddress))
     {
-        activation->setInterrupted(nullptr);
+        activation->setResumePC(nullptr);
         int32_t nextpc = int32_t(module.interruptExit());
         rt->mainThread.simulator()->set_resume_pc(nextpc);
         return true;
     }
 #endif
     return false;
 }
 
@@ -460,17 +460,17 @@ HandleException(PEXCEPTION_POINTERS exce
         return false;
 
     // If we faulted trying to execute code in 'module', this must be an
     // interrupt callback (see RequestInterruptForAsmJSCode). Redirect
     // execution to a trampoline which will call js::HandleExecutionInterrupt.
     // The trampoline will jump to activation->resumePC if execution isn't
     // interrupted.
     if (module.containsPC(faultingAddress)) {
-        activation->setInterrupted(pc);
+        activation->setResumePC(pc);
         *ppc = module.interruptExit();
 
         JSRuntime::AutoLockForInterrupt lock(rt);
         module.unprotectCode(rt);
         return true;
     }
 
 # if defined(JS_CODEGEN_X64)
@@ -663,17 +663,17 @@ HandleMachException(JSRuntime *rt, const
         return false;
 
     // If we faulted trying to execute code in 'module', this must be an
     // interrupt callback (see RequestInterruptForAsmJSCode). Redirect
     // execution to a trampoline which will call js::HandleExecutionInterrupt.
     // The trampoline will jump to activation->resumePC if execution isn't
     // interrupted.
     if (module.containsPC(faultingAddress)) {
-        activation->setInterrupted(pc);
+        activation->setResumePC(pc);
         *ppc = module.interruptExit();
 
         JSRuntime::AutoLockForInterrupt lock(rt);
         module.unprotectCode(rt);
 
         // 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;
@@ -913,17 +913,17 @@ HandleSignal(int signum, siginfo_t *info
         return false;
 
     // If we faulted trying to execute code in 'module', this must be an
     // interrupt callback (see RequestInterruptForAsmJSCode). Redirect
     // execution to a trampoline which will call js::HandleExecutionInterrupt.
     // The trampoline will jump to activation->resumePC if execution isn't
     // interrupted.
     if (module.containsPC(faultingAddress)) {
-        activation->setInterrupted(pc);
+        activation->setResumePC(pc);
         *ppc = module.interruptExit();
 
         JSRuntime::AutoLockForInterrupt lock(rt);
         module.unprotectCode(rt);
         return true;
     }
 
 # if defined(JS_CODEGEN_X64)
--- a/js/src/jit/Bailouts.cpp
+++ b/js/src/jit/Bailouts.cpp
@@ -17,16 +17,18 @@
 
 #include "jit/JitFrameIterator-inl.h"
 #include "vm/Probes-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
+using mozilla::IsInRange;
+
 // These constructor are exactly the same except for the type of the iterator
 // which is given to the SnapshotIterator constructor. Doing so avoid the
 // creation of virtual functions for the IonIterator but may introduce some
 // weirdness as IonInlineIterator is using a JitFrameIterator reference.
 //
 // If a function relies on ionScript() or to use OsiIndex(), due to the
 // lack of virtual, these functions will use the JitFrameIterator reference
 // contained in the InlineFrameIterator and thus are not able to recover
@@ -71,18 +73,18 @@ IonBailoutIterator::dump() const
 
 uint32_t
 jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo)
 {
     JSContext *cx = GetJSContextFromJitCode();
     JS_ASSERT(bailoutInfo);
 
     // We don't have an exit frame.
-    MOZ_ASSERT(size_t(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(IonCommonFrameLayout)) < 0x1000 &&
-               size_t(FAKE_JIT_TOP_FOR_BAILOUT) >= 0,
+    MOZ_ASSERT(IsInRange(FAKE_JIT_TOP_FOR_BAILOUT, 0, 0x1000) &&
+               IsInRange(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(IonCommonFrameLayout), 0, 0x1000),
                "Fake jitTop pointer should be within the first page.");
     cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
     gc::AutoSuppressGC suppress(cx);
 
     JitActivationIterator jitActivations(cx->runtime());
     IonBailoutIterator iter(jitActivations, sp);
     JitActivation *activation = jitActivations->asJit();
 
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -8568,17 +8568,17 @@ CodeGenerator::visitAsmJSCall(LAsmJSCall
     switch (callee.which()) {
       case MAsmJSCall::Callee::Internal:
         masm.call(mir->desc(), callee.internal());
         break;
       case MAsmJSCall::Callee::Dynamic:
         masm.call(mir->desc(), ToRegister(ins->getOperand(mir->dynamicCalleeOperandIndex())));
         break;
       case MAsmJSCall::Callee::Builtin:
-        masm.call(mir->desc(), AsmJSImmPtr(callee.builtin()));
+        masm.call(AsmJSImmPtr(callee.builtin()));
         break;
     }
 
     if (mir->spIncrement())
         masm.reserveStack(mir->spIncrement());
 
     postAsmJSCall(ins);
     return true;
--- a/js/src/jit/ParallelFunctions.cpp
+++ b/js/src/jit/ParallelFunctions.cpp
@@ -13,16 +13,18 @@
 #include "vm/ArrayObject.h"
 
 #include "jsgcinlines.h"
 #include "jsobjinlines.h"
 
 using namespace js;
 using namespace jit;
 
+using mozilla::IsInRange;
+
 using JS::AutoCheckCannotGC;
 
 using parallel::Spew;
 using parallel::SpewOps;
 using parallel::SpewBailouts;
 
 // Load the current thread context.
 ForkJoinContext *
@@ -519,18 +521,18 @@ jit::UrshValuesPar(ForkJoinContext *cx, 
 void
 jit::BailoutPar(BailoutStack *sp, uint8_t **entryFramePointer)
 {
     parallel::Spew(parallel::SpewBailouts, "Bailing");
 
     ForkJoinContext *cx = ForkJoinContext::current();
 
     // We don't have an exit frame.
-    MOZ_ASSERT(size_t(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(IonCommonFrameLayout)) < 0x1000 &&
-               size_t(FAKE_JIT_TOP_FOR_BAILOUT) >= 0,
+    MOZ_ASSERT(IsInRange(FAKE_JIT_TOP_FOR_BAILOUT, 0, 0x1000) &&
+               IsInRange(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(IonCommonFrameLayout), 0, 0x1000),
                "Fake jitTop pointer should be within the first page.");
     cx->perThreadData->jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
 
     JitActivationIterator jitActivations(cx->perThreadData);
     IonBailoutIterator frameIter(jitActivations, sp);
     SnapshotIterator snapIter(frameIter);
 
     cx->bailoutRecord->setIonBailoutKind(snapIter.bailoutKind());
--- a/js/src/jit/arm/Architecture-arm.h
+++ b/js/src/jit/arm/Architecture-arm.h
@@ -432,22 +432,27 @@ uint32_t GetARMFlags();
 bool HasMOVWT();
 bool HasVFPv3();
 bool HasVFP();
 bool Has32DP();
 bool HasIDIV();
 
 // Arm/D32 has double registers that can NOT be treated as float32
 // and this requires some dances in lowering.
-inline bool hasUnaliasedDouble() {
+inline bool
+hasUnaliasedDouble()
+{
     return Has32DP();
 }
+
 // On ARM, Dn aliases both S2n and S2n+1, so if you need to convert a float32
 // to a double as a temporary, you need a temporary double register.
-inline bool hasMultiAlias() {
+inline bool
+hasMultiAlias()
+{
     return true;
 }
 
 bool ParseARMHwCapFlags(const char *armHwCap);
 
 // If the simulator is used then the ABI choice is dynamic.  Otherwise the ABI is static
 // and useHardFpABI is inlined so that unused branches can be optimized away.
 #if defined(JS_ARM_SIMULATOR)
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -136,22 +136,16 @@ static MOZ_CONSTEXPR_VAR FloatRegister d
 // ldrd/strd (dual-register load/store) operate in a single cycle
 // when the address they are dealing with is 8 byte aligned.
 // Also, the ARM abi wants the stack to be 8 byte aligned at
 // function boundaries.  I'm trying to make sure this is always true.
 static const uint32_t StackAlignment = 8;
 static const uint32_t CodeAlignment = 8;
 static const bool StackKeptAligned = true;
 
-// As an invariant across architectures, within asm.js code:
-//    $sp % StackAlignment = (AsmJSFrameSize + masm.framePushed) % StackAlignment
-// To achieve this on ARM, the first instruction of the asm.js prologue pushes
-// lr without incrementing masm.framePushed.
-static const uint32_t AsmJSFrameSize = sizeof(void*);
-
 static const Scale ScalePointer = TimesFour;
 
 class Instruction;
 class InstBranchImm;
 uint32_t RM(Register r);
 uint32_t RS(Register r);
 uint32_t RD(Register r);
 uint32_t RT(Register r);
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -48,17 +48,17 @@ CodeGeneratorARM::generatePrologue()
     return true;
 }
 
 bool
 CodeGeneratorARM::generateAsmJSPrologue(Label *stackOverflowLabel)
 {
     JS_ASSERT(gen->compilingAsmJS());
 
-    // See comment in Assembler-arm.h about AsmJSFrameSize.
+    // See comment in Assembler-shared.h about AsmJSFrameSize.
     masm.push(lr);
 
     // The asm.js over-recursed handler wants to be able to assume that SP
     // points to the return address, so perform the check after pushing lr but
     // before pushing frameDepth.
     if (!omitOverRecursedCheck()) {
         masm.branchPtr(Assembler::AboveOrEqual,
                        AsmJSAbsoluteAddress(AsmJSImm_StackLimit),
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -1785,16 +1785,27 @@ MacroAssemblerARMCompat::callIon(Registe
         ma_callIonHalfPush(callee);
     } else {
         adjustFrame(sizeof(void*));
         ma_callIon(callee);
     }
 }
 
 void
+MacroAssemblerARMCompat::callIonFromAsmJS(Register callee)
+{
+    ma_callIonNoPush(callee);
+
+    // The Ion ABI has the callee pop the return address off the stack.
+    // The asm.js caller assumes that the call leaves sp unchanged, so bump
+    // the stack.
+    subPtr(Imm32(sizeof(void*)), sp);
+}
+
+void
 MacroAssemblerARMCompat::reserveStack(uint32_t amount)
 {
     if (amount)
         ma_sub(Imm32(amount), sp);
     adjustFrame(amount);
 }
 void
 MacroAssemblerARMCompat::freeStack(uint32_t amount)
@@ -3620,29 +3631,16 @@ MacroAssemblerARM::ma_call(ImmPtr dest)
     else
         rs = L_LDR;
 
     ma_movPatchable(dest, CallReg, Always, rs);
     as_blx(CallReg);
 }
 
 void
-MacroAssemblerARM::ma_callAndStoreRet(const Register r, uint32_t stackArgBytes)
-{
-    // Note: this function stores the return address to sp[0]. The caller must
-    // anticipate this by pushing additional space on the stack. The ABI does
-    // not provide space for a return address so this function may only be
-    // called if no argument are passed.
-    JS_ASSERT(stackArgBytes == 0);
-    AutoForbidPools afp(this);
-    as_dtr(IsStore, 32, Offset, pc, DTRAddr(sp, DtrOffImm(0)));
-    as_blx(r);
-}
-
-void
 MacroAssemblerARMCompat::breakpoint()
 {
     as_bkpt();
 }
 
 void
 MacroAssemblerARMCompat::ensureDouble(const ValueOperand &source, FloatRegister dest, Label *failure)
 {
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -392,19 +392,16 @@ class MacroAssemblerARM : public Assembl
     void ma_callIon(const Register reg);
     // callso an Ion function, assuming that sp has already been decremented
     void ma_callIonNoPush(const Register reg);
     // calls an ion function, assuming that the stack is currently not 8 byte aligned
     void ma_callIonHalfPush(const Register reg);
 
     void ma_call(ImmPtr dest);
 
-    // calls reg, storing the return address into sp[0]
-    void ma_callAndStoreRet(const Register reg, uint32_t stackArgBytes);
-
     // Float registers can only be loaded/stored in continuous runs
     // when using vstm/vldm.
     // This function breaks set into continuous runs and loads/stores
     // them at [rm]. rm will be modified and left in a state logically
     // suitable for the next load/store.
     // Returns the offset from [dm] for the logical next load/store.
     int32_t transferMultipleByRuns(FloatRegisterSet set, LoadStore ls,
                                    Register rm, DTMMode mode)
@@ -561,48 +558,23 @@ class MacroAssemblerARMCompat : public M
         if (HasMOVWT())
             rs = L_MOVWT;
         else
             rs = L_LDR;
 
         ma_movPatchable(ImmPtr(c->raw()), ScratchRegister, Always, rs);
         ma_callIonHalfPush(ScratchRegister);
     }
-
-    void appendCallSite(const CallSiteDesc &desc) {
-        // Add an extra sizeof(void*) to include the return address that was
-        // pushed by the call instruction (see CallSite::stackDepth).
-        enoughMemory_ &= append(CallSite(desc, currentOffset(), framePushed_ + AsmJSFrameSize));
-    }
-
     void call(const CallSiteDesc &desc, const Register reg) {
         call(reg);
-        appendCallSite(desc);
+        enoughMemory_ &= append(desc, currentOffset(), framePushed_);
     }
     void call(const CallSiteDesc &desc, Label *label) {
         call(label);
-        appendCallSite(desc);
-    }
-    void call(const CallSiteDesc &desc, AsmJSImmPtr imm) {
-        call(imm);
-        appendCallSite(desc);
-    }
-    void callExit(AsmJSImmPtr imm, uint32_t stackArgBytes) {
-        movePtr(imm, CallReg);
-        ma_callAndStoreRet(CallReg, stackArgBytes);
-        appendCallSite(CallSiteDesc::Exit());
-    }
-    void callIonFromAsmJS(const Register reg) {
-        ma_callIonNoPush(reg);
-        appendCallSite(CallSiteDesc::Exit());
-
-        // The Ion ABI has the callee pop the return address off the stack.
-        // The asm.js caller assumes that the call leaves sp unchanged, so bump
-        // the stack.
-        subPtr(Imm32(sizeof(void*)), sp);
+        enoughMemory_ &= append(desc, currentOffset(), framePushed_);
     }
 
     void branch(JitCode *c) {
         BufferOffset bo = m_buffer.nextOffset();
         addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
         RelocStyle rs;
         if (HasMOVWT())
             rs = L_MOVWT;
@@ -1282,16 +1254,17 @@ class MacroAssemblerARMCompat : public M
     bool buildFakeExitFrame(Register scratch, uint32_t *offset);
 
     void callWithExitFrame(JitCode *target);
     void callWithExitFrame(JitCode *target, Register dynStack);
 
     // Makes an Ion call using the only two methods that it is sane for
     // indep code to make a call
     void callIon(Register callee);
+    void callIonFromAsmJS(Register callee);
 
     void reserveStack(uint32_t amount);
     void freeStack(uint32_t amount);
     void freeStack(Register amount);
 
     void add32(Register src, Register dest);
     void add32(Imm32 imm, Register dest);
     void add32(Imm32 imm, const Address &dest);
--- a/js/src/jit/arm/Simulator-arm.cpp
+++ b/js/src/jit/arm/Simulator-arm.cpp
@@ -4065,17 +4065,17 @@ Simulator::execute()
         } else {
             SimInstruction *instr = reinterpret_cast<SimInstruction *>(program_counter);
             instructionDecode(instr);
             icount_++;
 
             int32_t rpc = resume_pc_;
             if (MOZ_UNLIKELY(rpc != 0)) {
                 // AsmJS signal handler ran and we have to adjust the pc.
-                activation->setInterrupted((void *)get_pc());
+                activation->setResumePC((void *)get_pc());
                 set_pc(rpc);
                 resume_pc_ = 0;
             }
         }
         program_counter = get_pc();
     }
 }
 
--- a/js/src/jit/mips/Assembler-mips.h
+++ b/js/src/jit/mips/Assembler-mips.h
@@ -147,22 +147,16 @@ static MOZ_CONSTEXPR_VAR FloatRegister f
 static MOZ_CONSTEXPR_VAR FloatRegister f30 = {FloatRegisters::f30};
 
 // MIPS CPUs can only load multibyte data that is "naturally"
 // four-byte-aligned, sp register should be eight-byte-aligned.
 static const uint32_t StackAlignment = 8;
 static const uint32_t CodeAlignment = 4;
 static const bool StackKeptAligned = true;
 
-// As an invariant across architectures, within asm.js code:
-//    $sp % StackAlignment = (AsmJSFrameSize + masm.framePushed) % StackAlignment
-// To achieve this on MIPS, the first instruction of the asm.js prologue pushes
-// ra without incrementing masm.framePushed.
-static const uint32_t AsmJSFrameSize = sizeof(void*);
-
 static const Scale ScalePointer = TimesFour;
 
 // MIPS instruction types
 //                +---------------------------------------------------------------+
 //                |    6      |    5    |    5    |    5    |    5    |    6      |
 //                +---------------------------------------------------------------+
 // Register type  |  Opcode   |    Rs   |    Rt   |    Rd   |    Sa   | Function  |
 //                +---------------------------------------------------------------+
--- a/js/src/jit/mips/CodeGenerator-mips.cpp
+++ b/js/src/jit/mips/CodeGenerator-mips.cpp
@@ -47,17 +47,17 @@ CodeGeneratorMIPS::generatePrologue()
     return true;
 }
 
 bool
 CodeGeneratorMIPS::generateAsmJSPrologue(Label *stackOverflowLabel)
 {
     JS_ASSERT(gen->compilingAsmJS());
 
-    // See comment in Assembler-mips.h about AsmJSFrameSize.
+    // See comment in Assembler-shared.h about AsmJSFrameSize.
     masm.push(ra);
 
     // The asm.js over-recursed handler wants to be able to assume that SP
     // points to the return address, so perform the check after pushing ra but
     // before pushing frameDepth.
     if (!omitOverRecursedCheck()) {
         masm.branchPtr(Assembler::AboveOrEqual,
                        AsmJSAbsoluteAddress(AsmJSImm_StackLimit),
--- a/js/src/jit/mips/MacroAssembler-mips.cpp
+++ b/js/src/jit/mips/MacroAssembler-mips.cpp
@@ -1520,16 +1520,26 @@ MacroAssemblerMIPSCompat::callIon(Regist
     MOZ_ASSERT((framePushed() & 3) == 0);
     if ((framePushed() & 7) == 4) {
         ma_callIonHalfPush(callee);
     } else {
         adjustFrame(sizeof(uint32_t));
         ma_callIon(callee);
     }
 }
+void
+MacroAssemblerMIPSCompat::callIonFromAsmJS(Register callee)
+{
+    ma_callIonNoPush(reg);
+
+    // The Ion ABI has the callee pop the return address off the stack.
+    // The asm.js caller assumes that the call leaves sp unchanged, so bump
+    // the stack.
+    subPtr(Imm32(sizeof(void*)), StackPointer);
+}
 
 void
 MacroAssemblerMIPSCompat::reserveStack(uint32_t amount)
 {
     if (amount)
         ma_subu(StackPointer, StackPointer, Imm32(amount));
     adjustFrame(amount);
 }
@@ -2956,31 +2966,16 @@ MacroAssemblerMIPS::ma_callIonHalfPush(c
 {
     // This is a MIPS hack to push return address during jalr delay slot.
     as_addiu(StackPointer, StackPointer, -sizeof(intptr_t));
     as_jalr(r);
     as_sw(ra, StackPointer, 0);
 }
 
 void
-MacroAssemblerMIPS::ma_callAndStoreRet(const Register r, uint32_t stackArgBytes)
-{
-    // Note: this function stores the return address to sp[16]. The caller
-    // must anticipate this by reserving additional space on the stack.
-    // The ABI does not provide space for a return address so this function
-    // stores 'ra' before any ABI arguments.
-    // This function may only be called if there are 4 or less arguments.
-    JS_ASSERT(stackArgBytes == 4 * sizeof(uintptr_t));
-
-    // This is a MIPS hack to push return address during jalr delay slot.
-    as_jalr(r);
-    as_sw(ra, StackPointer, 4 * sizeof(uintptr_t));
-}
-
-void
 MacroAssemblerMIPS::ma_call(ImmPtr dest)
 {
     ma_liPatchable(CallReg, dest);
     as_jalr(CallReg);
     as_nop();
 }
 
 void
--- a/js/src/jit/mips/MacroAssembler-mips.h
+++ b/js/src/jit/mips/MacroAssembler-mips.h
@@ -296,19 +296,16 @@ class MacroAssemblerMIPS : public Assemb
   public:
     // calls an Ion function, assumes that the stack is untouched (8 byte alinged)
     void ma_callIon(const Register reg);
     // callso an Ion function, assuming that sp has already been decremented
     void ma_callIonNoPush(const Register reg);
     // calls an ion function, assuming that the stack is currently not 8 byte aligned
     void ma_callIonHalfPush(const Register reg);
 
-    // calls reg, storing the return address into sp[stackArgBytes]
-    void ma_callAndStoreRet(const Register reg, uint32_t stackArgBytes);
-
     void ma_call(ImmPtr dest);
 
     void ma_jump(ImmPtr dest);
 
     void ma_cmp_set(Register dst, Register lhs, Register rhs, Condition c);
     void ma_cmp_set(Register dst, Register lhs, Imm32 imm, Condition c);
     void ma_cmp_set(Register dst, Register lhs, ImmPtr imm, Condition c) {
         ma_cmp_set(dst, lhs, Imm32(uint32_t(imm.value)), c);
@@ -410,48 +407,23 @@ class MacroAssemblerMIPSCompat : public 
         call(CallReg);
     }
     void call(JitCode *c) {
         BufferOffset bo = m_buffer.nextOffset();
         addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
         ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw()));
         ma_callIonHalfPush(ScratchRegister);
     }
-
-    void appendCallSite(const CallSiteDesc &desc) {
-        // Add an extra sizeof(void*) to include the return address that was
-        // pushed by the call instruction (see CallSite::stackDepth).
-        enoughMemory_ &= append(CallSite(desc, currentOffset(), framePushed_ + AsmJSFrameSize));
-    }
-
     void call(const CallSiteDesc &desc, const Register reg) {
         call(reg);
-        appendCallSite(desc);
+        enoughMemory_ &= append(desc, currentOffset(), framePushed_);
     }
     void call(const CallSiteDesc &desc, Label *label) {
         call(label);
-        appendCallSite(desc);
-    }
-    void call(const CallSiteDesc &desc, AsmJSImmPtr imm) {
-        call(imm);
-        appendCallSite(desc);
-    }
-    void callExit(AsmJSImmPtr imm, uint32_t stackArgBytes) {
-        movePtr(imm, CallReg);
-        ma_callAndStoreRet(CallReg, stackArgBytes);
-        appendCallSite(CallSiteDesc::Exit());
-    }
-    void callIonFromAsmJS(const Register reg) {
-        ma_callIonNoPush(reg);
-        appendCallSite(CallSiteDesc::Exit());
-
-        // The Ion ABI has the callee pop the return address off the stack.
-        // The asm.js caller assumes that the call leaves sp unchanged, so bump
-        // the stack.
-        subPtr(Imm32(sizeof(void*)), StackPointer);
+        enoughMemory_ &= append(desc, currentOffset(), framePushed_);
     }
 
     void branch(JitCode *c) {
         BufferOffset bo = m_buffer.nextOffset();
         addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
         ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw()));
         as_jr(ScratchRegister);
         as_nop();
@@ -988,16 +960,17 @@ public:
     bool buildFakeExitFrame(Register scratch, uint32_t *offset);
 
     void callWithExitFrame(JitCode *target);
     void callWithExitFrame(JitCode *target, Register dynStack);
 
     // Makes an Ion call using the only two methods that it is sane for
     // indep code to make a call
     void callIon(Register callee);
+    void callIonFromAsmJS(Register callee);
 
     void reserveStack(uint32_t amount);
     void freeStack(uint32_t amount);
     void freeStack(Register amount);
 
     void add32(Register src, Register dest);
     void add32(Imm32 imm, Register dest);
     void add32(Imm32 imm, const Address &dest);
--- a/js/src/jit/shared/Assembler-shared.h
+++ b/js/src/jit/shared/Assembler-shared.h
@@ -572,58 +572,29 @@ class CodeLocationLabel
         return raw_;
     }
     uint8_t *offset() const {
         JS_ASSERT(state_ == Relative);
         return raw_;
     }
 };
 
-// Describes the user-visible properties of a callsite.
-//
-// A few general notes about the stack-walking supported by CallSite(Desc):
-//  - This information facilitates stack-walking performed by FrameIter which
-//    is used by Error.stack and other user-visible stack-walking functions.
-//  - Ion/asm.js calling conventions do not maintain a frame-pointer so
-//    stack-walking must lookup the stack depth based on the PC.
-//  - Stack-walking only occurs from C++ after a synchronous calls (JS-to-JS and
-//    JS-to-C++). Thus, we do not need to map arbitrary PCs to stack-depths,
-//    just the return address at callsites.
-//  - An exception to the above rule is the interrupt callback which can happen
-//    at arbitrary PCs. In such cases, we drop frames from the stack-walk. In
-//    the future when a full PC->stack-depth map is maintained, we handle this
-//    case.
+// While the frame-pointer chain allows the stack to be unwound without
+// metadata, Error.stack still needs to know the line/column of every call in
+// the chain. A CallSiteDesc describes the line/column of a single callsite.
+// A CallSiteDesc is created by callers of MacroAssembler.
 class CallSiteDesc
 {
     uint32_t line_;
     uint32_t column_;
-    uint32_t functionNameIndex_;
-
-    static const uint32_t sEntryTrampoline = UINT32_MAX;
-    static const uint32_t sExit = UINT32_MAX - 1;
-
   public:
-    static const uint32_t FUNCTION_NAME_INDEX_MAX = UINT32_MAX - 2;
-
     CallSiteDesc() {}
-
-    CallSiteDesc(uint32_t line, uint32_t column, uint32_t functionNameIndex)
-     : line_(line), column_(column), functionNameIndex_(functionNameIndex)
-    {}
-
-    static CallSiteDesc Entry() { return CallSiteDesc(0, 0, sEntryTrampoline); }
-    static CallSiteDesc Exit() { return CallSiteDesc(0, 0, sExit); }
-
-    bool isEntry() const { return functionNameIndex_ == sEntryTrampoline; }
-    bool isExit() const { return functionNameIndex_ == sExit; }
-    bool isNormal() const { return !(isEntry() || isExit()); }
-
-    uint32_t line() const { JS_ASSERT(isNormal()); return line_; }
-    uint32_t column() const { JS_ASSERT(isNormal()); return column_; }
-    uint32_t functionNameIndex() const { JS_ASSERT(isNormal()); return functionNameIndex_; }
+    CallSiteDesc(uint32_t line, uint32_t column) : line_(line), column_(column) {}
+    uint32_t line() const { return line_; }
+    uint32_t column() const { return column_; }
 };
 
 // Adds to CallSiteDesc the metadata necessary to walk the stack given an
 // initial stack-pointer.
 struct CallSite : public CallSiteDesc
 {
     uint32_t returnAddressOffset_;
     uint32_t stackDepth_;
@@ -636,23 +607,31 @@ struct CallSite : public CallSiteDesc
         returnAddressOffset_(returnAddressOffset),
         stackDepth_(stackDepth)
     { }
 
     void setReturnAddressOffset(uint32_t r) { returnAddressOffset_ = r; }
     uint32_t returnAddressOffset() const { return returnAddressOffset_; }
 
     // The stackDepth measures the amount of stack space pushed since the
-    // function was called. In particular, this includes the word pushed by the
-    // call instruction on x86/x64.
-    uint32_t stackDepth() const { JS_ASSERT(!isEntry()); return stackDepth_; }
+    // function was called. In particular, this includes the pushed return
+    // address on all archs (whether or not the call instruction pushes the
+    // return address (x86/x64) or the prologue does (ARM/MIPS).
+    uint32_t stackDepth() const { return stackDepth_; }
 };
 
 typedef Vector<CallSite, 0, SystemAllocPolicy> CallSiteVector;
 
+// As an invariant across architectures, within asm.js code:
+//    $sp % StackAlignment = (AsmJSFrameSize + masm.framePushed) % StackAlignment
+// AsmJSFrameSize is 1 word, for the return address pushed by the call (or, in
+// the case of ARM/MIPS, by the first instruction of the prologue). This means
+// masm.framePushed never includes the pushed return address.
+static const uint32_t AsmJSFrameSize = sizeof(void*);
+
 // 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_;
@@ -816,17 +795,21 @@ class AssemblerShared
     void propagateOOM(bool success) {
         enoughMemory_ &= success;
     }
 
     bool oom() const {
         return !enoughMemory_;
     }
 
-    bool append(CallSite callsite) { return callsites_.append(callsite); }
+    bool append(const CallSiteDesc &desc, size_t currentOffset, size_t framePushed) {
+        // framePushed does not include AsmJSFrameSize, so add it in here (see
+        // CallSite::stackDepth).
+        return callsites_.append(CallSite(desc, currentOffset, framePushed + AsmJSFrameSize));
+    }
     CallSiteVector &&extractCallSites() { return Move(callsites_); }
 
     bool append(AsmJSHeapAccess access) { return asmJSHeapAccesses_.append(access); }
     AsmJSHeapAccessVector &&extractAsmJSHeapAccesses() { return Move(asmJSHeapAccesses_); }
 
     bool append(AsmJSGlobalAccess access) { return asmJSGlobalAccesses_.append(access); }
     size_t numAsmJSGlobalAccesses() const { return asmJSGlobalAccesses_.length(); }
     AsmJSGlobalAccess asmJSGlobalAccess(size_t i) const { return asmJSGlobalAccesses_[i]; }
--- a/js/src/jit/shared/MacroAssembler-x86-shared.h
+++ b/js/src/jit/shared/MacroAssembler-x86-shared.h
@@ -662,36 +662,33 @@ class MacroAssemblerX86Shared : public A
         lea(Operand(address), dest);
     }
 
     // Builds an exit frame on the stack, with a return address to an internal
     // non-function. Returns offset to be passed to markSafepointAt().
     bool buildFakeExitFrame(Register scratch, uint32_t *offset);
     void callWithExitFrame(JitCode *target);
 
+    void call(const CallSiteDesc &desc, Label *label) {
+        call(label);
+        enoughMemory_ &= append(desc, currentOffset(), framePushed_);
+    }
+    void call(const CallSiteDesc &desc, Register reg) {
+        call(reg);
+        enoughMemory_ &= append(desc, currentOffset(), framePushed_);
+    }
     void callIon(Register callee) {
         call(callee);
     }
-
-    void appendCallSite(const CallSiteDesc &desc) {
-        // Add an extra sizeof(void*) to include the return address that was
-        // pushed by the call instruction (see CallSite::stackDepth).
-        enoughMemory_ &= append(CallSite(desc, currentOffset(), framePushed_ + AsmJSFrameSize));
+    void callIonFromAsmJS(Register callee) {
+        call(callee);
     }
-
-    void call(const CallSiteDesc &desc, Label *label) {
-        call(label);
-        appendCallSite(desc);
-    }
-    void call(const CallSiteDesc &desc, Register reg) {
-        call(reg);
-        appendCallSite(desc);
-    }
-    void callIonFromAsmJS(Register reg) {
-        call(CallSiteDesc::Exit(), reg);
+    void call(AsmJSImmPtr target) {
+        mov(target, eax);
+        call(eax);
     }
 
     void checkStackAlignment() {
         // Exists for ARM compatibility.
     }
 
     CodeOffsetLabel labelForPatch() {
         return CodeOffsetLabel(size());
--- a/js/src/jit/x64/Architecture-x64.h
+++ b/js/src/jit/x64/Architecture-x64.h
@@ -236,21 +236,26 @@ struct FloatRegister {
     static uint32_t GetSizeInBytes(const TypedRegisterSet<FloatRegister> &s);
     static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister> &s);
     uint32_t getRegisterDumpOffsetInBytes();
 
 };
 
 // Arm/D32 has double registers that can NOT be treated as float32
 // and this requires some dances in lowering.
-inline bool hasUnaliasedDouble() {
+inline bool
+hasUnaliasedDouble()
+{
     return false;
 }
+
 // On ARM, Dn aliases both S2n and S2n+1, so if you need to convert a float32
 // to a double as a temporary, you need a temporary double register.
-inline bool hasMultiAlias() {
+inline bool
+hasMultiAlias()
+{
     return false;
 }
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_x64_Architecture_x64_h */
--- a/js/src/jit/x64/Assembler-x64.h
+++ b/js/src/jit/x64/Assembler-x64.h
@@ -180,23 +180,16 @@ static MOZ_CONSTEXPR_VAR Register OsrFra
 static MOZ_CONSTEXPR_VAR Register PreBarrierReg = rdx;
 
 // GCC stack is aligned on 16 bytes, but we don't maintain the invariant in
 // jitted code.
 static const uint32_t StackAlignment = 16;
 static const bool StackKeptAligned = false;
 static const uint32_t CodeAlignment = 8;
 
-// As an invariant across architectures, within asm.js code:
-//   $sp % StackAlignment = (AsmJSFrameSize + masm.framePushed) % StackAlignment
-// On x64, this naturally falls out of the fact that the 'call' instruction
-// pushes the return address on the stack and masm.framePushed = 0 at the first
-// instruction of the prologue.
-static const uint32_t AsmJSFrameSize = sizeof(void*);
-
 static const Scale ScalePointer = TimesEight;
 
 } // namespace jit
 } // namespace js
 
 #include "jit/shared/Assembler-x86-shared.h"
 
 namespace js {
--- a/js/src/jit/x64/MacroAssembler-x64.h
+++ b/js/src/jit/x64/MacroAssembler-x64.h
@@ -95,28 +95,16 @@ class MacroAssemblerX64 : public MacroAs
     /////////////////////////////////////////////////////////////////
     void call(ImmWord target) {
         mov(target, rax);
         call(rax);
     }
     void call(ImmPtr target) {
         call(ImmWord(uintptr_t(target.value)));
     }
-    void call(AsmJSImmPtr target) {
-        mov(target, rax);
-        call(rax);
-    }
-
-    void call(const CallSiteDesc &desc, AsmJSImmPtr target) {
-        call(target);
-        appendCallSite(desc);
-    }
-    void callExit(AsmJSImmPtr target, uint32_t stackArgBytes) {
-        call(CallSiteDesc::Exit(), target);
-    }
 
     // Refers to the upper 32 bits of a 64-bit Value operand.
     // On x86_64, the upper 32 bits do not necessarily only contain the type.
     Operand ToUpper32(Operand base) {
         switch (base.kind()) {
           case Operand::MEM_REG_DISP:
             return Operand(Register::FromCode(base.base()), base.disp() + 4);
 
--- a/js/src/jit/x86/Architecture-x86.h
+++ b/js/src/jit/x86/Architecture-x86.h
@@ -213,22 +213,26 @@ struct FloatRegister {
     static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister> &s);
     uint32_t getRegisterDumpOffsetInBytes();
 
 
 };
 
 // Arm/D32 has double registers that can NOT be treated as float32
 // and this requires some dances in lowering.
-inline bool hasUnaliasedDouble() {
+inline bool
+hasUnaliasedDouble()
+{
     return false;
 }
 
 // On ARM, Dn aliases both S2n and S2n+1, so if you need to convert a float32
 // to a double as a temporary, you need a temporary double register.
-inline bool hasMultiAlias() {
+inline bool
+hasMultiAlias()
+{
     return false;
 }
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_x86_Architecture_x86_h */
--- a/js/src/jit/x86/Assembler-x86.h
+++ b/js/src/jit/x86/Assembler-x86.h
@@ -108,23 +108,16 @@ static MOZ_CONSTEXPR_VAR Register AsmJSI
 #if defined(__GNUC__)
 static const uint32_t StackAlignment = 16;
 #else
 static const uint32_t StackAlignment = 4;
 #endif
 static const bool StackKeptAligned = false;
 static const uint32_t CodeAlignment = 8;
 
-// As an invariant across architectures, within asm.js code:
-//   $sp % StackAlignment = (AsmJSFrameSize + masm.framePushed) % StackAlignment
-// On x86, this naturally falls out of the fact that the 'call' instruction
-// pushes the return address on the stack and masm.framePushed = 0 at the first
-// instruction of the prologue.
-static const uint32_t AsmJSFrameSize = sizeof(void*);
-
 struct ImmTag : public Imm32
 {
     ImmTag(JSValueTag mask)
       : Imm32(int32_t(mask))
     { }
 };
 
 struct ImmType : public ImmTag
@@ -377,23 +370,16 @@ class Assembler : public AssemblerX86Sha
     }
     void call(ImmWord target) {
         call(ImmPtr((void*)target.value));
     }
     void call(ImmPtr target) {
         JmpSrc src = masm.call();
         addPendingJump(src, target, Relocation::HARDCODED);
     }
-    void call(AsmJSImmPtr target) {
-        // Moving to a register is suboptimal. To fix (use a single
-        // call-immediate instruction) we'll need to distinguish a new type of
-        // relative patch to an absolute address in AsmJSAbsoluteLink.
-        mov(target, eax);
-        call(eax);
-    }
 
     // Emit a CALL or CMP (nop) instruction. ToggleCall can be used to patch
     // this instruction.
     CodeOffsetLabel toggledCall(JitCode *target, bool enabled) {
         CodeOffsetLabel offset(size());
         JmpSrc src = enabled ? masm.call() : masm.cmp_eax();
         addPendingJump(src, ImmPtr(target->raw()), Relocation::JITCODE);
         JS_ASSERT(size() - offset.offset() == ToggledCallSize());
--- a/js/src/jit/x86/MacroAssembler-x86.h
+++ b/js/src/jit/x86/MacroAssembler-x86.h
@@ -1109,23 +1109,16 @@ class MacroAssemblerX86 : public MacroAs
     }
 
     void callWithExitFrame(JitCode *target, Register dynStack) {
         addPtr(Imm32(framePushed()), dynStack);
         makeFrameDescriptor(dynStack, JitFrame_IonJS);
         Push(dynStack);
         call(target);
     }
-    void call(const CallSiteDesc &desc, AsmJSImmPtr target) {
-        call(target);
-        appendCallSite(desc);
-    }
-    void callExit(AsmJSImmPtr target, uint32_t stackArgBytes) {
-        call(CallSiteDesc::Exit(), target);
-    }
 
 #ifdef JSGC_GENERATIONAL
     void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label *label);
     void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label *label);
 #endif
 };
 
 typedef MacroAssemblerX86 MacroAssemblerSpecific;
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -237,21 +237,21 @@ MSG_DEF(JSMSG_SC_NOT_TRANSFERABLE,    18
 MSG_DEF(JSMSG_SC_DUP_TRANSFERABLE,    184, 0, JSEXN_TYPEERR, "duplicate transferable for structured clone")
 MSG_DEF(JSMSG_CANT_REPORT_AS_NON_EXTENSIBLE, 185, 0, JSEXN_TYPEERR, "proxy can't report an extensible object as non-extensible")
 MSG_DEF(JSMSG_SYMBOL_TO_STRING,       186, 0, JSEXN_TYPEERR, "can't convert symbol to string")
 MSG_DEF(JSMSG_UNUSED187,              187, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_INCOMPATIBLE_METHOD,    188, 3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}")
 MSG_DEF(JSMSG_SYMBOL_TO_PRIMITIVE,    189, 0, JSEXN_TYPEERR, "can't convert symbol object to primitive")
 MSG_DEF(JSMSG_UNUSED190,              190, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_BAD_INDEX,              191, 0, JSEXN_RANGEERR, "invalid or out-of-range index")
-MSG_DEF(JSMSG_UNUSED192,              192, 0, JSEXN_NONE, "")
+MSG_DEF(JSMSG_SELFHOSTED_TOP_LEVEL_LET,192,0, JSEXN_SYNTAXERR, "self-hosted code cannot contain top-level 'let' declarations")
 MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP,      193, 0, JSEXN_SYNTAXERR, "invalid for each loop")
 MSG_DEF(JSMSG_OBJECT_WATCH_DEPRECATED,194, 0, JSEXN_NONE, "Object.prototype.watch and unwatch are very slow, non-standard, and deprecated; use a getter/setter instead")
 MSG_DEF(JSMSG_TYPE_ERR_BAD_ARGS,      195, 0, JSEXN_TYPEERR, "invalid arguments")
-MSG_DEF(JSMSG_UNUSED196,              196, 0, JSEXN_NONE, "")
+MSG_DEF(JSMSG_REDECLARED_CATCH_IDENTIFIER, 196, 1, JSEXN_TYPEERR, "redeclaration of identifier '{0}' in catch")
 MSG_DEF(JSMSG_INTERNAL_INTL_ERROR,    197, 0, JSEXN_ERR, "internal error while computing Intl data")
 MSG_DEF(JSMSG_DEFAULT_LOCALE_ERROR,   198, 0, JSEXN_ERR, "internal error getting the default locale")
 MSG_DEF(JSMSG_TOO_MANY_LOCALS,        199, 0, JSEXN_SYNTAXERR, "too many local variables")
 MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG,     200, 0, JSEXN_INTERNALERR, "array initialiser too large")
 MSG_DEF(JSMSG_REGEXP_TOO_COMPLEX,     201, 0, JSEXN_INTERNALERR, "regular expression too complex")
 MSG_DEF(JSMSG_BUFFER_TOO_SMALL,       202, 0, JSEXN_INTERNALERR, "buffer too small")
 MSG_DEF(JSMSG_BAD_SURROGATE_CHAR,     203, 1, JSEXN_TYPEERR, "bad surrogate character {0}")
 MSG_DEF(JSMSG_UTF8_CHAR_TOO_LARGE,    204, 1, JSEXN_TYPEERR, "UTF-8 character {0} too large")
--- a/js/src/jsapi-tests/testArrayBuffer.cpp
+++ b/js/src/jsapi-tests/testArrayBuffer.cpp
@@ -51,26 +51,26 @@ BEGIN_TEST(testArrayBuffer_bug720949_ste
         CHECK_SAME(v, INT_TO_JSVAL(MAGIC_VALUE_2));
 
         // Steal the contents
         void *contents = JS_StealArrayBufferContents(cx, obj);
         CHECK(contents != nullptr);
         CHECK(data != nullptr);
 
         // Check that the original ArrayBuffer is neutered
-        CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), 0);
+        CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), 0u);
         CHECK(JS_GetProperty(cx, obj, "byteLength", &v));
         CHECK_SAME(v, INT_TO_JSVAL(0));
         CHECK(JS_GetProperty(cx, view, "byteLength", &v));
         CHECK_SAME(v, INT_TO_JSVAL(0));
         CHECK(JS_GetProperty(cx, view, "byteOffset", &v));
         CHECK_SAME(v, INT_TO_JSVAL(0));
         CHECK(JS_GetProperty(cx, view, "length", &v));
         CHECK_SAME(v, INT_TO_JSVAL(0));
-        CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), 0);
+        CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), 0u);
         v = JSVAL_VOID;
         JS_GetElement(cx, obj, 0, &v);
         CHECK_SAME(v, JSVAL_VOID);
 
         // Transfer to a new ArrayBuffer
         JS::RootedObject dst(cx, JS_NewArrayBufferWithContents(cx, size, contents));
         CHECK(JS_IsArrayBufferObject(dst));
         data = JS_GetStableArrayBufferData(cx, obj);
--- a/js/src/jsapi-tests/testGCOutOfMemory.cpp
+++ b/js/src/jsapi-tests/testGCOutOfMemory.cpp
@@ -29,30 +29,30 @@ BEGIN_TEST(testGCOutOfMemory)
         "        array.push({});"
         "    array = []; array.push(0);"
         "})();";
     bool ok = JS_EvaluateScript(cx, global, source, strlen(source), "", 1, &root);
 
     /* Check that we get OOM. */
     CHECK(!ok);
     CHECK(!JS_IsExceptionPending(cx));
-    CHECK_EQUAL(errorCount, 1);
+    CHECK_EQUAL(errorCount, 1u);
     JS_GC(rt);
 
     // Temporarily disabled to reopen the tree. Bug 847579.
     return true;
 
     EVAL("(function() {"
          "    var array = [];"
          "    for (var i = max >> 2; i != 0;) {"
          "        --i;"
          "        array.push({});"
          "    }"
          "})();", &root);
-    CHECK_EQUAL(errorCount, 1);
+    CHECK_EQUAL(errorCount, 1u);
     return true;
 }
 
 virtual JSRuntime * createRuntime() {
     JSRuntime *rt = JS_NewRuntime(768 * 1024);
     if (!rt)
         return nullptr;
     setNativeStackQuota(rt);
--- a/js/src/jsapi-tests/testMappedArrayBuffer.cpp
+++ b/js/src/jsapi-tests/testMappedArrayBuffer.cpp
@@ -67,33 +67,33 @@ JSObject *CreateNewObject(const int offs
     JSObject *obj = JS_NewMappedArrayBufferWithContents(cx, length, ptr);
     if (!obj) {
         JS_ReleaseMappedArrayBufferContents(ptr, length);
         return nullptr;
     }
     return obj;
 }
 
-bool VerifyObject(JS::HandleObject obj, const int offset, const int length, const bool mapped)
+bool VerifyObject(JS::HandleObject obj, uint32_t offset, uint32_t length, const bool mapped)
 {
     CHECK(obj);
     CHECK(JS_IsArrayBufferObject(obj));
     CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), length);
     if (mapped)
         CHECK(JS_IsMappedArrayBufferObject(obj));
     else
         CHECK(!JS_IsMappedArrayBufferObject(obj));
     const char *data = reinterpret_cast<const char *>(JS_GetArrayBufferData(obj));
     CHECK(data);
     CHECK(memcmp(data, test_data + offset, length) == 0);
 
     return true;
 }
 
-bool TestCreateObject(const int offset, const int length)
+bool TestCreateObject(uint32_t offset, uint32_t length)
 {
     JS::RootedObject obj(cx, CreateNewObject(offset, length));
     CHECK(VerifyObject(obj, offset, length, true));
 
     return true;
 }
 
 bool TestReleaseContents()
--- a/js/src/jsapi-tests/testNewObject.cpp
+++ b/js/src/jsapi-tests/testNewObject.cpp
@@ -64,26 +64,26 @@ BEGIN_TEST(testNewObject_1)
 
     // With no arguments.
     JS::RootedObject obj(cx, JS_New(cx, Array, JS::HandleValueArray::empty()));
     CHECK(obj);
     JS::RootedValue rt(cx, JS::ObjectValue(*obj));
     CHECK(JS_IsArrayObject(cx, obj));
     uint32_t len;
     CHECK(JS_GetArrayLength(cx, obj, &len));
-    CHECK_EQUAL(len, 0);
+    CHECK_EQUAL(len, 0u);
 
     // With one argument.
     argv[0].setInt32(4);
     obj = JS_New(cx, Array, JS::HandleValueArray::subarray(argv, 0, 1));
     CHECK(obj);
     rt = OBJECT_TO_JSVAL(obj);
     CHECK(JS_IsArrayObject(cx, obj));
     CHECK(JS_GetArrayLength(cx, obj, &len));
-    CHECK_EQUAL(len, 4);
+    CHECK_EQUAL(len, 4u);
 
     // With N arguments.
     for (size_t i = 0; i < N; i++)
         argv[i].setInt32(i);
     obj = JS_New(cx, Array, JS::HandleValueArray::subarray(argv, 0, N));
     CHECK(obj);
     rt = OBJECT_TO_JSVAL(obj);
     CHECK(JS_IsArrayObject(cx, obj));
--- a/js/src/jsapi-tests/testRegExp.cpp
+++ b/js/src/jsapi-tests/testRegExp.cpp
@@ -22,17 +22,17 @@ END_TEST(testObjectIsRegExp)
 
 BEGIN_TEST(testGetRegExpFlags)
 {
     JS::RootedValue val(cx);
     JS::RootedObject obj(cx);
 
     EVAL("/foopy/", &val);
     obj = val.toObjectOrNull();
-    CHECK_EQUAL(JS_GetRegExpFlags(cx, obj), 0);
+    CHECK_EQUAL(JS_GetRegExpFlags(cx, obj), 0u);
 
     EVAL("/foopy/g", &val);
     obj = val.toObjectOrNull();
     CHECK_EQUAL(JS_GetRegExpFlags(cx, obj), JSREG_GLOB);
 
     EVAL("/foopy/gi", &val);
     obj = val.toObjectOrNull();
     CHECK_EQUAL(JS_GetRegExpFlags(cx, obj), (JSREG_FOLD | JSREG_GLOB));
--- a/js/src/jsapi-tests/testResolveRecursion.cpp
+++ b/js/src/jsapi-tests/testResolveRecursion.cpp
@@ -57,18 +57,18 @@ BEGIN_TEST(testResolveRecursion)
     obj2 = nullptr;
     JS::RemoveObjectRoot(cx, &obj1);
     JS::RemoveObjectRoot(cx, &obj2);
     return true;
 }
 
 JS::Heap<JSObject *> obj1;
 JS::Heap<JSObject *> obj2;
-unsigned resolveEntryCount;
-unsigned resolveExitCount;
+int resolveEntryCount;
+int resolveExitCount;
 
 struct AutoIncrCounters {
 
     explicit AutoIncrCounters(cls_testResolveRecursion *t) : t(t) {
         t->resolveEntryCount++;
     }
 
     ~AutoIncrCounters() {
--- a/js/src/jsapi-tests/testScriptInfo.cpp
+++ b/js/src/jsapi-tests/testScriptInfo.cpp
@@ -32,17 +32,17 @@ BEGIN_TEST(testScriptInfo)
     JS::RootedScript script(cx, JS_CompileScript(cx, global, code, strlen(code),
                                                  options));
 
     CHECK(script);
 
     jsbytecode *start = JS_LineNumberToPC(cx, script, startLine);
     CHECK_EQUAL(JS_GetScriptBaseLineNumber(cx, script), startLine);
     CHECK_EQUAL(JS_PCToLineNumber(cx, script, start), startLine);
-    CHECK_EQUAL(JS_GetScriptLineExtent(cx, script), 11);
+    CHECK_EQUAL(JS_GetScriptLineExtent(cx, script), 11u);
     CHECK(strcmp(JS_GetScriptFilename(script), __FILE__) == 0);
     const jschar *sourceMap = JS_GetScriptSourceMap(cx, script);
     CHECK(sourceMap);
     CHECK(CharsMatch(sourceMap, "http://example.com/path/to/source-map.json"));
 
     return true;
 }
 static bool
--- a/js/src/jsapi-tests/testTypedArrays.cpp
+++ b/js/src/jsapi-tests/testTypedArrays.cpp
@@ -67,18 +67,18 @@ TestPlainTypedArray(JSContext *cx)
     RootedObject array(cx, Create(cx, 7));
     CHECK(JS_IsTypedArrayObject(array));
     RootedObject proto(cx);
     JS_GetPrototype(cx, array, &proto);
     CHECK(!JS_IsTypedArrayObject(proto));
     RootedObject dummy(cx, JS_GetParent(proto));
     CHECK(!JS_IsTypedArrayObject(dummy));
 
-    CHECK_EQUAL(JS_GetTypedArrayLength(array), 7);
-    CHECK_EQUAL(JS_GetTypedArrayByteOffset(array), 0);
+    CHECK_EQUAL(JS_GetTypedArrayLength(array), 7u);
+    CHECK_EQUAL(JS_GetTypedArrayByteOffset(array), 0u);
     CHECK_EQUAL(JS_GetTypedArrayByteLength(array), sizeof(Element) * 7);
 
     Element *data;
     CHECK(data = GetData(array));
     *data = 13;
     RootedValue v(cx);
     CHECK(JS_GetElement(cx, array, 0, &v));
     CHECK_SAME(v, INT_TO_JSVAL(13));
@@ -102,31 +102,31 @@ TestArrayFromBuffer(JSContext *cx)
 
     {
         RootedObject notArray(cx, CreateWithBuffer(cx, buffer, UINT32_MAX, -1));
         CHECK(!notArray);
     }
 
     RootedObject array(cx, CreateWithBuffer(cx, buffer, 0, -1));
     CHECK_EQUAL(JS_GetTypedArrayLength(array), elts);
-    CHECK_EQUAL(JS_GetTypedArrayByteOffset(array), 0);
+    CHECK_EQUAL(JS_GetTypedArrayByteOffset(array), 0u);
     CHECK_EQUAL(JS_GetTypedArrayByteLength(array), nbytes);
     CHECK_EQUAL(JS_GetArrayBufferViewBuffer(cx, array), (JSObject*) buffer);
 
     Element *data;
     CHECK(data = GetData(array));
     CHECK(bufdata = JS_GetStableArrayBufferData(cx, buffer));
     CHECK_EQUAL((void*) data, (void*) bufdata);
 
-    CHECK_EQUAL(*bufdata, 1);
-    CHECK_EQUAL(*reinterpret_cast<uint8_t*>(data), 1);
+    CHECK_EQUAL(*bufdata, 1u);
+    CHECK_EQUAL(*reinterpret_cast<uint8_t*>(data), 1u);
 
     RootedObject shortArray(cx, CreateWithBuffer(cx, buffer, 0, elts / 2));
     CHECK_EQUAL(JS_GetTypedArrayLength(shortArray), elts / 2);
-    CHECK_EQUAL(JS_GetTypedArrayByteOffset(shortArray), 0);
+    CHECK_EQUAL(JS_GetTypedArrayByteOffset(shortArray), 0u);
     CHECK_EQUAL(JS_GetTypedArrayByteLength(shortArray), nbytes / 2);
 
     RootedObject ofsArray(cx, CreateWithBuffer(cx, buffer, nbytes / 2, -1));
     CHECK_EQUAL(JS_GetTypedArrayLength(ofsArray), elts / 2);
     CHECK_EQUAL(JS_GetTypedArrayByteOffset(ofsArray), nbytes / 2);
     CHECK_EQUAL(JS_GetTypedArrayByteLength(ofsArray), nbytes / 2);
 
     // Make sure all 3 views reflect the same buffer at the expected locations
--- a/js/src/jsapi-tests/tests.h
+++ b/js/src/jsapi-tests/tests.h
@@ -2,16 +2,18 @@
  * 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 jsapi_tests_tests_h
 #define jsapi_tests_tests_h
 
+#include "mozilla/TypeTraits.h"
+
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "jsalloc.h"
 #include "jscntxt.h"
 #include "jsgc.h"
@@ -156,17 +158,22 @@ class JSAPITest
     }
 
     // Note that in some still-supported GCC versions (we think anything before
     // GCC 4.6), this template does not work when the second argument is
     // nullptr. It infers type U = long int. Use CHECK_NULL instead.
     template <typename T, typename U>
     bool checkEqual(const T &actual, const U &expected,
                     const char *actualExpr, const char *expectedExpr,
-                    const char *filename, int lineno) {
+                    const char *filename, int lineno)
+    {
+        static_assert(mozilla::IsSigned<T>::value == mozilla::IsSigned<U>::value,
+                      "using CHECK_EQUAL with different-signed inputs triggers compiler warnings");
+        static_assert(mozilla::IsUnsigned<T>::value == mozilla::IsUnsigned<U>::value,
+                      "using CHECK_EQUAL with different-signed inputs triggers compiler warnings");
         return (actual == expected) ||
             fail(JSAPITestString("CHECK_EQUAL failed: expected (") +
                  expectedExpr + ") = " + toSource(expected) +
                  ", got (" + actualExpr + ") = " + toSource(actual), filename, lineno);
     }
 
 #define CHECK_EQUAL(actual, expected) \
     do { \
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -4655,20 +4655,20 @@ JS_ObjectIsDate(JSContext *cx, JS::Handl
 extern JS_PUBLIC_API(void)
 JS_ClearDateCaches(JSContext *cx);
 
 /************************************************************************/
 
 /*
  * Regular Expressions.
  */
-#define JSREG_FOLD      0x01    /* fold uppercase to lowercase */
-#define JSREG_GLOB      0x02    /* global exec, creates array of matches */
-#define JSREG_MULTILINE 0x04    /* treat ^ and $ as begin and end of line */
-#define JSREG_STICKY    0x08    /* only match starting at lastIndex */
+#define JSREG_FOLD      0x01u   /* fold uppercase to lowercase */
+#define JSREG_GLOB      0x02u   /* global exec, creates array of matches */
+#define JSREG_MULTILINE 0x04u   /* treat ^ and $ as begin and end of line */
+#define JSREG_STICKY    0x08u   /* only match starting at lastIndex */
 
 extern JS_PUBLIC_API(JSObject *)
 JS_NewRegExpObject(JSContext *cx, JS::HandleObject obj, char *bytes, size_t length,
                    unsigned flags);
 
 extern JS_PUBLIC_API(JSObject *)
 JS_NewUCRegExpObject(JSContext *cx, JS::HandleObject obj, jschar *chars, size_t length,
                      unsigned flags);
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -49,18 +49,16 @@
 
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 using namespace js::frontend;
 
 using mozilla::ArrayLength;
 using mozilla::PodCopy;
-using mozilla::Range;
-using mozilla::RangedPtr;
 
 static bool
 fun_getProperty(JSContext *cx, HandleObject obj_, HandleId id, MutableHandleValue vp)
 {
     RootedObject obj(cx, obj_);
     while (!obj->is<JSFunction>()) {
         if (!JSObject::getProto(cx, obj, &obj))
             return false;
@@ -760,17 +758,17 @@ js::FindBody(JSContext *cx, HandleFuncti
         options.setVersion(fun->nonLazyScript()->getVersion());
 
     AutoKeepAtoms keepAtoms(cx->perThreadData);
 
     AutoStableStringChars stableChars(cx);
     if (!stableChars.initTwoByte(cx, src))
         return false;
 
-    const Range<const jschar> srcChars = stableChars.twoByteRange();
+    const mozilla::Range<const jschar> srcChars = stableChars.twoByteRange();
     TokenStream ts(cx, options, srcChars.start().get(), srcChars.length(), nullptr);
     int nest = 0;
     bool onward = true;
     // Skip arguments list.
     do {
         switch (ts.getToken()) {
           case TOK_NAME:
           case TOK_YIELD:
@@ -796,17 +794,17 @@ js::FindBody(JSContext *cx, HandleFuncti
         tt = ts.getToken();
     if (tt == TOK_ERROR)
         return false;
     bool braced = tt == TOK_LC;
     JS_ASSERT_IF(fun->isExprClosure(), !braced);
     *bodyStart = ts.currentToken().pos.begin;
     if (braced)
         *bodyStart += 1;
-    RangedPtr<const jschar> end = srcChars.end();
+    mozilla::RangedPtr<const jschar> end = srcChars.end();
     if (end[-1] == '}') {
         end--;
     } else {
         JS_ASSERT(!braced);
         for (; unicode::IsSpaceOrBOM2(end[-1]); end--)
             ;
     }
     *bodyEnd = end - srcChars.start();
@@ -1736,17 +1734,17 @@ FunctionConstructor(JSContext *cx, unsig
 
     if (hasRest)
         fun->setHasRest();
 
     AutoStableStringChars stableChars(cx);
     if (!stableChars.initTwoByte(cx, str))
         return false;
 
-    Range<const jschar> chars = stableChars.twoByteRange();
+    mozilla::Range<const jschar> chars = stableChars.twoByteRange();
     SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller()
                                               ? SourceBufferHolder::GiveOwnership
                                               : SourceBufferHolder::NoOwnership;
     bool ok;
     SourceBufferHolder srcBuf(chars.start().get(), chars.length(), ownership);
     if (isStarGenerator)
         ok = frontend::CompileStarGeneratorBody(cx, &fun, options, formals, srcBuf);
     else
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -232,17 +232,17 @@ struct SortComparatorIds
         if (JSID_IS_SYMBOL(a)) {
             MOZ_ASSERT(JSID_IS_SYMBOL(b));
             JS::SymbolCode ca = JSID_TO_SYMBOL(a)->code();
             JS::SymbolCode cb = JSID_TO_SYMBOL(b)->code();
             if (ca != cb) {
                 *lessOrEqualp = uint32_t(ca) <= uint32_t(cb);
                 return true;
             }
-            JS_ASSERT(ca == JS::SymbolCode::InSymbolRegistry || ca == JS::SymbolCode::Unique);
+            JS_ASSERT(ca == JS::SymbolCode::InSymbolRegistry || ca == JS::SymbolCode::UniqueSymbol);
             astr = JSID_TO_SYMBOL(a)->description();
             bstr = JSID_TO_SYMBOL(b)->description();
             if (!astr || !bstr) {
                 *lessOrEqualp = !astr;
                 return true;
             }
 
             // Fall through to string comparison on the descriptions. The sort
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -242,16 +242,17 @@ if CONFIG['ENABLE_TRACE_LOGGING']:
         'vm/TraceLogging.cpp',
     ]
 
 if CONFIG['ENABLE_ION']:
     UNIFIED_SOURCES += [
         'irregexp/NativeRegExpMacroAssembler.cpp',
         'jit/AliasAnalysis.cpp',
         'jit/AsmJS.cpp',
+        'jit/AsmJSFrameIterator.cpp',
         'jit/AsmJSLink.cpp',
         'jit/AsmJSModule.cpp',
         'jit/AsmJSSignalHandlers.cpp',
         'jit/BacktrackingAllocator.cpp',
         'jit/Bailouts.cpp',
         'jit/BaselineBailouts.cpp',
         'jit/BaselineCompiler.cpp',
         'jit/BaselineDebugModeOSR.cpp',
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -2953,17 +2953,17 @@ EvalInWorker(JSContext *cx, unsigned arg
     if (!args[0].toString()->ensureLinear(cx))
         return false;
 
     JSLinearString *str = &args[0].toString()->asLinear();
 
     jschar *chars = (jschar *) js_malloc(str->length() * sizeof(jschar));
     if (!chars)
         return false;
-    PodCopy(chars, str->chars(), str->length());
+    CopyChars(chars, *str);
 
     WorkerInput *input = js_new<WorkerInput>(cx->runtime(), chars, str->length());
     if (!input)
         return false;
 
     PRThread *thread = PR_CreateThread(PR_USER_THREAD, WorkerMain, input,
                                        PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
     if (!thread || !workerThreads.append(thread))
@@ -4523,16 +4523,21 @@ static bool
 ToLatin1(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (!args.get(0).isString() || !args[0].toString()->isLinear()) {
         args.rval().setUndefined();
         return true;
     }
 
+    if (args[0].toString()->hasLatin1Chars()) {
+        args.rval().set(args[0]);
+        return true;
+    }
+
     JSLinearString *s = &args[0].toString()->asLinear();
     s->debugUnsafeConvertToLatin1();
     args.rval().setString(s);
     return true;
 }
 
 static const JSFunctionSpecWithHelp shell_functions[] = {
     JS_FN_HELP("version", Version, 0, 0,
@@ -6306,16 +6311,17 @@ main(int argc, char **argv, char **envp)
         || !op.addBoolOption('\0', "no-fpu", "Pretend CPU does not support floating-point operations "
                              "to test JIT codegen (no-op on platforms other than x86).")
         || !op.addBoolOption('\0', "no-sse3", "Pretend CPU does not support SSE3 instructions and above "
                              "to test JIT codegen (no-op on platforms other than x86 and x64).")
         || !op.addBoolOption('\0', "no-sse4", "Pretend CPU does not support SSE4 instructions"
                              "to test JIT codegen (no-op on platforms other than x86 and x64).")
         || !op.addBoolOption('\0', "fuzzing-safe", "Don't expose functions that aren't safe for "
                              "fuzzers to call")
+        || !op.addBoolOption('\0', "latin1-strings", "Enable Latin1 strings (default: off)")
 #ifdef DEBUG
         || !op.addBoolOption('\0', "dump-entrained-variables", "Print variables which are "
                              "unnecessarily entrained by inner functions")
 #endif
 #ifdef JSGC_GENERATIONAL
         || !op.addBoolOption('\0', "no-ggc", "Disable Generational GC")
 #endif
         || !op.addIntOption('\0', "available-memory", "SIZE",
@@ -6378,16 +6384,21 @@ main(int argc, char **argv, char **envp)
     if (op.getBoolOption("no-sse4")) {
         JSC::MacroAssembler::SetSSE4Disabled();
         PropagateFlagToNestedShells("--no-sse4");
     }
 #endif
 
 #endif // DEBUG
 
+    // Set this option before initializing the JSRuntime, so that Latin1 strings
+    // are used for strings allocated during initialization.
+    if (op.getBoolOption("latin1-strings"))
+        js::EnableLatin1Strings = true;
+
 #ifdef JS_THREADSAFE
     // The fake thread count must be set before initializing the Runtime,
     // which spins up the thread pool.
     int32_t threadCount = op.getIntOption("thread-count");
     if (threadCount >= 0)
         SetFakeCPUCount(threadCount);
 #endif /* JS_THREADSAFE */
 
new file mode 100644
--- /dev/null
+++ b/js/src/tests/js1_8_5/extensions/redeclaration-of-catch-warning.js
@@ -0,0 +1,37 @@
+// |reftest| skip-if(!xulRuntime.shell)
+//
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 622646;
+var summary = "Shadowing an exception identifier in a catch block with a " +
+              "|const| or |let| declaration should throw an error";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+options("strict");
+
+function assertRedeclarationErrorThrown(expression)
+{
+  try
+  {
+    evaluate(expression);
+    throw new Error("Redeclaration error wasn't thrown");
+  }
+  catch(e)
+  {
+    assertEq(e.message.indexOf("catch") > 0, true,
+             "wrong error, got " + e.message);
+  }
+}
+
+assertRedeclarationErrorThrown("try {} catch(e) { const e; }");
+assertRedeclarationErrorThrown("try {} catch(e) { let e; }");
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
--- a/js/src/tests/lib/tests.py
+++ b/js/src/tests/lib/tests.py
@@ -9,17 +9,17 @@ from threading import Thread
 
 from results import TestOutput
 
 # When run on tbpl, we run each test multiple times with the following arguments.
 TBPL_FLAGS = [
     [], # no flags, normal baseline and ion
     ['--ion-eager', '--ion-offthread-compile=off'], # implies --baseline-eager
     ['--ion-eager', '--ion-offthread-compile=off', '--ion-check-range-analysis', '--no-sse3'],
-    ['--baseline-eager'],
+    ['--baseline-eager', '--latin1-strings'],
     ['--baseline-eager', '--no-fpu'],
     ['--no-baseline', '--no-ion'],
 ]
 
 def do_run_cmd(cmd):
     l = [ None, None ]
     th_run_cmd(cmd, l)
     return l[1]
--- a/js/src/vm/OldDebugAPI.cpp
+++ b/js/src/vm/OldDebugAPI.cpp
@@ -1050,17 +1050,17 @@ FormatFrame(JSContext *cx, const NonBuil
     unsigned lineno = PCToLineNumber(script, pc);
     RootedFunction fun(cx, iter.maybeCallee());
     RootedString funname(cx);
     if (fun)
         funname = fun->atom();
 
     RootedValue thisVal(cx);
     AutoPropertyDescArray thisProps(cx);
-    if (iter.computeThis(cx)) {
+    if (iter.hasUsableAbstractFramePtr() && iter.computeThis(cx)) {
         thisVal = iter.computedThisValue();
         if (showThisProps && thisVal.isObject()) {
             RootedObject thisObj(cx, &thisVal.toObject());
             thisProps.fetch(thisObj);
         }
     }
 
     // print the frame number and function name
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -581,17 +581,17 @@ FrameIter::settleOnActivation()
             }
 
             nextJitFrame();
             data_.state_ = JIT;
             return;
         }
 
         if (activation->isAsmJS()) {
-            data_.asmJSFrames_ = AsmJSFrameIterator(data_.activations_->asAsmJS());
+            data_.asmJSFrames_ = AsmJSFrameIterator(*data_.activations_->asAsmJS());
 
             if (data_.asmJSFrames_.done()) {
                 ++data_.activations_;
                 continue;
             }
 
             data_.state_ = ASMJS;
             return;
@@ -633,17 +633,17 @@ FrameIter::Data::Data(ThreadSafeContext 
     contextOption_(contextOption),
     principals_(principals),
     pc_(nullptr),
     interpFrames_(nullptr),
     activations_(cx->perThreadData)
 #ifdef JS_ION
   , jitFrames_((uint8_t *)nullptr, SequentialExecution)
   , ionInlineFrameNo_(0)
-  , asmJSFrames_(nullptr)
+  , asmJSFrames_()
 #endif
 {
 }
 
 FrameIter::Data::Data(const FrameIter::Data &other)
   : cx_(other.cx_),
     savedOption_(other.savedOption_),
     contextOption_(other.contextOption_),
@@ -1678,17 +1678,17 @@ jit::JitActivation::markRematerializedFr
 #endif // JS_ION
 
 AsmJSActivation::AsmJSActivation(JSContext *cx, AsmJSModule &module)
   : Activation(cx, AsmJS),
     module_(module),
     errorRejoinSP_(nullptr),
     profiler_(nullptr),
     resumePC_(nullptr),
-    exitSP_(nullptr)
+    exitFP_(nullptr)
 {
     if (cx->runtime()->spsProfiler.enabled()) {
         // Use a profiler string that matches jsMatch regex in
         // browser/devtools/profiler/cleopatra/js/parserWorker.js.
         // (For now use a single static string to avoid further slowing down
         // calls into asm.js.)
         profiler_ = &cx->runtime()->spsProfiler;
         profiler_->enterNative("asm.js code :0", this);
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -7,17 +7,17 @@
 #ifndef vm_Stack_h
 #define vm_Stack_h
 
 #include "mozilla/MemoryReporting.h"
 
 #include "jsfun.h"
 #include "jsscript.h"
 
-#include "jit/AsmJSLink.h"
+#include "jit/AsmJSFrameIterator.h"
 #include "jit/JitFrameIterator.h"
 #ifdef CHECK_OSIPOINT_REGISTERS
 #include "jit/Registers.h" // for RegisterDump
 #endif
 #include "js/OldDebugAPI.h"
 
 struct JSCompartment;
 struct JSGenerator;
@@ -1506,44 +1506,44 @@ class InterpreterFrameIterator
 // all kinds of jit code.
 class AsmJSActivation : public Activation
 {
     AsmJSModule &module_;
     AsmJSActivation *prevAsmJS_;
     void *errorRejoinSP_;
     SPSProfiler *profiler_;
     void *resumePC_;
-    uint8_t *exitSP_;
-
-    static const intptr_t InterruptedSP = -1;
+    uint8_t *exitFP_;
 
   public:
     AsmJSActivation(JSContext *cx, AsmJSModule &module);
     ~AsmJSActivation();
 
     inline JSContext *cx();
     AsmJSModule &module() const { return module_; }
     AsmJSActivation *prevAsmJS() const { return prevAsmJS_; }
 
     // Read by JIT code:
     static unsigned offsetOfContext() { return offsetof(AsmJSActivation, cx_); }
     static unsigned offsetOfResumePC() { return offsetof(AsmJSActivation, resumePC_); }
 
     // Initialized by JIT code:
     static unsigned offsetOfErrorRejoinSP() { return offsetof(AsmJSActivation, errorRejoinSP_); }
-    static unsigned offsetOfExitSP() { return offsetof(AsmJSActivation, exitSP_); }
+    static unsigned offsetOfExitFP() { return offsetof(AsmJSActivation, exitFP_); }
 
     // Set from SIGSEGV handler:
-    void setInterrupted(void *pc) { resumePC_ = pc; exitSP_ = (uint8_t*)InterruptedSP; }
-    bool isInterruptedSP() const { return exitSP_ == (uint8_t*)InterruptedSP; }
+    void setResumePC(void *pc) { resumePC_ = pc; }
 
-    // Note: exitSP is the sp right before the call instruction. On x86, this
-    // means before the return address is pushed on the stack, on ARM, this
-    // means after.
-    uint8_t *exitSP() const { JS_ASSERT(!isInterruptedSP()); return exitSP_; }
+    // If pc is in C++/Ion code, exitFP points to the innermost asm.js frame
+    // (the one that called into C++). While in asm.js code, exitFP is either
+    // null or points to the innermost asm.js frame. Thus, it is always valid to
+    // unwind a non-null exitFP. The only way C++ can observe a null exitFP is
+    // asychronous interruption of asm.js execution (viz., via the profiler,
+    // a signal handler, or the interrupt exit).
+    uint8_t *exitFP() const { return exitFP_; }
 };
 
 // A FrameIter walks over the runtime's stack of JS script activations,
 // abstracting over whether the JS scripts were running in the interpreter or
 // different modes of compiled code.
 //
 // FrameIter is parameterized by what it includes in the stack iteration:
 //  - The SavedOption controls whether FrameIter stops when it finds an
--- a/js/src/vm/String.cpp
+++ b/js/src/vm/String.cpp
@@ -860,16 +860,18 @@ AutoStableStringChars::initTwoByte(JSCon
     chars[s_->length()] = 0;
 
     state_ = TwoByte;
     ownsChars_ = true;
     twoByteChars_ = chars;
     return true;
 }
 
+bool js::EnableLatin1Strings = false;
+
 #ifdef DEBUG
 void
 JSAtom::dump()
 {
     fprintf(stderr, "JSAtom* (%p) = ", (void *) this);
     this->JSString::dump();
 }
 #endif /* DEBUG */
--- a/js/src/vm/String.h
+++ b/js/src/vm/String.h
@@ -514,19 +514,16 @@ class JSString : public js::gc::Barriere
     }
 
   private:
     JSString() MOZ_DELETE;
     JSString(const JSString &other) MOZ_DELETE;
     void operator=(const JSString &other) MOZ_DELETE;
 };
 
-/* Temporary flag to enable Latin1 strings (bug 998392). */
-static const bool EnableLatin1Strings = false;
-
 class JSRope : public JSString
 {
     template <typename CharT>
     bool copyCharsInternal(js::ThreadSafeContext *cx, js::ScopedJSFreePtr<CharT> &out,
                            bool nullTerminate) const;
 
     enum UsingBarrier { WithIncrementalBarrier, NoBarrier };
 
@@ -997,16 +994,19 @@ class JSAtom : public JSFlatString
     void dump();
 #endif
 };
 
 JS_STATIC_ASSERT(sizeof(JSAtom) == sizeof(JSString));
 
 namespace js {
 
+/* Temporary flag to enable Latin1 strings (bug 998392). */
+extern bool EnableLatin1Strings;
+
 /*
  * Thread safe RAII wrapper for inspecting the contents of JSStrings. The
  * thread safe operations such as |getCharsNonDestructive| require allocation
  * of a char array. This allocation is not always required, such as when the
  * string is already linear. This wrapper makes dealing with this detail more
  * convenient by encapsulating the allocation logic.
  *
  * As the name suggests, this class is scoped. Return values from chars() and
--- a/js/xpconnect/src/dom_quickstubs.qsconf
+++ b/js/xpconnect/src/dom_quickstubs.qsconf
@@ -36,19 +36,17 @@ members = [
     'nsIDOMStorage.setItem',
     'nsIDOMStorage.length',
     'nsIDOMStorage.getItem',
     'nsIDOMStorage.key',
     'nsIDOMStorage.removeItem',
     'nsIDOMStorage.clear',
 
     # dom/interfaces/xpath
-    'nsIDOMXPathExpression.evaluate',
     'nsIDOMXPathNSResolver.lookupNamespaceURI',
-    'nsIDOMNSXPathExpression.evaluateWithContext',
 
     # layout/xul/base/public
     'nsIBoxObject.x',
     'nsIBoxObject.y',
     'nsIBoxObject.screenX',
     'nsIBoxObject.screenY',
     'nsIBoxObject.width',
     'nsIBoxObject.height',
--- a/layout/base/SelectionCarets.cpp
+++ b/layout/base/SelectionCarets.cpp
@@ -377,17 +377,17 @@ SelectionCarets::UpdateSelectionCarets()
   if (range->Collapsed()) {
     SetVisibility(false);
     return;
   }
 
   nsLayoutUtils::FirstAndLastRectCollector collector;
   nsRange::CollectClientRects(&collector, range,
                               range->GetStartParent(), range->StartOffset(),
-                              range->GetEndParent(), range->EndOffset());
+                              range->GetEndParent(), range->EndOffset(), true);
 
   nsIFrame* canvasFrame = mPresShell->GetCanvasFrame();
   nsIFrame* rootFrame = mPresShell->GetRootFrame();
 
   if (!canvasFrame || !rootFrame) {
     SetVisibility(false);
     return;
   }
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -211,17 +211,43 @@ nsImageFrame::DestroyFrom(nsIFrame* aDes
 
   // If we were displaying an icon, take ourselves off the list
   if (mDisplayingIcon)
     gIconLoad->RemoveIconObserver(this);
 
   nsSplittableFrame::DestroyFrom(aDestructRoot);
 }
 
+void
+nsImageFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
+{
+  ImageFrameSuper::DidSetStyleContext(aOldStyleContext);
 
+  if (!mImage) {
+    // We'll pick this change up whenever we do get an image.
+    return;
+  }
+
+  nsStyleImageOrientation newOrientation = StyleVisibility()->mImageOrientation;
+
+  // We need to update our orientation either if we had no style context before
+  // because this is the first time it's been set, or if the image-orientation
+  // property changed from its previous value.
+  bool shouldUpdateOrientation =
+    !aOldStyleContext ||
+    aOldStyleContext->StyleVisibility()->mImageOrientation != newOrientation;
+
+  if (shouldUpdateOrientation) {
+    nsCOMPtr<imgIContainer> image(mImage->Unwrap());
+    mImage = nsLayoutUtils::OrientImage(image, newOrientation);
+
+    UpdateIntrinsicSize(mImage);
+    UpdateIntrinsicRatio(mImage);
+  }
+}
 
 void
 nsImageFrame::Init(nsIContent*       aContent,
                    nsContainerFrame* aParent,
                    nsIFrame*         aPrevInFlow)
 {
   nsSplittableFrame::Init(aContent, aParent, aPrevInFlow);
 
@@ -599,26 +625,29 @@ nsImageFrame::OnDataAvailable(imgIReques
     return NS_OK;
   }
   
   if (IsPendingLoad(aRequest)) {
     // We don't care
     return NS_OK;
   }
 
+  nsIntRect rect = mImage ? mImage->GetImageSpaceInvalidationRect(*aRect)
+                          : *aRect;
+
 #ifdef DEBUG_decode
   printf("Source rect (%d,%d,%d,%d)\n",
          aRect->x, aRect->y, aRect->width, aRect->height);
 #endif
 
-  if (aRect->IsEqualInterior(nsIntRect::GetMaxSizedIntRect())) {
+  if (rect.IsEqualInterior(nsIntRect::GetMaxSizedIntRect())) {
     InvalidateFrame(nsDisplayItem::TYPE_IMAGE);
     InvalidateFrame(nsDisplayItem::TYPE_ALT_FEEDBACK);
   } else {
-    nsRect invalid = SourceRectToDest(*aRect);
+    nsRect invalid = SourceRectToDest(rect);
     InvalidateFrameWithRect(invalid, nsDisplayItem::TYPE_IMAGE);
     InvalidateFrameWithRect(invalid, nsDisplayItem::TYPE_ALT_FEEDBACK);
   }
 
   return NS_OK;
 }
 
 nsresult
--- a/layout/generic/nsImageFrame.h
+++ b/layout/generic/nsImageFrame.h
@@ -68,16 +68,18 @@ public:
   NS_DECL_FRAMEARENA_HELPERS
 
   nsImageFrame(nsStyleContext* aContext);
 
   NS_DECL_QUERYFRAME_TARGET(nsImageFrame)
   NS_DECL_QUERYFRAME
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE;
+  virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) MOZ_OVERRIDE;
+
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) MOZ_OVERRIDE;
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) MOZ_OVERRIDE;
   virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
   virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
new file mode 100644
--- /dev/null
+++ b/layout/reftests/image/image-orientation-dynamic-ref.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<img src="big.png" style="image-orientation: 90deg">
new file mode 100644
--- /dev/null
+++ b/layout/reftests/image/image-orientation-dynamic.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <img src="big.png">
+  <script>
+    document.addEventListener("MozReftestInvalidate", function() {
+      document.querySelector("img").style.imageOrientation = "90deg";
+      document.documentElement.className = "";
+    });
+  </script>
+</html>
--- a/layout/reftests/image/reftest.list
+++ b/layout/reftests/image/reftest.list
@@ -86,8 +86,9 @@ fuzzy(1,1) == image-orientation-backgrou
 != image-orientation-generated-content-ref.html?0    image-orientation-generated-content-ref.html?270
 != image-orientation-generated-content-ref.html?90   image-orientation-generated-content-ref.html?180
 != image-orientation-generated-content-ref.html?90   image-orientation-generated-content-ref.html?270
 != image-orientation-generated-content-ref.html?180  image-orientation-generated-content-ref.html?270
 != image-orientation-generated-content-ref.html?0    image-orientation-generated-content-ref.html?0&flip
 != image-orientation-generated-content-ref.html?90   image-orientation-generated-content-ref.html?90&flip
 != image-orientation-generated-content-ref.html?180  image-orientation-generated-content-ref.html?180&flip
 != image-orientation-generated-content-ref.html?270  image-orientation-generated-content-ref.html?270&flip
+== image-orientation-dynamic.html image-orientation-dynamic-ref.html
--- a/layout/reftests/indic-shaping/reftest.list
+++ b/layout/reftests/indic-shaping/reftest.list
@@ -1,22 +1,22 @@
-skip-if(B2G) pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) == devanagari-1a.html devanagari-1-ref.html
-pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) != devanagari-1b.html devanagari-1-ref.html
-pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) == devanagari-2.html devanagari-2-ref.html
-pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) != devanagari-3a.html devanagari-3-ref.html
-pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) == devanagari-3b.html devanagari-3-ref.html
-pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) != devanagari-4.html devanagari-4-notref.html
+skip-if(B2G) HTTP(..) == devanagari-1a.html devanagari-1-ref.html
+HTTP(..) != devanagari-1b.html devanagari-1-ref.html
+HTTP(..) == devanagari-2.html devanagari-2-ref.html
+HTTP(..) != devanagari-3a.html devanagari-3-ref.html
+HTTP(..) == devanagari-3b.html devanagari-3-ref.html
+HTTP(..) != devanagari-4.html devanagari-4-notref.html
 
-pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) == gujarati-1a.html gujarati-1-ref.html
-pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) != gujarati-1b.html gujarati-1-ref.html
-pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) == gujarati-2.html gujarati-2-ref.html
-pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) != gujarati-3a.html gujarati-3-ref.html
-skip-if(B2G) pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) == gujarati-3b.html gujarati-3-ref.html
-pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) != gujarati-4.html gujarati-4-notref.html
+HTTP(..) == gujarati-1a.html gujarati-1-ref.html
+HTTP(..) != gujarati-1b.html gujarati-1-ref.html
+HTTP(..) == gujarati-2.html gujarati-2-ref.html
+HTTP(..) != gujarati-3a.html gujarati-3-ref.html
+skip-if(B2G) HTTP(..) == gujarati-3b.html gujarati-3-ref.html
+HTTP(..) != gujarati-4.html gujarati-4-notref.html
 
-skip-if(B2G) pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) == bengali-1a.html bengali-1-ref.html
-pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) != bengali-1b.html bengali-1-ref.html
-pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) != bengali-2a.html bengali-2-ref.html
-pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) != bengali-2b.html bengali-2-ref.html
-skip-if(B2G) pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) == bengali-3a.html bengali-3-ref.html
-pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) != bengali-3b.html bengali-3-ref.html
-pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) != bengali-3c.html bengali-3-ref.html
-pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) != bengali-3c.html bengali-3b.html
+skip-if(B2G) HTTP(..) == bengali-1a.html bengali-1-ref.html
+HTTP(..) != bengali-1b.html bengali-1-ref.html
+HTTP(..) != bengali-2a.html bengali-2-ref.html
+HTTP(..) != bengali-2b.html bengali-2-ref.html
+skip-if(B2G) HTTP(..) == bengali-3a.html bengali-3-ref.html
+HTTP(..) != bengali-3b.html bengali-3-ref.html
+HTTP(..) != bengali-3c.html bengali-3-ref.html
+HTTP(..) != bengali-3c.html bengali-3b.html
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -2649,16 +2649,17 @@ nsChangeHint nsStyleVisibility::CalcDiff
 {
   nsChangeHint hint = nsChangeHint(0);
 
   if (mDirection != aOther.mDirection || mWritingMode != aOther.mWritingMode) {
     NS_UpdateHint(hint, nsChangeHint_ReconstructFrame);
   } else {
     if ((mImageOrientation != aOther.mImageOrientation)) {
       NS_UpdateHint(hint, nsChangeHint_AllReflowHints);
+      NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
     }
     if (mVisible != aOther.mVisible) {
       if ((NS_STYLE_VISIBILITY_COLLAPSE == mVisible) ||
           (NS_STYLE_VISIBILITY_COLLAPSE == aOther.mVisible)) {
         NS_UpdateHint(hint, NS_STYLE_HINT_REFLOW);
       } else {
         NS_UpdateHint(hint, NS_STYLE_HINT_VISUAL);
       }
--- a/layout/tools/reftest/remotereftest.py
+++ b/layout/tools/reftest/remotereftest.py
@@ -66,20 +66,16 @@ class RemoteOptions(ReftestOptions):
                     help = "Port for https traffic to the web server")
         defaults["sslPort"] = automation.DEFAULT_SSL_PORT
 
         self.add_option("--remote-logfile", action="store",
                     type = "string", dest = "remoteLogFile",
                     help = "Name of log file on the device relative to device root.  PLEASE USE ONLY A FILENAME.")
         defaults["remoteLogFile"] = None
 
-        self.add_option("--enable-privilege", action="store_true", dest = "enablePrivilege",
-                    help = "add webserver and port to the user.js file for remote script access and universalXPConnect")
-        defaults["enablePrivilege"] = False
-
         self.add_option("--pidfile", action = "store",
                     type = "string", dest = "pidFile",
                     help = "name of the pidfile to generate")
         defaults["pidFile"] = ""
 
         self.add_option("--bootstrap", action="store_true", dest = "bootstrap",
                     help = "test with a bootstrap addon required for native Fennec")
         defaults["bootstrap"] = False
--- a/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp
+++ b/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp
@@ -278,17 +278,21 @@ public:
     mWidth = aWidth;
     mHeight = aHeight;
 
     sp<Surface> surface = nullptr;
     mNativeWindow = new GonkNativeWindow();
     if (mNativeWindow.get()) {
       // listen to buffers queued by MediaCodec::RenderOutputBufferAndRelease().
       mNativeWindow->setNewFrameCallback(this);
-      surface = new Surface(mNativeWindow->getBufferQueue());
+      // XXX remove buffer changes after a better solution lands - bug 1009420
+      sp<GonkBufferQueue> bq = mNativeWindow->getBufferQueue();
+      // More spare buffers to avoid OMX decoder waiting for native window
+      bq->setMaxAcquiredBufferCount(WEBRTC_OMX_H264_MIN_DECODE_BUFFERS);
+      surface = new Surface(bq);
     }
     status_t result = mCodec->configure(config, surface, nullptr, 0);
     if (result == OK) {
       CODEC_LOGD("OMX:%p decoder configured", this);
       result = Start();
     }
     return result;
   }
--- a/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.h
+++ b/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.h
@@ -19,16 +19,19 @@ namespace android {
   class OMXVideoEncoder;
 }
 
 namespace mozilla {
 
 class WebrtcOMXDecoder;
 class OMXOutputDrain;
 
+// XXX see if we can reduce this
+#define WEBRTC_OMX_H264_MIN_DECODE_BUFFERS 10
+
 class WebrtcOMXH264VideoEncoder : public WebrtcVideoEncoder
 {
 public:
   WebrtcOMXH264VideoEncoder();
 
   virtual ~WebrtcOMXH264VideoEncoder();
 
   // Implement VideoEncoder interface.
--- a/mfbt/ArrayUtils.h
+++ b/mfbt/ArrayUtils.h
@@ -13,17 +13,19 @@
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 
 #include <stddef.h>
 
 #ifdef __cplusplus
 
+#include "mozilla/Alignment.h"
 #include "mozilla/Array.h"
+#include "mozilla/TypeTraits.h"
 
 namespace mozilla {
 
 /*
  * Safely subtract two pointers when it is known that aEnd >= aBegin.  This
  * avoids the common compiler bug that if (size_t(aEnd) - size_t(aBegin)) has
  * the MSB set, the unsigned subtraction followed by right shift will produce
  * -1, or size_t(-1), instead of the real difference.
@@ -79,16 +81,79 @@ template<typename T, size_t N>
 MOZ_CONSTEXPR const T*
 ArrayEnd(const Array<T, N>& aArr)
 {
   return &aArr[0] + ArrayLength(aArr);
 }
 
 namespace detail {
 
+template<typename AlignType, typename Pointee>
+struct AlignedChecker
+{
+  static void
+  test(Pointee* aPtr)
+  {
+    MOZ_ASSERT((uintptr_t(aPtr) % MOZ_ALIGNOF(AlignType)) == 0,
+               "performing a range-check with a misaligned pointer");
+  }
+};
+
+template<typename Pointee>
+struct AlignedChecker<void, Pointee>
+{
+  static void
+  test(Pointee* aPtr)
+  {
+  }
+};
+
+} // namespace detail
+
+/**
+ * Determines whether |aPtr| points at an object in the range [aBegin, aEnd).
+ *
+ * |aPtr| must have the same alignment as |aBegin| and |aEnd|.  This usually
+ * should be achieved by ensuring |aPtr| points at a |U|, not just that it
+ * points at a |T|.
+ *
+ * It is a usage error for any argument to be misaligned.
+ *
+ * It's okay for T* to be void*, and if so U* may also be void*.  In the latter
+ * case no argument is required to be aligned (obviously, as void* implies no
+ * particular alignment).
+ */
+template<typename T, typename U>
+inline typename EnableIf<IsSame<T, U>::value ||
+                         IsBaseOf<T, U>::value ||
+                         IsVoid<T>::value,
+                         bool>::Type
+IsInRange(T* aPtr, U* aBegin, U* aEnd)
+{
+  MOZ_ASSERT(aBegin <= aEnd);
+  detail::AlignedChecker<U, T>::test(aPtr);
+  detail::AlignedChecker<U, U>::test(aBegin);
+  detail::AlignedChecker<U, U>::test(aEnd);
+  return aBegin <= static_cast<U*>(aPtr) && static_cast<U*>(aPtr) < aEnd;
+}
+
+/**
+ * Convenience version of the above method when the valid range is specified as
+ * uintptr_t values.  As above, |aPtr| must be aligned, and |aBegin| and |aEnd|
+ * must be aligned with respect to |T|.
+ */
+template<typename T>
+inline bool
+IsInRange(T* aPtr, uintptr_t aBegin, uintptr_t aEnd)
+{
+  return IsInRange(aPtr, reinterpret_cast<T*>(aBegin), reinterpret_cast<T*>(aEnd));
+}
+
+namespace detail {
+
 /*
  * Helper for the MOZ_ARRAY_LENGTH() macro to make the length a typesafe
  * compile-time constant even on compilers lacking constexpr support.
  */
 template <typename T, size_t N>
 char (&ArrayLengthHelper(T (&array)[N]))[N];
 
 } /* namespace detail */
--- a/mfbt/BinarySearch.h
+++ b/mfbt/BinarySearch.h
@@ -36,17 +36,20 @@ BinarySearch(const Container& aContainer
              T aTarget, size_t* aMatchOrInsertionPoint)
 {
   MOZ_ASSERT(aBegin <= aEnd);
 
   size_t low = aBegin;
   size_t high = aEnd;
   while (low != high) {
     size_t middle = low + (high - low) / 2;
-    const T& middleValue = aContainer[middle];
+
+    // Allow any intermediate type so long as it provides a suitable ordering
+    // relation.
+    const auto& middleValue = aContainer[middle];
 
     MOZ_ASSERT(aContainer[low] <= aContainer[middle]);
     MOZ_ASSERT(aContainer[middle] <= aContainer[high - 1]);
     MOZ_ASSERT(aContainer[low] <= aContainer[high - 1]);
 
     if (aTarget == middleValue) {
       *aMatchOrInsertionPoint = middle;
       return true;
new file mode 100644
--- /dev/null
+++ b/mfbt/Pair.h
@@ -0,0 +1,182 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=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/. */
+
+/* A class holding a pair of objects that tries to conserve storage space. */
+
+#ifndef mozilla_Pair_h
+#define mozilla_Pair_h
+
+#include "mozilla/Attributes.h"
+#include "mozilla/Move.h"
+#include "mozilla/TypeTraits.h"
+
+namespace mozilla {
+
+namespace detail {
+
+enum StorageType { AsBase, AsMember };
+
+// Optimize storage using the Empty Base Optimization -- that empty base classes
+// don't take up space -- to optimize size when one or the other class is
+// stateless and can be used as a base class.
+//
+// The extra conditions on storage for B are necessary so that PairHelper won't
+// ambiguously inherit from either A or B, such that one or the other base class
+// would be inaccessible.
+template<typename A, typename B,
+         detail::StorageType =
+           IsEmpty<A>::value ? detail::AsBase : detail::AsMember,
+         detail::StorageType =
+           IsEmpty<B>::value && !IsBaseOf<A, B>::value && !IsBaseOf<B, A>::value
+           ? detail::AsBase
+           : detail::AsMember>
+struct PairHelper;
+
+template<typename A, typename B>
+struct PairHelper<A, B, AsMember, AsMember>
+{
+  protected:
+    template<typename AArg, typename BArg>
+    PairHelper(AArg&& a, BArg&& b)
+      : firstA(Forward<AArg>(a)),
+        secondB(Forward<BArg>(b))
+    {}
+
+    A& first() { return firstA; }
+    const A& first() const { return firstA; }
+    B& second() { return secondB; }
+    const B& second() const { return secondB; }
+
+    void swap(PairHelper& other) {
+      Swap(firstA, other.firstA);
+      Swap(secondB, other.secondB);
+    }
+
+  private:
+    A firstA;
+    B secondB;
+};
+
+template<typename A, typename B>
+struct PairHelper<A, B, AsMember, AsBase> : private B
+{
+  protected:
+    template<typename AArg, typename BArg>
+    PairHelper(AArg&& a, BArg&& b)
+      : B(Forward<BArg>(b)),
+        firstA(Forward<AArg>(a))
+    {}
+
+    A& first() { return firstA; }
+    const A& first() const { return firstA; }
+    B& second() { return *this; }
+    const B& second() const { return *this; }
+
+    void swap(PairHelper& other) {
+      Swap(firstA, other.firstA);
+      Swap(static_cast<B&>(*this), static_cast<B&>(other));
+    }
+
+  private:
+    A firstA;
+};
+
+template<typename A, typename B>
+struct PairHelper<A, B, AsBase, AsMember> : private A
+{
+  protected:
+    template<typename AArg, typename BArg>
+    PairHelper(AArg&& a, BArg&& b)
+      : A(Forward<AArg>(a)),
+        secondB(Forward<BArg>(b))
+    {}
+
+    A& first() { return *this; }
+    const A& first() const { return *this; }
+    B& second() { return secondB; }
+    const B& second() const { return secondB; }
+
+    void swap(PairHelper& other) {
+      Swap(static_cast<A&>(*this), static_cast<A&>(other));
+      Swap(secondB, other.secondB);
+    }
+
+  private:
+    B secondB;
+};
+
+template<typename A, typename B>
+struct PairHelper<A, B, AsBase, AsBase> : private A, private B
+{
+  protected:
+    template<typename AArg, typename BArg>
+    PairHelper(AArg&& a, BArg&& b)
+      : A(Forward<AArg>(a)),
+        B(Forward<BArg>(b))
+    {}
+
+    A& first() { return static_cast<A&>(*this); }
+    const A& first() const { return static_cast<A&>(*this); }
+    B& second() { return static_cast<B&>(*this); }
+    const B& second() const { return static_cast<B&>(*this); }
+
+    void swap(PairHelper& other) {
+      Swap(static_cast<A&>(*this), static_cast<A&>(other));
+      Swap(static_cast<B&>(*this), static_cast<B&>(other));
+    }
+};
+
+} // namespace detail
+
+/**
+ * Pair is the logical concatenation of an instance of A with an instance B.
+ * Space is conserved when possible.  Neither A nor B may be a final class.
+ *
+ * It's typically clearer to have individual A and B member fields.  Except if
+ * you want the space-conserving qualities of Pair, you're probably better off
+ * not using this!
+ *
+ * No guarantees are provided about the memory layout of A and B, the order of
+ * initialization or destruction of A and B, and so on.  (This is approximately
+ * required to optimize space usage.)  The first/second names are merely
+ * conceptual!
+ */
+template<typename A, typename B>
+struct Pair
+  : private detail::PairHelper<A, B>
+{
+    typedef typename detail::PairHelper<A, B> Base;
+
+  public:
+    template<typename AArg, typename BArg>
+    Pair(AArg&& a, BArg&& b)
+      : Base(Forward<AArg>(a), Forward<BArg>(b))
+    {}
+
+    /** The A instance. */
+    using Base::first;
+    /** The B instance. */
+    using Base::second;
+
+    /** Swap this pair with another pair. */
+    void swap(Pair& other) {
+      Base::swap(other);
+    }
+
+  private:
+    Pair(const Pair&) MOZ_DELETE;
+};
+
+template<typename A, class B>
+void
+Swap(Pair<A, B>& x, Pair<A, B>& y)
+{
+  x.swap(y);
+}
+
+} // namespace mozilla
+
+#endif /* mozilla_Pair_h */
--- a/mfbt/TypeTraits.h
+++ b/mfbt/TypeTraits.h
@@ -412,69 +412,76 @@ template<typename T>
 struct IsEmpty : detail::IsEmptyHelper<typename RemoveCV<T>::Type>
 {};
 
 
 namespace detail {
 
 template<typename T,
          bool = IsFloatingPoint<T>::value,
+         bool = IsIntegral<T>::value,
          typename NoCV = typename RemoveCV<T>::Type>
 struct IsSignedHelper;
 
+// Floating point is signed.
 template<typename T, typename NoCV>
-struct IsSignedHelper<T, true, NoCV> : TrueType {};
+struct IsSignedHelper<T, true, false, NoCV> : TrueType {};
 
+// Integral is conditionally signed.
 template<typename T, typename NoCV>
-struct IsSignedHelper<T, false, NoCV>
-  : IntegralConstant<bool, IsArithmetic<T>::value && NoCV(-1) < NoCV(1)>
+struct IsSignedHelper<T, false, true, NoCV>
+  : IntegralConstant<bool, bool(NoCV(-1) < NoCV(1))>
 {};
 
+// Non-floating point, non-integral is not signed.
+template<typename T, typename NoCV>
+struct IsSignedHelper<T, false, false, NoCV> : FalseType {};
+
 } // namespace detail
 
 /**
  * IsSigned determines whether a type is a signed arithmetic type.  |char| is
  * considered a signed type if it has the same representation as |signed char|.
  *
- * Don't use this if the type might be user-defined!  You might or might not get
- * a compile error, depending.
- *
  * mozilla::IsSigned<int>::value is true;
  * mozilla::IsSigned<const unsigned int>::value is false;
  * mozilla::IsSigned<unsigned char>::value is false;
  * mozilla::IsSigned<float>::value is true.
  */
 template<typename T>
 struct IsSigned : detail::IsSignedHelper<T> {};
 
 namespace detail {
 
 template<typename T,
          bool = IsFloatingPoint<T>::value,
+         bool = IsIntegral<T>::value,
          typename NoCV = typename RemoveCV<T>::Type>
 struct IsUnsignedHelper;
 
+// Floating point is not unsigned.
 template<typename T, typename NoCV>
-struct IsUnsignedHelper<T, true, NoCV> : FalseType {};
+struct IsUnsignedHelper<T, true, false, NoCV> : FalseType {};
 
+// Integral is conditionally unsigned.
 template<typename T, typename NoCV>
-struct IsUnsignedHelper<T, false, NoCV>
+struct IsUnsignedHelper<T, false, true, NoCV>
   : IntegralConstant<bool,
-                     IsArithmetic<T>::value &&
-                     (IsSame<NoCV, bool>::value || NoCV(1) < NoCV(-1))>
+                     (IsSame<NoCV, bool>::value || bool(NoCV(1) < NoCV(-1)))>
 {};
 
+// Non-floating point, non-integral is not unsigned.
+template<typename T, typename NoCV>
+struct IsUnsignedHelper<T, false, false, NoCV> : FalseType {};
+
 } // namespace detail
 
 /**
  * IsUnsigned determines whether a type is an unsigned arithmetic type.
  *
- * Don't use this if the type might be user-defined!  You might or might not get
- * a compile error, depending.
- *
  * mozilla::IsUnsigned<int>::value is false;
  * mozilla::IsUnsigned<const unsigned int>::value is true;
  * mozilla::IsUnsigned<unsigned char>::value is true;
  * mozilla::IsUnsigned<float>::value is false.
  */
 template<typename T>
 struct IsUnsigned : detail::IsUnsignedHelper<T> {};
 
--- a/mfbt/moz.build
+++ b/mfbt/moz.build
@@ -43,16 +43,17 @@ EXPORTS.mozilla = [
     'Maybe.h',
     'MaybeOneOf.h',
     'MemoryChecking.h',
     'MemoryReporting.h',
     'Move.h',
     'MSIntTypes.h',
     'NullPtr.h',
     'NumericLimits.h',
+    'Pair.h',
     'PodOperations.h',
     'Poison.h',
     'Range.h',
     'RangedPtr.h',
     'RefCountType.h',
     'ReentrancyGuard.h',
     'RefPtr.h',
     'RollingMean.h',
new file mode 100644
--- /dev/null
+++ b/mfbt/tests/TestArrayUtils.cpp
@@ -0,0 +1,307 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/NullPtr.h"
+
+using mozilla::IsInRange;
+
+static void
+TestIsInRangeNonClass()
+{
+  void* nul = nullptr;
+  int* intBegin = nullptr;
+  int* intEnd = intBegin + 1;
+  int* intEnd2 = intBegin + 2;
+
+  MOZ_RELEASE_ASSERT(IsInRange(nul, intBegin, intEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(nul, intEnd, intEnd2));
+
+  MOZ_RELEASE_ASSERT(IsInRange(intBegin, intBegin, intEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(intEnd, intBegin, intEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(intBegin, intBegin, intEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(intEnd, intBegin, intEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(intEnd2, intBegin, intEnd2));
+
+  uintptr_t uintBegin = uintptr_t(intBegin);
+  uintptr_t uintEnd = uintptr_t(intEnd);
+  uintptr_t uintEnd2 = uintptr_t(intEnd2);
+
+  MOZ_RELEASE_ASSERT(IsInRange(nul, uintBegin, uintEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(nul, uintEnd, uintEnd2));
+
+  MOZ_RELEASE_ASSERT(IsInRange(intBegin, uintBegin, uintEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(intEnd, uintBegin, uintEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(intBegin, uintBegin, uintEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(intEnd, uintBegin, uintEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(intEnd2, uintBegin, uintEnd2));
+}
+
+static void
+TestIsInRangeVoid()
+{
+  int* intBegin = nullptr;
+  int* intEnd = intBegin + 1;
+  int* intEnd2 = intBegin + 2;
+
+  void* voidBegin = intBegin;
+  void* voidEnd = intEnd;
+  void* voidEnd2 = intEnd2;
+
+  MOZ_RELEASE_ASSERT(IsInRange(voidBegin, intBegin, intEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(voidEnd, intBegin, intEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(voidBegin, voidBegin, voidEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(voidEnd, voidBegin, voidEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(voidBegin, intBegin, intEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(voidEnd, intBegin, intEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(voidEnd2, intBegin, intEnd2));
+
+  MOZ_RELEASE_ASSERT(IsInRange(voidBegin, voidBegin, voidEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(voidEnd, voidBegin, voidEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(voidEnd2, voidBegin, voidEnd2));
+
+  uintptr_t uintBegin = uintptr_t(intBegin);
+  uintptr_t uintEnd = uintptr_t(intEnd);
+  uintptr_t uintEnd2 = uintptr_t(intEnd2);
+
+  MOZ_RELEASE_ASSERT(IsInRange(voidBegin, uintBegin, uintEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(voidEnd, uintBegin, uintEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(voidBegin, uintBegin, uintEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(voidEnd, uintBegin, uintEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(voidEnd2, uintBegin, uintEnd2));
+}
+
+struct Base { int x; };
+
+static void
+TestIsInRangeClass()
+{
+  void* nul = nullptr;
+  Base* baseBegin = nullptr;
+  Base* baseEnd = baseBegin + 1;
+  Base* baseEnd2 = baseBegin + 2;
+
+  MOZ_RELEASE_ASSERT(IsInRange(nul, baseBegin, baseEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(nul, baseEnd, baseEnd2));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, baseBegin, baseEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, baseBegin, baseEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, baseBegin, baseEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(baseEnd, baseBegin, baseEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, baseBegin, baseEnd2));
+
+  uintptr_t ubaseBegin = uintptr_t(baseBegin);
+  uintptr_t ubaseEnd = uintptr_t(baseEnd);
+  uintptr_t ubaseEnd2 = uintptr_t(baseEnd2);
+
+  MOZ_RELEASE_ASSERT(IsInRange(nul, ubaseBegin, ubaseEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(nul, ubaseEnd, ubaseEnd2));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, ubaseBegin, ubaseEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, ubaseBegin, ubaseEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, ubaseBegin, ubaseEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(baseEnd, ubaseBegin, ubaseEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, ubaseBegin, ubaseEnd2));
+}
+
+struct EmptyBase {};
+
+static void
+TestIsInRangeEmptyClass()
+{
+  void* nul = nullptr;
+  EmptyBase* baseBegin = nullptr;
+  EmptyBase* baseEnd = baseBegin + 1;
+  EmptyBase* baseEnd2 = baseBegin + 2;
+
+  MOZ_RELEASE_ASSERT(IsInRange(nul, baseBegin, baseEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(nul, baseEnd, baseEnd2));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, baseBegin, baseEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, baseBegin, baseEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, baseBegin, baseEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(baseEnd, baseBegin, baseEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, baseBegin, baseEnd2));
+
+  uintptr_t ubaseBegin = uintptr_t(baseBegin);
+  uintptr_t ubaseEnd = uintptr_t(baseEnd);
+  uintptr_t ubaseEnd2 = uintptr_t(baseEnd2);
+
+  MOZ_RELEASE_ASSERT(IsInRange(nul, ubaseBegin, ubaseEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(nul, ubaseEnd, ubaseEnd2));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, ubaseBegin, ubaseEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, ubaseBegin, ubaseEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, ubaseBegin, ubaseEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(baseEnd, ubaseBegin, ubaseEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, ubaseBegin, ubaseEnd2));
+}
+
+struct Derived : Base {};
+
+static void
+TestIsInRangeClassDerived()
+{
+  void* nul = nullptr;
+  Derived* derivedBegin = nullptr;
+  Derived* derivedEnd = derivedBegin + 1;
+  Derived* derivedEnd2 = derivedBegin + 2;
+
+  Base* baseBegin = static_cast<Base*>(derivedBegin);
+  Base* baseEnd = static_cast<Base*>(derivedEnd);
+  Base* baseEnd2 = static_cast<Base*>(derivedEnd2);
+
+  MOZ_RELEASE_ASSERT(IsInRange(nul, derivedBegin, derivedEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(nul, derivedEnd, derivedEnd2));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedBegin, derivedEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, derivedBegin, derivedEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedBegin, derivedEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(baseEnd, derivedBegin, derivedEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, derivedBegin, derivedEnd2));
+
+  uintptr_t uderivedBegin = uintptr_t(derivedBegin);
+  uintptr_t uderivedEnd = uintptr_t(derivedEnd);
+  uintptr_t uderivedEnd2 = uintptr_t(derivedEnd2);
+
+  MOZ_RELEASE_ASSERT(IsInRange(derivedBegin, uderivedBegin, uderivedEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(derivedEnd, uderivedBegin, uderivedEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(derivedBegin, uderivedBegin, uderivedEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(derivedEnd, uderivedBegin, uderivedEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(derivedEnd2, uderivedBegin, uderivedEnd2));
+}
+
+struct DerivedEmpty : EmptyBase {};
+
+static void
+TestIsInRangeClassDerivedEmpty()
+{
+  void* nul = nullptr;
+  DerivedEmpty* derivedEmptyBegin = nullptr;
+  DerivedEmpty* derivedEmptyEnd = derivedEmptyBegin + 1;
+  DerivedEmpty* derivedEmptyEnd2 = derivedEmptyBegin + 2;
+
+  EmptyBase* baseBegin = static_cast<EmptyBase*>(derivedEmptyBegin);
+  EmptyBase* baseEnd = static_cast<EmptyBase*>(derivedEmptyEnd);
+  EmptyBase* baseEnd2 = static_cast<EmptyBase*>(derivedEmptyEnd2);
+
+  MOZ_RELEASE_ASSERT(IsInRange(nul, derivedEmptyBegin, derivedEmptyEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(nul, derivedEmptyEnd, derivedEmptyEnd2));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedEmptyBegin, derivedEmptyEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, derivedEmptyBegin, derivedEmptyEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedEmptyBegin, derivedEmptyEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(baseEnd, derivedEmptyBegin, derivedEmptyEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, derivedEmptyBegin, derivedEmptyEnd2));
+
+  uintptr_t uderivedEmptyBegin = uintptr_t(derivedEmptyBegin);
+  uintptr_t uderivedEmptyEnd = uintptr_t(derivedEmptyEnd);
+  uintptr_t uderivedEmptyEnd2 = uintptr_t(derivedEmptyEnd2);
+
+  MOZ_RELEASE_ASSERT(IsInRange(derivedEmptyBegin, uderivedEmptyBegin, uderivedEmptyEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(derivedEmptyEnd, uderivedEmptyBegin, uderivedEmptyEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(derivedEmptyBegin, uderivedEmptyBegin, uderivedEmptyEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(derivedEmptyEnd, uderivedEmptyBegin, uderivedEmptyEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(derivedEmptyEnd2, uderivedEmptyBegin, uderivedEmptyEnd2));
+}
+
+struct ExtraDerived : Base { int y; };
+
+static void
+TestIsInRangeClassExtraDerived()
+{
+  void* nul = nullptr;
+  ExtraDerived* derivedBegin = nullptr;
+  ExtraDerived* derivedEnd = derivedBegin + 1;
+  ExtraDerived* derivedEnd2 = derivedBegin + 2;
+
+  Base* baseBegin = static_cast<Base*>(derivedBegin);
+  Base* baseEnd = static_cast<Base*>(derivedEnd);
+  Base* baseEnd2 = static_cast<Base*>(derivedEnd2);
+
+  MOZ_RELEASE_ASSERT(IsInRange(nul, derivedBegin, derivedEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(nul, derivedEnd, derivedEnd2));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedBegin, derivedEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, derivedBegin, derivedEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedBegin, derivedEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(baseEnd, derivedBegin, derivedEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, derivedBegin, derivedEnd2));
+
+  uintptr_t uderivedBegin = uintptr_t(derivedBegin);
+  uintptr_t uderivedEnd = uintptr_t(derivedEnd);
+  uintptr_t uderivedEnd2 = uintptr_t(derivedEnd2);
+
+  MOZ_RELEASE_ASSERT(IsInRange(derivedBegin, uderivedBegin, uderivedEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(derivedEnd, uderivedBegin, uderivedEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(derivedBegin, uderivedBegin, uderivedEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(derivedEnd, uderivedBegin, uderivedEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(derivedEnd2, uderivedBegin, uderivedEnd2));
+}
+
+struct ExtraDerivedEmpty : EmptyBase { int y; };
+
+static void
+TestIsInRangeClassExtraDerivedEmpty()
+{
+  void* nul = nullptr;
+  ExtraDerivedEmpty* derivedBegin = nullptr;
+  ExtraDerivedEmpty* derivedEnd = derivedBegin + 1;
+  ExtraDerivedEmpty* derivedEnd2 = derivedBegin + 2;
+
+  EmptyBase* baseBegin = static_cast<EmptyBase*>(derivedBegin);
+  EmptyBase* baseEnd = static_cast<EmptyBase*>(derivedEnd);
+  EmptyBase* baseEnd2 = static_cast<EmptyBase*>(derivedEnd2);
+
+  MOZ_RELEASE_ASSERT(IsInRange(nul, derivedBegin, derivedEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(nul, derivedEnd, derivedEnd2));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedBegin, derivedEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, derivedBegin, derivedEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedBegin, derivedEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(baseEnd, derivedBegin, derivedEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, derivedBegin, derivedEnd2));
+
+  uintptr_t uderivedBegin = uintptr_t(derivedBegin);
+  uintptr_t uderivedEnd = uintptr_t(derivedEnd);
+  uintptr_t uderivedEnd2 = uintptr_t(derivedEnd2);
+
+  MOZ_RELEASE_ASSERT(IsInRange(derivedBegin, uderivedBegin, uderivedEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(derivedEnd, uderivedBegin, uderivedEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(derivedBegin, uderivedBegin, uderivedEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(derivedEnd, uderivedBegin, uderivedEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(derivedEnd2, uderivedBegin, uderivedEnd2));
+}
+
+int main()
+{
+  TestIsInRangeNonClass();
+  TestIsInRangeVoid();
+  TestIsInRangeClass();
+  TestIsInRangeEmptyClass();
+  TestIsInRangeClassDerived();
+  TestIsInRangeClassDerivedEmpty();
+  TestIsInRangeClassExtraDerived();
+  TestIsInRangeClassExtraDerivedEmpty();
+  return 0;
+}
new file mode 100644
--- /dev/null
+++ b/mfbt/tests/TestPair.cpp
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/Pair.h"
+
+using mozilla::Pair;
+
+// Sizes aren't part of the guaranteed Pair interface, but we want to verify our
+// attempts at compactness through EBO are moderately functional, *somewhere*.
+#define INSTANTIATE(T1, T2, name, size) \
+  Pair<T1, T2> name##_1(T1(0), T2(0)); \
+  static_assert(sizeof(name##_1.first()) > 0, \
+                "first method should work on Pair<" #T1 ", " #T2 ">"); \
+  static_assert(sizeof(name##_1.second()) > 0, \
+                "second method should work on Pair<" #T1 ", " #T2 ">"); \
+  static_assert(sizeof(name##_1) == (size), \
+                "Pair<" #T1 ", " #T2 "> has an unexpected size"); \
+  Pair<T2, T1> name##_2(T2(0), T1(0)); \
+  static_assert(sizeof(name##_2.first()) > 0, \
+                "first method should work on Pair<" #T2 ", " #T1 ">"); \
+  static_assert(sizeof(name##_2.second()) > 0, \
+                "second method should work on Pair<" #T2 ", " #T1 ">"); \
+  static_assert(sizeof(name##_2) == (size), \
+                "Pair<" #T2 ", " #T1 "> has an unexpected size");
+
+INSTANTIATE(int, int, prim1, 2 * sizeof(int));
+INSTANTIATE(int, long, prim2, 2 * sizeof(long));
+
+struct EmptyClass { EmptyClass(int) {} };
+struct NonEmpty { char c; NonEmpty(int) {} };
+
+INSTANTIATE(int, EmptyClass, both1, sizeof(int));
+INSTANTIATE(int, NonEmpty, both2, 2 * sizeof(int));
+INSTANTIATE(EmptyClass, NonEmpty, both3, 1);
+
+struct A { char dummy; A(int) {} };
+struct B : A { B(int i) : A(i) {} };
+
+INSTANTIATE(A, A, class1, 2);
+INSTANTIATE(A, B, class2, 2);
+INSTANTIATE(A, EmptyClass, class3, 1);
+
+struct OtherEmpty : EmptyClass { OtherEmpty(int i) : EmptyClass(i) {} };
+
+// C++11 requires distinct objects of the same type, within the same "most
+// derived object", to have different addresses.  Pair allocates its elements as
+// two bases, a base and a member, or two members.  If the two elements have
+// non-zero size or are unrelated, no big deal.  But if they're both empty and
+// related, something -- possibly both -- must be inflated.  Exactly which are
+// inflated depends which PairHelper specialization is used.  We could
+// potentially assert something about size for this case, but whatever we could
+// assert would be very finicky.  Plus it's two empty classes -- hardly likely.
+// So don't bother trying to assert anything about this case.
+//INSTANTIATE(EmptyClass, OtherEmpty, class4, ...something finicky...);
+
+int
+main()
+{
+}
--- a/mfbt/tests/TestTypeTraits.cpp
+++ b/mfbt/tests/TestTypeTraits.cpp
@@ -148,16 +148,26 @@ static_assert(!IsUnsigned<volatile doubl
 static_assert(IsSigned<long double>::value, "long double should be signed");
 static_assert(!IsUnsigned<long double>::value, "long double shouldn't be unsigned");
 
 static_assert(IsSigned<const volatile long double>::value,
               "const volatile long double should be signed");
 static_assert(!IsUnsigned<const volatile long double>::value,
               "const volatile long double shouldn't be unsigned");
 
+class NotIntConstructible
+{
+  NotIntConstructible(int) MOZ_DELETE;
+};
+
+static_assert(!IsSigned<NotIntConstructible>::value,
+              "non-arithmetic types are not signed");
+static_assert(!IsUnsigned<NotIntConstructible>::value,
+              "non-arithmetic types are not unsigned");
+
 namespace CPlusPlus11IsBaseOf {
 
 // Adapted from C++11 ยง 20.9.6.
 struct B {};
 struct B1 : B {};
 struct B2 : B {};
 struct D : private B1, private B2 {};
 
--- a/mfbt/tests/moz.build
+++ b/mfbt/tests/moz.build
@@ -1,29 +1,31 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 CPP_UNIT_TESTS += [
+    'TestArrayUtils.cpp',
     'TestAtomics.cpp',
     'TestBinarySearch.cpp',
     'TestBloomFilter.cpp',
     'TestCasting.cpp',
     'TestCeilingFloor.cpp',
     'TestCheckedInt.cpp',
     'TestCountPopulation.cpp',
     'TestCountZeroes.cpp',
     'TestEndian.cpp',
     'TestEnumSet.cpp',
     'TestFloatingPoint.cpp',
     'TestIntegerPrintfMacros.cpp',
     'TestMacroArgs.cpp',
     'TestMacroForEach.cpp',
+    'TestPair.cpp',
     'TestRollingMean.cpp',
     'TestSHA1.cpp',
     'TestTypedEnum.cpp',
     'TestTypeTraits.cpp',
     'TestWeakPtr.cpp',
 ]
 
 if not CONFIG['MOZ_ASAN']:
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -443,33 +443,16 @@ pref("gfx.font_rendering.fallback.always
 // cache shaped word results
 pref("gfx.font_rendering.wordcache.charlimit", 32);
 
 // cache shaped word results
 pref("gfx.font_rendering.wordcache.maxentries", 10000);
 
 pref("gfx.font_rendering.graphite.enabled", true);
 
-// Check intl/unicharutil/util/nsUnicodeProperties.h for definitions of script bits
-// in the ShapingType enumeration
-// Currently-defined bits:
-//  SHAPING_DEFAULT   = 0x0001,
-//  SHAPING_ARABIC    = 0x0002,
-//  SHAPING_HEBREW    = 0x0004,
-//  SHAPING_HANGUL    = 0x0008,
-//  SHAPING_MONGOLIAN = 0x0010,
-//  SHAPING_INDIC     = 0x0020,
-//  SHAPING_THAI      = 0x0040
-// (see http://mxr.mozilla.org/mozilla-central/ident?i=ShapingType)
-// Scripts not listed are grouped in the default category.
-// Set the pref to 255 to have all text shaped via the harfbuzz backend.
-// Default setting:
-// We use harfbuzz for all scripts (except when using AAT fonts on OS X).
-pref("gfx.font_rendering.harfbuzz.scripts", 255);
-
 #ifdef XP_WIN
 pref("gfx.font_rendering.directwrite.enabled", false);
 pref("gfx.font_rendering.directwrite.use_gdi_table_loading", true);
 #endif
 
 pref("gfx.font_rendering.opentype_svg.enabled", true);
 
 #ifdef XP_WIN
--- a/netwerk/protocol/http/Http2Session.cpp
+++ b/netwerk/protocol/http/Http2Session.cpp
@@ -93,16 +93,18 @@ Http2Session::Http2Session(nsISocketTran
   , mServerInitialStreamWindow(kDefaultRwin)
   , mLocalSessionWindow(kDefaultRwin)
   , mServerSessionWindow(kDefaultRwin)
   , mOutputQueueSize(kDefaultQueueSize)
   , mOutputQueueUsed(0)
   , mOutputQueueSent(0)
   , mLastReadEpoch(PR_IntervalNow())
   , mPingSentEpoch(0)
+  , mWaitingForSettingsAck(false)
+  , mGoAwayOnPush(false)
 {
   MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
 
   static uint64_t sSerial;
   mSerial = ++sSerial;
 
   LOG3(("Http2Session::Http2Session %p serial=0x%X\n", this, mSerial));
 
@@ -803,16 +805,18 @@ Http2Session::SendHello()
     // set ENABLE_PUSH to 0
     CopyAsNetwork16(packet + 8 + (6 * numberOfEntries), SETTINGS_TYPE_ENABLE_PUSH);
     // The value portion of the setting pair is already initialized to 0
     numberOfEntries++;
 
     CopyAsNetwork16(packet + 8 + (6 * numberOfEntries), SETTINGS_TYPE_MAX_CONCURRENT);
     // The value portion of the setting pair is already initialized to 0
     numberOfEntries++;
+
+    mWaitingForSettingsAck = true;
   }
 
   // Advertise the Push RWIN for the session, and on each new pull stream
   // send a window update with END_FLOW_CONTROL
   CopyAsNetwork16(packet + 8 + (6 * numberOfEntries), SETTINGS_TYPE_INITIAL_WINDOW);
   CopyAsNetwork32(packet + 8 + (6 * numberOfEntries) + 2, mPushAllowance);
   numberOfEntries++;
 
@@ -1354,18 +1358,21 @@ Http2Session::RecvSettings(Http2Session 
 
     default:
       break;
     }
   }
 
   self->ResetDownstreamState();
 
-  if (!(self->mInputFrameFlags & kFlag_ACK))
+  if (!(self->mInputFrameFlags & kFlag_ACK)) {
     self->GenerateSettingsAck();
+  } else if (self->mWaitingForSettingsAck) {
+    self->mGoAwayOnPush = true;
+  }
 
   return NS_OK;
 }
 
 nsresult
 Http2Session::RecvPushPromise(Http2Session *self)
 {
   MOZ_ASSERT(self->mInputFrameType == FRAME_TYPE_PUSH_PROMISE);
@@ -1439,18 +1446,22 @@ Http2Session::RecvPushPromise(Http2Sessi
   bool resetStream = true;
   SpdyPushCache *cache = nullptr;
 
   if (self->mShouldGoAway) {
     LOG3(("Http2Session::RecvPushPromise %p push while in GoAway "
           "mode refused.\n", self));
     self->GenerateRstStream(REFUSED_STREAM_ERROR, promisedID);
   } else if (!gHttpHandler->AllowPush()) {
-    // MAX_CONCURRENT_STREAMS of 0 in settings disabled push
+    // ENABLE_PUSH and MAX_CONCURRENT_STREAMS of 0 in settings disabled push
     LOG3(("Http2Session::RecvPushPromise Push Recevied when Disabled\n"));
+    if (self->mGoAwayOnPush) {
+      LOG3(("Http2Session::RecvPushPromise sending GOAWAY"));
+      RETURN_SESSION_ERROR(self, PROTOCOL_ERROR);
+    }
     self->GenerateRstStream(REFUSED_STREAM_ERROR, promisedID);
   } else if (!(self->mInputFrameFlags & kFlag_END_PUSH_PROMISE)) {
     LOG3(("Http2Session::RecvPushPromise no support for multi frame push\n"));
     self->GenerateRstStream(REFUSED_STREAM_ERROR, promisedID);
   } else if (!associatedStream) {
     LOG3(("Http2Session::RecvPushPromise %p lookup associated ID failed.\n", self));
     self->GenerateRstStream(PROTOCOL_ERROR, promisedID);
   } else {
--- a/netwerk/protocol/http/Http2Session.h
+++ b/netwerk/protocol/http/Http2Session.h
@@ -436,16 +436,23 @@ private:
   // used as a temporary buffer while enumerating the stream hash during GoAway
   nsDeque  mGoAwayStreamsToRestart;
 
   // Each session gets a unique serial number because the push cache is correlated
   // by the load group and the serial number can be used as part of the cache key
   // to make sure streams aren't shared across sessions.
   uint64_t        mSerial;
 
+  // If push is disabled, we want to be able to send PROTOCOL_ERRORs if we
+  // receive a PUSH_PROMISE, but we have to wait for the SETTINGS ACK before
+  // we can actually tell the other end to go away. These help us keep track
+  // of that state so we can behave appropriately.
+  bool mWaitingForSettingsAck;
+  bool mGoAwayOnPush;
+
 private:
 /// connect tunnels
   void DispatchOnTunnel(nsAHttpTransaction *, nsIInterfaceRequestor *);
   void RegisterTunnel(Http2Stream *);
   void UnRegisterTunnel(Http2Stream *);
   uint32_t FindTunnelCount(nsHttpConnectionInfo *);
 
   nsDataHashtable<nsCStringHashKey, uint32_t> mTunnelHash;
--- a/netwerk/sctp/datachannel/DataChannel.cpp
+++ b/netwerk/sctp/datachannel/DataChannel.cpp
@@ -675,22 +675,22 @@ DataChannelConnection::SctpDtlsInput(Tra
     }
   }
 #endif
   // Pass the data to SCTP
   usrsctp_conninput(static_cast<void *>(this), data, len, 0);
 }
 
 int
-DataChannelConnection::SendPacket(const unsigned char *data, size_t len, bool release)
+DataChannelConnection::SendPacket(unsigned char data[], size_t len, bool release)
 {
   //LOG(("%p: SCTP/DTLS sent %ld bytes", this, len));
   int res = mTransportFlow->SendPacket(data, len) < 0 ? 1 : 0;
   if (release)
-    delete data;
+    delete [] data;
   return res;
 }
 
 /* static */
 int
 DataChannelConnection::SctpDtlsOutput(void *addr, void *buffer, size_t length,
                                       uint8_t tos, uint8_t set_df)
 {
--- a/netwerk/sctp/datachannel/DataChannel.h
+++ b/netwerk/sctp/datachannel/DataChannel.h
@@ -195,17 +195,17 @@ protected:
   // Use from main thread only as WeakPtr is not threadsafe
   WeakPtr<DataConnectionListener> mListener;
 
 private:
   friend class DataChannelConnectRunnable;
 
 #ifdef SCTP_DTLS_SUPPORTED
   static void DTLSConnectThread(void *data);
-  int SendPacket(const unsigned char* data, size_t len, bool release);
+  int SendPacket(unsigned char data[], size_t len, bool release);
   void SctpDtlsInput(TransportFlow *flow, const unsigned char *data, size_t len);
   static int SctpDtlsOutput(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df);
 #endif
   DataChannel* FindChannelByStream(uint16_t stream);
   uint16_t FindFreeStream();
   bool RequestMoreStreams(int32_t aNeeded = 16);
   int32_t SendControlMessage(void *msg, uint32_t len, uint16_t stream);
   int32_t SendOpenRequestMessage(const nsACString& label, const nsACString& protocol,
--- a/parser/html/nsHtml5Module.cpp
+++ b/parser/html/nsHtml5Module.cpp
@@ -98,16 +98,18 @@ class nsHtml5ParserThreadTerminator MOZ_
                    "Unexpected topic");
       if (mThread) {
         mThread->Shutdown();
         mThread = nullptr;
       }
       return NS_OK;
     }
   private:
+    ~nsHtml5ParserThreadTerminator() {}
+
     nsCOMPtr<nsIThread> mThread;
 };
 
 NS_IMPL_ISUPPORTS(nsHtml5ParserThreadTerminator, nsIObserver)
 
 // static 
 nsIThread*
 nsHtml5Module::GetStreamParserThread()
--- a/parser/html/nsHtml5Parser.h
+++ b/parser/html/nsHtml5Parser.h
@@ -32,17 +32,16 @@ class nsHtml5Parser : public nsIParser,
 {
   public:
     NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
     NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsHtml5Parser, nsIParser)
 
     nsHtml5Parser();
-    virtual ~nsHtml5Parser();
 
     /* Start nsIParser */
     /**
      * No-op for backwards compat.
      */
     NS_IMETHOD_(void) SetContentSink(nsIContentSink* aSink);
 
     /**
@@ -261,16 +260,18 @@ class nsHtml5Parser : public nsIParser,
 
     /**
      * Parse until pending data is exhausted or a script blocks the parser
      */
     void ParseUntilBlocked();
 
   private:
 
+    virtual ~nsHtml5Parser();
+
     // State variables
 
     /**
      * Whether the last character tokenized was a carriage return (for CRLF)
      */
     bool                          mLastWasCR;
 
     /**
--- a/parser/html/nsHtml5StreamListener.h
+++ b/parser/html/nsHtml5StreamListener.h
@@ -28,27 +28,28 @@
  * threads, so there is no need to have a mutex around nsHtml5RefPtr to
  * prevent it from double-releasing nsHtml5StreamParser.
  */
 class nsHtml5StreamListener : public nsIStreamListener,
                               public nsIThreadRetargetableStreamListener
 {
 public:
   nsHtml5StreamListener(nsHtml5StreamParser* aDelegate);
-  virtual ~nsHtml5StreamListener();
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
   NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
 
   inline nsHtml5StreamParser* GetDelegate()
   {
     return mDelegate;
   }
 
   void DropDelegate();
 
 private:
+  virtual ~nsHtml5StreamListener();
+
   nsHtml5RefPtr<nsHtml5StreamParser> mDelegate;
 };
 
 #endif // nsHtml5StreamListener_h
--- a/parser/html/nsHtml5StreamParser.h
+++ b/parser/html/nsHtml5StreamParser.h
@@ -112,18 +112,16 @@ class nsHtml5StreamParser : public nsICh
     NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsHtml5StreamParser,
                                              nsICharsetDetectionObserver)
 
     static void InitializeStatics();
 
     nsHtml5StreamParser(nsHtml5TreeOpExecutor* aExecutor,
                         nsHtml5Parser* aOwner,
                         eParserMode aMode);
-                        
-    virtual ~nsHtml5StreamParser();
 
     // Methods that nsHtml5StreamListener calls
     nsresult CheckListenerChain();
 
     nsresult OnStartRequest(nsIRequest* aRequest, nsISupports* aContext);
 
     nsresult OnDataAvailable(nsIRequest* aRequest,
                              nsISupports* aContext,
@@ -204,16 +202,17 @@ class nsHtml5StreamParser : public nsICh
     /**
      * Sets the URL for View Source title in case this parser ends up being
      * used for View Source. If aURL is a view-source: URL, takes the inner
      * URL. data: URLs are shown with an ellipsis instead of the actual data.
      */
     void SetViewSourceTitle(nsIURI* aURL);
 
   private:
+    virtual ~nsHtml5StreamParser();
 
 #ifdef DEBUG
     bool IsParserThread() {
       bool ret;
       mThread->IsOnCurrentThread(&ret);
       return ret;
     }
 #endif
--- a/parser/html/nsHtml5StringParser.h
+++ b/parser/html/nsHtml5StringParser.h
@@ -20,17 +20,16 @@ class nsHtml5StringParser : public nsPar
 
     NS_DECL_ISUPPORTS
 
     /**
      * Constructor for use ONLY by nsContentUtils. Others, please call the
      * nsContentUtils statics that wrap this.
      */
     nsHtml5StringParser();
-    virtual ~nsHtml5StringParser();
 
     /**
      * Invoke the fragment parsing algorithm (innerHTML).
      * DO NOT CALL from outside nsContentUtils.cpp.
      *
      * @param aSourceBuffer the string being set as innerHTML
      * @param aTargetNode the target container
      * @param aContextLocalName local name of context node
@@ -53,16 +52,18 @@ class nsHtml5StringParser : public nsPar
      *
      */
     nsresult ParseDocument(const nsAString& aSourceBuffer,
                            nsIDocument* aTargetDoc,
                            bool aScriptingEnabledForNoscriptParsing);
 
   private:
 
+    virtual ~nsHtml5StringParser();
+
     nsresult Tokenize(const nsAString& aSourceBuffer,
                       nsIDocument* aDocument,
                       bool aScriptingEnabledForNoscriptParsing);
 
     /**
      * The tree operation executor
      */
     nsRefPtr<nsHtml5OplessBuilder>      mBuilder;
--- a/parser/html/nsParserUtils.h
+++ b/parser/html/nsParserUtils.h
@@ -8,15 +8,16 @@
 
 #include "nsIScriptableUnescapeHTML.h"
 #include "nsIParserUtils.h"
 #include "mozilla/Attributes.h"
 
 class nsParserUtils MOZ_FINAL : public nsIScriptableUnescapeHTML,
                                 public nsIParserUtils
 {
+  ~nsParserUtils() {}
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSISCRIPTABLEUNESCAPEHTML
   NS_DECL_NSIPARSERUTILS
 };
 
 #endif // nsParserUtils_h
--- a/parser/htmlparser/src/CNavDTD.h
+++ b/parser/htmlparser/src/CNavDTD.h
@@ -19,19 +19,20 @@ class nsIHTMLContentSink;
 #endif
 
 class CNavDTD : public nsIDTD
 {
 #ifdef _MSC_VER
 #pragma warning( default : 4275 )
 #endif
 
+    virtual ~CNavDTD();
+
 public:
     CNavDTD();
-    virtual ~CNavDTD();
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIDTD
 };
 
 #endif
 
 
--- a/parser/htmlparser/src/nsExpatDriver.h
+++ b/parser/htmlparser/src/nsExpatDriver.h
@@ -18,24 +18,25 @@
 
 class nsIExpatSink;
 class nsIExtendedExpatSink;
 struct nsCatalogData;
 
 class nsExpatDriver : public nsIDTD,
                       public nsITokenizer
 {
+  virtual ~nsExpatDriver();
+
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSIDTD
   NS_DECL_NSITOKENIZER
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsExpatDriver, nsIDTD)
 
   nsExpatDriver();
-  virtual ~nsExpatDriver();
 
   int HandleExternalEntityRef(const char16_t *aOpenEntityNames,
                               const char16_t *aBase,
                               const char16_t *aSystemId,
                               const char16_t *aPublicId);
   nsresult HandleStartElement(const char16_t *aName, const char16_t **aAtts);
   nsresult HandleEndElement(const char16_t *aName);
   nsresult HandleCharacterData(const char16_t *aCData, const uint32_t aLength);
--- a/parser/htmlparser/src/nsHTMLTokenizer.h
+++ b/parser/htmlparser/src/nsHTMLTokenizer.h
@@ -17,18 +17,19 @@
 #include "nsISupports.h"
 #include "nsITokenizer.h"
 
 #ifdef _MSC_VER
 #pragma warning( disable : 4275 )
 #endif
 
 class nsHTMLTokenizer MOZ_FINAL : public nsITokenizer {
+  ~nsHTMLTokenizer() {}
+
 public:
-  
   NS_DECL_ISUPPORTS
   NS_DECL_NSITOKENIZER
   nsHTMLTokenizer();
 };
 
 #endif
 
 
--- a/parser/htmlparser/src/nsParser.h
+++ b/parser/htmlparser/src/nsParser.h
@@ -61,16 +61,22 @@ class nsIRunnable;
 #pragma warning( disable : 4275 )
 #endif
 
 
 class nsParser : public nsIParser,
                  public nsIStreamListener,
                  public nsSupportsWeakReference
 {
+    /**
+     * Destructor
+     * @update  gess5/11/98
+     */
+    virtual ~nsParser();
+
   public:
     /**
      * Called on module init
      */
     static nsresult Init();
 
     /**
      * Called on module shutdown
@@ -82,22 +88,16 @@ class nsParser : public nsIParser,
 
     /**
      * default constructor
      * @update	gess5/11/98
      */
     nsParser();
 
     /**
-     * Destructor
-     * @update	gess5/11/98
-     */
-    virtual ~nsParser();
-
-    /**
      * Select given content sink into parser for parser output
      * @update	gess5/11/98
      * @param   aSink is the new sink to be used by parser
      * @return  old sink, or nullptr
      */
     NS_IMETHOD_(void) SetContentSink(nsIContentSink* aSink);
 
     /**
--- a/parser/htmlparser/src/nsParserService.h
+++ b/parser/htmlparser/src/nsParserService.h
@@ -9,19 +9,20 @@
 #include "nsIParserService.h"
 
 extern "C" int MOZ_XMLIsLetter(const char* ptr);
 extern "C" int MOZ_XMLIsNCNameChar(const char* ptr);
 extern "C" int MOZ_XMLTranslateEntity(const char* ptr, const char* end,
                                       const char** next, char16_t* result);
 
 class nsParserService : public nsIParserService {
+  virtual ~nsParserService();
+
 public:
   nsParserService();
-  virtual ~nsParserService();
 
   NS_DECL_ISUPPORTS
 
   int32_t HTMLAtomTagToId(nsIAtom* aAtom) const;
 
   int32_t HTMLCaseSensitiveAtomTagToId(nsIAtom* aAtom) const;
 
   int32_t HTMLStringTagToId(const nsAString& aTag) const;
--- a/parser/xml/src/nsSAXAttributes.h
+++ b/parser/xml/src/nsSAXAttributes.h
@@ -31,12 +31,13 @@ struct SAXAttr
 class nsSAXAttributes MOZ_FINAL : public nsISAXMutableAttributes
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSISAXATTRIBUTES
   NS_DECL_NSISAXMUTABLEATTRIBUTES
 
 private:
+  ~nsSAXAttributes() {}
   nsTArray<SAXAttr> mAttrs;
 };
 
 #endif // nsSAXAttributes_h__
--- a/parser/xml/src/nsSAXLocator.h
+++ b/parser/xml/src/nsSAXLocator.h
@@ -23,15 +23,17 @@ public:
   NS_DECL_NSISAXLOCATOR
 
   nsSAXLocator(nsString& aPublicId,
                nsString& aSystemId,
                int32_t aLineNumber,
                int32_t aColumnNumber);
 
 private:
+  ~nsSAXLocator() {}
+
   nsString mPublicId;
   nsString mSystemId;
   int32_t mLineNumber;
   int32_t mColumnNumber;
 };
 
 #endif //nsSAXLocator_h__
--- a/parser/xml/src/nsSAXXMLReader.h
+++ b/parser/xml/src/nsSAXXMLReader.h
@@ -70,16 +70,18 @@ public:
   }
   
   virtual nsISupports *GetTarget()
   {
     return nullptr;
   }
 
 private:
+  ~nsSAXXMLReader() {}
+
   nsCOMPtr<nsISAXContentHandler> mContentHandler;
   nsCOMPtr<nsISAXDTDHandler> mDTDHandler;
   nsCOMPtr<nsISAXErrorHandler> mErrorHandler;
   nsCOMPtr<nsISAXLexicalHandler> mLexicalHandler;
   nsCOMPtr<nsIMozSAXXMLDeclarationHandler> mDeclarationHandler;
   nsCOMPtr<nsIURI> mBaseURI;
   nsCOMPtr<nsIStreamListener> mListener;
   nsCOMPtr<nsIRequestObserver> mParserObserver;
--- a/security/pkix/test/gtest/pkixcheck_CheckKeyUsage_tests.cpp
+++ b/security/pkix/test/gtest/pkixcheck_CheckKeyUsage_tests.cpp
@@ -129,16 +129,50 @@ TEST(pkixchekc_CheckKeyusage, tooManyUnu
     siBuffer,
     twoValueBytesData,
     sizeof(twoValueBytesData)
   };
   ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &twoValueBytes,
                            KeyUsage::digitalSignature));
 }
 
+TEST(pkixcheck_CheckKeyUsage, NoValueBytes_NoPaddingBits)
+{
+  static const uint8_t DER_BYTES[] = {
+    0x03/*BIT STRING*/, 0x01/*LENGTH=1*/, 0/*unused bits*/
+  };
+  static const SECItem DER = {
+    siBuffer,
+    const_cast<uint8_t*>(DER_BYTES),
+    sizeof(DER_BYTES)
+  };
+
+  ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &DER,
+                           KeyUsage::digitalSignature));
+  ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &DER,
+                           KeyUsage::keyCertSign));
+}
+
+TEST(pkixcheck_CheckKeyUsage, NoValueBytes_7PaddingBits)
+{
+  static const uint8_t DER_BYTES[] = {
+    0x03/*BIT STRING*/, 0x01/*LENGTH=1*/, 7/*unused bits*/
+  };
+  static const SECItem DER = {
+    siBuffer,
+    const_cast<uint8_t*>(DER_BYTES),
+    sizeof(DER_BYTES)
+  };
+
+  ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &DER,
+                           KeyUsage::digitalSignature));
+  ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &DER,
+                           KeyUsage::keyCertSign));
+}
+
 void ASSERT_SimpleCase(uint8_t unusedBits, uint8_t bits, KeyUsage usage)
 {
   // Test that only the right bit is accepted for the usage for both EE and CA
   // certs.
   NAMED_SIMPLE_KU(good, unusedBits, bits);
   ASSERT_Success(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &good, usage));
   ASSERT_Success(CheckKeyUsage(EndEntityOrCA::MustBeCA, &good, usage));
 
--- a/toolkit/components/downloads/ApplicationReputation.cpp
+++ b/toolkit/components/downloads/ApplicationReputation.cpp
@@ -975,22 +975,27 @@ PendingLookup::OnStopRequestInternal(nsI
   safe_browsing::ClientDownloadResponse response;
   if (!response.ParseFromString(buf)) {
     NS_WARNING("Could not parse protocol buffer");
     Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_SERVER,
                                    SERVER_RESPONSE_INVALID);
     return NS_ERROR_CANNOT_CONVERT_DATA;
   }
 
-  // There are several more verdicts, but we only respect one for now and treat
-  // everything else as SAFE.
+  // There are several more verdicts, but we only respect DANGEROUS and
+  // DANGEROUS_HOST for now and treat everything else as SAFE.
   Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_SERVER,
     SERVER_RESPONSE_VALID);
-  if (response.verdict() == safe_browsing::ClientDownloadResponse::DANGEROUS) {
-    *aShouldBlock = true;
+  switch(response.verdict()) {
+    case safe_browsing::ClientDownloadResponse::DANGEROUS:
+    case safe_browsing::ClientDownloadResponse::DANGEROUS_HOST:
+      *aShouldBlock = true;
+      break;
+    default:
+      break;
   }
 
   return NS_OK;
 }
 
 NS_IMPL_ISUPPORTS(ApplicationReputationService,
                   nsIApplicationReputationService)
 
--- a/toolkit/components/downloads/csd.pb.cc
+++ b/toolkit/components/downloads/csd.pb.cc
@@ -8,1565 +8,70 @@
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/wire_format_lite_inl.h>
 // @@protoc_insertion_point(includes)
 
 namespace safe_browsing {
 
 void protobuf_ShutdownFile_csd_2eproto() {
-  delete ClientPhishingRequest::default_instance_;
-  delete ClientPhishingRequest_Feature::default_instance_;
-  delete ClientPhishingResponse::default_instance_;
-  delete ClientMalwareRequest::default_instance_;
-  delete ClientMalwareRequest_Feature::default_instance_;
-  delete ClientMalwareResponse::default_instance_;
   delete ClientDownloadRequest::default_instance_;
   delete ClientDownloadRequest_Digests::default_instance_;
   delete ClientDownloadRequest_Resource::default_instance_;
   delete ClientDownloadRequest_CertificateChain::default_instance_;
   delete ClientDownloadRequest_CertificateChain_Element::default_instance_;
   delete ClientDownloadRequest_SignatureInfo::default_instance_;
+  delete ClientDownloadRequest_PEImageHeaders::default_instance_;
+  delete ClientDownloadRequest_PEImageHeaders_DebugData::default_instance_;
+  delete ClientDownloadRequest_ImageHeaders::default_instance_;
   delete ClientDownloadResponse::default_instance_;
   delete ClientDownloadResponse_MoreInfo::default_instance_;
-  delete ClientDownloadReport::default_instance_;
-  delete ClientDownloadReport_UserInformation::default_instance_;
-  delete ClientUploadResponse::default_instance_;
 }
 
 void protobuf_AddDesc_csd_2eproto() {
   static bool already_here = false;
   if (already_here) return;
   already_here = true;
   GOOGLE_PROTOBUF_VERIFY_VERSION;
 
-  ClientPhishingRequest::default_instance_ = new ClientPhishingRequest();
-  ClientPhishingRequest_Feature::default_instance_ = new ClientPhishingRequest_Feature();
-  ClientPhishingResponse::default_instance_ = new ClientPhishingResponse();
-  ClientMalwareRequest::default_instance_ = new ClientMalwareRequest();
-  ClientMalwareRequest_Feature::default_instance_ = new ClientMalwareRequest_Feature();
-  ClientMalwareResponse::default_instance_ = new ClientMalwareResponse();
   ClientDownloadRequest::default_instance_ = new ClientDownloadRequest();
   ClientDownloadRequest_Digests::default_instance_ = new ClientDownloadRequest_Digests();
   ClientDownloadRequest_Resource::default_instance_ = new ClientDownloadRequest_Resource();
   ClientDownloadRequest_CertificateChain::default_instance_ = new ClientDownloadRequest_CertificateChain();
   ClientDownloadRequest_CertificateChain_Element::default_instance_ = new ClientDownloadRequest_CertificateChain_Element();
   ClientDownloadRequest_SignatureInfo::default_instance_ = new ClientDownloadRequest_SignatureInfo();
+  ClientDownloadRequest_PEImageHeaders::default_instance_ = new ClientDownloadRequest_PEImageHeaders();
+  ClientDownloadRequest_PEImageHeaders_DebugData::default_instance_ = new ClientDownloadRequest_PEImageHeaders_DebugData();
+  ClientDownloadRequest_ImageHeaders::default_instance_ = new ClientDownloadRequest_ImageHeaders();
   ClientDownloadResponse::default_instance_ = new ClientDownloadResponse();
   ClientDownloadResponse_MoreInfo::default_instance_ = new ClientDownloadResponse_MoreInfo();
-  ClientDownloadReport::default_instance_ = new ClientDownloadReport();
-  ClientDownloadReport_UserInformation::default_instance_ = new ClientDownloadReport_UserInformation();
-  ClientUploadResponse::default_instance_ = new ClientUploadResponse();
-  ClientPhishingRequest::default_instance_->InitAsDefaultInstance();
-  ClientPhishingRequest_Feature::default_instance_->InitAsDefaultInstance();
-  ClientPhishingResponse::default_instance_->InitAsDefaultInstance();
-  ClientMalwareRequest::default_instance_->InitAsDefaultInstance();
-  ClientMalwareRequest_Feature::default_instance_->InitAsDefaultInstance();
-  ClientMalwareResponse::default_instance_->InitAsDefaultInstance();
   ClientDownloadRequest::default_instance_->InitAsDefaultInstance();
   ClientDownloadRequest_Digests::default_instance_->InitAsDefaultInstance();
   ClientDownloadRequest_Resource::default_instance_->InitAsDefaultInstance();
   ClientDownloadRequest_CertificateChain::default_instance_->InitAsDefaultInstance();
   ClientDownloadRequest_CertificateChain_Element::default_instance_->InitAsDefaultInstance();
   ClientDownloadRequest_SignatureInfo::default_instance_->InitAsDefaultInstance();
+  ClientDownloadRequest_PEImageHeaders::default_instance_->InitAsDefaultInstance();
+  ClientDownloadRequest_PEImageHeaders_DebugData::default_instance_->InitAsDefaultInstance();
+  ClientDownloadRequest_ImageHeaders::default_instance_->InitAsDefaultInstance();
   ClientDownloadResponse::default_instance_->InitAsDefaultInstance();
   ClientDownloadResponse_MoreInfo::default_instance_->InitAsDefaultInstance();
-  ClientDownloadReport::default_instance_->InitAsDefaultInstance();
-  ClientDownloadReport_UserInformation::default_instance_->InitAsDefaultInstance();
-  ClientUploadResponse::default_instance_->InitAsDefaultInstance();
   ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_csd_2eproto);
 }
 
 // Force AddDescriptors() to be called at static initialization time.
 struct StaticDescriptorInitializer_csd_2eproto {
   StaticDescriptorInitializer_csd_2eproto() {
     protobuf_AddDesc_csd_2eproto();
   }
 } static_descriptor_initializer_csd_2eproto_;
 
 
 // ===================================================================
 
-#ifndef _MSC_VER
-const int ClientPhishingRequest_Feature::kNameFieldNumber;
-const int ClientPhishingRequest_Feature::kValueFieldNumber;
-#endif  // !_MSC_VER
-
-ClientPhishingRequest_Feature::ClientPhishingRequest_Feature()
-  : ::google::protobuf::MessageLite() {
-  SharedCtor();
-}
-
-void ClientPhishingRequest_Feature::InitAsDefaultInstance() {
-}
-
-ClientPhishingRequest_Feature::ClientPhishingRequest_Feature(const ClientPhishingRequest_Feature& from)
-  : ::google::protobuf::MessageLite() {
-  SharedCtor();
-  MergeFrom(from);
-}
-
-void ClientPhishingRequest_Feature::SharedCtor() {
-  _cached_size_ = 0;
-  name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
-  value_ = 0;
-  ::memset(_has_bits_, 0, sizeof(_has_bits_));
-}
-
-ClientPhishingRequest_Feature::~ClientPhishingRequest_Feature() {
-  SharedDtor();
-}
-
-void ClientPhishingRequest_Feature::SharedDtor() {
-  if (name_ != &::google::protobuf::internal::kEmptyString) {
-    delete name_;
-  }
-  if (this != default_instance_) {
-  }
-}
-
-void ClientPhishingRequest_Feature::SetCachedSize(int size) const {
-  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
-  _cached_size_ = size;
-  GOOGLE_SAFE_CONCURRENT_WRITES_END();
-}
-const ClientPhishingRequest_Feature& ClientPhishingRequest_Feature::default_instance() {
-  if (default_instance_ == NULL) protobuf_AddDesc_csd_2eproto();  return *default_instance_;
-}
-
-ClientPhishingRequest_Feature* ClientPhishingRequest_Feature::default_instance_ = NULL;
-
-ClientPhishingRequest_Feature* ClientPhishingRequest_Feature::New() const {
-  return new ClientPhishingRequest_Feature;
-}
-
-void ClientPhishingRequest_Feature::Clear() {
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
-    if (has_name()) {
-      if (name_ != &::google::protobuf::internal::kEmptyString) {
-        name_->clear();
-      }
-    }
-    value_ = 0;
-  }
-  ::memset(_has_bits_, 0, sizeof(_has_bits_));
-}
-
-bool ClientPhishingRequest_Feature::MergePartialFromCodedStream(
-    ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
-  ::google::protobuf::uint32 tag;
-  while ((tag = input->ReadTag()) != 0) {
-    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
-      // required string name = 1;
-      case 1: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
-          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
-                input, this->mutable_name()));
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectTag(17)) goto parse_value;
-        break;
-      }
-      
-      // required double value = 2;
-      case 2: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_FIXED64) {
-         parse_value:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   double, ::google::protobuf::internal::WireFormatLite::TYPE_DOUBLE>(
-                 input, &value_)));
-          set_has_value();
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectAtEnd()) return true;
-        break;
-      }
-      
-      default: {
-      handle_uninterpreted:
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
-          return true;
-        }
-        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
-        break;
-      }
-    }
-  }
-  return true;
-#undef DO_
-}
-
-void ClientPhishingRequest_Feature::SerializeWithCachedSizes(
-    ::google::protobuf::io::CodedOutputStream* output) const {
-  // required string name = 1;
-  if (has_name()) {
-    ::google::protobuf::internal::WireFormatLite::WriteString(
-      1, this->name(), output);
-  }
-  
-  // required double value = 2;
-  if (has_value()) {
-    ::google::protobuf::internal::WireFormatLite::WriteDouble(2, this->value(), output);
-  }
-  
-}
-
-int ClientPhishingRequest_Feature::ByteSize() const {
-  int total_size = 0;
-  
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
-    // required string name = 1;
-    if (has_name()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::StringSize(
-          this->name());
-    }
-    
-    // required double value = 2;
-    if (has_value()) {
-      total_size += 1 + 8;
-    }
-    
-  }
-  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
-  _cached_size_ = total_size;
-  GOOGLE_SAFE_CONCURRENT_WRITES_END();
-  return total_size;
-}
-
-void ClientPhishingRequest_Feature::CheckTypeAndMergeFrom(
-    const ::google::protobuf::MessageLite& from) {
-  MergeFrom(*::google::protobuf::down_cast<const ClientPhishingRequest_Feature*>(&from));
-}
-
-void ClientPhishingRequest_Feature::MergeFrom(const ClientPhishingRequest_Feature& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
-    if (from.has_name()) {
-      set_name(from.name());
-    }
-    if (from.has_value()) {
-      set_value(from.value());
-    }
-  }
-}
-
-void ClientPhishingRequest_Feature::CopyFrom(const ClientPhishingRequest_Feature& from) {
-  if (&from == this) return;
-  Clear();
-  MergeFrom(from);
-}
-
-bool ClientPhishingRequest_Feature::IsInitialized() const {
-  if ((_has_bits_[0] & 0x00000003) != 0x00000003) return false;
-  
-  return true;
-}
-
-void ClientPhishingRequest_Feature::Swap(ClientPhishingRequest_Feature* other) {
-  if (other != this) {
-    std::swap(name_, other->name_);
-    std::swap(value_, other->value_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
-}
-
-::std::string ClientPhishingRequest_Feature::GetTypeName() const {
-  return "safe_browsing.ClientPhishingRequest.Feature";
-}
-
-
-// -------------------------------------------------------------------
-
-#ifndef _MSC_VER
-const int ClientPhishingRequest::kUrlFieldNumber;
-const int ClientPhishingRequest::kOBSOLETEHashPrefixFieldNumber;
-const int ClientPhishingRequest::kClientScoreFieldNumber;
-const int ClientPhishingRequest::kIsPhishingFieldNumber;
-const int ClientPhishingRequest::kFeatureMapFieldNumber;
-const int ClientPhishingRequest::kModelVersionFieldNumber;
-const int ClientPhishingRequest::kNonModelFeatureMapFieldNumber;
-const int ClientPhishingRequest::kOBSOLETEReferrerUrlFieldNumber;
-#endif  // !_MSC_VER
-
-ClientPhishingRequest::ClientPhishingRequest()
-  : ::google::protobuf::MessageLite() {
-  SharedCtor();
-}
-
-void ClientPhishingRequest::InitAsDefaultInstance() {
-}
-
-ClientPhishingRequest::ClientPhishingRequest(const ClientPhishingRequest& from)
-  : ::google::protobuf::MessageLite() {
-  SharedCtor();
-  MergeFrom(from);
-}
-
-void ClientPhishingRequest::SharedCtor() {
-  _cached_size_ = 0;
-  url_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
-  obsolete_hash_prefix_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
-  client_score_ = 0;
-  is_phishing_ = false;
-  model_version_ = 0;
-  obsolete_referrer_url_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
-  ::memset(_has_bits_, 0, sizeof(_has_bits_));
-}
-
-ClientPhishingRequest::~ClientPhishingRequest() {
-  SharedDtor();
-}
-
-void ClientPhishingRequest::SharedDtor() {
-  if (url_ != &::google::protobuf::internal::kEmptyString) {
-    delete url_;
-  }
-  if (obsolete_hash_prefix_ != &::google::protobuf::internal::kEmptyString) {
-    delete obsolete_hash_prefix_;
-  }
-  if (obsolete_referrer_url_ != &::google::protobuf::internal::kEmptyString) {
-    delete obsolete_referrer_url_;
-  }
-  if (this != default_instance_) {
-  }
-}
-
-void ClientPhishingRequest::SetCachedSize(int size) const {
-  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
-  _cached_size_ = size;