Merge inbound to central, a=merge
authorWes Kocher <wkocher@mozilla.com>
Tue, 08 Aug 2017 15:14:28 -0700
changeset 642916 1d042bcb2632ea6a38fa08dbe21a6e8a0ee46961
parent 642885 be392d4638052977f11e3fdd7fe6aac78057351c (current diff)
parent 642828 99837e8b5a692ac96257d2bae03a3867c4c80e7e (diff)
child 642917 b624d1be6aec334f9dd5bf49b5649e3b2d229714
child 642931 8d74a95bad52cf912cd941413bf7fd868488f6df
child 642961 7a8936f1a4f42133145336d19d768f01c54ea477
child 642969 59d125bb4173491aa7d71c9bcb23a8e70851fd70
child 642970 634d6f9619f1edd797d794989f88aa769b4a2e90
child 642971 8097d7664e1627157dbb0e6818362596a3c6df9a
child 642975 2ecfb016244ed5b09987ca6f7f0eb743deef150e
child 642977 a847064e17e76e56037afdb8218642959db25b0a
child 642983 09a5bf19e709698865b0b903200f875da285268c
child 642998 dc5ac2c298a2f70cb7ba8c9f683a2e7ae27b4678
child 643036 b1ba78436cb0bd8e0e91ed103c6552f262ca68be
child 643040 9b1a8fe1cb7144f3e859af6b5ddc04f37d4332f6
child 643047 53c091b66934b541123539d0218e4ce34fc1c1ab
child 643049 c7624966d30330825b05f46c3c906cbcf9a00101
child 643050 c6702c7663b843c63868a44dd5001a167d7ce051
child 643061 a21ee5f096f6a264f1d109385962596f2280d8b3
child 643067 dd4d6c27c745911598c2741fce59da06bb3ccdcf
child 643068 eb39f60ba8e3d2372e16ecd4f17e1d7c9577412a
child 643071 cae708eacf3ba8ba94ea868b3835375839c25203
child 643073 d5c6358f88581dc6e6f20e6b80ae8835bde5b33a
child 643074 b141ae2756e6ff898448c5a9393aef5464cfb0b0
child 643079 1d21efce1cacb9d95df41e74d2e8e94d917d68a7
child 643082 7140e5e5f7ae24acd0fd1937bef2de05878f36cc
child 643098 cd2a5a3606843da36f60acde93b452c2ae581e19
child 643153 bd107e4bf104aad9b98aff57839452bbbf3baed4
child 643179 6bf67f5b2e5380d495f289fcd521e1dd0258e463
child 643183 c06c11634eaebafe4281b035a2e618531b9122e0
child 643187 ca1940f0a05187ab06b115dac9950a35dfcab3d5
child 643201 2c03e85a4d967c97a2c44f782e8d13eab657eb25
child 643251 06e23b933aa066319f156b121c0be6564db84fa3
child 643307 2f99b41553757d660cb0cd9d6946c7bf92bd5187
child 643310 8956b0ae224e0bd231f5cc2c1823b5dadbea116a
child 643374 f7eb1f632c0dc7fdbc6e4901137bac34b2e40bfc
child 643375 fbd85c7a439494d4cf99af94914fd87ffd893a06
child 643617 b89291dfe13be0685500fe411023cb3c6c47f6de
child 643692 f813757270f01dc087d5c9e6036da7a1e763525c
child 643776 e92ad59fc6fb3421de9c3e6b343dbe51b2a6dd10
child 643780 d35d827a8a47bc4970d219fa4a44ba07ff775e86
child 643784 5aec5320f57e7ca98a4c8496ff0f0a9cfdf414d3
child 643787 1a746acd619aaeed702e6e179a4874416c9ec887
child 643933 8947a801c12c0ea27a36cfc30f8fe3c55aa8779a
child 643954 5fcf17c07ff43bc036846752ba0383aeba476538
child 643957 bd3a7ab6c50829997d2164e30da95f1d3c8c25a8
child 644112 b11863591ad62175c87426eb4462c17106e7362d
child 644119 8654ed8c2dc94c1fdfbeade9049fd59cb6d6dbba
child 644241 2790f05cad67e5ba747468183e77be8184f2440d
child 644252 8e4e02bb47ec8ee9e798568395b75d51af4f485b
child 652876 8550366d7232421df2070f516646f566a1a18451
child 653992 5031e7124c5842ce28d8dab8e01fae6c1e9eca6f
child 654131 b74817f5ce4e74b8218044cd7cbc515d4b5757e1
push id72921
push userbmo:jld@mozilla.com
push dateWed, 09 Aug 2017 00:09:28 +0000
reviewersmerge
milestone57.0a1
Merge inbound to central, a=merge MozReview-Commit-ID: HpVAbc2vi78
toolkit/components/telemetry/TelemetryStorage.jsm
--- a/accessible/base/nsAccessibilityService.cpp
+++ b/accessible/base/nsAccessibilityService.cpp
@@ -925,16 +925,31 @@ nsAccessibilityService::GetStringEventTy
     aString.AssignLiteral("unknown");
     return;
   }
 
   CopyUTF8toUTF16(kEventTypeNames[aEventType], aString);
 }
 
 void
+nsAccessibilityService::GetStringEventType(uint32_t aEventType,
+                                           nsACString& aString)
+{
+  MOZ_ASSERT(nsIAccessibleEvent::EVENT_LAST_ENTRY == ArrayLength(kEventTypeNames),
+             "nsIAccessibleEvent constants are out of sync to kEventTypeNames");
+
+  if (aEventType >= ArrayLength(kEventTypeNames)) {
+    aString.AssignLiteral("unknown");
+    return;
+  }
+
+  aString = nsDependentCString(kEventTypeNames[aEventType]);
+}
+
+void
 nsAccessibilityService::GetStringRelationType(uint32_t aRelationType,
                                               nsAString& aString)
 {
   NS_ENSURE_TRUE_VOID(aRelationType <= static_cast<uint32_t>(RelationType::LAST));
 
 #define RELATIONTYPE(geckoType, geckoTypeName, atkType, msaaType, ia2Type) \
   case RelationType::geckoType: \
     aString.AssignLiteral(geckoTypeName); \
--- a/accessible/base/nsAccessibilityService.h
+++ b/accessible/base/nsAccessibilityService.h
@@ -119,16 +119,21 @@ public:
                        nsISupports **aStringStates);
 
   /**
    * Get a string equivalent for an accessible event value.
    */
   void GetStringEventType(uint32_t aEventType, nsAString& aString);
 
   /**
+   * Get a string equivalent for an accessible event value.
+   */
+  void GetStringEventType(uint32_t aEventType, nsACString& aString);
+
+  /**
    * Get a string equivalent for an accessible relation type.
    */
   void GetStringRelationType(uint32_t aRelationType, nsAString& aString);
 
   // nsAccesibilityService
   /**
    * Notification used to update the accessible tree when deck panel is
    * switched.
--- a/build/clang-plugin/Checks.inc
+++ b/build/clang-plugin/Checks.inc
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // The list of checker classes that are compatible with clang-tidy.
 
 CHECK(ArithmeticArgChecker, "arithmetic-argument")
 CHECK(AssertAssignmentChecker, "assignment-in-assert")
+CHECK(DanglingOnTemporaryChecker, "dangling-on-temporary")
 CHECK(ExplicitImplicitChecker, "implicit-constructor")
 CHECK(ExplicitOperatorBoolChecker, "explicit-operator-bool")
 CHECK(KungFuDeathGripChecker, "kungfu-death-grip")
 CHECK(MustOverrideChecker, "must-override")
 CHECK(MustReturnFromCallerChecker, "must-return-from-caller")
 CHECK(MustUseChecker, "must-use")
 CHECK(NaNExprChecker, "nan-expr")
 CHECK(NeedsNoVTableTypeChecker, "needs-no-vtable-type")
--- a/build/clang-plugin/ChecksIncludes.inc
+++ b/build/clang-plugin/ChecksIncludes.inc
@@ -2,16 +2,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/. */
 
 // The list of #include directives necessary for the checker classes that
 // are compatible with clang-tidy.
 
 #include "ArithmeticArgChecker.h"
 #include "AssertAssignmentChecker.h"
+#include "DanglingOnTemporaryChecker.h"
 #include "ExplicitImplicitChecker.h"
 #include "ExplicitOperatorBoolChecker.h"
 #include "KungFuDeathGripChecker.h"
 #include "MustOverrideChecker.h"
 #include "MustReturnFromCallerChecker.h"
 #include "MustUseChecker.h"
 #include "NaNExprChecker.h"
 #include "NeedsNoVTableTypeChecker.h"
--- a/build/clang-plugin/CustomMatchers.h
+++ b/build/clang-plugin/CustomMatchers.h
@@ -24,21 +24,50 @@ AST_MATCHER(Decl, noArithmeticExprInArgs
 }
 
 /// This matcher will match any C++ class that is marked as having a trivial
 /// constructor and destructor.
 AST_MATCHER(CXXRecordDecl, hasTrivialCtorDtor) {
   return hasCustomAnnotation(&Node, "moz_trivial_ctor_dtor");
 }
 
+/// This matcher will match lvalue-ref-qualified methods.
+AST_MATCHER(CXXMethodDecl, isLValueRefQualified) {
+  return Node.getRefQualifier() == RQ_LValue;
+}
+
+/// This matcher will match rvalue-ref-qualified methods.
+AST_MATCHER(CXXMethodDecl, isRValueRefQualified) {
+  return Node.getRefQualifier() == RQ_RValue;
+}
+
+AST_POLYMORPHIC_MATCHER(isFirstParty,                                          \
+                        AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt)) {
+  return !inThirdPartyPath(&Node, &Finder->getASTContext()) &&
+         !ASTIsInSystemHeader(Finder->getASTContext(), Node);
+}
+
+/// This matcher will match temporary expressions.
+/// We need this matcher for compatibility with clang 3.* (clang 4 and above
+/// insert a MaterializeTemporaryExpr everywhere).
+AST_MATCHER(Expr, isTemporary) {
+  return Node.isRValue() || Node.isXValue() ||
+         isa<MaterializeTemporaryExpr>(&Node);
+}
+
+/// This matcher will match any method declaration that is marked as returning
+/// a pointer deleted by the destructor of the class.
+AST_MATCHER(CXXMethodDecl, noDanglingOnTemporaries) {
+  return hasCustomAnnotation(&Node, "moz_no_dangling_on_temporaries");
+}
+
 /// This matcher will match any function declaration that is marked to prohibit
 /// calling AddRef or Release on its return value.
 AST_MATCHER(FunctionDecl, hasNoAddRefReleaseOnReturnAttr) {
-  return hasCustomAnnotation(&Node,
-                                         "moz_no_addref_release_on_return");
+  return hasCustomAnnotation(&Node, "moz_no_addref_release_on_return");
 }
 
 /// This matcher will match all arithmetic binary operators.
 AST_MATCHER(BinaryOperator, binaryArithmeticOperator) {
   BinaryOperatorKind OpCode = Node.getOpcode();
   return OpCode == BO_Mul || OpCode == BO_Div || OpCode == BO_Rem ||
          OpCode == BO_Add || OpCode == BO_Sub || OpCode == BO_Shl ||
          OpCode == BO_Shr || OpCode == BO_And || OpCode == BO_Xor ||
@@ -77,21 +106,17 @@ AST_MATCHER(QualType, isFloat) { return 
 /// with old clangs that we use on infra.
 AST_MATCHER(BinaryOperator, isInSystemHeader) {
   return ASTIsInSystemHeader(Finder->getASTContext(), Node);
 }
 
 /// This matcher will match a list of files.  These files contain
 /// known NaN-testing expressions which we would like to whitelist.
 AST_MATCHER(BinaryOperator, isInWhitelistForNaNExpr) {
-  const char* whitelist[] = {
-    "SkScalar.h",
-    "json_writer.cpp",
-    "State.cpp"
-  };
+  const char *whitelist[] = {"SkScalar.h", "json_writer.cpp", "State.cpp"};
 
   SourceLocation Loc = Node.getOperatorLoc();
   auto &SourceManager = Finder->getASTContext().getSourceManager();
   SmallString<1024> FileName = SourceManager.getFilename(Loc);
 
   for (auto itr = std::begin(whitelist); itr != std::end(whitelist); itr++) {
     if (llvm::sys::path::rbegin(FileName)->equals(*itr)) {
       return true;
@@ -150,16 +175,20 @@ AST_MATCHER(CXXConstructorDecl, isIntere
       Declaration->isConvertingConstructor(false) &&
       // We don't want copy of move constructors, as those are allowed to be
       // implicit
       !Declaration->isCopyOrMoveConstructor() &&
       // We don't want deleted constructors.
       !Declaration->isDeleted();
 }
 
+AST_MATCHER_P(Expr, ignoreTrivials, internal::Matcher<Expr>, InnerMatcher) {
+  return InnerMatcher.matches(*IgnoreTrivials(&Node), Finder, Builder);
+}
+
 // We can't call this "isImplicit" since it clashes with an existing matcher in
 // clang.
 AST_MATCHER(CXXConstructorDecl, isMarkedImplicit) {
   return hasCustomAnnotation(&Node, "moz_implicit");
 }
 
 AST_MATCHER(CXXRecordDecl, isConcreteClass) { return !Node.isAbstract(); }
 
@@ -179,57 +208,52 @@ AST_MATCHER(CXXConstructorDecl, isExplic
 AST_MATCHER(CXXConstructorDecl, isCompilerProvidedCopyConstructor) {
   return !Node.isUserProvided() && Node.isCopyConstructor();
 }
 
 AST_MATCHER(CallExpr, isAssertAssignmentTestFunc) {
   static const std::string AssertName = "MOZ_AssertAssignmentTest";
   const FunctionDecl *Method = Node.getDirectCallee();
 
-  return Method
-      && Method->getDeclName().isIdentifier()
-      && Method->getName() == AssertName;
+  return Method && Method->getDeclName().isIdentifier() &&
+         Method->getName() == AssertName;
 }
 
 AST_MATCHER(CallExpr, isSnprintfLikeFunc) {
   static const std::string Snprintf = "snprintf";
   static const std::string Vsnprintf = "vsnprintf";
   const FunctionDecl *Func = Node.getDirectCallee();
 
   if (!Func || isa<CXXMethodDecl>(Func)) {
     return false;
   }
 
   StringRef Name = getNameChecked(Func);
   if (Name != Snprintf && Name != Vsnprintf) {
     return false;
   }
 
-  return !isIgnoredPathForSprintfLiteral(&Node, Finder->getASTContext().getSourceManager());
+  return !isIgnoredPathForSprintfLiteral(
+      &Node, Finder->getASTContext().getSourceManager());
 }
 
-AST_MATCHER(CXXRecordDecl, isLambdaDecl) {
-  return Node.isLambda();
-}
+AST_MATCHER(CXXRecordDecl, isLambdaDecl) { return Node.isLambda(); }
 
-AST_MATCHER(QualType, isRefPtr) {
-  return typeIsRefPtr(Node);
-}
+AST_MATCHER(QualType, isRefPtr) { return typeIsRefPtr(Node); }
 
 AST_MATCHER(CXXRecordDecl, hasBaseClasses) {
   const CXXRecordDecl *Decl = Node.getCanonicalDecl();
 
   // Must have definition and should inherit other classes
   return Decl && Decl->hasDefinition() && Decl->getNumBases();
 }
 
 AST_MATCHER(CXXMethodDecl, isRequiredBaseMethod) {
   const CXXMethodDecl *Decl = Node.getCanonicalDecl();
-  return Decl
-      && hasCustomAnnotation(Decl, "moz_required_base_method");
+  return Decl && hasCustomAnnotation(Decl, "moz_required_base_method");
 }
 
 AST_MATCHER(CXXMethodDecl, isNonVirtual) {
   const CXXMethodDecl *Decl = Node.getCanonicalDecl();
   return Decl && !Decl->isVirtual();
 }
 
 AST_MATCHER(FunctionDecl, isMozMustReturnFromCaller) {
new file mode 100644
--- /dev/null
+++ b/build/clang-plugin/DanglingOnTemporaryChecker.cpp
@@ -0,0 +1,262 @@
+/* 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 "DanglingOnTemporaryChecker.h"
+#include "CustomMatchers.h"
+#include "VariableUsageHelpers.h"
+
+void DanglingOnTemporaryChecker::registerMatchers(MatchFinder *AstMatcher) {
+  ////////////////////////////////////////
+  // Quick annotation conflict checkers //
+  ////////////////////////////////////////
+
+  AstMatcher->addMatcher(
+      // This is a matcher on a method declaration,
+      cxxMethodDecl(
+          // which is marked as no dangling on temporaries,
+          noDanglingOnTemporaries(),
+
+          // and which is && ref-qualified.
+          isRValueRefQualified(),
+
+          decl().bind("invalidMethodRefQualified")),
+      this);
+
+  AstMatcher->addMatcher(
+      // This is a matcher on a method declaration,
+      cxxMethodDecl(
+          // which is marked as no dangling on temporaries,
+          noDanglingOnTemporaries(),
+
+          // which returns a primitive type,
+          returns(builtinType()),
+
+          // and which doesn't return a pointer.
+          unless(returns(pointerType())),
+
+          decl().bind("invalidMethodPointer")),
+      this);
+
+  //////////////////
+  // Main checker //
+  //////////////////
+
+  auto hasParentCall =
+      hasParent(expr(anyOf(
+          cxxOperatorCallExpr(
+              // If we're in a lamda, we may have an operator call expression
+              // ancestor in the AST, but the temporary we're matching
+              // against is not going to have the same lifetime as the
+              // constructor call.
+              unless(has(expr(ignoreTrivials(lambdaExpr())))),
+              expr().bind("parentOperatorCallExpr")),
+          callExpr(
+              // If we're in a lamda, we may have a call expression
+              // ancestor in the AST, but the temporary we're matching
+              // against is not going to have the same lifetime as the
+              // function call.
+              unless(has(expr(ignoreTrivials(lambdaExpr())))),
+              expr().bind("parentCallExpr")),
+          objcMessageExpr(
+              // If we're in a lamda, we may have an objc message expression
+              // ancestor in the AST, but the temporary we're matching
+              // against is not going to have the same lifetime as the
+              // function call.
+              unless(has(expr(ignoreTrivials(lambdaExpr())))),
+              expr().bind("parentObjCMessageExpr")),
+          cxxConstructExpr(
+              // If we're in a lamda, we may have a construct expression
+              // ancestor in the AST, but the temporary we're matching
+              // against is not going to have the same lifetime as the
+              // constructor call.
+              unless(has(expr(ignoreTrivials(lambdaExpr())))),
+              expr().bind("parentConstructExpr")))));
+
+  AstMatcher->addMatcher(
+      // This is a matcher on a method call,
+      cxxMemberCallExpr(
+          // which is in first party code,
+          isFirstParty(),
+
+          // and which is performed on a temporary,
+          on(allOf(
+              unless(hasType(pointerType())),
+              isTemporary(),
+              // but which is not `this`.
+              unless(cxxThisExpr()))),
+
+          // and which is marked as no dangling on temporaries.
+          callee(cxxMethodDecl(noDanglingOnTemporaries())),
+
+          expr().bind("memberCallExpr"),
+
+          // We optionally match a parent call expression or a parent construct
+          // expression because using a temporary inside a call is fine as long
+          // as the pointer doesn't escape the function call.
+          anyOf(
+              // This is the case where the call is the direct parent, so we
+              // know that the member call expression is the argument.
+              allOf(hasParentCall, expr().bind("parentCallArg")),
+
+              // This is the case where the call is not the direct parent, so we
+              // get its child to know in which argument tree we are.
+              hasAncestor(expr(
+                  hasParentCall,
+                  expr().bind("parentCallArg"))),
+              // To make it optional.
+              anything())),
+      this);
+}
+
+void DanglingOnTemporaryChecker::check(const MatchFinder::MatchResult &Result) {
+  ///////////////////////////////////////
+  // Quick annotation conflict checker //
+  ///////////////////////////////////////
+
+  const char *ErrorInvalidRefQualified = "methods annotated with "
+                                         "MOZ_NO_DANGLING_ON_TEMPORARIES "
+                                         "cannot be && ref-qualified";
+
+  const char *ErrorInvalidPointer = "methods annotated with "
+                                    "MOZ_NO_DANGLING_ON_TEMPORARIES must "
+                                    "return a pointer";
+
+  if (auto InvalidRefQualified =
+          Result.Nodes.getNodeAs<CXXMethodDecl>("invalidMethodRefQualified")) {
+    diag(InvalidRefQualified->getLocation(), ErrorInvalidRefQualified,
+         DiagnosticIDs::Error);
+    return;
+  }
+
+  if (auto InvalidPointer =
+          Result.Nodes.getNodeAs<CXXMethodDecl>("invalidMethodPointer")) {
+    diag(InvalidPointer->getLocation(), ErrorInvalidPointer,
+         DiagnosticIDs::Error);
+    return;
+  }
+
+  //////////////////
+  // Main checker //
+  //////////////////
+
+  const char *Error = "calling `%0` on a temporary, potentially allowing use "
+                      "after free of the raw pointer";
+
+  const char *EscapeStmtNote =
+      "the raw pointer escapes the function scope here";
+
+  const ObjCMessageExpr *ParentObjCMessageExpr =
+      Result.Nodes.getNodeAs<ObjCMessageExpr>("parentObjCMessageExpr");
+
+  // We don't care about cases in ObjC message expressions.
+  if (ParentObjCMessageExpr) {
+    return;
+  }
+
+  const CXXMemberCallExpr *MemberCall =
+      Result.Nodes.getNodeAs<CXXMemberCallExpr>("memberCallExpr");
+
+  const CallExpr *ParentCallExpr =
+      Result.Nodes.getNodeAs<CallExpr>("parentCallExpr");
+  const CXXConstructExpr *ParentConstructExpr =
+      Result.Nodes.getNodeAs<CXXConstructExpr>("parentConstructExpr");
+  const CXXOperatorCallExpr *ParentOperatorCallExpr =
+      Result.Nodes.getNodeAs<CXXOperatorCallExpr>("parentOperatorCallExpr");
+  const Expr *ParentCallArg =
+      Result.Nodes.getNodeAs<Expr>("parentCallArg");
+
+  // Just in case.
+  if (!MemberCall) {
+    return;
+  }
+
+  // If we have a parent call, we check whether or not we escape the function
+  // being called.
+  if (ParentOperatorCallExpr || ParentCallExpr || ParentConstructExpr) {
+    // Just in case.
+    if (!ParentCallArg) {
+      return;
+    }
+
+    // No default constructor so we can't construct it using if/else.
+    auto FunctionEscapeData
+        = ParentOperatorCallExpr
+            ? escapesFunction(ParentCallArg, ParentOperatorCallExpr)
+          : ParentCallExpr
+              ? escapesFunction(ParentCallArg, ParentCallExpr)
+          : escapesFunction(ParentCallArg, ParentConstructExpr);
+
+    // If there was an error in the escapesFunction call.
+    if (std::error_code ec = FunctionEscapeData.getError()) {
+      // FIXME: For now we ignore the variadic case and just consider that the
+      // argument doesn't escape the function. Same for the case where we can't
+      // find the function declaration or if the function is builtin.
+      if (static_cast<EscapesFunctionError>(ec.value()) ==
+          EscapesFunctionError::FunctionIsVariadic ||
+          static_cast<EscapesFunctionError>(ec.value()) ==
+          EscapesFunctionError::FunctionDeclNotFound ||
+          static_cast<EscapesFunctionError>(ec.value()) ==
+          EscapesFunctionError::FunctionIsBuiltin) {
+        return;
+      }
+
+      // We emit the internal checker error and return.
+      diag(MemberCall->getExprLoc(),
+           std::string(ec.category().name()) + " error: " + ec.message(),
+           DiagnosticIDs::Error);
+      return;
+    }
+
+    // We deconstruct the function escape data.
+    const Stmt *EscapeStmt;
+    const Decl *EscapeDecl;
+    std::tie(EscapeStmt, EscapeDecl) = *FunctionEscapeData;
+
+    // If we didn't escape a parent function, we're done: we don't emit any
+    // diagnostic.
+    if (!EscapeStmt || !EscapeDecl) {
+      return;
+    }
+
+    // We emit the error diagnostic indicating that we are calling the method
+    // temporary.
+    diag(MemberCall->getExprLoc(), Error, DiagnosticIDs::Error)
+        << MemberCall->getMethodDecl()->getName()
+        << MemberCall->getSourceRange();
+
+    // We indicate the escape statement.
+    diag(EscapeStmt->getLocStart(), EscapeStmtNote, DiagnosticIDs::Note)
+        << EscapeStmt->getSourceRange();
+
+    // We build the escape note along with its source range.
+    StringRef EscapeDeclNote;
+    SourceRange EscapeDeclRange;
+    if (isa<ParmVarDecl>(EscapeDecl)) {
+      EscapeDeclNote = "through the parameter declared here";
+      EscapeDeclRange = EscapeDecl->getSourceRange();
+    } else if (isa<VarDecl>(EscapeDecl)) {
+      EscapeDeclNote = "through the variable declared here";
+      EscapeDeclRange = EscapeDecl->getSourceRange();
+    } else if (isa<FieldDecl>(EscapeDecl)) {
+      EscapeDeclNote = "through the field declared here";
+      EscapeDeclRange = EscapeDecl->getSourceRange();
+    } else if (auto FuncDecl = dyn_cast<FunctionDecl>(EscapeDecl)) {
+      EscapeDeclNote = "through the return value of the function declared here";
+      EscapeDeclRange = FuncDecl->getReturnTypeSourceRange();
+    } else {
+      return;
+    }
+
+    // We emit the declaration note indicating through which decl the argument
+    // escapes.
+    diag(EscapeDecl->getLocation(), EscapeDeclNote, DiagnosticIDs::Note)
+        << EscapeDeclRange;
+  } else {
+    // We emit the error diagnostic indicating that we are calling the method
+    // temporary.
+    diag(MemberCall->getExprLoc(), Error, DiagnosticIDs::Error)
+        << MemberCall->getMethodDecl()->getName()
+        << MemberCall->getSourceRange();
+    }
+}
new file mode 100644
--- /dev/null
+++ b/build/clang-plugin/DanglingOnTemporaryChecker.h
@@ -0,0 +1,19 @@
+/* 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 DanglingOnTemporaryChecker_h__
+#define DanglingOnTemporaryChecker_h__
+
+#include "plugin.h"
+
+class DanglingOnTemporaryChecker : public BaseCheck {
+public:
+  DanglingOnTemporaryChecker(StringRef CheckName,
+                             ContextType *Context = nullptr)
+      : BaseCheck(CheckName, Context) {}
+  void registerMatchers(MatchFinder *AstMatcher) override;
+  void check(const MatchFinder::MatchResult &Result) override;
+};
+
+#endif
--- a/build/clang-plugin/Utils.h
+++ b/build/clang-plugin/Utils.h
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef Utils_h__
 #define Utils_h__
 
+#include "ThirdPartyPaths.h"
 #include "plugin.h"
-#include "ThirdPartyPaths.h"
 
 // Check if the given expression contains an assignment expression.
 // This can either take the form of a Binary Operator or a
 // Overloaded Operator Call.
 inline bool hasSideEffectAssignment(const Expr *Expression) {
   if (auto OpCallExpr = dyn_cast_or_null<CXXOperatorCallExpr>(Expression)) {
     auto BinOp = OpCallExpr->getOperator();
     if (BinOp == OO_Equal || (BinOp >= OO_PlusEqual && BinOp <= OO_PipeEqual)) {
@@ -29,27 +29,27 @@ inline bool hasSideEffectAssignment(cons
     if (ChildExpr && hasSideEffectAssignment(ChildExpr)) {
       return true;
     }
   }
 
   return false;
 }
 
-template <class T> inline bool ASTIsInSystemHeader(const ASTContext &AC, const T &D) {
+template <class T>
+inline bool ASTIsInSystemHeader(const ASTContext &AC, const T &D) {
   auto &SourceManager = AC.getSourceManager();
   auto ExpansionLoc = SourceManager.getExpansionLoc(D.getLocStart());
   if (ExpansionLoc.isInvalid()) {
     return false;
   }
   return SourceManager.isInSystemHeader(ExpansionLoc);
 }
 
-template<typename T>
-inline StringRef getNameChecked(const T& D) {
+template <typename T> inline StringRef getNameChecked(const T &D) {
   return D->getIdentifier() ? D->getName() : "";
 }
 
 /// A cached data of whether classes are refcounted or not.
 typedef DenseMap<const CXXRecordDecl *, std::pair<const Decl *, bool>>
     RefCountedMap;
 extern RefCountedMap RefCountedClasses;
 
@@ -224,17 +224,18 @@ inline bool isIgnoredPathForImplicitConv
       // Ignore security/sandbox/chromium but not ipc/chromium.
       ++Begin;
       return Begin != End && Begin->compare_lower(StringRef("sandbox")) == 0;
     }
   }
   return false;
 }
 
-inline bool isIgnoredPathForSprintfLiteral(const CallExpr *Call, const SourceManager &SM) {
+inline bool isIgnoredPathForSprintfLiteral(const CallExpr *Call,
+                                           const SourceManager &SM) {
   SourceLocation Loc = Call->getLocStart();
   SmallString<1024> FileName = SM.getFilename(Loc);
   llvm::sys::fs::make_absolute(FileName);
   llvm::sys::path::reverse_iterator Begin = llvm::sys::path::rbegin(FileName),
                                     End = llvm::sys::path::rend(FileName);
   for (; Begin != End; ++Begin) {
     if (Begin->compare_lower(StringRef("angle")) == 0 ||
         Begin->compare_lower(StringRef("chromium")) == 0 ||
@@ -315,18 +316,18 @@ inline const Stmt *IgnoreTrivials(const 
     if (!s) {
       return nullptr;
     } else if (auto *ewc = dyn_cast<ExprWithCleanups>(s)) {
       s = ewc->getSubExpr();
     } else if (auto *mte = dyn_cast<MaterializeTemporaryExpr>(s)) {
       s = mte->GetTemporaryExpr();
     } else if (auto *bte = dyn_cast<CXXBindTemporaryExpr>(s)) {
       s = bte->getSubExpr();
-    } else if (auto *ice = dyn_cast<ImplicitCastExpr>(s)) {
-      s = ice->getSubExpr();
+    } else if (auto *ce = dyn_cast<CastExpr>(s)) {
+      s = ce->getSubExpr();
     } else if (auto *pe = dyn_cast<ParenExpr>(s)) {
       s = pe->getSubExpr();
     } else {
       break;
     }
   }
 
   return s;
@@ -375,18 +376,17 @@ inline bool hasCustomAnnotation(const De
   return false;
 }
 
 inline bool isPlacementNew(const CXXNewExpr *Expression) {
   // Regular new expressions aren't placement new
   if (Expression->getNumPlacementArgs() == 0)
     return false;
   const FunctionDecl *Declaration = Expression->getOperatorNew();
-  if (Declaration && hasCustomAnnotation(Declaration,
-                 "moz_heap_allocator")) {
+  if (Declaration && hasCustomAnnotation(Declaration, "moz_heap_allocator")) {
     return false;
   }
   return true;
 }
 
 inline bool inThirdPartyPath(SourceLocation Loc, const SourceManager &SM) {
   SmallString<1024> FileName = SM.getFilename(Loc);
   llvm::sys::fs::make_absolute(FileName);
@@ -415,17 +415,47 @@ inline bool inThirdPartyPath(SourceLocat
         return true;
       }
     }
   }
 
   return false;
 }
 
-inline bool inThirdPartyPath(const Decl *D) {
+inline bool inThirdPartyPath(const Decl *D, ASTContext *context) {
   D = D->getCanonicalDecl();
   SourceLocation Loc = D->getLocation();
-  const SourceManager &SM = D->getASTContext().getSourceManager();
+  const SourceManager &SM = context->getSourceManager();
+
+  return inThirdPartyPath(Loc, SM);
+}
+
+inline bool inThirdPartyPath(const Decl *D) {
+  return inThirdPartyPath(D, &D->getASTContext());
+}
+
+inline bool inThirdPartyPath(const Stmt *S, ASTContext *context) {
+  SourceLocation Loc = S->getLocStart();
+  const SourceManager &SM = context->getSourceManager();
 
   return inThirdPartyPath(Loc, SM);
 }
 
+/// Polyfill for CXXOperatorCallExpr::isInfixBinaryOp()
+inline bool isInfixBinaryOp(const CXXOperatorCallExpr* OpCall) {
+#if CLANG_VERSION_FULL >= 400
+  return OpCall->isInfixBinaryOp();
+#else
+  // Taken from clang source.
+  if (OpCall->getNumArgs() != 2)
+     return false;
+
+  switch (OpCall->getOperator()) {
+   case OO_Call: case OO_Subscript:
+     return false;
+   default:
+     return true;
+  }
 #endif
+}
+
+
+#endif
new file mode 100644
--- /dev/null
+++ b/build/clang-plugin/VariableUsageHelpers.cpp
@@ -0,0 +1,279 @@
+#include "VariableUsageHelpers.h"
+#include "Utils.h"
+
+std::vector<const Stmt*>
+getUsageAsRvalue(const ValueDecl* ValueDeclaration,
+                 const FunctionDecl* FuncDecl) {
+  std::vector<const Stmt*> UsageStatements;
+
+  // We check the function declaration has a body.
+  auto Body = FuncDecl->getBody();
+  if (!Body) {
+    return std::vector<const Stmt*>();
+  }
+
+  // We build a Control Flow Graph (CFG) fron the body of the function
+  // declaration.
+  std::unique_ptr<CFG> StatementCFG
+      = CFG::buildCFG(FuncDecl, Body, &FuncDecl->getASTContext(),
+                      CFG::BuildOptions());
+
+  // We iterate through all the CFGBlocks, which basically means that we go over
+  // all the possible branches of the code and therefore cover all statements.
+  for (auto& Block : *StatementCFG) {
+    // We iterate through all the statements of the block.
+    for (auto& BlockItem : *Block) {
+      Optional<CFGStmt> CFGStatement = BlockItem.getAs<CFGStmt>();
+      if (!CFGStatement) {
+        continue;
+      }
+
+      // FIXME: Right now this function/if chain is very basic and only covers
+      // the cases we need for escapesFunction()
+      if (auto BinOp = dyn_cast<BinaryOperator>(CFGStatement->getStmt())) {
+        // We only care about assignments.
+        if (BinOp->getOpcode() != BO_Assign) {
+          continue;
+        }
+
+        // We want our declaration to be used on the right hand side of the
+        // assignment.
+        auto DeclRef = dyn_cast<DeclRefExpr>(IgnoreTrivials(BinOp->getRHS()));
+        if (!DeclRef) {
+          continue;
+        }
+
+        if (DeclRef->getDecl() != ValueDeclaration) {
+          continue;
+        }
+      } else if (auto Return = dyn_cast<ReturnStmt>(CFGStatement->getStmt())) {
+        // We want our declaration to be used as the expression of the return
+        // statement.
+        auto DeclRef = dyn_cast_or_null<DeclRefExpr>(
+                            IgnoreTrivials(Return->getRetValue()));
+        if (!DeclRef) {
+          continue;
+        }
+
+        if (DeclRef->getDecl() != ValueDeclaration) {
+          continue;
+        }
+      } else {
+        continue;
+      }
+
+      // We didn't early-continue, so we add the statement to the list.
+      UsageStatements.push_back(CFGStatement->getStmt());
+    }
+  }
+
+  return UsageStatements;
+}
+
+// We declare our EscapesFunctionError enum to be an error code enum.
+namespace std
+{
+  template <>
+    struct is_error_code_enum<EscapesFunctionError> : true_type {};
+}
+
+// We define the EscapesFunctionErrorCategory which contains the error messages
+// corresponding to each enum variant.
+namespace {
+  struct EscapesFunctionErrorCategory : std::error_category
+  {
+    const char* name() const noexcept override;
+    std::string message(int ev) const override;
+  };
+
+  const char* EscapesFunctionErrorCategory::name() const noexcept
+  {
+    return "escapes function";
+  }
+
+  std::string EscapesFunctionErrorCategory::message(int ev) const
+  {
+    switch (static_cast<EscapesFunctionError>(ev))
+    {
+    case EscapesFunctionError::ConstructorDeclNotFound:
+      return "constructor declaration not found";
+
+    case EscapesFunctionError::FunctionDeclNotFound:
+      return "function declaration not found";
+
+    case EscapesFunctionError::FunctionIsBuiltin:
+      return "function is builtin";
+
+    case EscapesFunctionError::FunctionIsVariadic:
+      return "function is variadic";
+
+    case EscapesFunctionError::ExprNotInCall:
+      return "expression is not in call";
+
+    case EscapesFunctionError::NoParamForArg:
+      return "no parameter for argument";
+
+    case EscapesFunctionError::ArgAndParamNotPointers:
+      return "argument and parameter are not pointers";
+    }
+  }
+
+  const EscapesFunctionErrorCategory TheEscapesFunctionErrorCategory {};
+}
+
+std::error_code make_error_code(EscapesFunctionError e)
+{
+  return {static_cast<int>(e), TheEscapesFunctionErrorCategory};
+}
+
+ErrorOr<std::tuple<const Stmt*, const Decl*>>
+escapesFunction(const Expr* Arg, const CXXConstructExpr* Construct) {
+  // We get the function declaration corresponding to the call.
+  auto CtorDecl = Construct->getConstructor();
+  if (!CtorDecl) {
+    return EscapesFunctionError::ConstructorDeclNotFound;
+  }
+
+  return escapesFunction(Arg, CtorDecl, Construct->getArgs(),
+                         Construct->getNumArgs());
+}
+
+ErrorOr<std::tuple<const Stmt*, const Decl*>>
+escapesFunction(const Expr* Arg, const CallExpr* Call) {
+  // We get the function declaration corresponding to the call.
+  auto FuncDecl = Call->getDirectCallee();
+  if (!FuncDecl) {
+    return EscapesFunctionError::FunctionDeclNotFound;
+  }
+
+  return escapesFunction(Arg, FuncDecl, Call->getArgs(), Call->getNumArgs());
+}
+
+ErrorOr<std::tuple<const Stmt*, const Decl*>>
+escapesFunction(const Expr* Arg, const CXXOperatorCallExpr* OpCall) {
+  // We get the function declaration corresponding to the operator call.
+  auto FuncDecl = OpCall->getDirectCallee();
+  if (!FuncDecl) {
+    return EscapesFunctionError::FunctionDeclNotFound;
+  }
+
+  auto Args = OpCall->getArgs();
+  auto NumArgs = OpCall->getNumArgs();
+  // If this is an infix binary operator defined as a one-param method, we
+  // remove the first argument as it is inserted explicitly and creates a
+  // mismatch with the parameters of the method declaration.
+  if (isInfixBinaryOp(OpCall) && FuncDecl->getNumParams() == 1) {
+    Args++;
+    NumArgs--;
+  }
+
+  return escapesFunction(Arg, FuncDecl, Args, NumArgs);
+}
+
+ErrorOr<std::tuple<const Stmt*, const Decl*>>
+escapesFunction(const Expr* Arg, const FunctionDecl *FuncDecl,
+                const Expr* const* Arguments, unsigned NumArgs) {
+  if (!NumArgs) {
+    return std::make_tuple((const Stmt*)nullptr, (const Decl*)nullptr);
+  }
+
+  if (FuncDecl->getBuiltinID() != 0 ||
+      ASTIsInSystemHeader(FuncDecl->getASTContext(), *FuncDecl)) {
+    return EscapesFunctionError::FunctionIsBuiltin;
+  }
+
+  // FIXME: should probably be handled at some point, but it's too annoying
+  // for now.
+  if (FuncDecl->isVariadic()) {
+    return EscapesFunctionError::FunctionIsVariadic;
+  }
+
+  // We find the argument number corresponding to the Arg expression.
+  unsigned ArgNum = 0;
+  for (unsigned i = 0; i < NumArgs; i++) {
+    if (IgnoreTrivials(Arg) == IgnoreTrivials(Arguments[i])) {
+      break;
+    }
+    ++ArgNum;
+  }
+  // If we don't find it, we early-return NoneType.
+  if (ArgNum >= NumArgs) {
+    return EscapesFunctionError::ExprNotInCall;
+  }
+
+  // Now we get the associated parameter.
+  if (ArgNum >= FuncDecl->getNumParams()) {
+    return EscapesFunctionError::NoParamForArg;
+  }
+  auto Param = FuncDecl->getParamDecl(ArgNum);
+
+  // We want both the argument and the parameter to be of pointer type.
+  // FIXME: this is enough for the DanglingOnTemporaryChecker, because the
+  // analysed methods only return pointers, but more cases should probably be
+  // handled when we want to use this function more broadly.
+  if ((!Arg->getType().getNonReferenceType()->isPointerType() &&
+       Arg->getType().getNonReferenceType()->isBuiltinType()) ||
+      (!Param->getType().getNonReferenceType()->isPointerType() &&
+       Param->getType().getNonReferenceType()->isBuiltinType())) {
+    return EscapesFunctionError::ArgAndParamNotPointers;
+  }
+
+  // We retrieve the usages of the parameter in the function.
+  auto Usages = getUsageAsRvalue(Param, FuncDecl);
+
+  // For each usage, we check if it doesn't allow the parameter to escape the
+  // function scope.
+  for (auto Usage : Usages) {
+    // In the case of an assignment.
+    if (auto BinOp = dyn_cast<BinaryOperator>(Usage)) {
+      // We retrieve the declaration the parameter is assigned to.
+      auto DeclRef = dyn_cast<DeclRefExpr>(BinOp->getLHS());
+      if (!DeclRef) {
+        continue;
+      }
+
+      if (auto ParamDeclaration = dyn_cast<ParmVarDecl>(DeclRef->getDecl())) {
+        // This is the case where the parameter escapes through another
+        // parameter.
+
+        // FIXME: for now we only care about references because we only detect
+        // trivial LHS with just a DeclRefExpr, and not more complex cases like:
+        // void func(Type* param1, Type** param2) {
+        //   *param2 = param1;
+        // }
+        // This should be fixed when we have better/more helper functions to
+        // help deal with this kind of lvalue expressions.
+        if (!ParamDeclaration->getType()->isReferenceType()) {
+          continue;
+        }
+
+        return std::make_tuple(Usage, (const Decl*)ParamDeclaration);
+      } else if (auto VarDeclaration = dyn_cast<VarDecl>(DeclRef->getDecl())) {
+        // This is the case where the parameter escapes through a global/static
+        // variable.
+        if (!VarDeclaration->hasGlobalStorage()) {
+          continue;
+        }
+
+        return std::make_tuple(Usage, (const Decl*)VarDeclaration);
+      } else if (auto FieldDeclaration = dyn_cast<FieldDecl>(DeclRef->getDecl())) {
+        // This is the case where the parameter escapes through a field.
+
+        return std::make_tuple(Usage, (const Decl*)FieldDeclaration);
+      }
+    } else if (isa<ReturnStmt>(Usage)) {
+      // This is the case where the parameter escapes through the return value
+      // of the function.
+      if (!FuncDecl->getReturnType()->isPointerType()
+          && !FuncDecl->getReturnType()->isReferenceType()) {
+        continue;
+      }
+
+      return std::make_tuple(Usage, (const Decl*)FuncDecl);
+    }
+  }
+
+  // No early-return, this means that we haven't found any case of funciton
+  // escaping and that therefore the parameter remains in the function scope.
+  return std::make_tuple((const Stmt*)nullptr, (const Decl*)nullptr);
+}
new file mode 100644
--- /dev/null
+++ b/build/clang-plugin/VariableUsageHelpers.h
@@ -0,0 +1,65 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+#ifndef VariableUsageHelpers_h__
+#define VariableUsageHelpers_h__
+
+#include "plugin.h"
+
+/// Returns a list of the statements where the given declaration is used as an
+/// rvalue (within the provided function).
+///
+/// WARNING: incomplete behaviour/implementation for general-purpose use outside
+/// of escapesFunction(). This only detects very basic usages (see
+/// implementation for more details).
+std::vector<const Stmt*>
+getUsageAsRvalue(const ValueDecl* ValueDeclaration,
+                 const FunctionDecl* FuncDecl);
+
+/// This is the error enumeration for escapesFunction(), describing all the
+/// possible error cases.
+enum class EscapesFunctionError {
+  ConstructorDeclNotFound = 1,
+  FunctionDeclNotFound,
+  FunctionIsBuiltin,
+  FunctionIsVariadic,
+  ExprNotInCall,
+  NoParamForArg,
+  ArgAndParamNotPointers
+};
+
+/// Required by the std::error_code system to convert our enum into a general
+/// error code.
+std::error_code make_error_code(EscapesFunctionError);
+
+/// Returns a (statement, decl) tuple if an argument from an argument list
+/// escapes the function scope through globals/statics/other things. The
+/// statement is where the value escapes the function, while the declaration
+/// points to what it escapes through. If the argument doesn't escape the
+/// function, the tuple will only contain nullptrs.
+/// If the analysis runs into an unexpected error or into an unimplemented
+/// configuration, it will return an error_code of type EscapesFunctionError
+/// representing the precise issue.
+///
+/// WARNING: incomplete behaviour/implementation for general-purpose use outside
+/// of DanglingOnTemporaryChecker. This only covers a limited set of cases,
+/// mainly in terms of arguments and parameter types.
+ErrorOr<std::tuple<const Stmt*, const Decl*>>
+escapesFunction(const Expr* Arg, const FunctionDecl *FuncDecl,
+                const Expr* const* Arguments, unsigned NumArgs);
+
+/// Helper function taking a call expression.
+ErrorOr<std::tuple<const Stmt*, const Decl*>>
+escapesFunction(const Expr* Arg, const CallExpr* Call);
+
+/// Helper function taking a construct expression.
+ErrorOr<std::tuple<const Stmt*, const Decl*>>
+escapesFunction(const Expr* Arg, const CXXConstructExpr* Construct);
+
+/// Helper function taking an operator call expression.
+ErrorOr<std::tuple<const Stmt*, const Decl*>>
+escapesFunction(const Expr* Arg, const CXXOperatorCallExpr* OpCall);
+
+#endif
--- a/build/clang-plugin/moz.build
+++ b/build/clang-plugin/moz.build
@@ -7,16 +7,17 @@
 SharedLibrary('clang-plugin')
 
 SOURCES += ['!ThirdPartyPaths.cpp']
 
 UNIFIED_SOURCES += [
     'ArithmeticArgChecker.cpp',
     'AssertAssignmentChecker.cpp',
     'CustomTypeAnnotation.cpp',
+    'DanglingOnTemporaryChecker.cpp',
     'DiagnosticsMatcher.cpp',
     'ExplicitImplicitChecker.cpp',
     'ExplicitOperatorBoolChecker.cpp',
     'KungFuDeathGripChecker.cpp',
     'MozCheckAction.cpp',
     'MustOverrideChecker.cpp',
     'MustReturnFromCallerChecker.cpp',
     'MustUseChecker.cpp',
@@ -31,16 +32,17 @@ UNIFIED_SOURCES += [
     'NonParamInsideFunctionDeclChecker.cpp',
     'OverrideBaseCallChecker.cpp',
     'OverrideBaseCallUsageChecker.cpp',
     'RefCountedCopyConstructorChecker.cpp',
     'RefCountedInsideLambdaChecker.cpp',
     'ScopeChecker.cpp',
     'SprintfLiteralChecker.cpp',
     'TrivialCtorDtorChecker.cpp',
+    'VariableUsageHelpers.cpp',
 ]
 
 GENERATED_FILES += ['ThirdPartyPaths.cpp']
 third_party_paths = GENERATED_FILES['ThirdPartyPaths.cpp']
 third_party_paths.script = "ThirdPartyPaths.py:generate"
 third_party_paths.inputs = [
     '/tools/rewriting/ThirdPartyPaths.txt',
 ]
new file mode 100644
--- /dev/null
+++ b/build/clang-plugin/tests/TestDanglingOnTemporary.cpp
@@ -0,0 +1,45 @@
+#define MOZ_NO_DANGLING_ON_TEMPORARIES                                              \
+  __attribute__((annotate("moz_no_dangling_on_temporaries")))
+
+class AnnotateConflict {
+  MOZ_NO_DANGLING_ON_TEMPORARIES int *get() && { return nullptr; } // expected-error {{methods annotated with MOZ_NO_DANGLING_ON_TEMPORARIES cannot be && ref-qualified}}
+  MOZ_NO_DANGLING_ON_TEMPORARIES int test() { return 0; } // expected-error {{methods annotated with MOZ_NO_DANGLING_ON_TEMPORARIES must return a pointer}}
+};
+
+class NS_ConvertUTF8toUTF16 {
+public:
+  MOZ_NO_DANGLING_ON_TEMPORARIES int *get() { return nullptr; }
+  operator int*()
+  {
+    return get(); // This should be ignored because the call is implcitly on this
+  }
+};
+
+NS_ConvertUTF8toUTF16 TemporaryFunction() { return NS_ConvertUTF8toUTF16(); }
+
+void UndefinedFunction(int* test);
+
+void NoEscapeFunction(int *test) {}
+
+int *glob; // expected-note {{through the variable declared here}}
+void EscapeFunction1(int *test) { glob = test; } // expected-note {{the raw pointer escapes the function scope here}}
+
+void EscapeFunction2(int *test, int *&escape) { escape = test; } // expected-note {{the raw pointer escapes the function scope here}} \
+                                                                    expected-note {{through the parameter declared here}}
+
+int *EscapeFunction3(int *test) { return test; } // expected-note {{the raw pointer escapes the function scope here}} \
+                                                    expected-note {{through the return value of the function declared here}}
+
+int main() {
+  int *test = TemporaryFunction().get(); // expected-error {{calling `get` on a temporary, potentially allowing use after free of the raw pointer}}
+  int *test2 = NS_ConvertUTF8toUTF16().get(); // expected-error {{calling `get` on a temporary, potentially allowing use after free of the raw pointer}}
+
+  UndefinedFunction(NS_ConvertUTF8toUTF16().get());
+
+  NoEscapeFunction(TemporaryFunction().get());
+  EscapeFunction1(TemporaryFunction().get()); // expected-error {{calling `get` on a temporary, potentially allowing use after free of the raw pointer}}
+
+  int *escape;
+  EscapeFunction2(TemporaryFunction().get(), escape); // expected-error {{calling `get` on a temporary, potentially allowing use after free of the raw pointer}}
+  int *escape2 = EscapeFunction3(TemporaryFunction().get()); // expected-error {{calling `get` on a temporary, potentially allowing use after free of the raw pointer}}
+}
--- a/build/clang-plugin/tests/moz.build
+++ b/build/clang-plugin/tests/moz.build
@@ -6,16 +6,17 @@
 
 # dummy library name to avoid skipping building the sources here.
 Library('clang-plugin-tests')
 
 SOURCES += [
     'TestAssertWithAssignment.cpp',
     'TestBadImplicitConversionCtor.cpp',
     'TestCustomHeap.cpp',
+    'TestDanglingOnTemporary.cpp',
     'TestExplicitOperatorBool.cpp',
     'TestGlobalClass.cpp',
     'TestHeapClass.cpp',
     'TestInheritTypeAnnotationsFromTemplateArgs.cpp',
     'TestKungFuDeathGrip.cpp',
     'TestMultipleAnnotations.cpp',
     'TestMustOverride.cpp',
     'TestMustReturnFromCaller.cpp',
--- a/devtools/client/preferences/debugger.js
+++ b/devtools/client/preferences/debugger.js
@@ -15,17 +15,17 @@ pref("devtools.debugger.ignore-caught-ex
 pref("devtools.debugger.source-maps-enabled", true);
 pref("devtools.debugger.client-source-maps-enabled", true);
 pref("devtools.debugger.pretty-print-enabled", true);
 pref("devtools.debugger.auto-pretty-print", false);
 pref("devtools.debugger.auto-black-box", true);
 pref("devtools.debugger.workers", false);
 
 // The default Debugger UI settings
-pref("devtools.debugger.prefs-schema-version", "1.0.2");
+pref("devtools.debugger.prefs-schema-version", "1.0.0");
 pref("devtools.debugger.ui.panes-workers-and-sources-width", 200);
 pref("devtools.debugger.ui.panes-instruments-width", 300);
 pref("devtools.debugger.ui.panes-visible-on-startup", false);
 pref("devtools.debugger.ui.variables-sorting-enabled", true);
 pref("devtools.debugger.ui.variables-only-enum-visible", false);
 pref("devtools.debugger.ui.variables-searchbox-visible", false);
 pref("devtools.debugger.ui.framework-grouping-on", true);
 pref("devtools.debugger.call-stack-visible", false);
--- a/devtools/server/actors/webextension.js
+++ b/devtools/server/actors/webextension.js
@@ -331,16 +331,26 @@ WebExtensionChildActor.prototype._allowS
 /**
  * Return true if the given global is associated with this addon and should be
  * added as a debuggee, false otherwise.
  */
 WebExtensionChildActor.prototype._shouldAddNewGlobalAsDebuggee = function (newGlobal) {
   const global = unwrapDebuggerObjectGlobal(newGlobal);
 
   if (global instanceof Ci.nsIDOMWindow) {
+    try {
+      global.document;
+    } catch (e) {
+      // The global might be a sandbox with a window object in its proto chain. If the
+      // window navigated away since the sandbox was created, it can throw a security
+      // exception during this property check as the sandbox no longer has access to
+      // its own proto.
+      return false;
+    }
+
     // Filter out any global which contains a XUL document.
     if (global.document instanceof Ci.nsIDOMXULDocument) {
       return false;
     }
 
     // Change top level document as a simulated frame switching.
     if (global.document.ownerGlobal && this.isExtensionWindow(global)) {
       this._onNewExtensionWindow(global.document.ownerGlobal);
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -1300,17 +1300,17 @@ nsDocShell::LoadURI(nsIURI* aURI,
   nsCOMPtr<nsIInputStream> headersStream;
   nsCOMPtr<nsIPrincipal> triggeringPrincipal;
   bool inheritPrincipal = false;
   bool principalIsExplicit = false;
   bool sendReferrer = true;
   uint32_t referrerPolicy = mozilla::net::RP_Unset;
   bool isSrcdoc = false;
   nsCOMPtr<nsISHEntry> shEntry;
-  nsXPIDLString target;
+  nsString target;
   nsAutoString srcdoc;
   nsCOMPtr<nsIDocShell> sourceDocShell;
   nsCOMPtr<nsIURI> baseURI;
 
   uint32_t loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);
 
   NS_ENSURE_ARG(aURI);
 
@@ -4283,17 +4283,16 @@ nsDocShell::FindChildWithName(const nsAS
 
   // if we don't find one, we return NS_OK and a null result
   *aResult = nullptr;
 
   if (aName.IsEmpty()) {
     return NS_OK;
   }
 
-  nsXPIDLString childName;
   nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
   while (iter.HasMore()) {
     nsCOMPtr<nsIDocShellTreeItem> child = do_QueryObject(iter.GetNext());
     NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
     int32_t childType = child->ItemType();
 
     if (aSameType && (childType != mItemType)) {
       continue;
--- a/docshell/base/nsDocShellTreeOwner.cpp
+++ b/docshell/base/nsDocShellTreeOwner.cpp
@@ -1377,39 +1377,36 @@ ChromeTooltipListener::sTooltipCallback(
       // release tooltip target if there is one, NO MATTER WHAT
       self->mPossibleTooltipNode = nullptr;
       return;
     }
 
     // if there is text associated with the node, show the tip and fire
     // off a timer to auto-hide it.
 
-    nsXPIDLString tooltipText;
-    nsXPIDLString directionText;
     if (self->mTooltipTextProvider) {
+      nsString tooltipText;
+      nsString directionText;
       bool textFound = false;
-
       self->mTooltipTextProvider->GetNodeText(
         self->mPossibleTooltipNode, getter_Copies(tooltipText),
         getter_Copies(directionText), &textFound);
 
       if (textFound) {
-        nsString tipText(tooltipText);
-        nsString dirText(directionText);
         LayoutDeviceIntPoint screenDot = widget->WidgetToScreenOffset();
         double scaleFactor = 1.0;
         if (shell->GetPresContext()) {
           nsDeviceContext* dc = shell->GetPresContext()->DeviceContext();
           scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel()) /
                         dc->AppUnitsPerDevPixelAtUnitFullZoom();
         }
         // ShowTooltip expects widget-relative position.
         self->ShowTooltip(self->mMouseScreenX - screenDot.x / scaleFactor,
                           self->mMouseScreenY - screenDot.y / scaleFactor,
-                          tipText, dirText);
+                          tooltipText, directionText);
       }
     }
 
     // release tooltip target if there is one, NO MATTER WHAT
     self->mPossibleTooltipNode = nullptr;
   }
 }
 
--- a/docshell/shistory/nsSHistory.cpp
+++ b/docshell/shistory/nsSHistory.cpp
@@ -699,17 +699,17 @@ nsSHistory::PrintHistory()
     nsCOMPtr<nsISHEntry> entry;
     rv = txn->GetSHEntry(getter_AddRefs(entry));
     if (NS_FAILED(rv) && !entry) {
       return NS_ERROR_FAILURE;
     }
 
     nsCOMPtr<nsILayoutHistoryState> layoutHistoryState;
     nsCOMPtr<nsIURI> uri;
-    nsXPIDLString title;
+    nsString title;
 
     entry->GetLayoutHistoryState(getter_AddRefs(layoutHistoryState));
     entry->GetURI(getter_AddRefs(uri));
     entry->GetTitle(getter_Copies(title));
 
 #if 0
     nsAutoCString url;
     if (uri) {
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -13319,17 +13319,17 @@ nsGlobalWindow::SecurityCheckURL(const c
   if (doc) {
     baseURI = doc->GetDocBaseURI();
     encoding = doc->GetDocumentCharacterSet();
   }
   nsCOMPtr<nsIURI> uri;
   nsresult rv = NS_NewURI(getter_AddRefs(uri), nsDependentCString(aURL),
                           encoding, baseURI);
   if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
+    return NS_ERROR_DOM_SYNTAX_ERR;
   }
 
   if (NS_FAILED(nsContentUtils::GetSecurityManager()->
         CheckLoadURIFromScript(cx, uri))) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
--- a/dom/bindings/test/test_exceptionSanitization.html
+++ b/dom/bindings/test/test_exceptionSanitization.html
@@ -28,17 +28,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     // NOTE: The idea here is to call something that will end up throwing an
     // exception in a JS component and then propagate back to C++ code before
     // returning to us.  If opening a feed: URI stops doing that, we will need a
     // new guinea pig here.
     open('feed://java:script:codeshouldgohere','eWin');
     ok(false, "Should have thrown!");
   } catch(e){
     try {
-      is(e.name, "NS_ERROR_UNEXPECTED", "Should have the right exception");
+      is(e.name, "SyntaxError", "Should have the right exception");
       is(e.filename, location.href,
          "Should not be seeing where the exception really came from");
     } catch (e2) {
       ok(false, "Should be able to work with the exception");
     }
   }
   </script>
 </body>
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -1191,24 +1191,29 @@ public:
                                 nsIChannel::LOAD_CALL_CONTENT_SNIFFERS);
 
     if (NS_FAILED(rv)) {
       // Notify load error so the element will try next resource candidate.
       aElement->NotifyLoadError();
       return;
     }
 
-    nsCOMPtr<nsIClassOfService> cos;
-    if (aElement->mUseUrgentStartForChannel &&
-        (cos = do_QueryInterface(channel))) {
-      cos->AddClassFlags(nsIClassOfService::UrgentStart);
-
-      // Reset the flag to avoid loading again without initiated by user
-      // interaction.
-      aElement->mUseUrgentStartForChannel = false;
+    nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
+    if (cos) {
+      if (aElement->mUseUrgentStartForChannel) {
+        cos->AddClassFlags(nsIClassOfService::UrgentStart);
+
+        // Reset the flag to avoid loading again without initiated by user
+        // interaction.
+        aElement->mUseUrgentStartForChannel = false;
+      }
+
+      // Unconditionally disable throttling since we want the media to fluently
+      // play even when we switch the tab to background.
+      cos->AddClassFlags(nsIClassOfService::DontThrottle);
     }
 
     // The listener holds a strong reference to us.  This creates a
     // reference cycle, once we've set mChannel, which is manually broken
     // in the listener's OnStartRequest method after it is finished with
     // the element. The cycle will also be broken if we get a shutdown
     // notification before OnStartRequest fires.  Necko guarantees that
     // OnStartRequest will eventually fire if we don't shut down first.
--- a/dom/html/HTMLMetaElement.cpp
+++ b/dom/html/HTMLMetaElement.cpp
@@ -98,17 +98,17 @@ HTMLMetaElement::BindToTree(nsIDocument*
   if (aDocument &&
       AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, nsGkAtoms::viewport, eIgnoreCase)) {
     nsAutoString content;
     rv = GetContent(content);
     NS_ENSURE_SUCCESS(rv, rv);
     nsContentUtils::ProcessViewportInfo(aDocument, content);
   }
 
-  if (CSPService::sCSPEnabled && aDocument &&
+  if (CSPService::sCSPEnabled && aDocument && !aDocument->IsLoadedAsData() &&
       AttrValueIs(kNameSpaceID_None, nsGkAtoms::httpEquiv, nsGkAtoms::headerCSP, eIgnoreCase)) {
 
     // only accept <meta http-equiv="Content-Security-Policy" content=""> if it appears
     // in the <head> element.
     Element* headElt = aDocument->GetHeadElement();
     if (headElt && nsContentUtils::ContentIsDescendantOf(this, headElt)) {
 
       nsAutoString content;
--- a/dom/html/MediaDocument.cpp
+++ b/dom/html/MediaDocument.cpp
@@ -356,17 +356,17 @@ MediaDocument::LinkScript(const nsAStrin
 
 void
 MediaDocument::UpdateTitleAndCharset(const nsACString& aTypeStr,
                                      nsIChannel* aChannel,
                                      const char* const* aFormatNames,
                                      int32_t aWidth, int32_t aHeight,
                                      const nsAString& aStatus)
 {
-  nsXPIDLString fileStr;
+  nsAutoString fileStr;
   GetFileName(fileStr, aChannel);
 
   NS_ConvertASCIItoUTF16 typeStr(aTypeStr);
   nsAutoString title;
 
   if (mStringBundle) {
     // if we got a valid size (not all media have a size)
     if (aWidth != 0 && aHeight != 0) {
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -444,17 +444,17 @@ ConsoleListener::Observe(nsIConsoleMessa
     rv = scriptError->GetFlags(&flags);
     NS_ENSURE_SUCCESS(rv, rv);
 
     mChild->SendScriptError(msg, sourceName, sourceLine,
                             lineNum, colNum, flags, category);
     return NS_OK;
   }
 
-  nsXPIDLString msg;
+  nsString msg;
   nsresult rv = aMessage->GetMessageMoz(getter_Copies(msg));
   NS_ENSURE_SUCCESS(rv, rv);
   mChild->SendConsoleMessage(msg);
   return NS_OK;
 }
 
 class BackgroundChildPrimer final :
   public nsIIPCBackgroundChildCreateCallback
@@ -486,17 +486,16 @@ NS_IMPL_ISUPPORTS(BackgroundChildPrimer,
 ContentChild* ContentChild::sSingleton;
 
 ContentChild::ContentChild()
  : mID(uint64_t(-1))
 #if defined(XP_WIN) && defined(ACCESSIBILITY)
  , mMainChromeTid(0)
  , mMsaaID(0)
 #endif
- , mCanOverrideProcessName(true)
  , mIsAlive(true)
  , mShuttingDown(false)
 {
   // This process is a content process, so it's clearly running in
   // multiprocess mode!
   nsDebugImpl::SetMultiprocessMode("Child");
 }
 
@@ -622,28 +621,24 @@ ContentChild::Init(MessageLoop* aIOLoop,
 
 #ifdef MOZ_CRASHREPORTER
   CrashReporterClient::InitSingleton(this);
 #endif
 
   mID = aChildID;
   mIsForBrowser = aIsForBrowser;
 
-  SetProcessName(NS_LITERAL_STRING("Web Content"), true);
+  SetProcessName(NS_LITERAL_STRING("Web Content"));
 
   return true;
 }
 
 void
-ContentChild::SetProcessName(const nsAString& aName, bool aDontOverride)
+ContentChild::SetProcessName(const nsAString& aName)
 {
-  if (!mCanOverrideProcessName) {
-    return;
-  }
-
   char* name;
   if ((name = PR_GetEnv("MOZ_DEBUG_APP_PROCESS")) &&
     aName.EqualsASCII(name)) {
 #ifdef OS_POSIX
     printf_stderr("\n\nCHILDCHILDCHILDCHILD\n  [%s] debug me @%d\n\n", name,
                   getpid());
     sleep(30);
 #elif defined(OS_WIN)
@@ -652,20 +647,16 @@ ContentChild::SetProcessName(const nsASt
     NS_DebugBreak(NS_DEBUG_BREAK,
                  "Invoking NS_DebugBreak() to debug child process",
                  nullptr, __FILE__, __LINE__);
 #endif
   }
 
   mProcessName = aName;
   mozilla::ipc::SetThisProcessName(NS_LossyConvertUTF16toASCII(aName).get());
-
-  if (aDontOverride) {
-    mCanOverrideProcessName = false;
-  }
 }
 
 NS_IMETHODIMP
 ContentChild::ProvideWindow(mozIDOMWindowProxy* aParent,
                             uint32_t aChromeFlags,
                             bool aCalledFromJS,
                             bool aPositionSpecified,
                             bool aSizeSpecified,
@@ -2623,16 +2614,27 @@ ContentChild::RecvAppInfo(const nsCStrin
 }
 
 mozilla::ipc::IPCResult
 ContentChild::RecvRemoteType(const nsString& aRemoteType)
 {
   MOZ_ASSERT(DOMStringIsNull(mRemoteType));
 
   mRemoteType.Assign(aRemoteType);
+
+  // For non-default ("web") types, update the process name so about:memory's
+  // process names are more obvious.
+  if (aRemoteType.EqualsLiteral(FILE_REMOTE_TYPE)) {
+    SetProcessName(NS_LITERAL_STRING("file:// Content"));
+  } else if (aRemoteType.EqualsLiteral(EXTENSION_REMOTE_TYPE)) {
+    SetProcessName(NS_LITERAL_STRING("WebExtensions"));
+  } else if (aRemoteType.EqualsLiteral(LARGE_ALLOCATION_REMOTE_TYPE)) {
+    SetProcessName(NS_LITERAL_STRING("Large Allocation Web Content"));
+  }
+
   return IPC_OK();
 }
 
 const nsAString&
 ContentChild::GetRemoteType() const
 {
   return mRemoteType;
 }
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -115,17 +115,17 @@ public:
     return sSingleton;
   }
 
   const AppInfo& GetAppInfo()
   {
     return mAppInfo;
   }
 
-  void SetProcessName(const nsAString& aName, bool aDontOverride = false);
+  void SetProcessName(const nsAString& aName);
 
   void GetProcessName(nsAString& aName) const;
 
   void GetProcessName(nsACString& aName) const;
 
 #if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
   void GetProfileDir(nsIFile** aProfileDir) const
   {
@@ -726,17 +726,16 @@ private:
    */
   uint32_t mMsaaID;
 #endif
 
   AppInfo mAppInfo;
 
   bool mIsForBrowser;
   nsString mRemoteType = NullString();
-  bool mCanOverrideProcessName;
   bool mIsAlive;
   nsString mProcessName;
 
   static ContentChild* sSingleton;
 
   nsCOMPtr<nsIDomainPolicy> mPolicy;
   nsCOMPtr<nsITimer> mForceKillTimer;
 
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -34,16 +34,19 @@
 #include "PermissionMessageUtils.h"
 #include "DriverCrashGuard.h"
 
 #define CHILD_PROCESS_SHUTDOWN_MESSAGE NS_LITERAL_STRING("child-process-shutdown")
 
 #define NO_REMOTE_TYPE ""
 
 // These must match the similar ones in E10SUtils.jsm.
+// Process names as reported by about:memory are defined in
+// ContentChild:RecvRemoteType.  Add your value there too or it will be called
+// "Web Content".
 #define DEFAULT_REMOTE_TYPE "web"
 #define FILE_REMOTE_TYPE "file"
 #define EXTENSION_REMOTE_TYPE "extension"
 
 // This must start with the DEFAULT_REMOTE_TYPE above.
 #define LARGE_ALLOCATION_REMOTE_TYPE "webLargeAllocation"
 
 class nsConsoleService;
--- a/dom/ipc/PreallocatedProcessManager.cpp
+++ b/dom/ipc/PreallocatedProcessManager.cpp
@@ -128,18 +128,20 @@ PreallocatedProcessManagerImpl::Observe(
     Preferences::RemoveObserver(this, "dom.ipc.processPrelaunch.enabled");
     Preferences::RemoveObserver(this, "dom.ipc.processCount");
     nsCOMPtr<nsIObserverService> os = services::GetObserverService();
     if (os) {
       os->RemoveObserver(this, "ipc:content-shutdown");
       os->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
       os->RemoveObserver(this, "profile-change-teardown");
     }
+    // Let's prevent any new preallocated processes from starting. ContentParent will
+    // handle the shutdown of the existing process and the mPreallocatedProcess reference
+    // will be cleared by the ClearOnShutdown of the manager singleton.
     mShutdown = true;
-    CloseProcess();
   } else {
     MOZ_ASSERT(false);
   }
 
   return NS_OK;
 }
 
 void
--- a/dom/media/MediaResource.cpp
+++ b/dom/media/MediaResource.cpp
@@ -9,16 +9,17 @@
 #include "DecoderTraits.h"
 #include "MediaResource.h"
 #include "MediaResourceCallback.h"
 
 #include "mozilla/Mutex.h"
 #include "nsDebug.h"
 #include "nsNetUtil.h"
 #include "nsThreadUtils.h"
+#include "nsIClassOfService.h"
 #include "nsIFile.h"
 #include "nsIFileChannel.h"
 #include "nsIFileStreams.h"
 #include "nsIHttpChannel.h"
 #include "nsISeekableStream.h"
 #include "nsIInputStream.h"
 #include "nsIRequestObserver.h"
 #include "nsIStreamListener.h"
@@ -842,16 +843,23 @@ ChannelMediaResource::RecreateChannel()
                               element,
                               securityFlags,
                               contentPolicyType,
                               loadGroup,
                               nullptr,  // aCallbacks
                               loadFlags);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(mChannel));
+  if (cos) {
+    // Unconditionally disable throttling since we want the media to fluently
+    // play even when we switch the tab to background.
+    cos->AddClassFlags(nsIClassOfService::DontThrottle);
+  }
+
   mSuspendAgent.NotifyChannelOpened(mChannel);
 
   // Tell the cache to reset the download status when the channel is reopened.
   mCacheStream.NotifyChannelRecreated();
 
   return rv;
 }
 
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/file_data_doc_ignore_meta_csp.html
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Bug 1382869: data document should ignore meta csp</title>
+  <meta charset="utf-8">
+</head>
+<body>
+<script type="application/javascript">
+  // 1) create a data document
+  const doc = document.implementation.createHTMLDocument();
+  // 2) add meta csp to that document
+  const metaEl = doc.createElement('meta');
+  metaEl.setAttribute('http-equiv', 'Content-Security-Policy');
+  metaEl.setAttribute('content', "img-src 'none'");
+  doc.head.appendChild(metaEl);
+  // 3) let the parent know we are done here
+  var result = "dataDocCreated";
+  window.parent.postMessage({result}, "*");
+</script>
+
+</body>
+</html>
--- a/dom/security/test/csp/mochitest.ini
+++ b/dom/security/test/csp/mochitest.ini
@@ -213,16 +213,17 @@ support-files =
   file_image_nonce.html
   file_image_nonce.html^headers^
   file_ignore_xfo.html
   file_ignore_xfo.html^headers^
   file_ro_ignore_xfo.html
   file_ro_ignore_xfo.html^headers^
   file_data_csp_inheritance.html
   file_data_csp_merge.html
+  file_data_doc_ignore_meta_csp.html
 
 [test_base-uri.html]
 [test_blob_data_schemes.html]
 [test_connect-src.html]
 [test_CSP.html]
 [test_allow_https_schemes.html]
 [test_bug663567.html]
 [test_bug802872.html]
@@ -306,8 +307,9 @@ tags = mcb
 [test_iframe_sandbox_srcdoc.html]
 [test_iframe_srcdoc.html]
 [test_image_nonce.html]
 [test_websocket_self.html]
 skip-if = toolkit == 'android'
 [test_ignore_xfo.html]
 [test_data_csp_inheritance.html]
 [test_data_csp_merge.html]
+[test_data_doc_ignore_meta_csp.html]
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/test_data_doc_ignore_meta_csp.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Bug 1382869: data document should ignore meta csp</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/* Description of the test:
+ * We load an iframe creating a new data document which defines
+ * a meta csp. We make sure the meta CSP is ignored and does not
+ * apply to the actual iframe document.
+ */
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+  window.removeEventListener("message", receiveMessage);
+  is(event.data.result, "dataDocCreated", "sanity: received msg from loaded frame");
+
+  var frame = document.getElementById("testframe");
+  var principal = SpecialPowers.wrap(frame.contentDocument).nodePrincipal;
+  var cspJSON = principal.cspJSON;
+  is(cspJSON, "{}", "there should be no CSP attached to the iframe");
+  SimpleTest.finish();
+}
+
+document.getElementById("testframe").src = "file_data_doc_ignore_meta_csp.html";
+
+</script>
+</body>
+</html>
--- a/dom/system/android/AndroidLocationProvider.cpp
+++ b/dom/system/android/AndroidLocationProvider.cpp
@@ -22,34 +22,38 @@ AndroidLocationProvider::AndroidLocation
 AndroidLocationProvider::~AndroidLocationProvider()
 {
     NS_IF_RELEASE(gLocationCallback);
 }
 
 NS_IMETHODIMP
 AndroidLocationProvider::Startup()
 {
-    java::GeckoAppShell::EnableLocation(true);
-    return NS_OK;
+    if (java::GeckoAppShell::EnableLocation(true)) {
+        return NS_OK;
+    }
+    return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 AndroidLocationProvider::Watch(nsIGeolocationUpdate* aCallback)
 {
     NS_IF_RELEASE(gLocationCallback);
     gLocationCallback = aCallback;
     NS_IF_ADDREF(gLocationCallback);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 AndroidLocationProvider::Shutdown()
 {
-    java::GeckoAppShell::EnableLocation(false);
-    return NS_OK;
+    if (java::GeckoAppShell::EnableLocation(false)) {
+        return NS_OK;
+    }
+    return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 AndroidLocationProvider::SetHighAccuracy(bool enable)
 {
     java::GeckoAppShell::EnableLocationHighAccuracy(enable);
     return NS_OK;
 }
--- a/dom/webbrowserpersist/nsWebBrowserPersist.cpp
+++ b/dom/webbrowserpersist/nsWebBrowserPersist.cpp
@@ -2621,17 +2621,17 @@ nsWebBrowserPersist::SaveSubframeContent
 {
     NS_ENSURE_ARG_POINTER(aData);
 
     // Extract the content type for the frame's contents.
     nsAutoCString contentType;
     nsresult rv = aFrameContent->GetContentType(contentType);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    nsXPIDLString ext;
+    nsString ext;
     GetExtensionForContentType(NS_ConvertASCIItoUTF16(contentType).get(),
                                getter_Copies(ext));
 
     // We must always have an extension so we will try to re-assign
     // the original extension if GetExtensionForContentType fails.
     if (ext.IsEmpty()) {
         nsCOMPtr<nsIURI> docURI;
         rv = NS_NewURI(getter_AddRefs(docURI), aURISpec, mCurrentCharset.get());
--- a/editor/libeditor/HTMLEditorDataTransfer.cpp
+++ b/editor/libeditor/HTMLEditorDataTransfer.cpp
@@ -1166,17 +1166,17 @@ HTMLEditor::InsertFromTransferable(nsITr
                         aSourceDoc, aDestinationNode, aDestOffset, aDoDeleteSelection);
     } else if (bestFlavor.EqualsLiteral(kNativeHTMLMime)) {
       // note cf_html uses utf8, hence use length = len, not len/2 as in flavors below
       nsCOMPtr<nsISupportsCString> textDataObj = do_QueryInterface(genericDataObj);
       if (textDataObj && len > 0) {
         nsAutoCString cfhtml;
         textDataObj->GetData(cfhtml);
         NS_ASSERTION(cfhtml.Length() <= (len), "Invalid length!");
-        nsXPIDLString cfcontext, cffragment, cfselection; // cfselection left emtpy for now
+        nsString cfcontext, cffragment, cfselection; // cfselection left emtpy for now
 
         rv = ParseCFHTML(cfhtml, getter_Copies(cffragment), getter_Copies(cfcontext));
         if (NS_SUCCEEDED(rv) && !cffragment.IsEmpty()) {
           AutoEditBatch beginBatching(this);
           // If we have our private HTML flavor, we will only use the fragment
           // from the CF_HTML. The rest comes from the clipboard.
           if (havePrivateHTMLFlavor) {
             rv = DoInsertHTMLWithContext(cffragment,
@@ -1300,17 +1300,17 @@ HTMLEditor::InsertFromDataTransfer(DataT
                               aSourceDoc, aDestinationNode, aDestOffset, aDoDeleteSelection);
         }
       } else if (type.EqualsLiteral(kNativeHTMLMime)) {
         // Windows only clipboard parsing.
         nsAutoString text;
         GetStringFromDataTransfer(aDataTransfer, type, aIndex, text);
         NS_ConvertUTF16toUTF8 cfhtml(text);
 
-        nsXPIDLString cfcontext, cffragment, cfselection; // cfselection left emtpy for now
+        nsString cfcontext, cffragment, cfselection; // cfselection left emtpy for now
 
         nsresult rv = ParseCFHTML(cfhtml, getter_Copies(cffragment), getter_Copies(cfcontext));
         if (NS_SUCCEEDED(rv) && !cffragment.IsEmpty()) {
           AutoEditBatch beginBatching(this);
 
           if (hasPrivateHTMLFlavor) {
             // If we have our private HTML flavor, we will only use the fragment
             // from the CF_HTML. The rest comes from the clipboard.
--- a/extensions/pref/autoconfig/src/nsAutoConfig.cpp
+++ b/extensions/pref/autoconfig/src/nsAutoConfig.cpp
@@ -521,17 +521,17 @@ nsresult nsAutoConfig::PromptForEMailAdd
     nsAutoString title;
     rv = bundle->GetStringFromName("emailPromptTitle", title);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsAutoString err;
     rv = bundle->GetStringFromName("emailPromptMsg", err);
     NS_ENSURE_SUCCESS(rv, rv);
     bool check = false;
-    nsXPIDLString emailResult;
+    nsString emailResult;
     bool success;
     rv = promptService->Prompt(nullptr, title.get(), err.get(), getter_Copies(emailResult), nullptr, &check, &success);
     if (!success)
       return NS_ERROR_FAILURE;
     NS_ENSURE_SUCCESS(rv, rv);
     LossyCopyUTF16toASCII(emailResult, emailAddress);
     return NS_OK;
 }
--- a/extensions/spellcheck/src/mozSpellChecker.cpp
+++ b/extensions/spellcheck/src/mozSpellChecker.cpp
@@ -363,17 +363,17 @@ mozSpellChecker::GetCurrentDictionary(ns
     return NS_OK;
   }
 
   if (!mSpellCheckingEngine) {
     aDictionary.Truncate();
     return NS_OK;
   }
 
-  nsXPIDLString dictname;
+  nsAutoString dictname;
   mSpellCheckingEngine->GetDictionary(getter_Copies(dictname));
   aDictionary = dictname;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 mozSpellChecker::SetCurrentDictionary(const nsAString &aDictionary)
 {
@@ -411,20 +411,19 @@ mozSpellChecker::SetCurrentDictionary(co
     mSpellCheckingEngine = spellCheckingEngines[i];
 
     rv = mSpellCheckingEngine->SetDictionary(PromiseFlatString(aDictionary).get());
 
     if (NS_SUCCEEDED(rv)) {
       nsCOMPtr<mozIPersonalDictionary> personalDictionary = do_GetService("@mozilla.org/spellchecker/personaldictionary;1");
       mSpellCheckingEngine->SetPersonalDictionary(personalDictionary.get());
 
-      nsXPIDLString language;
       nsCOMPtr<mozISpellI18NManager> serv(do_GetService("@mozilla.org/spellchecker/i18nmanager;1", &rv));
       NS_ENSURE_SUCCESS(rv, rv);
-      return serv->GetUtil(language.get(),getter_AddRefs(mConverter));
+      return serv->GetUtil(nullptr, getter_AddRefs(mConverter));
     }
   }
 
   mSpellCheckingEngine = nullptr;
 
   // We could not find any engine with the requested dictionary
   return NS_ERROR_NOT_AVAILABLE;
 }
--- a/gfx/layers/AtomicRefCountedWithFinalize.h
+++ b/gfx/layers/AtomicRefCountedWithFinalize.h
@@ -170,16 +170,21 @@ public:
       return !!mRecycleCallback;
     }
 
     bool IsDead() const
     {
       return mRefCount < 0;
     }
 
+    bool HasOneRef() const
+    {
+      return mRefCount == 1;
+    }
+
 private:
     RecycleCallback mRecycleCallback;
     void *mClosure;
     Atomic<int> mRefCount;
 #ifdef DEBUG
 public:
     bool mSpew;
 private:
--- a/gfx/layers/PaintThread.cpp
+++ b/gfx/layers/PaintThread.cpp
@@ -19,50 +19,48 @@ namespace layers {
 using namespace gfx;
 
 StaticAutoPtr<PaintThread> PaintThread::sSingleton;
 StaticRefPtr<nsIThread> PaintThread::sThread;
 PlatformThreadId PaintThread::sThreadId;
 
 // RAII make sure we clean up and restore our draw targets
 // when we paint async.
-struct AutoCapturedPaintSetup {
-  AutoCapturedPaintSetup(DrawTarget* aTarget,
-                         DrawTargetCapture* aCapture,
-                         CompositorBridgeChild* aBridge)
-  : mTarget(aTarget)
-  , mRestorePermitsSubpixelAA(aTarget->GetPermitSubpixelAA())
-  , mOldTransform(aTarget->GetTransform())
+struct MOZ_STACK_CLASS AutoCapturedPaintSetup
+{
+  AutoCapturedPaintSetup(CapturedPaintState* aState, CompositorBridgeChild* aBridge)
+  : mState(aState)
+  , mTarget(aState->mTarget)
+  , mRestorePermitsSubpixelAA(mTarget->GetPermitSubpixelAA())
+  , mOldTransform(mTarget->GetTransform())
   , mBridge(aBridge)
   {
-    MOZ_ASSERT(mTarget);
-    MOZ_ASSERT(aCapture);
-
-    mTarget->SetTransform(aCapture->GetTransform());
-    mTarget->SetPermitSubpixelAA(aCapture->GetPermitSubpixelAA());
+    mTarget->SetTransform(aState->mCapture->GetTransform());
+    mTarget->SetPermitSubpixelAA(aState->mCapture->GetPermitSubpixelAA());
   }
 
   ~AutoCapturedPaintSetup()
   {
     mTarget->SetTransform(mOldTransform);
     mTarget->SetPermitSubpixelAA(mRestorePermitsSubpixelAA);
 
     // Textureclient forces a flush once we "end paint", so
     // users of this texture expect all the drawing to be complete.
     // Force a flush now.
     // TODO: This might be a performance bottleneck because
     // main thread painting only does one flush at the end of all paints
     // whereas we force a flush after each draw target paint.
     mTarget->Flush();
 
     if (mBridge) {
-      mBridge->NotifyFinishedAsyncPaint();
+      mBridge->NotifyFinishedAsyncPaint(mState);
     }
   }
 
+  RefPtr<CapturedPaintState> mState;
   DrawTarget* mTarget;
   bool mRestorePermitsSubpixelAA;
   Matrix mOldTransform;
   RefPtr<CompositorBridgeChild> mBridge;
 };
 
 void
 PaintThread::Release()
@@ -158,17 +156,17 @@ PaintThread::PaintContentsAsync(Composit
                                 PrepDrawTargetForPaintingCallback aCallback)
 {
   MOZ_ASSERT(IsOnPaintThread());
   MOZ_ASSERT(aState);
 
   DrawTarget* target = aState->mTarget;
   DrawTargetCapture* capture = aState->mCapture;
 
-  AutoCapturedPaintSetup setup(target, capture, aBridge);
+  AutoCapturedPaintSetup setup(aState, aBridge);
 
   if (!aCallback(aState)) {
     return;
   }
 
   // Draw all the things into the actual dest target.
   target->DrawCapturedDT(capture, Matrix());
 }
@@ -181,17 +179,17 @@ PaintThread::PaintContents(CapturedPaint
   MOZ_ASSERT(aState);
 
   // If painting asynchronously, we need to acquire the compositor bridge which
   // owns the underlying MessageChannel. Otherwise we leave it null and use
   // synchronous dispatch.
   RefPtr<CompositorBridgeChild> cbc;
   if (!gfxPrefs::LayersOMTPForceSync()) {
     cbc = CompositorBridgeChild::Get();
-    cbc->NotifyBeginAsyncPaint();
+    cbc->NotifyBeginAsyncPaint(aState);
   }
   RefPtr<CapturedPaintState> state(aState);
   RefPtr<DrawTargetCapture> capture(aState->mCapture);
 
   RefPtr<PaintThread> self = this;
   RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::PaintContents",
     [self, cbc, capture, state, aCallback]() -> void
   {
--- a/gfx/layers/PaintThread.h
+++ b/gfx/layers/PaintThread.h
@@ -6,48 +6,49 @@
 
 #ifndef MOZILLA_LAYERS_PAINTTHREAD_H
 #define MOZILLA_LAYERS_PAINTTHREAD_H
 
 #include "base/platform_thread.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/UniquePtr.h"
+#include "mozilla/layers/TextureClient.h"
 #include "nsThreadUtils.h"
 
 namespace mozilla {
 namespace gfx {
 class DrawTarget;
 class DrawTargetCapture;
 };
 
 namespace layers {
 
 // Holds the key parts from a RotatedBuffer::PaintState
 // required to draw the captured paint state
 class CapturedPaintState {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CapturedPaintState)
 public:
   CapturedPaintState(nsIntRegion& aRegionToDraw,
-                     gfx::DrawTargetCapture* aCapture,
                      gfx::DrawTarget* aTarget,
                      gfx::DrawTarget* aTargetOnWhite,
-                     gfx::Matrix aTargetTransform,
+                     const gfx::Matrix& aTargetTransform,
                      SurfaceMode aSurfaceMode,
                      gfxContentType aContentType)
   : mRegionToDraw(aRegionToDraw)
-  , mCapture(aCapture)
   , mTarget(aTarget)
   , mTargetOnWhite(aTargetOnWhite)
   , mTargetTransform(aTargetTransform)
   , mSurfaceMode(aSurfaceMode)
   , mContentType(aContentType)
   {}
 
   nsIntRegion mRegionToDraw;
+  RefPtr<TextureClient> mTextureClient;
+  RefPtr<TextureClient> mTextureClientOnWhite;
   RefPtr<gfx::DrawTargetCapture> mCapture;
   RefPtr<gfx::DrawTarget> mTarget;
   RefPtr<gfx::DrawTarget> mTargetOnWhite;
   gfx::Matrix mTargetTransform;
   SurfaceMode mSurfaceMode;
   gfxContentType mContentType;
 
 protected:
--- a/gfx/layers/RotatedBuffer.cpp
+++ b/gfx/layers/RotatedBuffer.cpp
@@ -735,35 +735,42 @@ RotatedContentBuffer::BeginPaint(Painted
   invalidate.Sub(aLayer->GetValidRegion(), destBufferRect);
   result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate);
   result.mClip = DrawRegionClip::DRAW;
   result.mMode = mode;
 
   return result;
 }
 
-DrawTarget*
+RefPtr<CapturedPaintState>
 RotatedContentBuffer::BorrowDrawTargetForRecording(PaintState& aPaintState,
-                                                   DrawIterator* aIter,
-                                                   gfx::Matrix* aOutMatrix)
+                                                   DrawIterator* aIter)
 {
-  MOZ_ASSERT(aOutMatrix);
   if (aPaintState.mMode == SurfaceMode::SURFACE_NONE) {
     return nullptr;
   }
 
+  Matrix transform;
   DrawTarget* result = BorrowDrawTargetForQuadrantUpdate(aPaintState.mRegionToDraw.GetBounds(),
                                                          BUFFER_BOTH, aIter,
-                                                         false, aOutMatrix);
+                                                         false, &transform);
   if (!result) {
     return nullptr;
   }
 
   ExpandDrawRegion(aPaintState, aIter, result->GetBackendType());
-  return result;
+
+  RefPtr<CapturedPaintState> state =
+    new CapturedPaintState(aPaintState.mRegionToDraw,
+                           result,
+                           nullptr, /* aTargetOnWhite */
+                           transform,
+                           aPaintState.mMode,
+                           aPaintState.mContentType);
+  return state;
 }
 
 /*static */ bool
 RotatedContentBuffer::PrepareDrawTargetForPainting(CapturedPaintState* aState)
 {
   RefPtr<DrawTarget> target = aState->mTarget;
   RefPtr<DrawTarget> whiteTarget = aState->mTargetOnWhite;
 
@@ -831,17 +838,16 @@ RotatedContentBuffer::BorrowDrawTargetFo
   ExpandDrawRegion(aPaintState, aIter, result->GetBackendType());
 
   nsIntRegion regionToDraw = aIter ? aIter->mDrawRegion
                                    : aPaintState.mRegionToDraw;
 
   // Can't stack allocate refcounted objects.
   RefPtr<CapturedPaintState> capturedPaintState =
     MakeAndAddRef<CapturedPaintState>(regionToDraw,
-                                      nullptr,
                                       mDTBuffer,
                                       mDTBufferOnWhite,
                                       Matrix(),
                                       aPaintState.mMode,
                                       aPaintState.mContentType);
 
   if (!RotatedContentBuffer::PrepareDrawTargetForPainting(capturedPaintState)) {
     return nullptr;
--- a/gfx/layers/RotatedBuffer.h
+++ b/gfx/layers/RotatedBuffer.h
@@ -297,19 +297,18 @@ public:
   gfx::DrawTarget* BorrowDrawTargetForPainting(PaintState& aPaintState,
                                                DrawIterator* aIter = nullptr);
 
   /**
    * Borrow a draw target for recording. The aOutTransform is not applied
    * to the returned DrawTarget, BUT it is required to be painting in the right
    * location whenever drawing does happen.
    */
-  gfx::DrawTarget* BorrowDrawTargetForRecording(PaintState& aPaintState,
-                                                DrawIterator* aIter,
-                                                gfx::Matrix* aOutTransform);
+  RefPtr<CapturedPaintState> BorrowDrawTargetForRecording(PaintState& aPaintState,
+                                                          DrawIterator* aIter);
 
   void ExpandDrawRegion(PaintState& aPaintState,
                         DrawIterator* aIter,
                         gfx::BackendType aBackendType);
 
   static bool PrepareDrawTargetForPainting(CapturedPaintState*);
   enum {
     BUFFER_COMPONENT_ALPHA = 0x02 // Dual buffers should be created for drawing with
--- a/gfx/layers/client/ClientPaintedLayer.cpp
+++ b/gfx/layers/client/ClientPaintedLayer.cpp
@@ -221,59 +221,52 @@ ClientPaintedLayer::PaintOffMainThread()
 
   PaintState state = mContentClient->BeginPaintBuffer(this, flags);
   if (!UpdatePaintRegion(state)) {
     return false;
   }
 
   bool didUpdate = false;
   RotatedContentBuffer::DrawIterator iter;
-  Matrix capturedTransform;
+
   // Debug Protip: Change to BorrowDrawTargetForPainting if using sync OMTP.
-  while (DrawTarget* target =
-          mContentClient->BorrowDrawTargetForRecording(state, &iter, &capturedTransform)) {
+  while (RefPtr<CapturedPaintState> captureState =
+          mContentClient->BorrowDrawTargetForRecording(state, &iter))
+  {
+    DrawTarget* target = captureState->mTarget;
     if (!target || !target->IsValid()) {
       if (target) {
         mContentClient->ReturnDrawTargetToBuffer(target);
       }
       continue;
     }
 
     RefPtr<DrawTargetCapture> captureDT =
       Factory::CreateCaptureDrawTarget(target->GetBackendType(),
                                        target->GetSize(),
                                        target->GetFormat());
 
-    captureDT->SetTransform(capturedTransform);
+    captureDT->SetTransform(captureState->mTargetTransform);
     SetAntialiasingFlags(this, captureDT);
 
     RefPtr<gfxContext> ctx = gfxContext::CreatePreservingTransformOrNull(captureDT);
     MOZ_ASSERT(ctx); // already checked the target above
 
     ClientManager()->GetPaintedLayerCallback()(this,
                                               ctx,
                                               iter.mDrawRegion,
                                               iter.mDrawRegion,
                                               state.mClip,
                                               state.mRegionToInvalidate,
                                               ClientManager()->GetPaintedLayerCallbackData());
 
     ctx = nullptr;
 
-    // TODO: Fixup component alpha
-    DrawTarget* targetOnWhite = nullptr;
-    RefPtr<CapturedPaintState> capturedState
-      = MakeAndAddRef<CapturedPaintState>(state.mRegionToDraw,
-                                          captureDT,
-                                          target, targetOnWhite,
-                                          capturedTransform,
-                                          state.mMode,
-                                          state.mContentType);
-
-    PaintThread::Get()->PaintContents(capturedState,
+    captureState->mCapture = captureDT.forget();
+    PaintThread::Get()->PaintContents(captureState,
                                       RotatedContentBuffer::PrepareDrawTargetForPainting);
 
     mContentClient->ReturnDrawTargetToBuffer(target);
 
     didUpdate = true;
   }
   mContentClient->EndPaint(nullptr);
 
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -152,16 +152,24 @@ ContentClientBasic::CreateBuffer(Content
   }
 #endif
 
   *aBlackDT = gfxPlatform::GetPlatform()->CreateDrawTargetForBackend(
     mBackend, size,
     gfxPlatform::GetPlatform()->Optimal2DFormatForContent(aType));
 }
 
+RefPtr<CapturedPaintState>
+ContentClientBasic::BorrowDrawTargetForRecording(PaintState& aPaintState,
+                                                 RotatedContentBuffer::DrawIterator* aIter)
+{
+  // BasicLayers does not yet support OMTP.
+  return nullptr;
+}
+
 void
 ContentClientRemoteBuffer::DestroyBuffers()
 {
   if (!mTextureClient) {
     return;
   }
 
   mOldTextures.AppendElement(mTextureClient);
@@ -169,16 +177,30 @@ ContentClientRemoteBuffer::DestroyBuffer
   if (mTextureClientOnWhite) {
     mOldTextures.AppendElement(mTextureClientOnWhite);
     mTextureClientOnWhite = nullptr;
   }
 
   DestroyFrontBuffer();
 }
 
+RefPtr<CapturedPaintState>
+ContentClientRemoteBuffer::BorrowDrawTargetForRecording(PaintState& aPaintState,
+                                                        RotatedContentBuffer::DrawIterator* aIter)
+{
+  RefPtr<CapturedPaintState> cps = RotatedContentBuffer::BorrowDrawTargetForRecording(aPaintState, aIter);
+  if (!cps) {
+    return nullptr;
+  }
+
+  cps->mTextureClient = mTextureClient;
+  cps->mTextureClientOnWhite = mTextureClientOnWhite;
+  return cps.forget();
+}
+
 class RemoteBufferReadbackProcessor : public TextureReadbackSink
 {
 public:
   RemoteBufferReadbackProcessor(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates,
                                 const IntRect& aBufferRect, const nsIntPoint& aBufferRotation)
     : mReadbackUpdates(*aReadbackUpdates)
     , mBufferRect(aBufferRect)
     , mBufferRotation(aBufferRotation)
--- a/gfx/layers/client/ContentClient.h
+++ b/gfx/layers/client/ContentClient.h
@@ -32,16 +32,17 @@
 namespace mozilla {
 namespace gfx {
 class DrawTarget;
 } // namespace gfx
 
 namespace layers {
 
 class PaintedLayer;
+class CapturedPaintState;
 
 /**
  * A compositable client for PaintedLayers. These are different to Image/Canvas
  * clients due to sending a valid region across IPC and because we do a lot more
  * optimisation work, encapsualted in RotatedContentBuffers.
  *
  * We use content clients for OMTC and non-OMTC, basic rendering so that
  * BasicPaintedLayer has only one interface to deal with. We support single and
@@ -91,19 +92,20 @@ public:
   virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix);
 
   virtual void Clear() = 0;
   virtual RotatedContentBuffer::PaintState BeginPaintBuffer(PaintedLayer* aLayer,
                                                             uint32_t aFlags) = 0;
   virtual gfx::DrawTarget* BorrowDrawTargetForPainting(RotatedContentBuffer::PaintState& aPaintState,
                                                        RotatedContentBuffer::DrawIterator* aIter = nullptr) = 0;
   virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) = 0;
-  virtual gfx::DrawTarget* BorrowDrawTargetForRecording(RotatedContentBuffer::PaintState& aPaintState,
-                                                        RotatedContentBuffer::DrawIterator* aIter,
-                                                        gfx::Matrix* aOutTransform) = 0;
+  virtual RefPtr<CapturedPaintState> BorrowDrawTargetForRecording(
+    RotatedContentBuffer::PaintState& aPaintState,
+    RotatedContentBuffer::DrawIterator* aIter) = 0;
+
   // Called as part of the layers transation reply. Conveys data about our
   // buffer(s) from the compositor. If appropriate we should swap references
   // to our buffers.
   virtual void SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) {}
 
   // call before and after painting into this content client
   virtual void BeginPaint() {}
   virtual void BeginAsyncPaint();
@@ -148,22 +150,19 @@ public:
   {
     return RotatedContentBuffer::BeginPaint(aLayer, aFlags);
   }
   virtual gfx::DrawTarget* BorrowDrawTargetForPainting(PaintState& aPaintState,
                                                        RotatedContentBuffer::DrawIterator* aIter = nullptr) override
   {
     return RotatedContentBuffer::BorrowDrawTargetForPainting(aPaintState, aIter);
   }
-  virtual gfx::DrawTarget* BorrowDrawTargetForRecording(PaintState& aPaintState,
-                                                       RotatedContentBuffer::DrawIterator* aIter,
-                                                       gfx::Matrix* aOutTransform) override
-  {
-    return RotatedContentBuffer::BorrowDrawTargetForRecording(aPaintState, aIter, aOutTransform);
-  }
+  virtual RefPtr<CapturedPaintState> BorrowDrawTargetForRecording(PaintState& aPaintState,
+                                                                  RotatedContentBuffer::DrawIterator* aIter) override;
+
   virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) override
   {
     BorrowDrawTarget::ReturnDrawTarget(aReturned);
   }
 
   void DrawTo(PaintedLayer* aLayer,
               gfx::DrawTarget* aTarget,
               float aOpacity,
@@ -237,22 +236,19 @@ public:
   {
     return RotatedContentBuffer::BeginPaint(aLayer, aFlags);
   }
   virtual gfx::DrawTarget* BorrowDrawTargetForPainting(PaintState& aPaintState,
                                                        RotatedContentBuffer::DrawIterator* aIter = nullptr) override
   {
     return RotatedContentBuffer::BorrowDrawTargetForPainting(aPaintState, aIter);
   }
-  virtual gfx::DrawTarget* BorrowDrawTargetForRecording(PaintState& aPaintState,
-                                                        RotatedContentBuffer::DrawIterator* aIter,
-                                                        gfx::Matrix* aOutTransform) override
-  {
-    return RotatedContentBuffer::BorrowDrawTargetForRecording(aPaintState, aIter, aOutTransform);
-  }
+  virtual RefPtr<CapturedPaintState> BorrowDrawTargetForRecording(PaintState& aPaintState,
+                                                                  RotatedContentBuffer::DrawIterator* aIter) override;
+
   virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) override
   {
     BorrowDrawTarget::ReturnDrawTarget(aReturned);
   }
 
   /**
    * Begin/End Paint map a gfxASurface from the texture client
    * into the buffer of RotatedBuffer. The surface is only
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -10,16 +10,17 @@
 #include "gfxPlatform.h"                // for gfxPlatform
 #include "mozilla/Atomics.h"
 #include "mozilla/SystemGroup.h"
 #include "mozilla/ipc/SharedMemory.h"   // for SharedMemory, etc
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/layers/ImageDataSerializer.h"
+#include "mozilla/layers/PaintThread.h"
 #include "mozilla/layers/TextureClientRecycleAllocator.h"
 #include "mozilla/Mutex.h"
 #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING, etc
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "ImageContainer.h"             // for PlanarYCbCrData, etc
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Logging.h"        // for gfxDebug
 #include "mozilla/layers/TextureClientOGL.h"
@@ -375,16 +376,19 @@ DeallocateTextureClient(TextureDeallocPa
     return;
   }
 
   actor->Destroy(params);
 }
 
 void TextureClient::Destroy()
 {
+  // Async paints should have been flushed by now.
+  MOZ_RELEASE_ASSERT(mPaintThreadRefs == 0);
+
   if (mActor && !mIsLocked) {
     mActor->Lock();
   }
 
   mBorrowedDrawTarget = nullptr;
   mReadLock = nullptr;
 
   RefPtr<TextureChild> actor = mActor;
@@ -600,16 +604,19 @@ TextureClient::SerializeReadLock(ReadLoc
   }
 
   aDescriptor = null_t();
   return false;
 }
 
 TextureClient::~TextureClient()
 {
+  // TextureClients should be kept alive while there are references on the
+  // paint thread.
+  MOZ_ASSERT(mPaintThreadRefs == 0);
   mReadLock = nullptr;
   Destroy();
 }
 
 void
 TextureClient::UpdateFromSurface(gfx::SourceSurface* aSurface)
 {
   MOZ_ASSERT(IsValid());
@@ -1696,16 +1703,31 @@ CrossProcessSemaphoreReadLock::Serialize
 void
 TextureClient::EnableBlockingReadLock()
 {
   if (!mReadLock) {
     mReadLock = new CrossProcessSemaphoreReadLock();
   }
 }
 
+void
+TextureClient::AddPaintThreadRef()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  mPaintThreadRefs += 1;
+}
+
+void
+TextureClient::DropPaintThreadRef()
+{
+  MOZ_RELEASE_ASSERT(PaintThread::IsOnPaintThread());
+  MOZ_RELEASE_ASSERT(mPaintThreadRefs >= 1);
+  mPaintThreadRefs -= 1;
+}
+
 bool
 UpdateYCbCrTextureClient(TextureClient* aTexture, const PlanarYCbCrData& aData)
 {
   MOZ_ASSERT(aTexture);
   MOZ_ASSERT(aTexture->IsLocked());
   MOZ_ASSERT(aTexture->GetFormat() == gfx::SurfaceFormat::YUV, "This textureClient can only use YCbCr data");
   MOZ_ASSERT(!aTexture->IsImmutable());
   MOZ_ASSERT(aTexture->IsValid());
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -6,16 +6,17 @@
 #ifndef MOZILLA_GFX_TEXTURECLIENT_H
 #define MOZILLA_GFX_TEXTURECLIENT_H
 
 #include <stddef.h>                     // for size_t
 #include <stdint.h>                     // for uint32_t, uint8_t, uint64_t
 #include "GLTextureImage.h"             // for TextureImage
 #include "ImageTypes.h"                 // for StereoMode
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
+#include "mozilla/Atomics.h"
 #include "mozilla/Attributes.h"         // for override
 #include "mozilla/DebugOnly.h"
 #include "mozilla/RefPtr.h"             // for RefPtr, RefCounted
 #include "mozilla/gfx/2D.h"             // for DrawTarget
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat
 #include "mozilla/ipc/Shmem.h"          // for Shmem
 #include "mozilla/layers/AtomicRefCountedWithFinalize.h"
@@ -625,16 +626,25 @@ public:
 
   bool IsReadLocked() const;
 
   bool TryReadLock();
   void ReadUnlock();
 
   bool SerializeReadLock(ReadLockDescriptor& aDescriptor);
 
+  // Mark that the TextureClient will be used by the paint thread, and should not
+  // free its underlying texture data. This must only be called from the main
+  // thread.
+  void AddPaintThreadRef();
+
+  // Mark that the TextureClient is no longer in use by the PaintThread. This
+  // must only be called from the PaintThread.
+  void DropPaintThreadRef();
+
 private:
   static void TextureClientRecycleCallback(TextureClient* aClient, void* aClosure);
  
   // Internal helpers for creating texture clients using the actual forwarder instead
   // of KnowsCompositor. TextureClientPool uses these to let it cache texture clients
   // per-process instead of per ShadowLayerForwarder, but everyone else should
   // use the public functions instead.
   friend class TextureClientPool;
@@ -714,16 +724,19 @@ protected:
 
   RefPtr<TextureReadbackSink> mReadbackSink;
 
   uint64_t mFwdTransactionId;
 
   // Serial id of TextureClient. It is unique in current process.
   const uint64_t mSerial;
 
+  // When non-zero, texture data must not be freed.
+  mozilla::Atomic<uintptr_t> mPaintThreadRefs;
+
   // External image id. It is unique if it is allocated.
   // The id is allocated in TextureClient::InitIPDLActor().
   // Its allocation is supported by
   // CompositorBridgeChild and ImageBridgeChild for now.
   wr::MaybeExternalImageId mExternalImageId;
 
   // Used to assign serial ids of TextureClient.
   static mozilla::Atomic<uint64_t> sSerialCounter;
--- a/gfx/layers/ipc/CompositorBridgeChild.cpp
+++ b/gfx/layers/ipc/CompositorBridgeChild.cpp
@@ -166,16 +166,19 @@ CompositorBridgeChild::Destroy()
   AutoTArray<PWebRenderBridgeChild*, 16> wrBridges;
   ManagedPWebRenderBridgeChild(wrBridges);
   for (int i = wrBridges.Length() - 1; i >= 0; --i) {
     RefPtr<WebRenderBridgeChild> wrBridge =
       static_cast<WebRenderBridgeChild*>(wrBridges[i]);
     wrBridge->Destroy(/* aIsSync */ false);
   }
 
+  // Flush async paints before we destroy texture data.
+  FlushAsyncPaints();
+
   const ManagedContainer<PTextureChild>& textures = ManagedPTextureChild();
   for (auto iter = textures.ConstIter(); !iter.Done(); iter.Next()) {
     RefPtr<TextureClient> texture = TextureClient::AsTextureClient(iter.Get()->GetKey());
 
     if (texture) {
       texture->Destroy();
     }
   }
@@ -1126,39 +1129,69 @@ CompositorBridgeChild::GetNextExternalIm
 
 wr::PipelineId
 CompositorBridgeChild::GetNextPipelineId()
 {
   return wr::AsPipelineId(GetNextResourceId());
 }
 
 void
-CompositorBridgeChild::NotifyBeginAsyncPaint()
+CompositorBridgeChild::NotifyBeginAsyncPaint(CapturedPaintState* aState)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   MonitorAutoLock lock(mPaintLock);
 
   // We must not be waiting for paints to complete yet. This would imply we
   // started a new paint without waiting for a previous one, which could lead to
   // incorrect rendering or IPDL deadlocks.
   MOZ_ASSERT(!mIsWaitingForPaint);
 
   mOutstandingAsyncPaints++;
+
+  // Mark texture clients that they are being used for async painting, and
+  // make sure we hold them alive on the main thread.
+  aState->mTextureClient->AddPaintThreadRef();
+  mTextureClientsForAsyncPaint.AppendElement(aState->mTextureClient);
+  if (aState->mTextureClientOnWhite) {
+    aState->mTextureClientOnWhite->AddPaintThreadRef();
+    mTextureClientsForAsyncPaint.AppendElement(aState->mTextureClientOnWhite);
+  }
 }
 
 void
-CompositorBridgeChild::NotifyFinishedAsyncPaint()
+CompositorBridgeChild::NotifyFinishedAsyncPaint(CapturedPaintState* aState)
 {
   MOZ_ASSERT(PaintThread::IsOnPaintThread());
 
   MonitorAutoLock lock(mPaintLock);
 
   mOutstandingAsyncPaints--;
 
+  // These textures should be held alive on the main thread. The ref we
+  // captured should not be the final ref.
+  MOZ_RELEASE_ASSERT(!aState->mTextureClient->HasOneRef());
+
+  // It's now safe to drop the paint thread ref we're holding, since we've
+  // flushed writes to the underlying TextureData. Note that we keep the
+  // main thread ref around until FlushAsyncPaints is called, lazily ensuring
+  // the Release occurs on the main thread (versus a message in the event
+  // loop).
+  //
+  // Note that we zap our ref immediately after. Otherwise, the main thread
+  // could wake up when we drop the lock, and we could still be holding a ref
+  // on the paint thread. If this causes TextureClient to destroy then it will
+  // be destroyed on the wrong thread.
+  aState->mTextureClient->DropPaintThreadRef();
+  aState->mTextureClient = nullptr;
+  if (aState->mTextureClientOnWhite) {
+    aState->mTextureClientOnWhite->DropPaintThreadRef();
+    aState->mTextureClientOnWhite = nullptr;
+  }
+
   // It's possible that we painted so fast that the main thread never reached
   // the code that starts delaying messages. If so, mIsWaitingForPaint will be
   // false, and we can safely return.
   if (mIsWaitingForPaint && mOutstandingAsyncPaints == 0) {
     ResumeIPCAfterAsyncPaint();
 
     // Notify the main thread in case it's blocking. We do this unconditionally
     // to avoid deadlocking.
@@ -1204,12 +1237,15 @@ void
 CompositorBridgeChild::FlushAsyncPaints()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   MonitorAutoLock lock(mPaintLock);
   while (mIsWaitingForPaint) {
     lock.Wait();
   }
+
+  // It's now safe to free any TextureClients that were used during painting.
+  mTextureClientsForAsyncPaint.Clear();
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ipc/CompositorBridgeChild.h
+++ b/gfx/layers/ipc/CompositorBridgeChild.h
@@ -40,16 +40,17 @@ using mozilla::dom::TabChild;
 class IAPZCTreeManager;
 class APZCTreeManagerChild;
 class ClientLayerManager;
 class CompositorBridgeParent;
 class CompositorManagerChild;
 class CompositorOptions;
 class TextureClient;
 class TextureClientPool;
+class CapturedPaintState;
 struct FrameMetrics;
 
 class CompositorBridgeChild final : public PCompositorBridgeChild,
                                     public TextureForwarder
 {
   typedef InfallibleTArray<AsyncParentMessageData> AsyncParentMessageArray;
 
 public:
@@ -218,21 +219,21 @@ public:
   }
 
   wr::MaybeExternalImageId GetNextExternalImageId() override;
 
   wr::PipelineId GetNextPipelineId();
 
   // Must only be called from the main thread. Notifies the CompositorBridge
   // that the paint thread is going to begin painting asynchronously.
-  void NotifyBeginAsyncPaint();
+  void NotifyBeginAsyncPaint(CapturedPaintState* aState);
 
   // Must only be called from the paint thread. Notifies the CompositorBridge
   // that the paint thread has finished an asynchronous paint request.
-  void NotifyFinishedAsyncPaint();
+  void NotifyFinishedAsyncPaint(CapturedPaintState* aState);
 
   // Must only be called from the main thread. Notifies the CompoistorBridge
   // that a transaction is about to be sent, and if the paint thread is
   // currently painting, to begin delaying IPC messages.
   void PostponeMessagesIfAsyncPainting();
 
   // Must only be called from the main thread. Ensures that any paints from
   // previous frames have been flushed. The main thread blocks until the
@@ -348,16 +349,20 @@ private:
   MessageLoop* mMessageLoop;
 
   AutoTArray<RefPtr<TextureClientPool>,2> mTexturePools;
 
   uint64_t mProcessToken;
 
   FixedSizeSmallShmemSectionAllocator* mSectionAllocator;
 
+  // TextureClients that must be kept alive during async painting. This
+  // is only accessed on the main thread.
+  nsTArray<RefPtr<TextureClient>> mTextureClientsForAsyncPaint;
+
   // Off-Main-Thread Painting state. This covers access to the OMTP-related
   // state below.
   Monitor mPaintLock;
 
   // Contains the number of outstanding asynchronous paints tied to a
   // PLayerTransaction on this bridge. This is R/W on both the main and paint
   // threads, and must be accessed within the paint lock.
   size_t mOutstandingAsyncPaints;
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -1507,17 +1507,19 @@ OOMTest(JSContext* cx, unsigned argc, Va
     }
     cx->runningOOMTest = true;
 
     MOZ_ASSERT(!cx->isExceptionPending());
     cx->runtime()->hadOutOfMemory = false;
 
     size_t compartmentCount = CountCompartments(cx);
 
+#ifdef JS_GC_ZEAL
     JS_SetGCZeal(cx, 0, JS_DEFAULT_ZEAL_FREQ);
+#endif
 
     for (unsigned thread = threadStart; thread < threadEnd; thread++) {
         if (verbose)
             fprintf(stderr, "thread %d\n", thread);
 
         HelperThreadState().waitForAllThreads();
         js::oom::targetThread = thread;
 
--- a/js/src/gdb/mozilla/JSString.py
+++ b/js/src/gdb/mozilla/JSString.py
@@ -33,16 +33,25 @@ class Common(mozilla.prettyprinters.Poin
 class JSStringPtr(Common):
     def display_hint(self):
         return "string"
 
     def chars(self):
         d = self.value['d']
         length = d['u1']['length']
         flags = d['u1']['flags']
+        corrupt = {
+            0x2f2f2f2f: 'JS_FRESH_NURSERY_PATTERN',
+            0x2b2b2b2b: 'JS_SWEPT_NURSERY_PATTERN',
+            0xe5e5e5e5: 'jemalloc freed memory',
+        }.get(flags & 0xffffffff)
+        if corrupt:
+            for ch in "<CORRUPT:%s>" % corrupt:
+                yield ch
+            return
         is_rope = ((flags & self.stc.TYPE_FLAGS_MASK) == self.stc.ROPE_FLAGS)
         if is_rope:
             for c in JSStringPtr(d['s']['u2']['left'], self.cache).chars():
                 yield c
             for c in JSStringPtr(d['s']['u3']['right'], self.cache).chars():
                 yield c
         else:
             is_inline = (flags & self.stc.INLINE_CHARS_BIT) != 0
@@ -55,18 +64,32 @@ class JSStringPtr(Common):
             else:
                 if is_latin1:
                     chars = d['s']['u2']['nonInlineCharsLatin1']
                 else:
                     chars = d['s']['u2']['nonInlineCharsTwoByte']
             for i in range(int(length)):
                 yield chars[i]
 
-    def to_string(self):
+    def to_string(self, maxlen=200):
         s = u''
+        invalid_chars_allowed = 2
         for c in self.chars():
-            s += chr(c)
+            if len(s) >= maxlen:
+                s += "..."
+                break
+
+            try:
+                # Convert from gdb.Value to string.
+                s += chr(c)
+            except ValueError:
+                if invalid_chars_allowed == 0:
+                    s += "<TOO_MANY_INVALID_CHARS>"
+                    break
+                else:
+                    invalid_chars_allowed -= 1
+                    s += "\\x%04x" % (c & 0xffff)
         return s
 
 @ptr_pretty_printer("JSAtom")
 class JSAtomPtr(Common):
     def to_string(self):
         return self.value.cast(self.cache.JSString_ptr_t)
--- a/js/src/irregexp/RegExpEngine.cpp
+++ b/js/src/irregexp/RegExpEngine.cpp
@@ -1783,17 +1783,17 @@ irregexp::CompilePattern(JSContext* cx, 
             first_step_node->AddAlternative(GuardedAlternative(char_class));
             node = first_step_node;
         } else {
             node = loop_node;
         }
     }
 
     if (compiler.isRegExpTooBig()) {
-        MOZ_ASSERT(compiler.cx()->isExceptionPending()); // over recursed
+        // This might erase the over-recurse error, if any.
         JS_ReportErrorASCII(cx, "regexp too big");
         return RegExpCode();
     }
 
     if (is_latin1) {
         node = node->FilterLATIN1(RegExpCompiler::kMaxRecursion, ignore_case, unicode);
         // Do it again to propagate the new nodes to places where they were not
         // put because they had not been calculated yet.
@@ -1907,17 +1907,17 @@ RegExpNode*
 RegExpDisjunction::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
 {
     if (!compiler->CheckOverRecursed())
         return on_success;
 
     const RegExpTreeVector& alternatives = this->alternatives();
     size_t length = alternatives.length();
     ChoiceNode* result = compiler->alloc()->newInfallible<ChoiceNode>(compiler->alloc(), length);
-    for (size_t i = 0; i < length; i++) {
+    for (size_t i = 0; i < length && !compiler->isRegExpTooBig(); i++) {
         GuardedAlternative alternative(alternatives[i]->ToNode(compiler, on_success));
         result->AddAlternative(alternative);
     }
     return result;
 }
 
 RegExpNode*
 RegExpQuantifier::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
@@ -2258,17 +2258,17 @@ RegExpCapture::ToNode(RegExpTree* body,
 RegExpNode*
 RegExpAlternative::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
 {
     if (!compiler->CheckOverRecursed())
         return on_success;
 
     const RegExpTreeVector& children = nodes();
     RegExpNode* current = on_success;
-    for (int i = children.length() - 1; i >= 0; i--)
+    for (int i = children.length() - 1; i >= 0 && !compiler->isRegExpTooBig(); i--)
         current = children[i]->ToNode(compiler, current);
     return current;
 }
 
 // -------------------------------------------------------------------
 // BoyerMooreLookahead
 
 ContainedInLattice
--- a/js/src/irregexp/RegExpInterpreter.cpp
+++ b/js/src/irregexp/RegExpInterpreter.cpp
@@ -128,17 +128,20 @@ irregexp::InterpretCode(JSContext* cx, c
     RegExpStackCursor stack(cx);
 
     if (!stack.init())
         return RegExpRunStatus_Error;
 
     int32_t numRegisters = Load32Aligned(pc);
     pc += 4;
 
-    Vector<int32_t, 0, SystemAllocPolicy> registers;
+    // Most of the time we need 8 or fewer registers.  Specify an initial
+    // size of 8 here, therefore, so that the vector contents can be stack
+    // allocated in the majority of cases.  See bug 1387394.
+    Vector<int32_t, 8, SystemAllocPolicy> registers;
     if (!registers.growByUninitialized(numRegisters)) {
         ReportOutOfMemory(cx);
         return RegExpRunStatus_Error;
     }
     for (size_t i = 0; i < (size_t) numRegisters; i++)
         registers[i] = -1;
 
     while (true) {
--- a/js/src/irregexp/RegExpMacroAssembler.cpp
+++ b/js/src/irregexp/RegExpMacroAssembler.cpp
@@ -151,28 +151,31 @@ InterpretedRegExpMacroAssembler::Advance
 }
 
 void
 InterpretedRegExpMacroAssembler::Backtrack()
 {
     Emit(BC_POP_BT, 0);
 }
 
+static const int32_t INVALID_OFFSET = -1;
+
 void
 InterpretedRegExpMacroAssembler::Bind(jit::Label* label)
 {
     advance_current_end_ = kInvalidPC;
     MOZ_ASSERT(!label->bound());
     if (label->used()) {
         int pos = label->offset();
-        while (pos != jit::Label::INVALID_OFFSET) {
+        MOZ_ASSERT(pos >= 0);
+        do {
             int fixup = pos;
             pos = *reinterpret_cast<int32_t*>(buffer_ + fixup);
             *reinterpret_cast<uint32_t*>(buffer_ + fixup) = pc_;
-        }
+        } while (pos != INVALID_OFFSET);
     }
     label->bind(pc_);
 }
 
 void
 InterpretedRegExpMacroAssembler::CheckAtStart(jit::Label* on_at_start)
 {
     Emit(BC_CHECK_AT_START, 0);
@@ -511,17 +514,18 @@ InterpretedRegExpMacroAssembler::BindBac
 void
 InterpretedRegExpMacroAssembler::EmitOrLink(jit::Label* label)
 {
     if (label == nullptr)
         label = &backtrack_;
     if (label->bound()) {
         Emit32(label->offset());
     } else {
-        int pos = label->use(pc_);
+        int pos = label->used() ? label->offset() : INVALID_OFFSET;
+        label->use(pc_);
         Emit32(pos);
     }
 }
 
 void
 InterpretedRegExpMacroAssembler::Emit(uint32_t byte, uint32_t twenty_four_bits)
 {
     uint32_t word = ((twenty_four_bits << BYTECODE_SHIFT) | byte);
--- a/js/src/irregexp/RegExpStack.h
+++ b/js/src/irregexp/RegExpStack.h
@@ -85,17 +85,17 @@ class RegExpStack
     void* base() { return base_; }
     void* limit() { return limit_; }
 
   private:
     // Artificial limit used when no memory has been allocated.
     static const uintptr_t kMemoryTop = static_cast<uintptr_t>(-1);
 
     // Minimal size of allocated stack area, in bytes.
-    static const size_t kMinimumStackSize = 256;
+    static const size_t kMinimumStackSize = 512;
 
     // Maximal size of allocated stack area, in bytes.
     static const size_t kMaximumStackSize = 64 * 1024 * 1024;
 
     // If size > 0 then base must be non-nullptr.
     void* base_;
 
     // Length in bytes of base.
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/huge-01.js
@@ -0,0 +1,19 @@
+
+function g(N, p) {
+    var prefix = p.repeat(N);
+    var str = prefix + "[AB]";
+
+    try {
+        var re = new RegExp(str);
+        re.exec(prefix + "A");
+    } catch(e) {
+        // 1. Regexp too big is raised by the lack of the 64k virtual registers
+        // reserved for the regexp evaluation.
+        // 2. The stack overflow can occur during the analysis of the regexp
+        assertEq(e.message.includes("regexp too big") || e.message.includes("Stack overflow"), true);
+    }
+}
+
+var prefix = "/(?=k)ok/";
+for (var i = 0; i < 18; i++)
+    g(Math.pow(2, i), prefix)
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -405,16 +405,17 @@ struct BaselineStackBuilder
         //  let X = STACK_START_ADDR + JitFrameLayout::Size() + PREV_FRAME_SIZE
         //      X + RectifierFrameLayout::Size()
         //        + ((RectifierFrameLayout*) X)->prevFrameLocalSize()
         //        - BaselineStubFrameLayout::reverseOffsetOfSavedFramePtr()
         size_t extraOffset = RectifierFrameLayout::Size() + priorFrame->prevFrameLocalSize() +
                              BaselineStubFrameLayout::reverseOffsetOfSavedFramePtr();
         return virtualPointerAtStackOffset(priorOffset + extraOffset);
 #elif defined(JS_CODEGEN_NONE)
+        (void) priorOffset;
         MOZ_CRASH();
 #else
 #  error "Bad architecture!"
 #endif
     }
 
     void setCheckGlobalDeclarationConflicts() {
         header_->checkGlobalDeclarationConflicts = true;
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -11162,16 +11162,18 @@ class OutOfLineSwitch : public OutOfLine
 template <SwitchTableType tableType>
 void
 CodeGenerator::visitOutOfLineSwitch(OutOfLineSwitch<tableType>* jumpTable)
 {
     jumpTable->setOutOfLine();
     if (tableType == SwitchTableType::OutOfLine) {
 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
         MOZ_CRASH("NYI: SwitchTableType::OutOfLine");
+#elif defined(JS_CODEGEN_NONE)
+        MOZ_CRASH();
 #else
         masm.haltingAlign(sizeof(void*));
         masm.use(jumpTable->start()->target());
         masm.addCodeLabel(*jumpTable->start());
 #endif
     }
 
     // Add table entries if the table is inlined.
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -7248,42 +7248,16 @@ IonBuilder::ensureDefiniteType(MDefiniti
         break;
       }
     }
 
     current->add(replace);
     return replace;
 }
 
-MDefinition*
-IonBuilder::ensureDefiniteTypeSet(MDefinition* def, TemporaryTypeSet* types)
-{
-    // We cannot arbitrarily add a typeset to a definition. It can be shared
-    // in another path. So we always need to create a new MIR.
-
-    // Use ensureDefiniteType to do unboxing. If that happened the type can
-    // be added on the newly created unbox operation.
-    MDefinition* replace = ensureDefiniteType(def, types->getKnownMIRType());
-    if (replace != def) {
-        replace->setResultTypeSet(types);
-        return replace;
-    }
-
-    // Don't replace if input type is more accurate than given typeset.
-    if (def->type() != types->getKnownMIRType()) {
-        MOZ_ASSERT(types->getKnownMIRType() == MIRType::Value);
-        return def;
-    }
-
-    // Create a NOP mir instruction to filter the typeset.
-    MFilterTypeSet* filter = MFilterTypeSet::New(alloc(), def, types);
-    current->add(filter);
-    return filter;
-}
-
 static size_t
 NumFixedSlots(JSObject* object)
 {
     // Note: we can't use object->numFixedSlots() here, as this will read the
     // shape and can race with the active thread if we are building off thread.
     // The allocation kind and object class (which goes through the type) can
     // be read freely, however.
     gc::AllocKind kind = object->asTenured().getAllocKind();
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -176,19 +176,16 @@ class IonBuilder
                                          JSFunction* func);
 
     // If definiteType is not known or def already has the right type, just
     // returns def.  Otherwise, returns an MInstruction that has that definite
     // type, infallibly unboxing ins as needed.  The new instruction will be
     // added to |current| in this case.
     MDefinition* ensureDefiniteType(MDefinition* def, MIRType definiteType);
 
-    // Creates a MDefinition based on the given def improved with type as TypeSet.
-    MDefinition* ensureDefiniteTypeSet(MDefinition* def, TemporaryTypeSet* types);
-
     void maybeMarkEmpty(MDefinition* ins);
 
     JSObject* getSingletonPrototype(JSFunction* target);
 
     MDefinition* createThisScripted(MDefinition* callee, MDefinition* newTarget);
     MDefinition* createThisScriptedSingleton(JSFunction* target, MDefinition* callee);
     MDefinition* createThisScriptedBaseline(MDefinition* callee);
     MDefinition* createThis(JSFunction* target, MDefinition* callee, MDefinition* newTarget);
--- a/js/src/jit/IonCacheIRCompiler.cpp
+++ b/js/src/jit/IonCacheIRCompiler.cpp
@@ -1,16 +1,17 @@
 /* -*- 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 "mozilla/DebugOnly.h"
 
+#include "jit/BaselineIC.h"
 #include "jit/CacheIRCompiler.h"
 #include "jit/IonCaches.h"
 #include "jit/IonIC.h"
 
 #include "jit/Linker.h"
 #include "jit/SharedICHelpers.h"
 #include "proxy/Proxy.h"
 
--- a/js/src/jit/JitSpewer.cpp
+++ b/js/src/jit/JitSpewer.cpp
@@ -553,17 +553,24 @@ jit::CheckLogging()
         EnableChannel(JitSpew_BaselineOp);
         EnableChannel(JitSpew_BaselineIC);
         EnableChannel(JitSpew_BaselineICFallback);
         EnableChannel(JitSpew_BaselineOSR);
         EnableChannel(JitSpew_BaselineBailouts);
         EnableChannel(JitSpew_BaselineDebugModeOSR);
     }
 
-    JitSpewPrinter().init(stderr);
+    FILE* spewfh = stderr;
+    const char* filename = getenv("ION_SPEW_FILENAME");
+    if (filename && *filename) {
+        spewfh = fopen(filename, "w");
+        MOZ_RELEASE_ASSERT(spewfh);
+        setbuf(spewfh, nullptr); // Make unbuffered
+    }
+    JitSpewPrinter().init(spewfh);
 }
 
 JitSpewIndent::JitSpewIndent(JitSpewChannel channel)
   : channel_(channel)
 {
     ChannelIndentLevel[channel]++;
 }
 
--- a/js/src/jit/Label.h
+++ b/js/src/jit/Label.h
@@ -9,75 +9,67 @@
 
 #include "jit/Ion.h"
 
 namespace js {
 namespace jit {
 
 struct LabelBase
 {
-  protected:
-    // offset_ >= 0 means that the label is either bound or has incoming
-    // uses and needs to be bound.
-    int32_t offset_ : 31;
-
+  private:
     // We use uint32_t instead of bool to ensure MSVC packs these fields
     // correctly.
     uint32_t bound_ : 1;
 
-    void operator =(const LabelBase& label) = delete;
+    // offset_ < INVALID_OFFSET means that the label is either bound or has
+    // incoming uses and needs to be bound.
+    uint32_t offset_ : 31;
+
+    void operator=(const LabelBase& label) = delete;
+
+    static const uint32_t INVALID_OFFSET = 0x7fffffff; // UINT31_MAX.
 
   public:
-    static const int32_t INVALID_OFFSET = -1;
-
-    LabelBase() : offset_(INVALID_OFFSET), bound_(false)
+    LabelBase() : bound_(false), offset_(INVALID_OFFSET)
     { }
 
     // If the label is bound, all incoming edges have been patched and any
     // future incoming edges will be immediately patched.
     bool bound() const {
         return bound_;
     }
     int32_t offset() const {
         MOZ_ASSERT(bound() || used());
         return offset_;
     }
-    void offsetBy(int32_t delta) {
-        MOZ_ASSERT(bound() || used());
-        MOZ_ASSERT(offset() + delta >= offset(), "no overflow");
-        mozilla::DebugOnly<int32_t> oldOffset(offset());
-        offset_ += delta;
-        MOZ_ASSERT(offset_ == delta + oldOffset, "new offset fits in 31 bits");
-    }
     // Returns whether the label is not bound, but has incoming uses.
     bool used() const {
-        return !bound() && offset_ > INVALID_OFFSET;
+        return !bound() && offset_ < INVALID_OFFSET;
     }
     // Binds the label, fixing its final position in the code stream.
     void bind(int32_t offset) {
         MOZ_ASSERT(!bound());
+        MOZ_ASSERT(offset >= 0);
+        MOZ_ASSERT(uint32_t(offset) < INVALID_OFFSET);
         offset_ = offset;
         bound_ = true;
         MOZ_ASSERT(offset_ == offset, "offset fits in 31 bits");
     }
     // Marks the label as neither bound nor used.
     void reset() {
         offset_ = INVALID_OFFSET;
         bound_ = false;
     }
-    // Sets the label's latest used position, returning the old use position in
-    // the process.
-    int32_t use(int32_t offset) {
+    // Sets the label's latest used position.
+    void use(int32_t offset) {
         MOZ_ASSERT(!bound());
-
-        int32_t old = offset_;
+        MOZ_ASSERT(offset >= 0);
+        MOZ_ASSERT(uint32_t(offset) < INVALID_OFFSET);
         offset_ = offset;
         MOZ_ASSERT(offset_ == offset, "offset fits in 31 bits");
-
-        return old;
     }
 };
 
 // A label represents a position in an assembly buffer that may or may not have
 // already been generated. Labels can either be "bound" or "unbound", the
 // former meaning that its position is known and the latter that its position
 // is not yet known.
 //
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -2885,16 +2885,20 @@ IonBuilder::inlineUnsafeSetReservedSlot(
     if (arg->type() != MIRType::Int32)
         return InliningStatus_NotInlined;
 
     // Don't inline if we don't have a constant slot.
     if (!arg->isConstant())
         return InliningStatus_NotInlined;
     uint32_t slot = uint32_t(arg->toConstant()->toInt32());
 
+    // Don't inline if it's not a fixed slot.
+    if (slot >= NativeObject::MAX_FIXED_SLOTS)
+        return InliningStatus_NotInlined;
+
     callInfo.setImplicitlyUsedUnchecked();
 
     MStoreFixedSlot* store =
         MStoreFixedSlot::NewBarriered(alloc(), obj, slot, callInfo.getArg(2));
     current->add(store);
     current->push(store);
 
     if (needsPostBarrier(callInfo.getArg(2)))
@@ -2919,16 +2923,20 @@ IonBuilder::inlineUnsafeGetReservedSlot(
     if (arg->type() != MIRType::Int32)
         return InliningStatus_NotInlined;
 
     // Don't inline if we don't have a constant slot.
     if (!arg->isConstant())
         return InliningStatus_NotInlined;
     uint32_t slot = uint32_t(arg->toConstant()->toInt32());
 
+    // Don't inline if it's not a fixed slot.
+    if (slot >= NativeObject::MAX_FIXED_SLOTS)
+        return InliningStatus_NotInlined;
+
     callInfo.setImplicitlyUsedUnchecked();
 
     MLoadFixedSlot* load = MLoadFixedSlot::New(alloc(), obj, slot);
     current->add(load);
     current->push(load);
     if (knownValueType != MIRType::Value) {
         // We know what type we have in this slot.  Assert that this is in fact
         // what we've seen coming from this slot in the past, then tell the
--- a/js/src/jit/arm/Assembler-arm.cpp
+++ b/js/src/jit/arm/Assembler-arm.cpp
@@ -949,18 +949,19 @@ Assembler::processCodeLabels(uint8_t* ra
 {
     for (size_t i = 0; i < codeLabels_.length(); i++) {
         CodeLabel label = codeLabels_[i];
         Bind(rawCode, label.patchAt(), rawCode + label.target()->offset());
     }
 }
 
 void
-Assembler::writeCodePointer(CodeOffset* label) {
-    BufferOffset off = writeInst(LabelBase::INVALID_OFFSET);
+Assembler::writeCodePointer(CodeOffset* label)
+{
+    BufferOffset off = writeInst(-1);
     label->bind(off.getOffset());
 }
 
 void
 Assembler::Bind(uint8_t* rawCode, CodeOffset* label, const void* address)
 {
     *reinterpret_cast<const void**>(rawCode + label->offset()) = address;
 }
@@ -2383,38 +2384,35 @@ Assembler::as_b(Label* l, Condition c)
         spewBranch(m_buffer.getInstOrNull(ret), l);
 #endif
         return ret;
     }
 
     if (oom())
         return BufferOffset();
 
-    int32_t old;
     BufferOffset ret;
     if (l->used()) {
-        old = l->offset();
+        int32_t old = l->offset();
         // This will currently throw an assertion if we couldn't actually
         // encode the offset of the branch.
         if (!BOffImm::IsInRange(old)) {
             m_buffer.fail_bail();
             return ret;
         }
         ret = as_b(BOffImm(old), c, l);
     } else {
-        old = LabelBase::INVALID_OFFSET;
         BOffImm inv;
         ret = as_b(inv, c, l);
     }
 
     if (oom())
         return BufferOffset();
 
-    DebugOnly<int32_t> check = l->use(ret.getOffset());
-    MOZ_ASSERT(check == old);
+    l->use(ret.getOffset());
     return ret;
 }
 
 BufferOffset
 Assembler::as_b(wasm::TrapDesc target, Condition c)
 {
     Label l;
     BufferOffset ret = as_b(&l, c);
@@ -2470,39 +2468,36 @@ Assembler::as_bl(Label* l, Condition c)
         spewBranch(m_buffer.getInstOrNull(ret), l);
 #endif
         return ret;
     }
 
     if (oom())
         return BufferOffset();
 
-    int32_t old;
     BufferOffset ret;
-    // See if the list was empty :(
+    // See if the list was empty.
     if (l->used()) {
         // This will currently throw an assertion if we couldn't actually encode
         // the offset of the branch.
-        old = l->offset();
+        int32_t old = l->offset();
         if (!BOffImm::IsInRange(old)) {
             m_buffer.fail_bail();
             return ret;
         }
         ret = as_bl(BOffImm(old), c, l);
     } else {
-        old = LabelBase::INVALID_OFFSET;
         BOffImm inv;
         ret = as_bl(inv, c, l);
     }
 
     if (oom())
         return BufferOffset();
 
-    DebugOnly<int32_t> check = l->use(ret.getOffset());
-    MOZ_ASSERT(check == old);
+    l->use(ret.getOffset());
     return ret;
 }
 
 BufferOffset
 Assembler::as_bl(BOffImm off, Condition c, BufferOffset inst)
 {
     *editSrc(inst) = InstBLImm(off, c);
     return inst;
@@ -2919,28 +2914,28 @@ Assembler::retarget(Label* label, Label*
             // Find the head of the use chain for label.
             while (nextLink(labelBranchOffset, &next))
                 labelBranchOffset = next;
 
             // Then patch the head of label's use chain to the tail of target's
             // use chain, prepending the entire use chain of target.
             Instruction branch = *editSrc(labelBranchOffset);
             Condition c = branch.extractCond();
-            int32_t prev = target->use(label->offset());
+            int32_t prev = target->offset();
+            target->use(label->offset());
             if (branch.is<InstBImm>())
                 as_b(BOffImm(prev), c, labelBranchOffset);
             else if (branch.is<InstBLImm>())
                 as_bl(BOffImm(prev), c, labelBranchOffset);
             else
                 MOZ_CRASH("crazy fixup!");
         } else {
             // The target is unbound and unused. We can just take the head of
             // the list hanging off of label, and dump that into target.
-            DebugOnly<uint32_t> prev = target->use(label->offset());
-            MOZ_ASSERT((int32_t)prev == Label::INVALID_OFFSET);
+            target->use(label->offset());
         }
     }
     label->reset();
 
 }
 
 static int stopBKPT = -1;
 void
--- a/js/src/jit/arm64/Assembler-arm64.cpp
+++ b/js/src/jit/arm64/Assembler-arm64.cpp
@@ -657,17 +657,16 @@ Assembler::retarget(Label* label, Label*
 
             // Then patch the head of label's use chain to the tail of target's
             // use chain, prepending the entire use chain of target.
             SetNextLink(labelBranchOffset, BufferOffset(target));
             target->use(label->offset());
         } else {
             // The target is unbound and unused. We can just take the head of
             // the list hanging off of label, and dump that into target.
-            DebugOnly<uint32_t> prev = target->use(label->offset());
-            MOZ_ASSERT((int32_t)prev == Label::INVALID_OFFSET);
+            target->use(label->offset());
         }
     }
     label->reset();
 }
 
 } // namespace jit
 } // namespace js
--- a/js/src/jit/arm64/Assembler-arm64.h
+++ b/js/src/jit/arm64/Assembler-arm64.h
@@ -363,31 +363,18 @@ class Assembler : public vixl::Assembler
             return reinterpret_cast<Instruction*>(&ldr);
         }
     };
 
     // Offset of the patchable target for the given entry.
     static const size_t OffsetOfJumpTableEntryPointer = 8;
 
   public:
-    void writeCodePointer(AbsoluteLabel* absoluteLabel) {
-        MOZ_ASSERT(!absoluteLabel->bound());
-        uintptr_t x = LabelBase::INVALID_OFFSET;
-        BufferOffset off = EmitData(&x, sizeof(uintptr_t));
-
-        // The x86/x64 makes general use of AbsoluteLabel and weaves a linked list
-        // of uses of an AbsoluteLabel through the assembly. ARM only uses labels
-        // for the case statements of switch jump tables. Thus, for simplicity, we
-        // simply treat the AbsoluteLabel as a label and bind it to the offset of
-        // the jump table entry that needs to be patched.
-        LabelBase* label = absoluteLabel;
-        label->bind(off.getOffset());
-    }
     void writeCodePointer(CodeOffset* label) {
-        uintptr_t x = LabelBase::INVALID_OFFSET;
+        uintptr_t x = uintptr_t(-1);
         BufferOffset off = EmitData(&x, sizeof(uintptr_t));
         label->bind(off.getOffset());
     }
 
 
     void verifyHeapAccessDisassembly(uint32_t begin, uint32_t end,
                                      const Disassembler::HeapAccess& heapAccess)
     {
--- a/js/src/jit/none/MacroAssembler-none.h
+++ b/js/src/jit/none/MacroAssembler-none.h
@@ -205,16 +205,17 @@ class MacroAssemblerNone : public Assemb
     void processCodeLabels(uint8_t*) { MOZ_CRASH(); }
 
     void flushBuffer() { MOZ_CRASH(); }
 
     template <typename T> void bind(T) { MOZ_CRASH(); }
     void bindLater(Label*, wasm::TrapDesc) { MOZ_CRASH(); }
     template <typename T> void j(Condition, T) { MOZ_CRASH(); }
     template <typename T> void jump(T) { MOZ_CRASH(); }
+    void writeCodePointer(CodeOffset* label) { MOZ_CRASH(); }
     void haltingAlign(size_t) { MOZ_CRASH(); }
     void nopAlign(size_t) { MOZ_CRASH(); }
     void checkStackAlignment() { MOZ_CRASH(); }
     uint32_t currentOffset() { MOZ_CRASH(); }
     uint32_t labelToPatchOffset(CodeOffset) { MOZ_CRASH(); }
     CodeOffset labelForPatch() { MOZ_CRASH(); }
 
     void nop() { MOZ_CRASH(); }
--- a/js/src/jit/shared/Assembler-shared.h
+++ b/js/src/jit/shared/Assembler-shared.h
@@ -394,42 +394,16 @@ class RepatchLabel
         MOZ_ASSERT(!bound());
         return offset_;
     }
     bool used() const {
         return !bound() && offset_ != (INVALID_OFFSET);
     }
 
 };
-// An absolute label is like a Label, except it represents an absolute
-// reference rather than a relative one. Thus, it cannot be patched until after
-// linking.
-struct AbsoluteLabel : public LabelBase
-{
-  public:
-    AbsoluteLabel()
-    { }
-    AbsoluteLabel(const AbsoluteLabel& label) : LabelBase(label)
-    { }
-    int32_t prev() const {
-        MOZ_ASSERT(!bound());
-        if (!used())
-            return INVALID_OFFSET;
-        return offset();
-    }
-    void setPrev(int32_t offset) {
-        use(offset);
-    }
-    void bind() {
-        bound_ = true;
-
-        // These labels cannot be used after being bound.
-        offset_ = -1;
-    }
-};
 
 class CodeOffset
 {
     size_t offset_;
 
     static const size_t NOT_BOUND = size_t(-1);
 
   public:
--- a/js/src/jit/x86-shared/Assembler-x86-shared.h
+++ b/js/src/jit/x86-shared/Assembler-x86-shared.h
@@ -444,18 +444,18 @@ class AssemblerX86Shared : public Assemb
   public:
     void haltingAlign(int alignment) {
         masm.haltingAlign(alignment);
     }
     void nopAlign(int alignment) {
         masm.nopAlign(alignment);
     }
     void writeCodePointer(CodeOffset* label) {
-        // A CodeOffset only has one use, bake in the "end of list" value.
-        masm.jumpTablePointer(LabelBase::INVALID_OFFSET);
+        // Use -1 as dummy value. This will be patched after codegen.
+        masm.jumpTablePointer(-1);
         label->bind(masm.size());
     }
     void cmovz(const Operand& src, Register dest) {
         switch (src.kind()) {
           case Operand::REG:
             masm.cmovz_rr(src.reg(), dest.encoding());
             break;
           case Operand::MEM_REG_DISP:
@@ -848,41 +848,50 @@ class AssemblerX86Shared : public Assemb
   protected:
     void jSrc(Condition cond, Label* label) {
         if (label->bound()) {
             // The jump can be immediately encoded to the correct destination.
             masm.jCC_i(static_cast<X86Encoding::Condition>(cond), JmpDst(label->offset()));
         } else {
             // Thread the jump list through the unpatched jump targets.
             JmpSrc j = masm.jCC(static_cast<X86Encoding::Condition>(cond));
-            JmpSrc prev = JmpSrc(label->use(j.offset()));
+            JmpSrc prev;
+            if (label->used())
+                prev = JmpSrc(label->offset());
+            label->use(j.offset());
             masm.setNextJump(j, prev);
         }
     }
     void jmpSrc(Label* label) {
         if (label->bound()) {
             // The jump can be immediately encoded to the correct destination.
             masm.jmp_i(JmpDst(label->offset()));
         } else {
             // Thread the jump list through the unpatched jump targets.
             JmpSrc j = masm.jmp();
-            JmpSrc prev = JmpSrc(label->use(j.offset()));
+            JmpSrc prev;
+            if (label->used())
+                prev = JmpSrc(label->offset());
+            label->use(j.offset());
             masm.setNextJump(j, prev);
         }
     }
 
     // Comparison of EAX against the address given by a Label.
     JmpSrc cmpSrc(Label* label) {
         JmpSrc j = masm.cmp_eax();
         if (label->bound()) {
             // The jump can be immediately patched to the correct destination.
             masm.linkJump(j, JmpDst(label->offset()));
         } else {
             // Thread the jump list through the unpatched jump targets.
-            JmpSrc prev = JmpSrc(label->use(j.offset()));
+            JmpSrc prev;
+            if (label->used())
+                prev = JmpSrc(label->offset());
+            label->use(j.offset());
             masm.setNextJump(j, prev);
         }
         return j;
     }
 
     JmpSrc jSrc(Condition cond, RepatchLabel* label) {
         JmpSrc j = masm.jCC(static_cast<X86Encoding::Condition>(cond));
         if (label->bound()) {
@@ -987,17 +996,20 @@ class AssemblerX86Shared : public Assemb
         do {
             JmpSrc next;
             more = masm.nextJump(jmp, &next);
             if (target->bound()) {
                 // The jump can be immediately patched to the correct destination.
                 masm.linkJump(jmp, JmpDst(target->offset()));
             } else {
                 // Thread the jump list through the unpatched jump targets.
-                JmpSrc prev(target->use(jmp.offset()));
+                JmpSrc prev;
+                if (target->used())
+                    prev = JmpSrc(target->offset());
+                target->use(jmp.offset());
                 masm.setNextJump(jmp, prev);
             }
             jmp = JmpSrc(next.offset());
         } while (more);
         label->reset();
     }
 
     static void Bind(uint8_t* raw, CodeOffset* label, const void* address) {
@@ -1015,21 +1027,24 @@ class AssemblerX86Shared : public Assemb
     void ret() {
         masm.ret();
     }
     void retn(Imm32 n) {
         // Remove the size of the return address which is included in the frame.
         masm.ret_i(n.value - sizeof(void*));
     }
     CodeOffset call(Label* label) {
+        JmpSrc j = masm.call();
         if (label->bound()) {
-            masm.linkJump(masm.call(), JmpDst(label->offset()));
+            masm.linkJump(j, JmpDst(label->offset()));
         } else {
-            JmpSrc j = masm.call();
-            JmpSrc prev = JmpSrc(label->use(j.offset()));
+            JmpSrc prev;
+            if (label->used())
+                prev = JmpSrc(label->offset());
+            label->use(j.offset());
             masm.setNextJump(j, prev);
         }
         return CodeOffset(masm.currentOffset());
     }
     CodeOffset call(Register reg) {
         masm.call_r(reg.encoding());
         return CodeOffset(masm.currentOffset());
     }
--- a/js/src/jit/x86-shared/Patching-x86-shared.h
+++ b/js/src/jit/x86-shared/Patching-x86-shared.h
@@ -57,61 +57,40 @@ GetRel32Target(void* where)
 {
     int32_t rel = GetInt32(where);
     return (char*)where + rel;
 }
 
 class JmpSrc {
   public:
     JmpSrc()
-        : offset_(-1)
-    {
-    }
-
-    explicit JmpSrc(int32_t offset)
-        : offset_(offset)
+      : offset_(-1)
     {
     }
-
-    int32_t offset() const {
-        return offset_;
-    }
-
-    bool isSet() const {
-        return offset_ != -1;
-    }
-
-  private:
-    int offset_;
-};
-
-class JmpDst {
-  public:
-    JmpDst()
-        : offset_(-1)
-        , used_(false)
+    explicit JmpSrc(int32_t offset)
+      : offset_(offset)
     {
     }
-
-    bool isUsed() const { return used_; }
-    void used() { used_ = true; }
-    bool isValid() const { return offset_ != -1; }
-
-    explicit JmpDst(int32_t offset)
-        : offset_(offset)
-        , used_(false)
-    {
-        MOZ_ASSERT(offset_ == offset);
-    }
     int32_t offset() const {
         return offset_;
     }
   private:
-    int32_t offset_ : 31;
-    bool used_ : 1;
+    int32_t offset_;
+};
+
+class JmpDst {
+  public:
+    explicit JmpDst(int32_t offset)
+      : offset_(offset)
+    {}
+    int32_t offset() const {
+        return offset_;
+    }
+  private:
+    int32_t offset_;
 };
 
 inline bool
 CanRelinkJump(void* from, void* to)
 {
     intptr_t offset = static_cast<char*>(to) - static_cast<char*>(from);
     return (offset == static_cast<int32_t>(offset));
 }
--- a/js/src/wasm/WasmSignalHandlers.cpp
+++ b/js/src/wasm/WasmSignalHandlers.cpp
@@ -432,25 +432,23 @@ ContextToFP(CONTEXT* context)
 {
 #ifdef JS_CODEGEN_NONE
     MOZ_CRASH();
 #else
     return reinterpret_cast<uint8_t*>(FP_sig(context));
 #endif
 }
 
+#ifndef JS_CODEGEN_NONE
 static uint8_t*
 ContextToSP(CONTEXT* context)
 {
-#ifdef JS_CODEGEN_NONE
-    MOZ_CRASH();
-#else
     return reinterpret_cast<uint8_t*>(SP_sig(context));
+}
 #endif
-}
 
 #if defined(__arm__) || defined(__aarch64__)
 static uint8_t*
 ContextToLR(CONTEXT* context)
 {
     return reinterpret_cast<uint8_t*>(LR_sig(context));
 }
 #endif
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -1001,21 +1001,21 @@ XPCConvert::ConstructException(nsresult 
                                nsIException** exceptn,
                                JSContext* cx,
                                Value* jsExceptionPtr)
 {
     MOZ_ASSERT(!cx == !jsExceptionPtr, "Expected cx and jsExceptionPtr to cooccur.");
 
     static const char format[] = "\'%s\' when calling method: [%s::%s]";
     const char * msg = message;
-    nsXPIDLString xmsg;
-    nsAutoCString sxmsg;
+    nsAutoCString sxmsg;    // must have the same lifetime as msg
 
     nsCOMPtr<nsIScriptError> errorObject = do_QueryInterface(data);
     if (errorObject) {
+        nsString xmsg;
         if (NS_SUCCEEDED(errorObject->GetMessageMoz(getter_Copies(xmsg)))) {
             CopyUTF16toUTF8(xmsg, sxmsg);
             msg = sxmsg.get();
         }
     }
     if (!msg)
         if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &msg) || ! msg)
             msg = "<error>";
--- a/js/xpconnect/src/XPCJSID.cpp
+++ b/js/xpconnect/src/XPCJSID.cpp
@@ -451,37 +451,36 @@ nsJSIID::Enumerate(nsIXPConnectWrappedNa
  *     there's chrome code that relies on this.
  *
  * This static method handles both complexities, returning either an XPCWN, a
  * DOM object, or null. The object may well be cross-compartment from |cx|.
  */
 static nsresult
 FindObjectForHasInstance(JSContext* cx, HandleObject objArg, MutableHandleObject target)
 {
+    using namespace mozilla::jsipc;
     RootedObject obj(cx, objArg), proto(cx);
-
-    while (obj && !IS_WN_REFLECTOR(obj) &&
-           !IsDOMObject(obj) && !mozilla::jsipc::IsCPOW(obj))
-    {
-        if (js::IsWrapper(obj)) {
-            obj = js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
-            continue;
+    while (true) {
+        // Try the object, or the wrappee if allowed.
+        JSObject* o = js::IsWrapper(obj) ? js::CheckedUnwrap(obj, false) : obj;
+        if (o && (IS_WN_REFLECTOR(o) || IsDOMObject(o) || IsCPOW(o))) {
+            target.set(o);
+            return NS_OK;
         }
 
-        {
-            JSAutoCompartment ac(cx, obj);
-            if (!js::GetObjectProto(cx, obj, &proto))
-                return NS_ERROR_FAILURE;
+        // Walk the prototype chain from the perspective of the callee (i.e.
+        // respecting Xrays if they exist).
+        if (!js::GetObjectProto(cx, obj, &proto))
+            return NS_ERROR_FAILURE;
+        if (!proto) {
+            target.set(nullptr);
+            return NS_OK;
         }
-
         obj = proto;
     }
-
-    target.set(obj);
-    return NS_OK;
 }
 
 nsresult
 xpc::HasInstance(JSContext* cx, HandleObject objArg, const nsID* iid, bool* bp)
 {
     *bp = false;
 
     RootedObject obj(cx);
--- a/layout/generic/nsAbsoluteContainingBlock.cpp
+++ b/layout/generic/nsAbsoluteContainingBlock.cpp
@@ -676,18 +676,18 @@ nsAbsoluteContainingBlock::ReflowAbsolut
   }
   ReflowInput kidReflowInput(aPresContext, aReflowInput, aKidFrame,
                                    LogicalSize(wm, availISize,
                                                NS_UNCONSTRAINEDSIZE),
                                    &logicalCBSize, rsFlags);
 
   // Get the border values
   WritingMode outerWM = aReflowInput.GetWritingMode();
-  const LogicalMargin border(outerWM,
-                             aReflowInput.mStyleBorder->GetComputedBorder());
+  const LogicalMargin border(outerWM, aDelegatingFrame->GetUsedBorder());
+
   LogicalMargin margin =
     kidReflowInput.ComputedLogicalMargin().ConvertTo(outerWM, wm);
 
   // If we're doing CSS Box Alignment in either axis, that will apply the
   // margin for us in that axis (since the thing that's aligned is the margin
   // box).  So, we clear out the margin here to avoid applying it twice.
   if (kidReflowInput.mFlags.mIOffsetsNeedCSSAlign) {
     margin.IStart(outerWM) = margin.IEnd(outerWM) = 0;
--- a/layout/generic/nsPageFrame.cpp
+++ b/layout/generic/nsPageFrame.cpp
@@ -634,25 +634,25 @@ nsPageFrame::PaintHeaderFooter(gfxContex
   nscoord ascent = 0;
   nscoord visibleHeight = 0;
   if (fontMet) {
     visibleHeight = fontMet->MaxHeight();
     ascent = fontMet->MaxAscent();
   }
 
   // print document headers and footers
-  nsXPIDLString headerLeft, headerCenter, headerRight;
+  nsString headerLeft, headerCenter, headerRight;
   mPD->mPrintSettings->GetHeaderStrLeft(getter_Copies(headerLeft));
   mPD->mPrintSettings->GetHeaderStrCenter(getter_Copies(headerCenter));
   mPD->mPrintSettings->GetHeaderStrRight(getter_Copies(headerRight));
   DrawHeaderFooter(aRenderingContext, *fontMet, eHeader,
                    headerLeft, headerCenter, headerRight,
                    rect, ascent, visibleHeight);
 
-  nsXPIDLString footerLeft, footerCenter, footerRight;
+  nsString footerLeft, footerCenter, footerRight;
   mPD->mPrintSettings->GetFooterStrLeft(getter_Copies(footerLeft));
   mPD->mPrintSettings->GetFooterStrCenter(getter_Copies(footerCenter));
   mPD->mPrintSettings->GetFooterStrRight(getter_Copies(footerRight));
   DrawHeaderFooter(aRenderingContext, *fontMet, eFooter,
                    footerLeft, footerCenter, footerRight,
                    rect, ascent, visibleHeight);
 }
 
--- a/layout/printing/nsPrintEngine.cpp
+++ b/layout/printing/nsPrintEngine.cpp
@@ -1021,17 +1021,17 @@ nsPrintEngine::CheckForPrinters(nsIPrint
   // Unless we are in the parent, we ignore this function
   if (!XRE_IsParentProcess()) {
     return NS_OK;
   }
 #endif
   NS_ENSURE_ARG_POINTER(aPrintSettings);
 
   // See if aPrintSettings already has a printer
-  nsXPIDLString printerName;
+  nsString printerName;
   nsresult rv = aPrintSettings->GetPrinterName(getter_Copies(printerName));
   if (NS_SUCCEEDED(rv) && !printerName.IsEmpty()) {
     return NS_OK;
   }
 
   // aPrintSettings doesn't have a printer set. Try to fetch the default.
   nsCOMPtr<nsIPrintSettingsService> printSettingsService =
     do_GetService(sPrintSettingsServiceContractID, &rv);
new file mode 100644
--- /dev/null
+++ b/layout/reftests/table-bordercollapse/bug1379306-ref.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<title>Table Cell Testcase, bug 1379306</title>
+<style>
+  table.collapse {
+    border-collapse: collapse;
+  }
+  td {
+    border: 20px solid #aaa;
+    width: 120px;
+    height: 150px;
+  }
+  .first {
+    background-color: #000;
+    position: absolute;
+    top: 20px;
+    left: 20px;
+    height: 10px;
+    width: 20px
+  }
+</style>
+<h1>Table Cell Testcase, bug 1379306</h1>
+
+<div style="position: relative;">
+  <table class="collapse">
+    <tr>
+      <td>
+        <div class="first"></div>
+      </td>
+    </tr>
+  </table>
+</div>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/table-bordercollapse/bug1379306.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>Table Cell Testcase, bug 1379306</title>
+<style>
+  table.collapse {
+    border-collapse: collapse;
+  }
+  td {
+    border: 20px solid #aaa;
+    width: 120px;
+    height: 150px;
+    position: relative;
+  }
+  div {
+    background-color: #000;
+    position: absolute;
+    top: 0;
+    left: 0;
+    height: 10px;
+    width: 20px
+  }
+</style>
+<h1>Table Cell Testcase, bug 1379306</h1>
+
+<table class="collapse">
+  <tr>
+    <td>
+      <div></div>
+    </td>
+  </tr>
+</table>
--- a/layout/reftests/table-bordercollapse/reftest.list
+++ b/layout/reftests/table-bordercollapse/reftest.list
@@ -1,13 +1,14 @@
 == bug1375518.html bug1375518-ref.html
 == bug1375518-2.html bug1375518-ref.html
 == bug1375518-3.html bug1375518-ref.html
 == bug1375518-4.html bug1375518-4-ref.html
 == bug1375518-5.html bug1375518-5-ref.html
+== bug1379306.html bug1379306-ref.html
 == bc_dyn_cell1.html bc_dyn_cell1_ref.html
 == bc_dyn_cell2.html bc_dyn_cell2_ref.html
 == bc_dyn_cell3.html bc_dyn_cell3_ref.html
 == bc_dyn_cell4.html bc_dyn_cell4_ref.html
 == bc_dyn_cell5.html bc_dyn_cell5_ref.html
 == bc_dyn_row1.html bc_dyn_rg1_ref.html
 == bc_dyn_row2.html bc_dyn_rg2_ref.html
 == bc_dyn_row3.html bc_dyn_rg3_ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/table-html/bug1379306-2-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<title>Table Row Testcase, bug 1379306</title>
+<style>
+
+table { background: yellow }
+td { height: 50px; width: 200px; background: aqua; }
+div { background: fuchsia; height: 10px; width: 20px }
+
+tr { position: relative; border: 30px solid blue; }
+div { position: absolute; top: 0; left: 0 }
+
+</style>
+<h1>Table Row Testcase, bug 1379306</h1>
+
+<table>
+  <tr>
+    <td>
+      <div></div>
+    </td>
+  </tr>
+</table>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/table-html/bug1379306-2.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<title>Testcase, bug 1379306</title>
+<style>
+
+table { background: yellow }
+td { height: 50px; width: 200px; background: aqua; }
+div { background: fuchsia; height: 10px; width: 20px }
+
+tr { position: relative; border: 10px solid blue }
+div { position: absolute; top: 0; left: 0 }
+
+</style>
+<h1>Table Row Testcase, bug 1379306</h1>
+
+<table>
+  <tr>
+    <td>
+      <div></div>
+    </td>
+  </tr>
+</table>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/table-html/bug1379306-3-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<title>Testcase, bug 1379306</title>
+<style>
+
+table { background: yellow }
+td { height: 50px; width: 200px; background: aqua; }
+div { background: fuchsia; height: 10px; width: 20px }
+
+tbody { position: relative; border: 30px solid blue }
+div { position: absolute; top: 0; left: 0 }
+
+</style>
+<h1>Table Row Group Testcase, bug 1379306</h1>
+
+<table>
+  <tbody>
+    <tr>
+      <td>
+        <div></div>
+      </td>
+    </tr>
+  </tbody>
+</table>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/table-html/bug1379306-3.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<title>Testcase, bug 1379306</title>
+<style>
+
+table { background: yellow }
+td { height: 50px; width: 200px; background: aqua; }
+div { background: fuchsia; height: 10px; width: 20px }
+
+tbody { position: relative; border: 10px solid blue }
+div { position: absolute; top: 0; left: 0 }
+
+</style>
+<h1>Table Row Group Testcase, bug 1379306</h1>
+
+<table>
+  <tbody>
+    <tr>
+      <td>
+        <div></div>
+      </td>
+    </tr>
+  </tbody>
+</table>
--- a/layout/reftests/table-html/reftest.list
+++ b/layout/reftests/table-html/reftest.list
@@ -1,2 +1,4 @@
 == cell-align-stopped-at-table-1-standards.html cell-align-stopped-at-table-1-standards-ref.html
 == cell-align-stopped-at-table-1-quirks.html cell-align-stopped-at-table-1-quirks-ref.html
+== bug1379306-2.html bug1379306-2-ref.html
+== bug1379306-3.html bug1379306-3-ref.html
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -1432,17 +1432,17 @@ FontFaceSet::SyncLoadFontData(gfxUserFon
     return NS_ERROR_FAILURE;
   }
   if (bufferLength64 > UINT32_MAX) {
     return NS_ERROR_FILE_TOO_BIG;
   }
   aBufferLength = static_cast<uint32_t>(bufferLength64);
 
   // read all the decoded data
-  aBuffer = static_cast<uint8_t*> (moz_xmalloc(sizeof(uint8_t) * aBufferLength));
+  aBuffer = static_cast<uint8_t*>(malloc(sizeof(uint8_t) * aBufferLength));
   if (!aBuffer) {
     aBufferLength = 0;
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   uint32_t numRead, totalRead = 0;
   while (NS_SUCCEEDED(rv =
            stream->Read(reinterpret_cast<char*>(aBuffer + totalRead),
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -356,21 +356,20 @@ nsTreeBodyFrame::EnsureView()
       return;
     }
     nsCOMPtr<nsIBoxObject> box = do_QueryInterface(mTreeBoxObject);
     if (box) {
       AutoWeakFrame weakFrame(this);
       nsCOMPtr<nsITreeView> treeView;
       mTreeBoxObject->GetView(getter_AddRefs(treeView));
       if (treeView && weakFrame.IsAlive()) {
-        nsXPIDLString rowStr;
+        nsString rowStr;
         box->GetProperty(u"topRow", getter_Copies(rowStr));
-        nsAutoString rowStr2(rowStr);
         nsresult error;
-        int32_t rowIndex = rowStr2.ToInteger(&error);
+        int32_t rowIndex = rowStr.ToInteger(&error);
 
         // Set our view.
         SetView(treeView);
         ENSURE_TRUE(weakFrame.IsAlive());
 
         // Scroll to the given row.
         // XXX is this optimal if we haven't laid out yet?
         ScrollToRow(rowIndex);
--- a/media/webrtc/trunk/webrtc/modules/audio_device/linux/audio_device_alsa_linux.cc
+++ b/media/webrtc/trunk/webrtc/modules/audio_device/linux/audio_device_alsa_linux.cc
@@ -12,24 +12,16 @@
 
 #include "webrtc/base/logging.h"
 #include "webrtc/modules/audio_device/audio_device_config.h"
 #include "webrtc/modules/audio_device/linux/audio_device_alsa_linux.h"
 
 #include "webrtc/system_wrappers/include/event_wrapper.h"
 #include "webrtc/system_wrappers/include/sleep.h"
 #include "webrtc/system_wrappers/include/trace.h"
- 
-#include "Latency.h"
-
-#define LOG_FIRST_CAPTURE(x) LogTime(AsyncLatencyLogger::AudioCaptureBase, \
-                                     reinterpret_cast<uint64_t>(x), 0)
-#define LOG_CAPTURE_FRAMES(x, frames) LogLatency(AsyncLatencyLogger::AudioCapture, \
-                                                 reinterpret_cast<uint64_t>(x), frames)
-
 
 webrtc_adm_linux_alsa::AlsaSymbolTable AlsaSymbolTable;
 
 // Accesses ALSA functions through our late-binding symbol table instead of
 // directly. This way we don't have to link to libasound, which means our binary
 // will work on systems that don't have it.
 #define LATE(sym) \
   LATESYM_GET(webrtc_adm_linux_alsa::AlsaSymbolTable, &AlsaSymbolTable, sym)
@@ -2138,20 +2130,18 @@ bool AudioDeviceLinuxALSA::RecThreadProc
                buffer, size);
         _recordingFramesLeft -= frames;
 
         if (!_recordingFramesLeft)
         { // buf is full
             _recordingFramesLeft = _recordingFramesIn10MS;
 
             if (_firstRecord) {
-              LOG_FIRST_CAPTURE(this);
               _firstRecord = false;
             }
-            LOG_CAPTURE_FRAMES(this, _recordingFramesIn10MS);
             // store the recorded buffer (no action will be taken if the
             // #recorded samples is not a full buffer)
             _ptrAudioBuffer->SetRecordedBuffer(_recordingBuffer,
                                                _recordingFramesIn10MS);
 
             uint32_t currentMicLevel = 0;
             uint32_t newMicLevel = 0;
 
--- a/media/webrtc/trunk/webrtc/modules/audio_device/sndio/audio_device_sndio.cc
+++ b/media/webrtc/trunk/webrtc/modules/audio_device/sndio/audio_device_sndio.cc
@@ -13,22 +13,16 @@
 
 #include "webrtc/modules/audio_device/audio_device_config.h"
 #include "webrtc/modules/audio_device/sndio/audio_device_sndio.h"
 
 #include "webrtc/system_wrappers/include/event_wrapper.h"
 #include "webrtc/system_wrappers/include/sleep.h"
 #include "webrtc/system_wrappers/include/trace.h"
 
-#include "Latency.h"
-
-#define LOG_FIRST_CAPTURE(x) LogTime(AsyncLatencyLogger::AudioCaptureBase, \
-                                     reinterpret_cast<uint64_t>(x), 0)
-#define LOG_CAPTURE_FRAMES(x, frames) LogLatency(AsyncLatencyLogger::AudioCapture, \
-                                                 reinterpret_cast<uint64_t>(x), frames)
 extern "C"
 {
     static void playOnmove(void *arg, int delta)
     {
         static_cast<webrtc::AudioDeviceSndio *>(arg)->_playDelay -= delta;
     }
 
     static void recOnmove(void *arg, int delta)
--- a/mfbt/Attributes.h
+++ b/mfbt/Attributes.h
@@ -526,16 +526,24 @@
  *   to be moved in memory using memmove().
  * MOZ_NEEDS_MEMMOVABLE_TYPE: Applies to template class declarations where the
  *   template arguments are required to be safe to move in memory using
  *   memmove().  Passing MOZ_NON_MEMMOVABLE types to these templates is a
  *   compile time error.
  * MOZ_NEEDS_MEMMOVABLE_MEMBERS: Applies to class declarations where each member
  *   must be safe to move in memory using memmove().  MOZ_NON_MEMMOVABLE types
  *   used in members of these classes are compile time errors.
+ * MOZ_NO_DANGLING_ON_TEMPORARIES: Applies to method declarations which return
+ *   a pointer that is freed when the destructor of the class is called. This
+ *   prevents these methods from being called on temporaries of the class,
+ *   reducing risks of use-after-free.
+ *   This attribute cannot be applied to && methods.
+ *   In some cases, adding a deleted &&-qualified overload is too restrictive as
+ *   this method should still be callable as a non-escaping argument to another
+ *   function. This annotation can be used in those cases.
  * MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS: Applies to template class
  *   declarations where an instance of the template should be considered, for
  *   static analysis purposes, to inherit any type annotations (such as
  *   MOZ_MUST_USE_TYPE and MOZ_STACK_CLASS) from its template arguments.
  * MOZ_INIT_OUTSIDE_CTOR: Applies to class member declarations. Occasionally
  *   there are class members that are not initialized in the constructor,
  *   but logic elsewhere in the class ensures they are initialized prior to use.
  *   Using this attribute on a member disables the check that this member must be
@@ -587,16 +595,17 @@
 #  define MOZ_NON_OWNING_REF __attribute__((annotate("moz_weak_ref")))
 #  define MOZ_UNSAFE_REF(reason) __attribute__((annotate("moz_weak_ref")))
 #  define MOZ_NO_ADDREF_RELEASE_ON_RETURN __attribute__((annotate("moz_no_addref_release_on_return")))
 #  define MOZ_MUST_USE_TYPE __attribute__((annotate("moz_must_use_type")))
 #  define MOZ_NEEDS_NO_VTABLE_TYPE __attribute__((annotate("moz_needs_no_vtable_type")))
 #  define MOZ_NON_MEMMOVABLE __attribute__((annotate("moz_non_memmovable")))
 #  define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type")))
 #  define MOZ_NEEDS_MEMMOVABLE_MEMBERS __attribute__((annotate("moz_needs_memmovable_members")))
+#  define MOZ_NO_DANGLING_ON_TEMPORARIES __attribute__((annotate("moz_no_dangling_on_temporaries")))
 #  define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS \
     __attribute__((annotate("moz_inherit_type_annotations_from_template_args")))
 #  define MOZ_NON_AUTOABLE __attribute__((annotate("moz_non_autoable")))
 #  define MOZ_INIT_OUTSIDE_CTOR \
     __attribute__((annotate("moz_ignore_ctor_initialization")))
 #  define MOZ_IS_CLASS_INIT \
     __attribute__((annotate("moz_is_class_init")))
 #  define MOZ_NON_PARAM \
@@ -632,16 +641,17 @@
 #  define MOZ_NON_OWNING_REF /* nothing */
 #  define MOZ_UNSAFE_REF(reason) /* nothing */
 #  define MOZ_NO_ADDREF_RELEASE_ON_RETURN /* nothing */
 #  define MOZ_MUST_USE_TYPE /* nothing */
 #  define MOZ_NEEDS_NO_VTABLE_TYPE /* nothing */
 #  define MOZ_NON_MEMMOVABLE /* nothing */
 #  define MOZ_NEEDS_MEMMOVABLE_TYPE /* nothing */
 #  define MOZ_NEEDS_MEMMOVABLE_MEMBERS /* nothing */
+#  define MOZ_NO_DANGLING_ON_TEMPORARIES /* nothing */
 #  define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS /* nothing */
 #  define MOZ_INIT_OUTSIDE_CTOR /* nothing */
 #  define MOZ_IS_CLASS_INIT /* nothing */
 #  define MOZ_NON_PARAM /* nothing */
 #  define MOZ_NON_AUTOABLE /* nothing */
 #  define MOZ_REQUIRED_BASE_METHOD /* nothing */
 #  define MOZ_MUST_RETURN_FROM_CALLER /* nothing */
 #  define MOZ_MAY_CALL_AFTER_MUST_RETURN /* nothing */
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -1604,16 +1604,18 @@ public class BrowserApp extends GeckoApp
         if (mFormAssistPopup != null)
             mFormAssistPopup.destroy();
         if (mTextSelection != null)
             mTextSelection.destroy();
         NotificationHelper.destroy();
         IntentHelper.destroy();
         GeckoNetworkManager.destroy();
 
+        EventDispatcher.getInstance().dispatch("Browser:ZombifyTabs", null);
+
         super.onDestroy();
     }
 
     @Override
     protected void initializeChrome() {
         super.initializeChrome();
 
         mDoorHangerPopup.setAnchor(mBrowserToolbar.getDoorHangerAnchor());
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -392,16 +392,17 @@ var BrowserApp = {
       "Tab:Selected",
       "Tab:Closed",
       "Tab:Move",
     ]);
 
     GlobalEventDispatcher.registerListener(this, [
       "Browser:LoadManifest",
       "Browser:Quit",
+      "Browser:ZombifyTabs",
       "Fonts:Reload",
       "FormHistory:Init",
       "FullScreen:Exit",
       "Locale:OS",
       "Locale:Changed",
       "Passwords:Init",
       "Sanitize:ClearData",
       "SaveAs:PDF",
@@ -1674,16 +1675,23 @@ var BrowserApp = {
         installManifest(browser, data);
         break;
       }
 
       case "Browser:Quit":
         this.quit(data);
         break;
 
+      case "Browser:ZombifyTabs":
+        let tabs = this._tabs;
+        for (let i = 0; i < tabs.length; i++) {
+          tabs[i].zombify();
+        }
+        break;
+
       case "Fonts:Reload":
         FontEnumerator.updateFontList();
         break;
 
       case "FormHistory:Init": {
         // Force creation/upgrade of formhistory.sqlite
         FormHistory.count({});
         GlobalEventDispatcher.unregisterListener(this, event);
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java
@@ -312,66 +312,59 @@ public class GeckoAppShell
         }
 
         return lastKnownLocation;
     }
 
     @WrapForJNI(calledFrom = "gecko")
     // Permissions are explicitly checked when requesting content permission.
     @SuppressLint("MissingPermission")
-    /* package */ static void enableLocation(final boolean enable) {
-        if (!ThreadUtils.isOnUiThread()) {
-            ThreadUtils.postToUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    try {
-                        enableLocation(enable);
-                    } catch (final SecurityException e) {
-                        Log.e(LOGTAG, "No location permission", e);
-                    }
-                }
-            });
-            return;
-        }
-
-        LocationManager lm = getLocationManager(getApplicationContext());
+    private static synchronized boolean enableLocation(final boolean enable) {
+        final LocationManager lm = getLocationManager(getApplicationContext());
         if (lm == null) {
-            return;
+            return false;
         }
 
         if (!enable) {
             lm.removeUpdates(getLocationListener());
-            return;
+            return true;
         }
 
-        Location lastKnownLocation = getLastKnownLocation(lm);
+        if (!lm.isProviderEnabled(LocationManager.GPS_PROVIDER) &&
+            !lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
+            return false;
+        }
+
+        final Location lastKnownLocation = getLastKnownLocation(lm);
         if (lastKnownLocation != null) {
             getLocationListener().onLocationChanged(lastKnownLocation);
         }
 
-        Criteria criteria = new Criteria();
+        final Criteria criteria = new Criteria();
         criteria.setSpeedRequired(false);
         criteria.setBearingRequired(false);
         criteria.setAltitudeRequired(false);
         if (locationHighAccuracyEnabled) {
             criteria.setAccuracy(Criteria.ACCURACY_FINE);
             criteria.setCostAllowed(true);
             criteria.setPowerRequirement(Criteria.POWER_HIGH);
         } else {
             criteria.setAccuracy(Criteria.ACCURACY_COARSE);
             criteria.setCostAllowed(false);
             criteria.setPowerRequirement(Criteria.POWER_LOW);
         }
 
-        String provider = lm.getBestProvider(criteria, true);
-        if (provider == null)
-            return;
+        final String provider = lm.getBestProvider(criteria, true);
+        if (provider == null) {
+            return false;
+        }
 
-        Looper l = Looper.getMainLooper();
+        final Looper l = Looper.getMainLooper();
         lm.requestLocationUpdates(provider, 100, 0.5f, getLocationListener(), l);
+        return true;
     }
 
     private static LocationManager getLocationManager(Context context) {
         try {
             return (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
         } catch (NoSuchFieldError e) {
             // Some Tegras throw exceptions about missing the CONTROL_LOCATION_UPDATES permission,
             // which allows enabling/disabling location update notifications from the cell radio.
@@ -386,17 +379,17 @@ public class GeckoAppShell
     private static void enableLocationHighAccuracy(final boolean enable) {
         locationHighAccuracyEnabled = enable;
     }
 
     @WrapForJNI(calledFrom = "ui", dispatchTo = "gecko")
     /* package */ static native void onSensorChanged(int hal_type, float x, float y, float z,
                                                      float w, int accuracy, long time);
 
-    @WrapForJNI(calledFrom = "ui", dispatchTo = "gecko")
+    @WrapForJNI(calledFrom = "any", dispatchTo = "gecko")
     /* package */ static native void onLocationChanged(double latitude, double longitude,
                                                        double altitude, float accuracy,
                                                        float bearing, float speed, long time);
 
     private static class DefaultListeners implements SensorEventListener,
                                                      LocationListener,
                                                      NotificationListener,
                                                      ScreenOrientationDelegate,
@@ -483,22 +476,22 @@ public class GeckoAppShell
                 break;
             }
 
             GeckoAppShell.onSensorChanged(hal_type, x, y, z, w, accuracy, time);
         }
 
         // Geolocation.
         @Override
-        public void onLocationChanged(Location location) {
+        public void onLocationChanged(final Location location) {
             // No logging here: user-identifying information.
-            GeckoAppShell.onLocationChanged(location.getLatitude(), location.getLongitude(),
-                                            location.getAltitude(), location.getAccuracy(),
-                                            location.getBearing(), location.getSpeed(),
-                                            location.getTime());
+            GeckoAppShell.onLocationChanged(
+                location.getLatitude(), location.getLongitude(),
+                location.getAltitude(), location.getAccuracy(),
+                location.getBearing(), location.getSpeed(), location.getTime());
         }
 
         @Override
         public void onProviderDisabled(String provider)
         {
         }
 
         @Override
--- a/modules/libpref/nsPrefBranch.cpp
+++ b/modules/libpref/nsPrefBranch.cpp
@@ -561,18 +561,17 @@ NS_IMETHODIMP nsPrefBranch::SetComplexVa
     }
     return rv;
   }
 
   if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString))) {
     nsCOMPtr<nsIPrefLocalizedString> theString = do_QueryInterface(aValue);
 
     if (theString) {
-      nsXPIDLString wideString;
-
+      nsString wideString;
       rv = theString->GetData(getter_Copies(wideString));
       if (NS_SUCCEEDED(rv)) {
         // Check sanity of string length before any lengthy conversion
         rv = CheckSanityOfStringLength(aPrefName, wideString);
         if (NS_FAILED(rv)) {
           return rv;
         }
         rv = SetCharPrefInternal(aPrefName, NS_ConvertUTF16toUTF8(wideString).get());
--- a/python/mozlint/mozlint/cli.py
+++ b/python/mozlint/mozlint/cli.py
@@ -108,16 +108,22 @@ def find_linters(linters=None):
 
 
 def run(paths, linters, fmt, outgoing, workdir, **lintargs):
     from mozlint import LintRoller, formatters
 
     lint = LintRoller(**lintargs)
     lint.read(find_linters(linters))
 
+    # Check if the path that is entered is a valid one.
+    invalid_paths = [path for path in paths if not os.path.exists(path)]
+    if invalid_paths:
+        print("Error: The following paths do not exist:\n{}".format("\n".join(invalid_paths)))
+        return 1
+
     # run all linters
     results = lint.roll(paths, outgoing=outgoing, workdir=workdir)
     formatter = formatters.get(fmt)
 
     # Encode output with 'replace' to avoid UnicodeEncodeErrors on
     # environments that aren't using utf-8.
     print(formatter(results, failed=lint.failed).encode(
         sys.stdout.encoding or 'ascii', 'replace'))
--- a/rdf/base/nsInMemoryDataSource.cpp
+++ b/rdf/base/nsInMemoryDataSource.cpp
@@ -822,25 +822,20 @@ InMemoryDataSource::LogOperation(const c
     nsCOMPtr<nsIRDFLiteral> literal;
 
     if ((resource = do_QueryInterface(aTarget)) != nullptr) {
         resource->GetValue(getter_Copies(uri));
         MOZ_LOG(gLog, LogLevel::Debug,
            ("  -->[(%p)%s]", aTarget, (const char*) uri));
     }
     else if ((literal = do_QueryInterface(aTarget)) != nullptr) {
-        nsXPIDLString value;
+        nsString value;
         literal->GetValue(getter_Copies(value));
-        nsAutoString valueStr(value);
-        char* valueCStr = ToNewCString(valueStr);
-
         MOZ_LOG(gLog, LogLevel::Debug,
-           ("  -->(\"%s\")\n", valueCStr));
-
-        free(valueCStr);
+           ("  -->(\"%s\")\n", NS_ConvertUTF16toUTF8(value).get()));
     }
     else {
         MOZ_LOG(gLog, LogLevel::Debug,
            ("  -->(unknown-type)\n"));
     }
 }
 
 
--- a/security/manager/ssl/LocalCertService.cpp
+++ b/security/manager/ssl/LocalCertService.cpp
@@ -298,18 +298,18 @@ private:
     if (NS_FAILED(rv)) {
       return rv;
     }
     if (!selfSigned) {
       return NS_ERROR_FAILURE;
     }
 
     // Check that subject and issuer match nickname
-    nsXPIDLString subjectName;
-    nsXPIDLString issuerName;
+    nsAutoString subjectName;
+    nsAutoString issuerName;
     mCert->GetSubjectName(subjectName);
     mCert->GetIssuerName(issuerName);
     if (!subjectName.Equals(issuerName)) {
       return NS_ERROR_FAILURE;
     }
     NS_NAMED_LITERAL_STRING(commonNamePrefix, "CN=");
     nsAutoString subjectNameFromNickname(
       commonNamePrefix + NS_ConvertASCIItoUTF16(mNickname));
--- a/security/manager/ssl/nsNSSCallbacks.cpp
+++ b/security/manager/ssl/nsNSSCallbacks.cpp
@@ -796,17 +796,17 @@ PK11PasswordPromptRunnable::RunOnTargetT
   rv = nssComponent->PIPBundleFormatStringFromName("CertPassPrompt",
                                                    formatStrings,
                                                    ArrayLength(formatStrings),
                                                    promptString);
   if (NS_FAILED(rv)) {
     return;
   }
 
-  nsXPIDLString password;
+  nsString password;
   // |checkState| is unused because |checkMsg| (the argument just before it) is
   // null, but XPConnect requires it to point to a valid bool nonetheless.
   bool checkState = false;
   bool userClickedOK = false;
   rv = prompt->PromptPassword(nullptr, promptString.get(),
                               getter_Copies(password), nullptr, &checkState,
                               &userClickedOK);
   if (NS_FAILED(rv) || !userClickedOK) {
--- a/security/manager/ssl/nsNSSCertHelper.cpp
+++ b/security/manager/ssl/nsNSSCertHelper.cpp
@@ -964,17 +964,17 @@ ProcessBMPString(SECItem* extData, nsASt
 
 static nsresult
 ProcessGeneralName(const UniquePLArenaPool& arena, CERTGeneralName* current,
                    nsAString& text)
 {
   NS_ENSURE_ARG_POINTER(current);
 
   nsAutoString key;
-  nsXPIDLString value;
+  nsAutoString value;
   nsresult rv = NS_OK;
 
   switch (current->type) {
     case certOtherName: {
       SECOidTag oidTag = SECOID_FindOIDTag(&current->name.OthName.oid);
       if (oidTag == SEC_OID(MS_NT_PRINCIPAL_NAME)) {
         /* The type of this name is apparently nowhere explicitly
          documented. However, in the generated templates, it is always
@@ -1880,17 +1880,17 @@ nsNSSCertificate::CreateTBSCertificateAS
   rv = ProcessSECAlgorithmID(&mCert->signature, getter_AddRefs(algID));
   if (NS_FAILED(rv))
     return rv;
 
   GetPIPNSSBundleString("CertDumpSigAlg", text);
   algID->SetDisplayName(text);
   asn1Objects->AppendElement(algID, false);
 
-  nsXPIDLString value;
+  nsString value;
   ProcessName(&mCert->issuer, getter_Copies(value));
 
   printableItem = new nsNSSASN1PrintableItem();
 
   printableItem->SetDisplayValue(value);
   GetPIPNSSBundleString("CertDumpIssuer", text);
   printableItem->SetDisplayName(text);
   asn1Objects->AppendElement(printableItem, false);
--- a/security/manager/ssl/nsNSSCertificateDB.cpp
+++ b/security/manager/ssl/nsNSSCertificateDB.cpp
@@ -298,20 +298,20 @@ nsNSSCertificateDB::handleCACertDownload
     nsCOMPtr<nsIX509Cert> certn_2;  // second to last cert
     nsCOMPtr<nsIX509Cert> certn_1;  // last cert
 
     cert0 = do_QueryElementAt(x509Certs, 0);
     cert1 = do_QueryElementAt(x509Certs, 1);
     certn_2 = do_QueryElementAt(x509Certs, numCerts-2);
     certn_1 = do_QueryElementAt(x509Certs, numCerts-1);
 
-    nsXPIDLString cert0SubjectName;
-    nsXPIDLString cert1IssuerName;
-    nsXPIDLString certn_2IssuerName;
-    nsXPIDLString certn_1SubjectName;
+    nsAutoString cert0SubjectName;
+    nsAutoString cert1IssuerName;
+    nsAutoString certn_2IssuerName;
+    nsAutoString certn_1SubjectName;
 
     cert0->GetSubjectName(cert0SubjectName);
     cert1->GetIssuerName(cert1IssuerName);
     certn_2->GetIssuerName(certn_2IssuerName);
     certn_1->GetSubjectName(certn_1SubjectName);
 
     if (cert1IssuerName.Equals(cert0SubjectName)) {
       // In this case, the first cert in the list signed the second,
--- a/security/manager/ssl/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/nsNSSIOLayer.cpp
@@ -675,17 +675,17 @@ nsHandleSSLError(nsNSSSocketInfo* socket
   if (socketInfo->GetErrorCode()) {
     // If the socket has been flagged as canceled,
     // the code who did was responsible for setting the error code.
     return;
   }
 
   // We must cancel first, which sets the error code.
   socketInfo->SetCanceled(err, SSLErrorMessageType::Plain);
-  nsXPIDLString errorString;
+  nsAutoString errorString;
   socketInfo->GetErrorLogMessage(err, errtype, errorString);
 
   if (!errorString.IsEmpty()) {
     nsContentUtils::LogSimpleConsoleError(errorString, "SSL");
   }
 }
 
 namespace {
--- a/taskcluster/ci/test/test-sets.yml
+++ b/taskcluster/ci/test/test-sets.yml
@@ -251,17 +251,16 @@ android-gradle-tests:
     - robocop
     - geckoview
 
 android-x86-tests:
     - mochitest-chrome
     - xpcshell
 
 windows8-tests:
-    - crashtest
     - mochitest
     - mochitest-browser-chrome
     - mochitest-devtools-chrome
     - mochitest-media
     - reftest
     - reftest-no-accel
     - mochitest-gpu
     - mochitest-webgl
--- a/taskcluster/ci/test/tests.yml
+++ b/taskcluster/ci/test/tests.yml
@@ -111,26 +111,18 @@ crashtest:
     suite: reftest/crashtest
     treeherder-symbol: tc-R(C)
     instance-size:
         by-test-platform:
             android.*: xlarge
             default: default
     run-on-projects:
         by-test-platform:
-            # Deactivate try on Buildbot, by default. We don't have enough machines
-            windows8-64.*: ['mozilla-release', 'mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland']
-            windows8-64-devedition/opt: built-projects  # No dev edition outside of supported branches
-            windows10.*: []
             macosx64-stylo/.*: ['autoland', 'mozilla-central', 'try']
             default: built-projects
-    worker-type:
-        by-test-platform:
-            windows8-64.*: buildbot-bridge/buildbot-bridge
-            default: null
     chunks:
         by-test-platform:
             android-4.3-arm7-api-15/debug: 10
             android.*: 4
             default: 1
     mozharness:
         by-test-platform:
             android.*:
@@ -168,16 +160,17 @@ firefox-ui-functional-local:
     mozharness:
         script: firefox_ui_tests/functional.py
         config:
             by-test-platform:
                 windows.*:
                     - firefox_ui_tests/taskcluster_windows.py
                 macosx.*:
                     - firefox_ui_tests/taskcluster.py
+                    - firefox_ui_tests/taskcluster_mac.py
                 linux.*:
                     - firefox_ui_tests/taskcluster.py
                     - remove_executables.py
         extra-options:
             - "--tag"
             - "local"
 
 firefox-ui-functional-remote:
@@ -189,16 +182,17 @@ firefox-ui-functional-remote:
     mozharness:
         script: firefox_ui_tests/functional.py
         config:
             by-test-platform:
                 windows.*:
                     - firefox_ui_tests/taskcluster_windows.py
                 macosx.*:
                     - firefox_ui_tests/taskcluster.py
+                    - firefox_ui_tests/taskcluster_mac.py
                 linux.*:
                     - firefox_ui_tests/taskcluster.py
                     - remove_executables.py
         extra-options:
             - "--tag"
             - "remote"
 
 geckoview:
@@ -374,16 +368,17 @@ marionette:
                 script: marionette.py
                 no-read-buildbot-config: true
                 config:
                     by-test-platform:
                         windows.*:
                             - marionette/windows_taskcluster_config.py
                         macosx.*:
                             - marionette/prod_config.py
+                            - marionette/mac_taskcluster_config.py
                         default:
                             - marionette/prod_config.py
                             - remove_executables.py
 
 marionette-headless:
     description: "Marionette headless unittest run"
     suite: marionette
     treeherder-symbol: tc(MnH)
@@ -405,16 +400,17 @@ marionette-headless:
                 script: marionette.py
                 no-read-buildbot-config: true
                 config:
                     by-test-platform:
                         windows.*:
                             - marionette/windows_taskcluster_config.py
                         macosx.*:
                             - marionette/prod_config.py
+                            - marionette/mac_taskcluster_config.py
                         default:
                             - marionette/prod_config.py
                             - remove_executables.py
                 extra-options:
                     by-test-platform:
                         default:
                             - --headless
 
new file mode 100644
--- /dev/null
+++ b/testing/mozharness/configs/firefox_ui_tests/taskcluster_mac.py
@@ -0,0 +1,4 @@
+# Configuration over-rides for taskcluter.py, for osx
+config = {
+    "tooltool_cache": "/builds/tooltool_cache",
+}
new file mode 100644
--- /dev/null
+++ b/testing/mozharness/configs/marionette/mac_taskcluster_config.py
@@ -0,0 +1,4 @@
+# Configuration over-rides for prod_config.py, for osx
+config = {
+    "tooltool_cache": "/builds/tooltool_cache",
+}
--- a/testing/web-platform/meta/url/failure.html.ini
+++ b/testing/web-platform/meta/url/failure.html.ini
@@ -307,73 +307,46 @@
     expected: FAIL
 
   [window.open(): file://example%/ should throw]
     expected: FAIL
 
   [window.open(): file://[example\]/ should throw]
     expected: FAIL
 
-  [window.open(): http://user:pass@/ should throw]
-    expected: FAIL
-
-  [window.open(): http://foo:-80/ should throw]
-    expected: FAIL
-
   [window.open(): http:/:@/www.example.com should throw]
     expected: FAIL
 
-  [window.open(): http://user@/www.example.com should throw]
-    expected: FAIL
-
   [window.open(): http:@/www.example.com should throw]
     expected: FAIL
 
   [window.open(): http:/@/www.example.com should throw]
     expected: FAIL
 
-  [window.open(): http://@/www.example.com should throw]
-    expected: FAIL
-
-  [window.open(): https:@/www.example.com should throw]
-    expected: FAIL
-
   [window.open(): http:a:b@/www.example.com should throw]
     expected: FAIL
 
   [window.open(): http:/a:b@/www.example.com should throw]
     expected: FAIL
 
-  [window.open(): http://a:b@/www.example.com should throw]
-    expected: FAIL
-
   [window.open(): http::@/www.example.com should throw]
     expected: FAIL
 
   [window.open(): http:@:www.example.com should throw]
     expected: FAIL
 
   [window.open(): http:/@:www.example.com should throw]
     expected: FAIL
 
-  [window.open(): http://@:www.example.com should throw]
-    expected: FAIL
-
   [window.open(): https://� should throw]
     expected: FAIL
 
   [window.open(): https://%EF%BF%BD should throw]
     expected: FAIL
 
-  [window.open(): https://x x:12 should throw]
-    expected: FAIL
-
-  [window.open(): http://[www.google.com\]/ should throw]
-    expected: FAIL
-
   [window.open(): sc://\x00/ should throw]
     expected: FAIL
 
   [window.open(): sc:// / should throw]
     expected: FAIL
 
   [window.open(): sc://@/ should throw]
     expected: FAIL
@@ -391,55 +364,16 @@
     expected: FAIL
 
   [window.open(): sc://\\/ should throw]
     expected: FAIL
 
   [window.open(): sc://\]/ should throw]
     expected: FAIL
 
-  [window.open(): ftp://example.com%80/ should throw]
-    expected: FAIL
-
-  [window.open(): ftp://example.com%A0/ should throw]
-    expected: FAIL
-
-  [window.open(): https://example.com%80/ should throw]
-    expected: FAIL
-
-  [window.open(): https://example.com%A0/ should throw]
-    expected: FAIL
-
-  [window.open(): https://[0::0::0\] should throw]
-    expected: FAIL
-
-  [window.open(): https://[0:.0\] should throw]
-    expected: FAIL
-
-  [window.open(): https://[0:0:\] should throw]
-    expected: FAIL
-
-  [window.open(): https://[0:1:2:3:4:5:6:7.0.0.0.1\] should throw]
-    expected: FAIL
-
-  [window.open(): https://[0:1.00.0.0.0\] should throw]
-    expected: FAIL
-
-  [window.open(): https://[0:1.290.0.0.0\] should throw]
-    expected: FAIL
-
-  [window.open(): https://[0:1.23.23\] should throw]
-    expected: FAIL
-
-  [window.open(): http://? should throw]
-    expected: FAIL
-
-  [window.open(): http://# should throw]
-    expected: FAIL
-
   [window.open(): non-special://[:80/ should throw]
     expected: FAIL
 
   [URL's href: https://0x100000000/test should throw]
     expected: FAIL
 
   [XHR: https://0x100000000/test should throw]
     expected: FAIL
@@ -465,12 +399,8 @@
   [Location's href: https://256.0.0.1/test should throw]
     expected: FAIL
 
   [window.open(): https://256.0.0.1/test should throw]
     expected: FAIL
 
   [Location's href: http://[::127.0.0.0.1\] should throw]
     expected: FAIL
-
-  [window.open(): http://[::127.0.0.0.1\] should throw]
-    expected: FAIL
-
--- a/toolkit/components/jsdownloads/src/DownloadLegacy.js
+++ b/toolkit/components/jsdownloads/src/DownloadLegacy.js
@@ -15,18 +15,16 @@
 "use strict";
 
 const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
                                   "resource://gre/modules/Downloads.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "PromiseUtils",
-                                  "resource://gre/modules/PromiseUtils.jsm");
 
 /**
  * nsITransfer implementation that provides a bridge to a Download object.
  *
  * Legacy downloads work differently than the JavaScript implementation.  In the
  * latter, the caller only provides the properties for the Download object and
  * the entire process is handled by the "start" method.  In the legacy
  * implementation, the caller must create a separate object to execute the
@@ -47,17 +45,17 @@ XPCOMUtils.defineLazyModuleGetter(this, 
  * cancellation requests, but after cancellation it cannot be reused again.
  *
  * Since the components that execute the download may be different and they
  * don't always give consistent results, this bridge takes care of enforcing the
  * expectations, for example by ensuring the target file exists when the
  * download is successful, even if the source has a size of zero bytes.
  */
 function DownloadLegacyTransfer() {
-  this._deferDownload = PromiseUtils.defer();
+  this._promiseDownload = new Promise(r => this._resolveDownload = r);
 }
 
 DownloadLegacyTransfer.prototype = {
   classID: Components.ID("{1b4c85df-cbdd-4bb6-b04e-613caece083c}"),
 
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
                                          Ci.nsIWebProgressListener2,
@@ -88,17 +86,17 @@ DownloadLegacyTransfer.prototype = {
       }
 
       if (blockedByParentalControls) {
         aRequest.cancel(Cr.NS_BINDING_ABORTED);
       }
 
       // The main request has just started.  Wait for the associated Download
       // object to be available before notifying.
-      this._deferDownload.promise.then(download => {
+      this._promiseDownload.then(download => {
         // If the request was blocked, now that we have the download object we
         // should set a flag that can be retrieved later when handling the
         // cancellation so that the proper error can be thrown.
         if (blockedByParentalControls) {
           download._blockedByParentalControls = true;
         }
 
         download.saver.onTransferStarted(
@@ -121,17 +119,17 @@ DownloadLegacyTransfer.prototype = {
             }
           }
         });
       }).catch(Cu.reportError);
     } else if ((aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) &&
         (aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK)) {
       // The last file has been received, or the download failed.  Wait for the
       // associated Download object to be available before notifying.
-      this._deferDownload.promise.then(download => {
+      this._promiseDownload.then(download => {
         // At this point, the hash has been set and we need to copy it to the
         // DownloadSaver.
         if (Components.isSuccessCode(aStatus)) {
           download.saver.setSha256Hash(this._sha256Hash);
           download.saver.setSignatureInfo(this._signatureInfo);
           download.saver.setRedirects(this._redirects);
         }
         download.saver.onTransferFinished(aStatus);
@@ -160,35 +158,65 @@ DownloadLegacyTransfer.prototype = {
                                               aMessage) {
     // The status change may optionally be received in addition to the state
     // change, but if no network request actually started, it is possible that
     // we only receive a status change with an error status code.
     if (!Components.isSuccessCode(aStatus)) {
       this._componentFailed = true;
 
       // Wait for the associated Download object to be available.
-      this._deferDownload.promise.then(function DLT_OSC_onDownload(aDownload) {
-        aDownload.saver.onTransferFinished(aStatus);
+      this._promiseDownload.then(download => {
+        download.saver.onTransferFinished(aStatus);
       }).catch(Cu.reportError);
     }
   },
 
   onSecurityChange() { },
 
   // nsIWebProgressListener2
   onProgressChange64: function DLT_onProgressChange64(aWebProgress, aRequest,
                                                       aCurSelfProgress,
                                                       aMaxSelfProgress,
                                                       aCurTotalProgress,
                                                       aMaxTotalProgress) {
-    // Wait for the associated Download object to be available.
-    this._deferDownload.promise.then(function DLT_OPC64_onDownload(aDownload) {
-      aDownload.saver.onProgressBytes(aCurTotalProgress, aMaxTotalProgress);
+    // Since this progress function is invoked frequently, we use a slightly
+    // more complex solution that optimizes the case where we already have an
+    // associated Download object, avoiding the Promise overhead.
+    if (this._download) {
+      this._hasDelayedProgress = false;
+      this._download.saver.onProgressBytes(aCurTotalProgress,
+                                           aMaxTotalProgress);
+      return;
+    }
+
+    // If we don't have a Download object yet, store the most recent progress
+    // notification to send later. We must do this because there is no guarantee
+    // that a future notification will be sent if the download stalls.
+    this._delayedCurTotalProgress = aCurTotalProgress;
+    this._delayedMaxTotalProgress = aMaxTotalProgress;
+
+    // Do not enqueue multiple callbacks for the progress report.
+    if (this._hasDelayedProgress) {
+      return;
+    }
+    this._hasDelayedProgress = true;
+
+    this._promiseDownload.then(download => {
+      // Check whether an immediate progress report has been already processed
+      // before we could send the delayed progress report.
+      if (!this._hasDelayedProgress) {
+        return;
+      }
+      download.saver.onProgressBytes(this._delayedCurTotalProgress,
+                                     this._delayedMaxTotalProgress);
     }).catch(Cu.reportError);
   },
+  _hasDelayedProgress: false,
+  _delayedCurTotalProgress: 0,
+  _delayedMaxTotalProgress: 0,
 
   // nsIWebProgressListener2
   onRefreshAttempted: function DLT_onRefreshAttempted(aWebProgress, aRefreshURI,
                                                       aMillis, aSameURI) {
     // Indicate that refreshes and redirects are allowed by default.  However,
     // note that download components don't usually call this method at all.
     return true;
   },
@@ -228,17 +256,18 @@ DownloadLegacyTransfer.prototype = {
       if (aTempFile) {
         aDownload.tryToKeepPartialData = true;
       }
 
       // Start the download before allowing it to be controlled.  Ignore errors.
       aDownload.start().catch(() => {});
 
       // Start processing all the other events received through nsITransfer.
-      this._deferDownload.resolve(aDownload);
+      this._download = aDownload;
+      this._resolveDownload(aDownload);
 
       // Add the download to the list, allowing it to be seen and canceled.
       return Downloads.getList(Downloads.ALL).then(list => list.add(aDownload));
     }).catch(Cu.reportError);
   },
 
   setSha256Hash(hash) {
     this._sha256Hash = hash;
@@ -248,20 +277,30 @@ DownloadLegacyTransfer.prototype = {
     this._signatureInfo = signatureInfo;
   },
 
   setRedirects(redirects) {
     this._redirects = redirects;
   },
 
   /**
-   * This deferred object contains a promise that is resolved with the Download
-   * object associated with this nsITransfer instance, when it is available.
+   * Download object associated with this nsITransfer instance. This is not
+   * available immediately when the nsITransfer instance is created.
    */
-  _deferDownload: null,
+  _download: null,
+
+  /**
+   * Promise that resolves to the Download object associated with this
+   * nsITransfer instance after the _resolveDownload method is invoked.
+   *
+   * Waiting on this promise using "then" ensures that the callbacks are invoked
+   * in the correct order even if enqueued before the object is available.
+   */
+  _promiseDownload: null,
+  _resolveDownload: null,
 
   /**
    * Reference to the component that is executing the download.  This component
    * allows cancellation through its nsICancelable interface.
    */
   _cancelable: null,
 
   /**
--- a/toolkit/components/passwordmgr/nsLoginManagerPrompter.js
+++ b/toolkit/components/passwordmgr/nsLoginManagerPrompter.js
@@ -1429,17 +1429,18 @@ LoginManagerPrompter.prototype = {
                              .getInterface(Ci.nsIWebNavigation)
                              .QueryInterface(Ci.nsIDocShell)
                              .chromeEventHandler.ownerGlobal;
       if (!chromeWin) {
         return null;
       }
 
       // gBrowser only exists on some apps, like Firefox.
-      let tabbrowser = chromeWin.gBrowser || chromeWin.getBrowser();
+      let tabbrowser = chromeWin.gBrowser ||
+        (typeof chromeWin.getBrowser == "function" ? chromeWin.getBrowser() : null);
       // At least serve the chrome window if getBrowser()
       // or getBrowserForContentWindow() are not supported.
       if (!tabbrowser || typeof tabbrowser.getBrowserForContentWindow != "function") {
         return { win: chromeWin };
       }
 
       let browser = tabbrowser.getBrowserForContentWindow(aWindow);
       return { win: chromeWin, browser };
--- a/toolkit/components/printingui/ipc/PrintingParent.cpp
+++ b/toolkit/components/printingui/ipc/PrintingParent.cpp
@@ -131,36 +131,37 @@ PrintingParent::ShowPrintDialog(PBrowser
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = mPrintSettingsSvc->DeserializeToPrintSettings(aData, settings);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = settings->SetPrintSilent(printSilently);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsXPIDLString printerName;
+  nsString printerName;
   settings->GetPrinterName(getter_Copies(printerName));
 #ifdef MOZ_X11
   // Requesting the default printer name on Linux has been removed in the child,
   // because it was causing a sandbox violation (see Bug 1329216).
   // If no printer name is set at this point, use the print settings service
   // to get the default printer name.
   if (printerName.IsEmpty()) {
     mPrintSettingsSvc->GetDefaultPrinterName(getter_Copies(printerName));
-    settings->SetPrinterName(printerName);
+    settings->SetPrinterName(printerName.get());
   }
-  mPrintSettingsSvc->InitPrintSettingsFromPrinter(printerName, settings);
+  mPrintSettingsSvc->InitPrintSettingsFromPrinter(printerName.get(), settings);
 #endif
 
   // If this is for print preview or we are printing silently then we just need
   // to initialize the print settings with anything specific from the printer.
   if (isPrintPreview || printSilently ||
       Preferences::GetBool("print.always_print_silent", printSilently)) {
     settings->SetIsInitializedFromPrinter(false);
-    mPrintSettingsSvc->InitPrintSettingsFromPrinter(printerName, settings);
+    mPrintSettingsSvc->InitPrintSettingsFromPrinter(printerName.get(),
+                                                    settings);
   } else {
     rv = pps->ShowPrintDialog(parentWin, wbp, settings);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if (isPrintPreview) {
     // For print preview we don't want a RemotePrintJob just the settings.
     rv = mPrintSettingsSvc->SerializeToPrintData(settings, nullptr, aResult);
--- a/toolkit/components/printingui/win/nsPrintDialogUtil.cpp
+++ b/toolkit/components/printingui/win/nsPrintDialogUtil.cpp
@@ -459,18 +459,17 @@ static UINT CALLBACK PrintHookProc(HWND 
 // Returns a Global Moveable Memory Handle to a DevMode
 // from the Printer by the name of aPrintName
 //
 // NOTE:
 //   This function assumes that aPrintName has already been converted from
 //   unicode
 //
 static nsReturnRef<nsHGLOBAL>
-CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName,
-                           nsIPrintSettings* aPS)
+CreateGlobalDevModeAndInit(const nsString& aPrintName, nsIPrintSettings* aPS)
 {
   nsHPRINTER hPrinter = nullptr;
   // const cast kludge for silly Win32 api's
   LPWSTR printName = const_cast<wchar_t*>(static_cast<const wchar_t*>(aPrintName.get()));
   BOOL status = ::OpenPrinterW(printName, &hPrinter, nullptr);
   if (!status) {
     return nsReturnRef<nsHGLOBAL>();
   }
@@ -527,17 +526,17 @@ CreateGlobalDevModeAndInit(const nsXPIDL
 
   ::GlobalUnlock(hDevMode);
 
   return globalDevMode.out();
 }
 
 //------------------------------------------------------------------
 // helper
-static void GetDefaultPrinterNameFromGlobalPrinters(nsXPIDLString &printerName)
+static void GetDefaultPrinterNameFromGlobalPrinters(nsAString &printerName)
 {
   nsCOMPtr<nsIPrinterEnumerator> prtEnum = do_GetService("@mozilla.org/gfx/printerenumerator;1");
   if (prtEnum) {
     prtEnum->GetDefaultPrinterName(getter_Copies(printerName));
   }
 }
 
 // Determine whether we have a completely native dialog
@@ -565,17 +564,17 @@ ShowNativePrintDialog(HWND              
                       nsIPrintSettings* aPrintSettings)
 {
   //NS_ENSURE_ARG_POINTER(aHWnd);
   NS_ENSURE_ARG_POINTER(aPrintSettings);
 
   gDialogWasExtended  = false;
 
   // Get the Print Name to be used
-  nsXPIDLString printerName;
+  nsString printerName;
   aPrintSettings->GetPrinterName(getter_Copies(printerName));
 
   // If there is no name then use the default printer
   if (printerName.IsEmpty()) {
     GetDefaultPrinterNameFromGlobalPrinters(printerName);
   } else {
     HANDLE hPrinter = nullptr;
     if(!::OpenPrinterW(const_cast<wchar_t*>(static_cast<const wchar_t*>(printerName.get())),
@@ -601,17 +600,17 @@ ShowNativePrintDialog(HWND              
   if (!pDevNames) {
     return NS_ERROR_FAILURE;
   }
   pDevNames->wDriverOffset = sizeof(DEVNAMES)/sizeof(wchar_t);
   pDevNames->wDeviceOffset = sizeof(DEVNAMES)/sizeof(wchar_t);
   pDevNames->wOutputOffset = sizeof(DEVNAMES)/sizeof(wchar_t)+len;
   pDevNames->wDefault      = 0;
 
-  memcpy(pDevNames+1, printerName, (len + 1) * sizeof(wchar_t));
+  memcpy(pDevNames+1, printerName.get(), (len + 1) * sizeof(wchar_t));
   ::GlobalUnlock(hDevNames);
 
   // Create a Moveable Memory Object that holds a new DevMode
   // from the Printer Name
   // The PRINTDLG.hDevMode requires that it be a moveable memory object
   // NOTE: autoDevMode is automatically freed when any error occurred
   nsAutoGlobalMem autoDevMode(CreateGlobalDevModeAndInit(printerName, aPrintSettings));
 
--- a/toolkit/components/telemetry/TelemetrySend.jsm
+++ b/toolkit/components/telemetry/TelemetrySend.jsm
@@ -101,16 +101,17 @@ const XHR_ERROR_TYPE = [
 /**
  * This is a policy object used to override behavior within this module.
  * Tests override properties on this object to allow for control of behavior
  * that would otherwise be very hard to cover.
  */
 var Policy = {
   now: () => new Date(),
   midnightPingFuzzingDelay: () => MIDNIGHT_FUZZING_DELAY_MS,
+  pingSubmissionTimeout: () => PING_SUBMIT_TIMEOUT_MS,
   setSchedulerTickTimeout: (callback, delayMs) => setTimeout(callback, delayMs),
   clearSchedulerTickTimeout: (id) => clearTimeout(id),
 };
 
 /**
  * Determine if the ping has the new v4 ping format or the legacy v2 one or earlier.
  */
 function isV4PingFormat(aPing) {
@@ -175,24 +176,16 @@ this.TelemetrySend = {
   get OVERDUE_PING_FILE_AGE() {
     return OVERDUE_PING_FILE_AGE;
   },
 
   get pendingPingCount() {
     return TelemetrySendImpl.pendingPingCount;
   },
 
-  testSetTimeoutForPingSubmit(timeoutInMS) {
-    TelemetrySendImpl._pingSubmissionTimeout = timeoutInMS;
-  },
-
-  testResetTimeOutToDefault() {
-    TelemetrySendImpl._pingSubmissionTimeout = PING_SUBMIT_TIMEOUT_MS;
-  },
-
   /**
    * Partial setup that runs immediately at startup. This currently triggers
    * the crash report annotations.
    */
   earlyInit() {
     TelemetrySendImpl.earlyInit();
   },
 
@@ -589,18 +582,16 @@ var TelemetrySendImpl = {
   _testMode: false,
   // This holds pings that we currently try and haven't persisted yet.
   _currentPings: new Map(),
   // Used to skip spawning the pingsender if OS is shutting down.
   _isOSShutdown: false,
   // Count of pending pings that were overdue.
   _overduePingCount: 0,
 
-  _pingSubmissionTimeout: PING_SUBMIT_TIMEOUT_MS,
-
   OBSERVER_TOPICS: [
     TOPIC_IDLE_DAILY,
     TOPIC_QUIT_APPLICATION_GRANTED,
     TOPIC_QUIT_APPLICATION_FORCED,
   ],
 
   OBSERVED_PREFERENCES: [
     TelemetryUtils.Preferences.TelemetryEnabled,
@@ -942,16 +933,22 @@ var TelemetrySendImpl = {
       }
     }
     this._pendingPingRequests.clear();
   },
 
   sendPings(currentPings, persistedPingIds) {
     let pingSends = [];
 
+    // Prioritize health pings to enable low-latency monitoring.
+    currentPings = [
+      ...currentPings.filter(ping => ping.type === "health"),
+      ...currentPings.filter(ping => ping.type !== "health"),
+    ];
+
     for (let current of currentPings) {
       let ping = current;
       let p = (async () => {
         try {
           await this._doPing(ping, ping.id, false);
         } catch (ex) {
           this._log.info("sendPings - ping " + ping.id + " not sent, saving to disk", ex);
           // Deletion pings must be saved to a special location.
@@ -1082,17 +1079,17 @@ var TelemetrySendImpl = {
 
     this._log.trace("_doPing - server: " + this._server + ", persisted: " + isPersisted +
                     ", id: " + id);
 
     const url = this._buildSubmissionURL(ping);
 
     let request = new ServiceRequest();
     request.mozBackgroundRequest = true;
-    request.timeout = this._pingSubmissionTimeout;
+    request.timeout = Policy.pingSubmissionTimeout();
 
     request.open("POST", url, true);
     request.overrideMimeType("text/plain");
     request.setRequestHeader("Content-Type", "application/json; charset=UTF-8");
     request.setRequestHeader("Date", Policy.now().toUTCString());
 
     this._pendingPingRequests.set(id, request);
 
--- a/toolkit/components/telemetry/TelemetryStorage.jsm
+++ b/toolkit/components/telemetry/TelemetryStorage.jsm
@@ -43,16 +43,18 @@ XPCOMUtils.defineLazyGetter(this, "gPing
 XPCOMUtils.defineLazyGetter(this, "gAbortedSessionFilePath", function() {
   return OS.Path.join(gDataReportingDir, ABORTED_SESSION_FILE_NAME);
 });
 XPCOMUtils.defineLazyGetter(this, "gDeletionPingFilePath", function() {
   return OS.Path.join(gDataReportingDir, DELETION_PING_FILE_NAME);
 });
 XPCOMUtils.defineLazyModuleGetter(this, "CommonUtils",
                                   "resource://services-common/utils.js");
+XPCOMUtils.defineLazyModuleGetter(this, "TelemetryHealthPing",
+                                  "resource://gre/modules/TelemetryHealthPing.jsm");
 // Maxmimum time, in milliseconds, archive pings should be retained.
 const MAX_ARCHIVED_PINGS_RETENTION_MS = 60 * 24 * 60 * 60 * 1000;  // 60 days
 
 // Maximum space the archive can take on disk (in Bytes).
 const ARCHIVE_QUOTA_BYTES = 120 * 1024 * 1024; // 120 MB
 // Maximum space the outgoing pings can take on disk, for Desktop (in Bytes).
 const PENDING_PINGS_QUOTA_BYTES_DESKTOP = 15 * 1024 * 1024; // 15 MB
 // Maximum space the outgoing pings can take on disk, for Mobile (in Bytes).
@@ -1360,16 +1362,20 @@ var TelemetryStorageImpl = {
 
     // Purge pings which are too big.
     if (fileSize > PING_FILE_MAXIMUM_SIZE_BYTES) {
       await this.removePendingPing(id);
       Telemetry.getHistogramById("TELEMETRY_DISCARDED_PENDING_PINGS_SIZE_MB")
                .add(Math.floor(fileSize / 1024 / 1024));
       Telemetry.getHistogramById("TELEMETRY_PING_SIZE_EXCEEDED_PENDING").add();
       TelemetryStopwatch.cancel("TELEMETRY_PENDING_LOAD_MS");
+
+      // Currently we don't have the ping type available without loading the ping from disk.
+      // Bug 1384903 will fix that.
+      TelemetryHealthPing.recordDiscardedPing("<unknown>");
       throw new Error("loadPendingPing - exceeded the maximum ping size: " + fileSize);
     }
 
     // Try to load the ping file. Update the related histograms on failure.
     let ping;
     try {
       ping = await this.loadPingFile(info.path, false);
     } catch (e) {
@@ -1593,16 +1599,20 @@ var TelemetryStorageImpl = {
           try {
             await OS.File.remove(file.path);
           } catch (ex) {
             this._log.error("_scanPendingPings - failed to remove file " + file.path, ex);
           } finally {
             Telemetry.getHistogramById("TELEMETRY_DISCARDED_PENDING_PINGS_SIZE_MB")
                      .add(Math.floor(info.size / 1024 / 1024));
             Telemetry.getHistogramById("TELEMETRY_PING_SIZE_EXCEEDED_PENDING").add();
+
+            // Currently we don't have the ping type available without loading the ping from disk.
+            // Bug 1384903 will fix that.
+            TelemetryHealthPing.recordDiscardedPing("<unknown>");
           }
           continue;
         }
 
         let id = OS.Path.basename(file.path);
         if (!UUID_REGEX.test(id)) {
           this._log.trace("_scanPendingPings - filename is not a UUID: " + id);
           id = Utils.generateUUID();
--- a/toolkit/components/telemetry/docs/data/health-ping.rst
+++ b/toolkit/components/telemetry/docs/data/health-ping.rst
@@ -60,16 +60,18 @@ The ``reason`` field contains the inform
 * delayed: The health ping was submitted after a delay.
 * shutdown: The health ping was submitted on shutdown.
 
 pingDiscardedForSize
 ~~~~~~~~~~~~~~~~~~~~
 The ``pingDiscardedForSize`` field contains the information about top ten pings, whose size exceeded the
 ping size limit (1 mb). This field lists the number of discarded pings per ping type.
 
+The ping type "<unknown>" is used to indicate that a pending pings size exceeded the limit. This is because we don't have the pending pings type available cheaply at the moment.
+
 This field is optional.
 
 sendFailure
 ~~~~~~~~~~~
 The ``sendFailure`` field contains the information about pings, which had failures on sending.
 This field lists the number of failed pings per ping send failure type.
 
 The recorded failure types are:
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryHealthPing.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryHealthPing.js
@@ -38,16 +38,21 @@ async function waitForConditionWithPromi
     try {
       return await promiseFn();
     } catch (ex) {}
     await new Promise(resolve => do_timeout(SINGLE_TRY_TIMEOUT, resolve));
   } while (++tries <= tryCount);
   throw new Error(timeoutMsg);
 }
 
+function fakeSendSubmissionTimeout(timeOut) {
+  let telemetryHealthPing = Cu.import("resource://gre/modules/TelemetrySend.jsm", {});
+  telemetryHealthPing.Policy.pingSubmissionTimeout = () => timeOut;
+}
+
 add_task(async function setup() {
   // Trigger a proper telemetry init.
   do_get_profile(true);
   // Make sure we don't generate unexpected pings due to pref changes.
   await setEmptyPrefWatchlist();
   Services.prefs.setBoolPref("toolkit.telemetry.enabled", true);
   Preferences.set(TelemetryUtils.Preferences.HealthPingEnabled, true);
 
@@ -116,27 +121,51 @@ add_task(async function test_sendOverSiz
     [TelemetryHealthPing.FailureType.DISCARDED_FOR_SIZE]: {
       [OVER_SIZED_PING_TYPE]: 1
     },
     "os": TelemetryHealthPing.OsInfo,
     "reason": TelemetryHealthPing.Reason.IMMEDIATE
   });
 });
 
+add_task(async function test_healthPingOnTop() {
+  PingServer.clearRequests();
+  TelemetryHealthPing.testReset();
+
+  let PING_TYPE = "priority-ping";
+
+  // Fake now to be in throttled state.
+  let now = fakeNow(2050, 1, 2, 0, 0, 0);
+  fakeMidnightPingFuzzingDelay(60 * 1000);
+
+  for (let value of [PING_TYPE, PING_TYPE, "health", PING_TYPE]) {
+    TelemetryController.submitExternalPing(value, {});
+  }
+
+  // Now trigger sending pings again.
+  fakeNow(futureDate(now, 5 * 60 * 1000));
+  await TelemetrySend.notifyCanUpload();
+  let scheduler = Cu.import("resource://gre/modules/TelemetrySend.jsm", {});
+  scheduler.SendScheduler.triggerSendingPings(true);
+
+  let pings = await PingServer.promiseNextPings(4);
+  Assert.equal(pings[0].type, "health", "Should have received the health ping first.");
+});
+
 add_task(async function test_sendOnTimeout() {
   TelemetryHealthPing.testReset();
   await TelemetrySend.reset();
   PingServer.clearRequests();
   let PING_TYPE = "ping-on-timeout";
 
   // Disable send retry to make this test more deterministic.
   fakePingSendTimer(() => {}, () => {});
 
   // Set up small ping submission timeout to always have timeout error.
-  TelemetrySend.testSetTimeoutForPingSubmit(2);
+  fakeSendSubmissionTimeout(2);
 
   await TelemetryController.submitExternalPing(PING_TYPE, {});
 
   let response;
   PingServer.registerPingHandler((req, res) => {
     PingServer.resetPingHandler();
     // We don't finish the response yet to make sure to trigger a timeout.
     res.processAsync();
@@ -149,17 +178,18 @@ add_task(async function test_sendOnTimeo
   await waitForConditionWithPromise(() => {
     ac.promiseFindPing("health", []);
   }, "Failed to find health ping");
 
   if (response) {
     response.finish();
   }
 
-  TelemetrySend.testResetTimeOutToDefault();
+  let telemetryHealthPing = Cu.import("resource://gre/modules/TelemetrySend.jsm", {});
+  fakeSendSubmissionTimeout(telemetryHealthPing.PING_SUBMIT_TIMEOUT_MS);
   PingServer.resetPingHandler();
   TelemetrySend.notifyCanUpload();
 
   let pings = await PingServer.promiseNextPings(2);
   let healthPing = pings.find(ping => ping.type === "health");
   checkHealthPingStructure(healthPing, {
     [TelemetryHealthPing.FailureType.SEND_FAILURE]: {
       "timeout": 1
@@ -211,16 +241,63 @@ add_task(async function test_sendOnlyTop
       [PING_TYPE + 5]: 4,
       [PING_TYPE + 4]: 3,
       [PING_TYPE + 3]: 2,
       [PING_TYPE + 2]: 1
     }
   });
 });
 
+add_task(async function test_discardedForSizePending() {
+  TelemetryHealthPing.testReset();
+  PingServer.clearRequests();
+
+  const PING_TYPE = "discarded-for-size-pending";
+
+  const OVERSIZED_PING_ID = "9b21ec8f-f762-4d28-a2c1-44e1c4694f24";
+  // Create a pending oversized ping.
+  let overSizedPayload = generateRandomString(2 * 1024 * 1024);
+  const OVERSIZED_PING = {
+    id: OVERSIZED_PING_ID,
+    type: PING_TYPE,
+    creationDate: (new Date()).toISOString(),
+    // Generate a 2MB string to use as the ping payload.
+    payload: overSizedPayload,
+  };
+
+  // Test loadPendingPing.
+  await TelemetryStorage.savePendingPing(OVERSIZED_PING);
+  // Try to manually load the oversized ping.
+  await Assert.rejects(TelemetryStorage.loadPendingPing(OVERSIZED_PING_ID),
+    "The oversized ping should have been pruned.");
+
+  let ping = await PingServer.promiseNextPing();
+  checkHealthPingStructure(ping, {
+    [TelemetryHealthPing.FailureType.DISCARDED_FOR_SIZE]: {
+      "<unknown>": 1
+    },
+    "os": TelemetryHealthPing.OsInfo,
+    "reason": TelemetryHealthPing.Reason.IMMEDIATE
+  });
+
+  // Test _scanPendingPings.
+  TelemetryHealthPing.testReset();
+  await TelemetryStorage.savePendingPing(OVERSIZED_PING);
+  await TelemetryStorage.loadPendingPingList();
+
+  ping = await PingServer.promiseNextPing();
+  checkHealthPingStructure(ping, {
+    [TelemetryHealthPing.FailureType.DISCARDED_FOR_SIZE]: {
+      "<unknown>": 1
+    },
+    "os": TelemetryHealthPing.OsInfo,
+    "reason": TelemetryHealthPing.Reason.IMMEDIATE
+  });
+});
+
 add_task(async function test_usePingSenderOnShutdown() {
   if (gIsAndroid ||
       (AppConstants.platform == "linux" && OS.Constants.Sys.bits == 32)) {
     // We don't support the pingsender on Android, yet, see bug 1335917.
     // We also don't support the pingsender testing on Treeherder for
     // Linux 32 bit (due to missing libraries). So skip it there too.
     // See bug 1310703 comment 78.
     return;
--- a/toolkit/xre/nsConsoleWriter.cpp
+++ b/toolkit/xre/nsConsoleWriter.cpp
@@ -73,17 +73,17 @@ WriteConsoleLog()
     PR_fprintf(file, NS_LINEBREAK
                      "*** Console log: %s ***" NS_LINEBREAK,
                datetime);
   }
 
   // From this point on, we have to release all the messages, and free
   // the memory allocated for the messages array. XPCOM arrays suck.
 
-  nsXPIDLString msg;
+  nsString msg;
   nsAutoCString nativemsg;
 
   for (uint32_t i = 0; i < mcount; ++i) {
     rv = messages[i]->GetMessageMoz(getter_Copies(msg));
     if (NS_SUCCEEDED(rv)) {
       NS_CopyUnicodeToNative(msg, nativemsg);
       PR_fprintf(file, "%s" NS_LINEBREAK, nativemsg.get());
     }
--- a/toolkit/xre/nsNativeAppSupportWin.cpp
+++ b/toolkit/xre/nsNativeAppSupportWin.cpp
@@ -984,17 +984,17 @@ nsNativeAppSupportWin::HandleDDENotifica
 
                         // Get the base window from the doc shell...
                         nsCOMPtr<nsIBaseWindow> baseWindow =
                           do_QueryInterface( internalContent->GetDocShell() );
                         if ( !baseWindow ) {
                             break;
                         }
                         // And from the base window we can get the title.
-                        nsXPIDLString title;
+                        nsString title;
                         if(!baseWindow) {
                             break;
                         }
                         baseWindow->GetTitle(getter_Copies(title));
                         // Escape any double-quotes in the title.
                         escapeQuotes( title );
 
                         // Use a string buffer for the output data, first
--- a/widget/android/GeneratedJNIWrappers.cpp
+++ b/widget/android/GeneratedJNIWrappers.cpp
@@ -183,17 +183,17 @@ constexpr char GeckoAppShell::EnableBatt
 auto GeckoAppShell::EnableBatteryNotifications() -> void
 {
     return mozilla::jni::Method<EnableBatteryNotifications_t>::Call(GeckoAppShell::Context(), nullptr);
 }
 
 constexpr char GeckoAppShell::EnableLocation_t::name[];
 constexpr char GeckoAppShell::EnableLocation_t::signature[];
 
-auto GeckoAppShell::EnableLocation(bool a0) -> void
+auto GeckoAppShell::EnableLocation(bool a0) -> bool
 {
     return mozilla::jni::Method<EnableLocation_t>::Call(GeckoAppShell::Context(), nullptr, a0);
 }
 
 constexpr char GeckoAppShell::EnableLocationHighAccuracy_t::name[];
 constexpr char GeckoAppShell::EnableLocationHighAccuracy_t::signature[];
 
 auto GeckoAppShell::EnableLocationHighAccuracy(bool a0) -> void
--- a/widget/android/GeneratedJNIWrappers.h
+++ b/widget/android/GeneratedJNIWrappers.h
@@ -566,33 +566,33 @@ public:
         static const mozilla::jni::DispatchTarget dispatchTarget =
                 mozilla::jni::DispatchTarget::CURRENT;
     };
 
     static auto EnableBatteryNotifications() -> void;
 
     struct EnableLocation_t {
         typedef GeckoAppShell Owner;
-        typedef void ReturnType;
-        typedef void SetterType;
+        typedef bool ReturnType;
+        typedef bool SetterType;
         typedef mozilla::jni::Args<
                 bool> Args;
         static constexpr char name[] = "enableLocation";
         static constexpr char signature[] =
-                "(Z)V";
+                "(Z)Z";
         static const bool isStatic = true;
         static const mozilla::jni::ExceptionMode exceptionMode =
                 mozilla::jni::ExceptionMode::ABORT;
         static const mozilla::jni::CallingThread callingThread =
                 mozilla::jni::CallingThread::GECKO;
         static const mozilla::jni::DispatchTarget dispatchTarget =
                 mozilla::jni::DispatchTarget::CURRENT;
     };
 
-    static auto EnableLocation(bool) -> void;
+    static auto EnableLocation(bool) -> bool;
 
     struct EnableLocationHighAccuracy_t {
         typedef GeckoAppShell Owner;
         typedef void ReturnType;
         typedef void SetterType;
         typedef mozilla::jni::Args<
                 bool> Args;
         static constexpr char name[] = "enableLocationHighAccuracy";
@@ -1387,17 +1387,17 @@ public:
                 int64_t> Args;
         static constexpr char name[] = "onLocationChanged";
         static constexpr char signature[] =
                 "(DDDFFFJ)V";
         static const bool isStatic = true;
         static const mozilla::jni::ExceptionMode exceptionMode =
                 mozilla::jni::ExceptionMode::ABORT;
         static const mozilla::jni::CallingThread callingThread =
-                mozilla::jni::CallingThread::UI;
+                mozilla::jni::CallingThread::ANY;
         static const mozilla::jni::DispatchTarget dispatchTarget =
                 mozilla::jni::DispatchTarget::GECKO;
     };
 
     struct OnSensorChanged_t {
         typedef GeckoAppShell Owner;
         typedef void ReturnType;
         typedef void SetterType;
--- a/widget/android/nsDeviceContextAndroid.cpp
+++ b/widget/android/nsDeviceContextAndroid.cpp
@@ -55,17 +55,17 @@ nsDeviceContextSpecAndroid::BeginDocumen
                                           int32_t aEndPage)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDeviceContextSpecAndroid::EndDocument()
 {
-  nsXPIDLString targetPath;
+  nsString targetPath;
   nsCOMPtr<nsIFile> destFile;
   mPrintSettings->GetToFileName(getter_Copies(targetPath));
 
   nsresult rv = NS_NewLocalFile(targetPath, false, getter_AddRefs(destFile));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoString destLeafName;
   rv = destFile->GetLeafName(destLeafName);
--- a/widget/cocoa/nsPrintDialogX.mm
+++ b/widget/cocoa/nsPrintDialogX.mm
@@ -230,17 +230,17 @@ nsPrintDialogServiceX::ShowPageSetup(nsP
 
 - (void)addLabel:(const char*)aLabel withFrame:(NSRect)aRect;
 
 - (void)addCenteredLabel:(const char*)aLabel withFrame:(NSRect)aRect;
 
 - (NSButton*)checkboxWithLabel:(const char*)aLabel andFrame:(NSRect)aRect;
 
 - (NSPopUpButton*)headerFooterItemListWithFrame:(NSRect)aRect
-                                   selectedItem:(const char16_t*)aCurrentString;
+                                   selectedItem:(const nsAString&)aCurrentString;
 
 - (void)addOptionsSection;
 
 - (void)addAppearanceSection;
 
 - (void)addFramesSection;
 
 - (void)addHeaderFooterSection;
@@ -359,17 +359,17 @@ static const char sHeaderFooterTags[][4]
   [checkbox setButtonType:NSSwitchButton];
   [checkbox setTitle:[self localizedString:aLabel]];
   [checkbox setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]];
   [checkbox sizeToFit];
   return checkbox;
 }
 
 - (NSPopUpButton*)headerFooterItemListWithFrame:(NSRect)aRect
-                                   selectedItem:(const char16_t*)aCurrentString
+                                   selectedItem:(const nsAString&)aCurrentString
 {
   NSPopUpButton* list = [[[NSPopUpButton alloc] initWithFrame:aRect pullsDown:NO] autorelease];
   [list setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
   [[list cell] setControlSize:NSSmallControlSize];
   NSArray* items =
     [NSArray arrayWithObjects:[self localizedString:"headerFooterBlank"],
                               [self localizedString:"headerFooterTitle"],
                               [self localizedString:"headerFooterURL"],
@@ -508,17 +508,17 @@ static const char sHeaderFooterTags[][4]
   // Labels
   [self addLabel:"pageHeadersTitleMac" withFrame:NSMakeRect(0, 44, 151, 22)];
   [self addLabel:"pageFootersTitleMac" withFrame:NSMakeRect(0, 0, 151, 22)];
   [self addCenteredLabel:"left" withFrame:NSMakeRect(156, 22, 100, 22)];
   [self addCenteredLabel:"center" withFrame:NSMakeRect(256, 22, 100, 22)];
   [self addCenteredLabel:"right" withFrame:NSMakeRect(356, 22, 100, 22)];
 
   // Lists
-  nsXPIDLString sel;
+  nsString sel;
 
   mSettings->GetHeaderStrLeft(getter_Copies(sel));
   mHeaderLeftList = [self headerFooterItemListWithFrame:NSMakeRect(156, 44, 100, 22)
                                            selectedItem:sel];
   [self addSubview:mHeaderLeftList];
 
   mSettings->GetHeaderStrCenter(getter_Copies(sel));
   mHeaderCenterList = [self headerFooterItemListWithFrame:NSMakeRect(256, 44, 100, 22)
--- a/widget/gtk/nsDeviceContextSpecG.cpp
+++ b/widget/gtk/nsDeviceContextSpecG.cpp
@@ -239,20 +239,20 @@ ns_release_macro(gpointer aData) {
 }
 
 /* static */
 gboolean nsDeviceContextSpecGTK::PrinterEnumerator(GtkPrinter *aPrinter,
                                                    gpointer aData) {
   nsDeviceContextSpecGTK *spec = (nsDeviceContextSpecGTK*)aData;
 
   // Find the printer whose name matches the one inside the settings.
-  nsXPIDLString printerName;
+  nsString printerName;
   nsresult rv =
     spec->mPrintSettings->GetPrinterName(getter_Copies(printerName));
-  if (NS_SUCCEEDED(rv) && printerName) {
+  if (NS_SUCCEEDED(rv) && !printerName.IsVoid()) {
     NS_ConvertUTF16toUTF8 requestedName(printerName);
     const char* currentName = gtk_printer_get_name(aPrinter);
     if (requestedName.Equals(currentName)) {
       spec->mPrintSettings->SetGtkPrinter(aPrinter);
 
       // Bug 1145916 - attempting to kick off a print job for this printer
       // during this tick of the event loop will result in the printer backend
       // misunderstanding what the capabilities of the printer are due to a
@@ -321,17 +321,17 @@ NS_IMETHODIMP nsDeviceContextSpecGTK::En
       // one with a matching name.
       NS_DispatchToCurrentThread(
         NewRunnableMethod("nsDeviceContextSpecGTK::EnumeratePrinters",
                           this,
                           &nsDeviceContextSpecGTK::EnumeratePrinters));
     }
   } else {
     // Handle print-to-file ourselves for the benefit of embedders
-    nsXPIDLString targetPath;
+    nsString targetPath;
     nsCOMPtr<nsIFile> destFile;
     mPrintSettings->GetToFileName(getter_Copies(targetPath));
 
     nsresult rv = NS_NewLocalFile(targetPath, false, getter_AddRefs(destFile));
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsAutoString destLeafName;
     rv = destFile->GetLeafName(destLeafName);
--- a/widget/gtk/nsPrintDialogGTK.cpp
+++ b/widget/gtk/nsPrintDialogGTK.cpp
@@ -270,17 +270,17 @@ nsPrintDialogWidgetGTK::nsPrintDialogWid
   gtk_misc_set_alignment(GTK_MISC(header_footer_label), 0, 0);
 
   GtkWidget* header_footer_container = gtk_alignment_new(0, 0, 0, 0);
   gtk_alignment_set_padding(GTK_ALIGNMENT(header_footer_container), 8, 0, 12, 0);
 
 
   // --- Table for making the header and footer options ---
   GtkWidget* header_footer_table = gtk_table_new(3, 3, FALSE); // 3x3 table
-  nsXPIDLString header_footer_str[3];
+  nsString header_footer_str[3];
 
   aSettings->GetHeaderStrLeft(getter_Copies(header_footer_str[0]));
   aSettings->GetHeaderStrCenter(getter_Copies(header_footer_str[1]));
   aSettings->GetHeaderStrRight(getter_Copies(header_footer_str[2]));
 
   for (unsigned int i = 0; i < ArrayLength(header_dropdown); i++) {
     header_dropdown[i] = ConstructHeaderFooterDropdown(header_footer_str[i].get());
     // Those 4 magic numbers in the middle provide the position in the table.
@@ -577,19 +577,19 @@ nsPrintDialogServiceGTK::ShowPageSetup(n
 
   nsCOMPtr<nsPrintSettingsGTK> aNSSettingsGTK(do_QueryInterface(aNSSettings));
   if (!aNSSettingsGTK)
     return NS_ERROR_FAILURE;
 
   // We need to init the prefs here because aNSSettings in its current form is a dummy in both uses of the word
   nsCOMPtr<nsIPrintSettingsService> psService = do_GetService("@mozilla.org/gfx/printsettings-service;1");
   if (psService) {
-    nsXPIDLString printName;
+    nsString printName;
     aNSSettings->GetPrinterName(getter_Copies(printName));
-    if (!printName) {
+    if (printName.IsVoid()) {
       psService->GetDefaultPrinterName(getter_Copies(printName));
       aNSSettings->SetPrinterName(printName.get());
     }
     psService->InitPrintSettingsFromPrefs(aNSSettings, true, nsIPrintSettings::kInitSaveAll);
   }
 
   GtkPrintSettings* gtkSettings = aNSSettingsGTK->GetGtkPrintSettings();
   GtkPageSetup* oldPageSetup = aNSSettingsGTK->GetGtkPageSetup();
--- a/widget/gtk/nsPrintSettingsGTK.cpp
+++ b/widget/gtk/nsPrintSettingsGTK.cpp
@@ -470,17 +470,17 @@ NS_IMETHODIMP
 nsPrintSettingsGTK::GetPrinterName(char16_t * *aPrinter)
 {
   const char* gtkPrintName = gtk_print_settings_get_printer(mPrintSettings);
   if (!gtkPrintName) {
     if (GTK_IS_PRINTER(mGTKPrinter)) {
       gtkPrintName = gtk_printer_get_name(mGTKPrinter);
     } else {
       // This mimics what nsPrintSettingsImpl does when we try to Get before we Set
-      nsXPIDLString nullPrintName;
+      nsString nullPrintName;
       *aPrinter = ToNewUnicode(nullPrintName);
       return NS_OK;
     }
   }
   *aPrinter = UTF8ToNewUnicode(nsDependentCString(gtkPrintName));
   return NS_OK;
 }
 
--- a/widget/nsPrintOptionsImpl.cpp
+++ b/widget/nsPrintOptionsImpl.cpp
@@ -134,80 +134,80 @@ nsPrintOptions::SerializeToPrintData(nsI
 
   aSettings->GetScaling(&data->scaling());
 
   aSettings->GetPrintBGColors(&data->printBGColors());
   aSettings->GetPrintBGImages(&data->printBGImages());
   aSettings->GetPrintRange(&data->printRange());
 
   // I have no idea if I'm doing this string copying correctly...
-  nsXPIDLString title;
+  nsString title;
   aSettings->GetTitle(getter_Copies(title));
   data->title() = title;
 
-  nsXPIDLString docURL;
+  nsString docURL;
   aSettings->GetDocURL(getter_Copies(docURL));
   data->docURL() = docURL;
 
   // Header strings...
-  nsXPIDLString headerStrLeft;
+  nsString headerStrLeft;
   aSettings->GetHeaderStrLeft(getter_Copies(headerStrLeft));
   data->headerStrLeft() = headerStrLeft;
 
-  nsXPIDLString headerStrCenter;
+  nsString headerStrCenter;
   aSettings->GetHeaderStrCenter(getter_Copies(headerStrCenter));
   data->headerStrCenter() = headerStrCenter;
 
-  nsXPIDLString headerStrRight;
+  nsString headerStrRight;
   aSettings->GetHeaderStrRight(getter_Copies(headerStrRight));
   data->headerStrRight() = headerStrRight;
 
   // Footer strings...
-  nsXPIDLString footerStrLeft;
+  nsString footerStrLeft;
   aSettings->GetFooterStrLeft(getter_Copies(footerStrLeft));
   data->footerStrLeft() = footerStrLeft;
 
-  nsXPIDLString footerStrCenter;
+  nsString footerStrCenter;
   aSettings->GetFooterStrCenter(getter_Copies(footerStrCenter));
   data->footerStrCenter() = footerStrCenter;
 
-  nsXPIDLString footerStrRight;
+  nsString footerStrRight;
   aSettings->GetFooterStrRight(getter_Copies(footerStrRight));
   data->footerStrRight() = footerStrRight;
 
   aSettings->GetHowToEnableFrameUI(&data->howToEnableFrameUI());
   aSettings->GetIsCancelled(&data->isCancelled());
   aSettings->GetPrintFrameTypeUsage(&data->printFrameTypeUsage());
   aSettings->GetPrintFrameType(&data->printFrameType());
   aSettings->GetPrintSilent(&data->printSilent());
   aSettings->GetShrinkToFit(&data->shrinkToFit());
   aSettings->GetShowPrintProgress(&data->showPrintProgress());
 
-  nsXPIDLString paperName;
+  nsString paperName;
   aSettings->GetPaperName(getter_Copies(paperName));
   data->paperName() = paperName;
 
   aSettings->GetPaperData(&data->paperData());
   aSettings->GetPaperWidth(&data->paperWidth());
   aSettings->GetPaperHeight(&data->paperHeight());
   aSettings->GetPaperSizeUnit(&data->paperSizeUnit());
 
   aSettings->GetPrintReversed(&data->printReversed());
   aSettings->GetPrintInColor(&data->printInColor());
   aSettings->GetOrientation(&data->orientation());
 
   aSettings->GetNumCopies(&data->numCopies());
 
-  nsXPIDLString printerName;
+  nsString printerName;
   aSettings->GetPrinterName(getter_Copies(printerName));
   data->printerName() = printerName;
 
   aSettings->GetPrintToFile(&data->printToFile());
 
-  nsXPIDLString toFileName;
+  nsString toFileName;
   aSettings->GetToFileName(getter_Copies(toFileName));
   data->toFileName() = toFileName;
 
   aSettings->GetOutputFormat(&data->outputFormat());
   aSettings->GetPrintPageDelay(&data->printPageDelay());
   aSettings->GetResolution(&data->resolution());
   aSettings->GetDuplex(&data->duplex());
   aSettings->GetIsInitializedFromPrinter(&data->isInitializedFromPrinter());
@@ -979,17 +979,17 @@ nsPrintOptions::WritePrefs(nsIPrintSetti
 nsresult nsPrintOptions::_CreatePrintSettings(nsIPrintSettings **_retval)
 {
   // does not initially ref count
   nsPrintSettings * printSettings = new nsPrintSettings();
   NS_ENSURE_TRUE(printSettings, NS_ERROR_OUT_OF_MEMORY);
 
   NS_ADDREF(*_retval = printSettings); // ref count
 
-  nsXPIDLString printerName;
+  nsString printerName;
   nsresult rv = GetDefaultPrinterName(getter_Copies(printerName));
   NS_ENSURE_SUCCESS(rv, rv);
   (*_retval)->SetPrinterName(printerName.get());
 
   (void)InitPrintSettingsFromPrefs(*_retval, false,
                                    nsIPrintSettings::kInitSaveAll);
 
   return NS_OK;
@@ -1060,17 +1060,17 @@ nsPrintOptions::InitPrintSettingsFromPri
   if (XRE_IsContentProcess() && Preferences::GetBool("print.print_via_parent")) {
     return NS_OK;
   }
 
   NS_ENSURE_ARG_POINTER(aPrintSettings);
   NS_ENSURE_ARG_POINTER(aPrinterName);
 
 #ifdef DEBUG
-  nsXPIDLString printerName;
+  nsString printerName;
   aPrintSettings->GetPrinterName(getter_Copies(printerName));
   if (!printerName.Equals(aPrinterName)) {
     NS_WARNING("Printer names should match!");
   }
 #endif
 
   bool isInitialized;
   aPrintSettings->GetIsInitializedFromPrinter(&isInitialized);
--- a/widget/windows/nsDeviceContextSpecWin.cpp
+++ b/widget/windows/nsDeviceContextSpecWin.cpp
@@ -260,17 +260,17 @@ already_AddRefed<PrintTarget> nsDeviceCo
     }
 
     // convert twips to points
     width  /= TWIPS_PER_POINT_FLOAT;
     height /= TWIPS_PER_POINT_FLOAT;
     IntSize size = IntSize::Truncate(width, height);
 
     if (mOutputFormat == nsIPrintSettings::kOutputFormatPDF) {
-      nsXPIDLString filename;
+      nsString filename;
       mPrintSettings->GetToFileName(getter_Copies(filename));
 
       nsAutoCString printFile(NS_ConvertUTF16toUTF8(filename).get());
       auto skStream = MakeUnique<SkFILEWStream>(printFile.get());
       return PrintTargetSkPDF::CreateOrNull(Move(skStream), size);
     }
 
     if (mDevMode) {
@@ -305,17 +305,17 @@ already_AddRefed<PrintTarget> nsDeviceCo
       mPDFTempFile->GetNativePath(filePath);
       auto skStream = MakeUnique<SkFILEWStream>(filePath.get());
       return PrintTargetSkPDF::CreateOrNull(Move(skStream), size);
     }
   }
 #endif
 
   if (mOutputFormat == nsIPrintSettings::kOutputFormatPDF) {
-    nsXPIDLString filename;
+    nsString filename;
     mPrintSettings->GetToFileName(getter_Copies(filename));
 
     double width, height;
     mPrintSettings->GetEffectivePageSize(&width, &height);
     if (width <= 0 || height <= 0) {
       return nullptr;
     }
 
--- a/xpcom/string/nsTString.h
+++ b/xpcom/string/nsTString.h
@@ -104,19 +104,19 @@ public:
     return *this;
   }
 
   /**
    * returns the null-terminated string
    */
 
 #if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER)
-  char16ptr_t get() const
+  MOZ_NO_DANGLING_ON_TEMPORARIES char16ptr_t get() const
 #else
-  const char_type* get() const
+  MOZ_NO_DANGLING_ON_TEMPORARIES const char_type* get() const
 #endif
   {
     return mData;
   }
 
 
   /**
    * returns character at specified index.
@@ -719,19 +719,19 @@ public:
     : string_type(char_traits::sEmptyBuffer, 0,
                   DataFlags::TERMINATED | DataFlags::VOIDED, ClassFlags(0))
   {
     Assign(aStr);
   }
 
   // return nullptr if we are voided
 #if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER)
-  char16ptr_t get() const
+  MOZ_NO_DANGLING_ON_TEMPORARIES char16ptr_t get() const
 #else
-  const char_type* get() const
+  MOZ_NO_DANGLING_ON_TEMPORARIES const char_type* get() const
 #endif
   {
     return (mDataFlags & DataFlags::VOIDED) ? nullptr : mData;
   }
 
   // this case operator is the reason why this class cannot just be a
   // typedef for nsTString
   operator const char_type*() const
--- a/xpfe/components/directory/nsDirectoryViewer.cpp
+++ b/xpfe/components/directory/nsDirectoryViewer.cpp
@@ -410,17 +410,17 @@ nsHTTPIndex::OnIndexAvailable(nsIRequest
     CopyASCIItoUTF16(entryuriC, str);
 
     rv = mDirRDF->GetLiteral(str.get(), getter_AddRefs(lit));
 
     if (NS_SUCCEEDED(rv)) {
       rv = Assert(entry, kNC_URL, lit, true);
       if (NS_FAILED(rv)) return rv;
 
-      nsXPIDLString xpstr;
+      nsString xpstr;
 
       // description
       rv = aIndex->GetDescription(getter_Copies(xpstr));
       if (NS_FAILED(rv)) return rv;
       if (xpstr.Last() == '/')
         xpstr.Truncate(xpstr.Length() - 1);
 
       rv = mDirRDF->GetLiteral(xpstr.get(), getter_AddRefs(lit));