merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 02 Feb 2015 13:19:59 +0100
changeset 240404 3bf7ed413e87f086a3f5ede1ddd475f310b117e0
parent 240390 b955d50b6ec34505f4f75c166fdc56825cea507c (current diff)
parent 240403 dc9aad9b9ce1521b5e4beb928cdf6d45e406f93f (diff)
child 240405 3a6352aec108516ba677529d9e4f387d48039c27
child 240406 c38fa63e49b397ec545d056d25843d3d134adfba
child 240421 7e188718dea295dd4e21b301da0c6efc7c84a978
child 240444 980dc854a29e6b4930597221a1c370f20ae51085
child 240448 74a5e4560149ea9d7923a67832ae6017e7daa04e
child 240460 90b2d872349cfac479faa456131a1be2c12125aa
child 240498 8b75594aa22567d89d8d05812fc75e02a67affe2
child 241962 56b9aa20fd144cc6749df9ab9626837add38a6b9
child 251373 d67cb5755083878b014055808b93e09d3447cb4a
push id535
push usercmanchester@mozilla.com
push dateMon, 02 Feb 2015 19:04:18 +0000
reviewersmerge
milestone38.0a1
merge mozilla-inbound to mozilla-central a=merge
memory/mozalloc/fallible.h
toolkit/components/telemetry/Histograms.json
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1109248 - This needed a CLOBBER on Windows and OSX.
+Bug 1120369 - Needed a CLOBBER on at least Linux and OSX.
--- a/accessible/base/nsCoreUtils.cpp
+++ b/accessible/base/nsCoreUtils.cpp
@@ -144,17 +144,17 @@ nsCoreUtils::DispatchTouchEvent(uint32_t
   if (!dom::TouchEvent::PrefEnabled())
     return;
 
   WidgetTouchEvent event(true, aEventType, aRootWidget);
 
   event.time = PR_IntervalNow();
 
   // XXX: Touch has an identifier of -1 to hint that it is synthesized.
-  nsRefPtr<dom::Touch> t = new dom::Touch(-1, nsIntPoint(aX, aY),
+  nsRefPtr<dom::Touch> t = new dom::Touch(-1, LayoutDeviceIntPoint(aX, aY),
                                           nsIntPoint(1, 1), 0.0f, 1.0f);
   t->SetTarget(aContent);
   event.touches.AppendElement(t);
   nsEventStatus status = nsEventStatus_eIgnore;
   aPresShell->HandleEventWithTarget(&event, aFrame, aContent, &status);
 }
 
 uint32_t
--- a/build/gecko_templates.mozbuild
+++ b/build/gecko_templates.mozbuild
@@ -73,16 +73,21 @@ def GeckoBinary(linkage='dependent', msv
                     if CONFIG['MOZ_LINKER']:
                         OS_LIBS += CONFIG['MOZ_ZLIB_LIBS']
             elif mozglue == 'library':
                 if not CONFIG['MOZ_GLUE_IN_PROGRAM']:
                     USE_LIBS += ['mozglue']
             else:
                 error('`mozglue` must be "program" or "library"')
 
+    if not CONFIG['JS_STANDALONE']:
+        USE_LIBS += [
+            'fallible',
+        ]
+
 
 @template
 def GeckoProgram(name, linkage='standalone', **kwargs):
     '''Template for program executables related to Gecko.
 
     `name` identifies the executable base name.
 
     See the documentation for `GeckoBinary` for other possible arguments,
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -13675,17 +13675,17 @@ nsDocShell::GetAppManifestURL(nsAString&
 
 NS_IMETHODIMP
 nsDocShell::GetAsyncPanZoomEnabled(bool* aOut)
 {
     if (TabChild* tabChild = TabChild::GetFrom(this)) {
         *aOut = tabChild->IsAsyncPanZoomEnabled();
         return NS_OK;
     }
-    *aOut = false;
+    *aOut = Preferences::GetBool("layers.async-pan-zoom.enabled", false);
     return NS_OK;
 }
 
 bool
 nsDocShell::HasUnloadedParent()
 {
     nsRefPtr<nsDocShell> parent = GetParentDocshell();
     while (parent) {
--- a/dom/base/DOMParser.cpp
+++ b/dom/base/DOMParser.cpp
@@ -104,17 +104,17 @@ DOMParser::ParseFromString(const nsAStri
     NS_ENSURE_SUCCESS(rv, rv);
 
     domDocument.forget(aResult);
     return rv;
   }
 
   nsAutoCString utf8str;
   // Convert from UTF16 to UTF8 using fallible allocations
-  if (!AppendUTF16toUTF8(str, utf8str, mozilla::fallible_t())) {
+  if (!AppendUTF16toUTF8(str, utf8str, mozilla::fallible)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   // The new stream holds a reference to the buffer
   nsCOMPtr<nsIInputStream> stream;
   rv = NS_NewByteInputStream(getter_AddRefs(stream),
                              utf8str.get(), utf8str.Length(),
                              NS_ASSIGNMENT_DEPEND);
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -2197,17 +2197,17 @@ public:
     u->mTextFragment = aTextFragment;
     u->mType = Unit::eTextFragmentWithEncode;
     u->mLength = aLen;
     mLength += aLen;
   }
 
   bool ToString(nsAString& aOut)
   {
-    if (!aOut.SetCapacity(mLength, fallible_t())) {
+    if (!aOut.SetCapacity(mLength, fallible)) {
       return false;
     }
 
     for (StringBuilder* current = this; current; current = current->mNext) {
       uint32_t len = current->mUnits.Length();
       for (uint32_t i = 0; i < len; ++i) {
         Unit& u = current->mUnits[i];
         switch (u.mType) {
--- a/dom/base/URLSearchParams.cpp
+++ b/dom/base/URLSearchParams.cpp
@@ -185,17 +185,17 @@ URLSearchParams::ConvertString(const nsA
   int32_t outputLength = 0;
 
   nsresult rv = mDecoder->GetMaxLength(aInput.BeginReading(), inputLength,
                                        &outputLength);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
-  if (!aOutput.SetLength(outputLength, fallible_t())) {
+  if (!aOutput.SetLength(outputLength, fallible)) {
     return;
   }
 
   int32_t newOutputLength = outputLength;
   rv = mDecoder->Convert(aInput.BeginReading(), &inputLength,
                          aOutput.BeginWriting(), &newOutputLength);
   if (NS_FAILED(rv)) {
     aOutput.Truncate();
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -727,17 +727,17 @@ nsContentUtils::Atob(const nsAString& aA
   if (!Is8bit(aAsciiBase64String)) {
     aBinaryData.Truncate();
     return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
   }
 
   const char16_t* start = aAsciiBase64String.BeginReading();
   const char16_t* end = aAsciiBase64String.EndReading();
   nsString trimmedString;
-  if (!trimmedString.SetCapacity(aAsciiBase64String.Length(), fallible_t())) {
+  if (!trimmedString.SetCapacity(aAsciiBase64String.Length(), fallible)) {
     return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
   }
   while (start < end) {
     if (!nsContentUtils::IsHTMLWhitespace(*start)) {
       trimmedString.Append(*start);
     }
     start++;
   }
@@ -4420,58 +4420,58 @@ nsContentUtils::SetNodeTextContent(nsICo
 
   nsresult rv = aContent->AppendChildTo(textContent, true);
   mb.NodesAdded();
   return rv;
 }
 
 static bool
 AppendNodeTextContentsRecurse(nsINode* aNode, nsAString& aResult,
-                              const mozilla::fallible_t&)
+                              const fallible_t& aFallible)
 {
   for (nsIContent* child = aNode->GetFirstChild();
        child;
        child = child->GetNextSibling()) {
     if (child->IsElement()) {
       bool ok = AppendNodeTextContentsRecurse(child, aResult,
-                                              mozilla::fallible_t());
+                                              aFallible);
       if (!ok) {
         return false;
       }
     }
     else if (child->IsNodeOfType(nsINode::eTEXT)) {
-      bool ok = child->AppendTextTo(aResult, mozilla::fallible_t());
+      bool ok = child->AppendTextTo(aResult, aFallible);
       if (!ok) {
         return false;
       }
     }
   }
 
   return true;
 }
 
 /* static */
 bool
 nsContentUtils::AppendNodeTextContent(nsINode* aNode, bool aDeep,
                                       nsAString& aResult,
-                                      const mozilla::fallible_t&)
+                                      const fallible_t& aFallible)
 {
   if (aNode->IsNodeOfType(nsINode::eTEXT)) {
     return static_cast<nsIContent*>(aNode)->AppendTextTo(aResult,
-                                                         mozilla::fallible_t());
+                                                         aFallible);
   }
   else if (aDeep) {
-    return AppendNodeTextContentsRecurse(aNode, aResult, mozilla::fallible_t());
+    return AppendNodeTextContentsRecurse(aNode, aResult, aFallible);
   }
   else {
     for (nsIContent* child = aNode->GetFirstChild();
          child;
          child = child->GetNextSibling()) {
       if (child->IsNodeOfType(nsINode::eTEXT)) {
-        bool ok = child->AppendTextTo(aResult, mozilla::fallible_t());
+        bool ok = child->AppendTextTo(aResult, fallible);
         if (!ok) {
             return false;
         }
       }
     }
   }
 
   return true;
@@ -6237,17 +6237,17 @@ void nsContentUtils::RemoveNewlines(nsSt
   // strip CR/LF and null
   static const char badChars[] = {'\r', '\n', 0};
   aString.StripChars(badChars);
 }
 
 void
 nsContentUtils::PlatformToDOMLineBreaks(nsString &aString)
 {
-  if (!PlatformToDOMLineBreaks(aString, mozilla::fallible_t())) {
+  if (!PlatformToDOMLineBreaks(aString, fallible)) {
     aString.AllocFailed(aString.Length());
   }
 }
 
 bool
 nsContentUtils::PlatformToDOMLineBreaks(nsString& aString, const fallible_t& aFallible)
 {
   if (aString.FindChar(char16_t('\r')) != -1) {
@@ -6957,17 +6957,17 @@ nsContentUtils::DOMWindowDumpEnabled()
   return true;
 #endif
 }
 
 bool
 nsContentUtils::GetNodeTextContent(nsINode* aNode, bool aDeep, nsAString& aResult)
 {
   aResult.Truncate();
-  return AppendNodeTextContent(aNode, aDeep, aResult, mozilla::fallible_t());
+  return AppendNodeTextContent(aNode, aDeep, aResult, fallible);
 }
 
 void
 nsContentUtils::DestroyMatchString(void* aData)
 {
   if (aData) {
     nsString* matchString = static_cast<nsString*>(aData);
     delete matchString;
--- a/dom/base/nsDOMFileReader.cpp
+++ b/dom/base/nsDOMFileReader.cpp
@@ -343,17 +343,17 @@ nsDOMFileReader::DoReadData(nsIAsyncInpu
   if (mDataFormat == FILE_AS_BINARY) {
     //Continuously update our binary string as data comes in
     uint32_t oldLen = mResult.Length();
     NS_ASSERTION(mResult.Length() == mDataLen,
                  "unexpected mResult length");
     if (uint64_t(oldLen) + aCount > UINT32_MAX)
       return NS_ERROR_OUT_OF_MEMORY;
     char16_t *buf = nullptr;
-    mResult.GetMutableData(&buf, oldLen + aCount, fallible_t());
+    mResult.GetMutableData(&buf, oldLen + aCount, fallible);
     NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY);
 
     uint32_t bytesRead = 0;
     aStream->ReadSegments(ReadFuncBinaryString, buf + oldLen, aCount,
                           &bytesRead);
     NS_ASSERTION(bytesRead == aCount, "failed to read data");
   }
   else {
@@ -517,17 +517,17 @@ nsDOMFileReader::GetAsDataURL(nsIDOMBlob
     aResult.AppendLiteral("application/octet-stream");
   }
   aResult.AppendLiteral(";base64,");
 
   nsCString encodedData;
   rv = Base64Encode(Substring(aFileData, aDataLen), encodedData);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (!AppendASCIItoUTF16(encodedData, aResult, fallible_t())) {
+  if (!AppendASCIItoUTF16(encodedData, aResult, fallible)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   return NS_OK;
 }
 
 /* virtual */ JSObject*
 nsDOMFileReader::WrapObject(JSContext* aCx)
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -1153,17 +1153,17 @@ nsDOMWindowUtils::SendTouchEventCommon(c
   if (!presContext) {
     return NS_ERROR_FAILURE;
   }
   event.touches.SetCapacity(aCount);
   for (uint32_t i = 0; i < aCount; ++i) {
     LayoutDeviceIntPoint pt =
       ToWidgetPoint(CSSPoint(aXs[i], aYs[i]), offset, presContext);
     nsRefPtr<Touch> t = new Touch(aIdentifiers[i],
-                                  LayoutDeviceIntPoint::ToUntyped(pt),
+                                  pt,
                                   nsIntPoint(aRxs[i], aRys[i]),
                                   aRotationAngles[i],
                                   aForces[i]);
     event.touches.AppendElement(t);
   }
 
   nsEventStatus status;
   if (aToWindow) {
@@ -3387,18 +3387,18 @@ nsDOMWindowUtils::SelectAtPoint(float aX
   nsIFrame* rootFrame = presShell->FrameManager()->GetRootFrame();
   if (!rootFrame) {
     return NS_ERROR_UNEXPECTED;
   }
 
   // Get the target frame at the client coordinates passed to us
   nsPoint offset;
   nsCOMPtr<nsIWidget> widget = GetWidget(&offset);
-  nsIntPoint pt = LayoutDeviceIntPoint::ToUntyped(
-    ToWidgetPoint(CSSPoint(aX, aY), offset, GetPresContext()));
+  LayoutDeviceIntPoint pt =
+    ToWidgetPoint(CSSPoint(aX, aY), offset, GetPresContext());
   nsPoint ptInRoot =
     nsLayoutUtils::GetEventCoordinatesRelativeTo(widget, pt, rootFrame);
   nsIFrame* targetFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, ptInRoot);
   // This can happen if the page hasn't loaded yet or if the point
   // is outside the frame.
   if (!targetFrame) {
     return NS_ERROR_INVALID_ARG;
   }
--- a/dom/base/nsDocumentEncoder.cpp
+++ b/dom/base/nsDocumentEncoder.cpp
@@ -567,17 +567,17 @@ ConvertAndWrite(const nsAString& aString
 
   if (!charLength) {
     // Nothing to write.  Besides, a length 0 string has an immutable buffer, so
     // attempts to null-terminate it will crash.
     return NS_OK;
   }
 
   nsAutoCString charXferString;
-  if (!charXferString.SetLength(charLength, fallible_t()))
+  if (!charXferString.SetLength(charLength, fallible))
     return NS_ERROR_OUT_OF_MEMORY;
 
   char* charXferBuf = charXferString.BeginWriting();
   nsresult convert_rv = NS_OK;
 
   do {
     unicodeLength = startLength;
     charLength = startCharLength;
--- a/dom/base/nsGenericDOMDataNode.cpp
+++ b/dom/base/nsGenericDOMDataNode.cpp
@@ -1069,19 +1069,20 @@ nsGenericDOMDataNode::HasTextForTranslat
 
 void
 nsGenericDOMDataNode::AppendTextTo(nsAString& aResult)
 {
   mText.AppendTo(aResult);
 }
 
 bool
-nsGenericDOMDataNode::AppendTextTo(nsAString& aResult, const mozilla::fallible_t&)
+nsGenericDOMDataNode::AppendTextTo(nsAString& aResult,
+                                   const mozilla::fallible_t& aFallible)
 {
-  return mText.AppendTo(aResult, mozilla::fallible_t());
+  return mText.AppendTo(aResult, aFallible);
 }
 
 already_AddRefed<nsIAtom>
 nsGenericDOMDataNode::GetCurrentValueAtom()
 {
   nsAutoString val;
   GetData(val);
   return NS_NewAtom(val);
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -2768,17 +2768,16 @@ nsJSArgArray::nsJSArgArray(JSContext *aC
                            nsresult *prv) :
     mContext(aContext),
     mArgv(nullptr),
     mArgc(argc)
 {
   // copy the array - we don't know its lifetime, and ours is tied to xpcom
   // refcounting.
   if (argc) {
-    static const fallible_t fallible = fallible_t();
     mArgv = new (fallible) JS::Heap<JS::Value>[argc];
     if (!mArgv) {
       *prv = NS_ERROR_OUT_OF_MEMORY;
       return;
     }
   }
 
   // Callers are allowed to pass in a null argv even for argc > 0. They can
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -156,17 +156,17 @@ public:
 
 template<typename T>
 inline bool
 AssignJSString(JSContext *cx, T &dest, JSString *s)
 {
   size_t len = js::GetStringLength(s);
   static_assert(js::MaxStringLength < (1 << 28),
                 "Shouldn't overflow here or in SetCapacity");
-  if (MOZ_UNLIKELY(!dest.SetLength(len, mozilla::fallible_t()))) {
+  if (MOZ_UNLIKELY(!dest.SetLength(len, mozilla::fallible))) {
     JS_ReportOutOfMemory(cx);
     return false;
   }
   return js::CopyStringChars(cx, dest.BeginWriting(), s, len);
 }
 
 inline void
 AssignJSFlatString(nsAString &dest, JSFlatString *s)
--- a/dom/base/nsScriptNameSpaceManager.cpp
+++ b/dom/base/nsScriptNameSpaceManager.cpp
@@ -323,23 +323,23 @@ nsScriptNameSpaceManager::Init()
     GlobalNameHashMatchEntry,
     PL_DHashMoveEntryStub,
     GlobalNameHashClearEntry,
     GlobalNameHashInitEntry
   };
 
   mIsInitialized = PL_DHashTableInit(&mGlobalNames, &hash_table_ops,
                                      sizeof(GlobalNameMapEntry),
-                                     fallible_t(),
+                                     fallible,
                                      GLOBALNAME_HASHTABLE_INITIAL_LENGTH);
   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_OUT_OF_MEMORY);
 
   mIsInitialized = PL_DHashTableInit(&mNavigatorNames, &hash_table_ops,
                                      sizeof(GlobalNameMapEntry),
-                                     fallible_t(),
+                                     fallible,
                                      GLOBALNAME_HASHTABLE_INITIAL_LENGTH);
   if (!mIsInitialized) {
     PL_DHashTableFinish(&mGlobalNames);
 
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   RegisterWeakMemoryReporter(this);
--- a/dom/base/nsTextFragment.h
+++ b/dom/base/nsTextFragment.h
@@ -120,71 +120,71 @@ public:
    * it includes any Bidi characters.
    */
   bool Append(const char16_t* aBuffer, uint32_t aLength, bool aUpdateBidi);
 
   /**
    * Append the contents of this string fragment to aString
    */
   void AppendTo(nsAString& aString) const {
-    if (!AppendTo(aString, mozilla::fallible_t())) {
+    if (!AppendTo(aString, mozilla::fallible)) {
       aString.AllocFailed(aString.Length() + GetLength());
     }
   }
 
   /**
    * Append the contents of this string fragment to aString
    * @return false if an out of memory condition is detected, true otherwise
    */
   bool AppendTo(nsAString& aString,
-                const mozilla::fallible_t&) const NS_WARN_UNUSED_RESULT {
+                const mozilla::fallible_t& aFallible) const NS_WARN_UNUSED_RESULT {
     if (mState.mIs2b) {
-      bool ok = aString.Append(m2b, mState.mLength, mozilla::fallible_t());
+      bool ok = aString.Append(m2b, mState.mLength, aFallible);
       if (!ok) {
         return false;
       }
 
       return true;
     } else {
       return AppendASCIItoUTF16(Substring(m1b, mState.mLength), aString,
-                                mozilla::fallible_t());
+                                aFallible);
     }
   }
 
   /**
    * Append a substring of the contents of this string fragment to aString.
    * @param aOffset where to start the substring in this text fragment
    * @param aLength the length of the substring
    */
   void AppendTo(nsAString& aString, int32_t aOffset, int32_t aLength) const {
-    if (!AppendTo(aString, aOffset, aLength, mozilla::fallible_t())) {
+    if (!AppendTo(aString, aOffset, aLength, mozilla::fallible)) {
       aString.AllocFailed(aString.Length() + aLength);
     }
   }
 
   /**
    * Append a substring of the contents of this string fragment to aString.
    * @param aString the string in which to append
    * @param aOffset where to start the substring in this text fragment
    * @param aLength the length of the substring
    * @return false if an out of memory condition is detected, true otherwise
    */
   bool AppendTo(nsAString& aString, int32_t aOffset, int32_t aLength,
-                const mozilla::fallible_t&) const NS_WARN_UNUSED_RESULT
+                const mozilla::fallible_t& aFallible) const NS_WARN_UNUSED_RESULT
   {
     if (mState.mIs2b) {
-      bool ok = aString.Append(m2b + aOffset, aLength, mozilla::fallible_t());
+      bool ok = aString.Append(m2b + aOffset, aLength, aFallible);
       if (!ok) {
         return false;
       }
 
       return true;
     } else {
       return AppendASCIItoUTF16(Substring(m1b + aOffset, aLength), aString,
-                                mozilla::fallible_t());
+                                aFallible);
     }
   }
 
   /**
    * Make a copy of the fragments contents starting at offset for
    * count characters. The offset and count will be adjusted to
    * lie within the fragments data. The fragments data is converted if
    * necessary.
--- a/dom/base/nsXMLHttpRequest.cpp
+++ b/dom/base/nsXMLHttpRequest.cpp
@@ -665,17 +665,17 @@ nsXMLHttpRequest::AppendToResponseText(c
 {
   NS_ENSURE_STATE(mDecoder);
 
   int32_t destBufferLen;
   nsresult rv = mDecoder->GetMaxLength(aSrcBuffer, aSrcBufferLen,
                                        &destBufferLen);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (!mResponseText.SetCapacity(mResponseText.Length() + destBufferLen, fallible_t())) {
+  if (!mResponseText.SetCapacity(mResponseText.Length() + destBufferLen, fallible)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   char16_t* destBuffer = mResponseText.BeginWriting() + mResponseText.Length();
 
   int32_t totalChars = mResponseText.Length();
 
   // This code here is basically a copy of a similar thing in
--- a/dom/bindings/MozMap.h
+++ b/dom/bindings/MozMap.h
@@ -97,19 +97,17 @@ public:
   void EnumerateValues(Enumerator aEnumerator, void *aClosure)
   {
     ValueEnumClosure args = { aEnumerator, aClosure };
     this->EnumerateEntries(ValueEnumerator, &args);
   }
 
   DataType* AddEntry(const nsAString& aKey) NS_WARN_UNUSED_RESULT
   {
-    // XXXbz can't just use fallible_t() because our superclass has a
-    // private typedef by that name.
-    EntryType* ent = this->PutEntry(aKey, mozilla::fallible_t());
+    EntryType* ent = this->PutEntry(aKey, fallible);
     if (!ent) {
       return nullptr;
     }
     return &ent->mData;
   }
 
 private:
   static PLDHashOperator
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -1055,17 +1055,16 @@ WebGLContext::GetImageBuffer(uint8_t** o
     MOZ_ASSERT(mOptions.premultipliedAlpha || !premult, "We must get unpremult when we ask for it!");
 
     RefPtr<DataSourceSurface> dataSurface = snapshot->GetDataSurface();
 
     DataSourceSurface::MappedSurface map;
     if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map))
         return;
 
-    static const fallible_t fallible = fallible_t();
     uint8_t* imageBuffer = new (fallible) uint8_t[mWidth * mHeight * 4];
     if (!imageBuffer) {
         dataSurface->Unmap();
         return;
     }
     memcpy(imageBuffer, map.mData, mWidth * mHeight * 4);
 
     dataSurface->Unmap();
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -576,17 +576,17 @@ WebGLContext::DoFakeVertexAttrib0(GLuint
         mFakeVertexAttrib0BufferObjectVector[2] = mVertexAttrib0Vector[2];
         mFakeVertexAttrib0BufferObjectVector[3] = mVertexAttrib0Vector[3];
 
         gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject);
 
         GetAndFlushUnderlyingGLErrors();
 
         if (mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray) {
-            UniquePtr<GLfloat[]> array(new ((fallible_t())) GLfloat[4 * vertexCount]);
+            UniquePtr<GLfloat[]> array(new (fallible) GLfloat[4 * vertexCount]);
             if (!array) {
                 ErrorOutOfMemory("Fake attrib0 array.");
                 return false;
             }
             for(size_t i = 0; i < vertexCount; ++i) {
                 array[4 * i + 0] = mVertexAttrib0Vector[0];
                 array[4 * i + 1] = mVertexAttrib0Vector[1];
                 array[4 * i + 2] = mVertexAttrib0Vector[2];
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -43,17 +43,16 @@
 #include "nsCocoaFeatures.h"
 #endif
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ImageData.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "mozilla/Endian.h"
-#include "mozilla/fallible.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 using namespace mozilla::gl;
 
 static const WebGLRectangleObject*
 CurValidFBRectObject(const WebGLContext* webgl,
@@ -2081,17 +2080,17 @@ WebGLContext::ReadPixels(GLint x, GLint 
         // no need to check again for integer overflow here, since we already know the sizes aren't greater than before
         uint32_t subrect_plainRowSize = subrect_width * bytesPerPixel;
     // There are checks above to ensure that this doesn't overflow.
         uint32_t subrect_alignedRowSize =
             RoundedToNextMultipleOf(subrect_plainRowSize, mPixelStorePackAlignment).value();
         uint32_t subrect_byteLength = (subrect_height-1)*subrect_alignedRowSize + subrect_plainRowSize;
 
         // create subrect buffer, call glReadPixels, copy pixels into destination buffer, delete subrect buffer
-        UniquePtr<GLubyte> subrect_data(new ((fallible_t())) GLubyte[subrect_byteLength]);
+        UniquePtr<GLubyte> subrect_data(new (fallible) GLubyte[subrect_byteLength]);
         if (!subrect_data)
             return ErrorOutOfMemory("readPixels: subrect_data");
 
         gl->fReadPixels(subrect_x, subrect_y, subrect_width, subrect_height,
                         format, type, subrect_data.get());
 
         // notice that this for loop terminates because we already checked that subrect_height is at most height
         for (GLint y_inside_subrect = 0; y_inside_subrect < subrect_height; ++y_inside_subrect) {
@@ -3198,17 +3197,17 @@ WebGLContext::TexImage2D_base(TexImageTa
             !mPixelStoreFlipY)
         {
             // no conversion, no flipping, so we avoid copying anything and just pass the source pointer
             pixels = data;
         }
         else
         {
             size_t convertedDataSize = height * dstStride;
-            convertedData = new ((fallible_t())) uint8_t[convertedDataSize];
+            convertedData = new (fallible) uint8_t[convertedDataSize];
             if (!convertedData) {
                 ErrorOutOfMemory("texImage2D: Ran out of memory when allocating"
                                  " a buffer for doing format conversion.");
                 return;
             }
             if (!ConvertImage(width, height, srcStride, dstStride,
                               static_cast<uint8_t*>(data), convertedData,
                               actualSrcFormat, srcPremultiplied,
@@ -3399,17 +3398,17 @@ WebGLContext::TexSubImage2D_base(TexImag
     // no conversion, no flipping, so we avoid copying anything and just pass the source pointer
     bool noConversion = (actualSrcFormat == dstFormat &&
                          srcPremultiplied == mPixelStorePremultiplyAlpha &&
                          srcStride == dstStride &&
                          !mPixelStoreFlipY);
 
     if (!noConversion) {
         size_t convertedDataSize = height * dstStride;
-        convertedData = new ((fallible_t())) uint8_t[convertedDataSize];
+        convertedData = new (fallible) uint8_t[convertedDataSize];
         if (!convertedData) {
             ErrorOutOfMemory("texImage2D: Ran out of memory when allocating"
                              " a buffer for doing format conversion.");
             return;
         }
         if (!ConvertImage(width, height, srcStride, dstStride,
                           static_cast<const uint8_t*>(data), convertedData,
                           actualSrcFormat, srcPremultiplied,
--- a/dom/encoding/TextDecoder.cpp
+++ b/dom/encoding/TextDecoder.cpp
@@ -58,17 +58,16 @@ TextDecoder::Decode(const char* aInput, 
   int32_t outLen;
   nsresult rv = mDecoder->GetMaxLength(aInput, aLength, &outLen);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
   // Need a fallible allocator because the caller may be a content
   // and the content can specify the length of the string.
-  static const fallible_t fallible = fallible_t();
   nsAutoArrayPtr<char16_t> buf(new (fallible) char16_t[outLen + 1]);
   if (!buf) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
 
   int32_t length = aLength;
   rv = mDecoder->Convert(aInput, &length, buf, &outLen);
--- a/dom/encoding/TextEncoder.cpp
+++ b/dom/encoding/TextEncoder.cpp
@@ -48,17 +48,16 @@ TextEncoder::Encode(JSContext* aCx,
   const char16_t* data = PromiseFlatString(aString).get();
   nsresult rv = mEncoder->GetMaxLength(data, srcLen, &maxLen);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
   // Need a fallible allocator because the caller may be a content
   // and the content can specify the length of the string.
-  static const fallible_t fallible = fallible_t();
   nsAutoArrayPtr<char> buf(new (fallible) char[maxLen + 1]);
   if (!buf) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
 
   int32_t dstLen = maxLen;
   rv = mEncoder->Convert(data, &srcLen, buf, &dstLen);
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -961,18 +961,17 @@ Event::GetClientCoords(nsPresContext* aP
     return CSSIntPoint(0, 0);
   }
 
   nsIFrame* rootFrame = shell->GetRootFrame();
   if (!rootFrame) {
     return CSSIntPoint(0, 0);
   }
   nsPoint pt =
-    nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
-      LayoutDeviceIntPoint::ToUntyped(aPoint), rootFrame);
+    nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, aPoint, rootFrame);
 
   return CSSIntPoint::FromAppUnitsRounded(pt);
 }
 
 // To be called ONLY by Event::GetType (which has the additional
 // logic for handling user-defined events).
 // static
 const char*
--- a/dom/events/Touch.cpp
+++ b/dom/events/Touch.cpp
@@ -28,30 +28,30 @@ Touch::Touch(EventTarget* aTarget,
              float aRotationAngle,
              float aForce)
 {
   mTarget = aTarget;
   mIdentifier = aIdentifier;
   mPagePoint = CSSIntPoint(aPageX, aPageY);
   mScreenPoint = nsIntPoint(aScreenX, aScreenY);
   mClientPoint = CSSIntPoint(aClientX, aClientY);
-  mRefPoint = nsIntPoint(0, 0);
+  mRefPoint = LayoutDeviceIntPoint(0, 0);
   mPointsInitialized = true;
   mRadius.x = aRadiusX;
   mRadius.y = aRadiusY;
   mRotationAngle = aRotationAngle;
   mForce = aForce;
 
   mChanged = false;
   mMessage = 0;
   nsJSContext::LikelyShortLivingObjectCreated();
 }
 
 Touch::Touch(int32_t aIdentifier,
-             nsIntPoint aPoint,
+             LayoutDeviceIntPoint aPoint,
              nsIntPoint aRadius,
              float aRotationAngle,
              float aForce)
 {
   mIdentifier = aIdentifier;
   mPagePoint = CSSIntPoint(0, 0);
   mScreenPoint = nsIntPoint(0, 0);
   mClientPoint = CSSIntPoint(0, 0);
@@ -101,23 +101,20 @@ Touch::GetTarget() const
 
 void
 Touch::InitializePoints(nsPresContext* aPresContext, WidgetEvent* aEvent)
 {
   if (mPointsInitialized) {
     return;
   }
   mClientPoint = Event::GetClientCoords(
-    aPresContext, aEvent, LayoutDeviceIntPoint::FromUntyped(mRefPoint),
-    mClientPoint);
+    aPresContext, aEvent, mRefPoint, mClientPoint);
   mPagePoint = Event::GetPageCoords(
-    aPresContext, aEvent, LayoutDeviceIntPoint::FromUntyped(mRefPoint),
-    mClientPoint);
-  mScreenPoint = Event::GetScreenCoords(aPresContext, aEvent,
-    LayoutDeviceIntPoint::FromUntyped(mRefPoint));
+    aPresContext, aEvent, mRefPoint, mClientPoint);
+  mScreenPoint = Event::GetScreenCoords(aPresContext, aEvent, mRefPoint);
   mPointsInitialized = true;
 }
 
 void
 Touch::SetTarget(EventTarget* aTarget)
 {
   mTarget = aTarget;
 }
--- a/dom/events/Touch.h
+++ b/dom/events/Touch.h
@@ -35,17 +35,17 @@ public:
         int32_t aScreenY,
         int32_t aClientX,
         int32_t aClientY,
         int32_t aRadiusX,
         int32_t aRadiusY,
         float aRotationAngle,
         float aForce);
   Touch(int32_t aIdentifier,
-        nsIntPoint aPoint,
+        LayoutDeviceIntPoint aPoint,
         nsIntPoint aRadius,
         float aRotationAngle,
         float aForce);
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Touch)
 
   void InitializePoints(nsPresContext* aPresContext, WidgetEvent* aEvent);
@@ -68,17 +68,17 @@ public:
   int32_t PageX() const { return mPagePoint.x; }
   int32_t PageY() const { return mPagePoint.y; }
   int32_t RadiusX() const { return mRadius.x; }
   int32_t RadiusY() const { return mRadius.y; }
   float RotationAngle() const { return mRotationAngle; }
   float Force() const { return mForce; }
 
   nsCOMPtr<EventTarget> mTarget;
-  nsIntPoint mRefPoint;
+  LayoutDeviceIntPoint mRefPoint;
   bool mChanged;
   uint32_t mMessage;
   int32_t mIdentifier;
   CSSIntPoint mPagePoint;
   CSSIntPoint mClientPoint;
   nsIntPoint mScreenPoint;
   nsIntPoint mRadius;
   float mRotationAngle;
--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -465,17 +465,17 @@ ExtractFromUSVString(const nsString& aSt
 
   int32_t destBufferLen;
   nsresult rv = encoder->GetMaxLength(aStr.get(), aStr.Length(), &destBufferLen);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   nsCString encoded;
-  if (!encoded.SetCapacity(destBufferLen, fallible_t())) {
+  if (!encoded.SetCapacity(destBufferLen, fallible)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   char* destBuffer = encoded.BeginWriting();
   int32_t srcLen = (int32_t) aStr.Length();
   int32_t outLen = destBufferLen;
   rv = encoder->Convert(aStr.get(), &srcLen, destBuffer, &outLen);
   if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -578,17 +578,17 @@ public:
   {
     int32_t destBufferLen;
     nsresult rv =
       mDecoder->GetMaxLength(aSrcBuffer, aSrcBufferLen, &destBufferLen);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
-    if (!mDecoded.SetCapacity(mDecoded.Length() + destBufferLen, fallible_t())) {
+    if (!mDecoded.SetCapacity(mDecoded.Length() + destBufferLen, fallible)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     char16_t* destBuffer = mDecoded.BeginWriting() + mDecoded.Length();
     int32_t totalChars = mDecoded.Length();
 
     int32_t srcLen = (int32_t) aSrcBufferLen;
     int32_t outLen = destBufferLen;
--- a/dom/filehandle/MemoryStreams.cpp
+++ b/dom/filehandle/MemoryStreams.cpp
@@ -21,17 +21,17 @@ MemoryOutputStream::Create(uint64_t aSiz
 {
   NS_ASSERTION(aSize, "Passed zero size!");
 
   NS_ENSURE_TRUE(aSize <= UINT32_MAX, nullptr);
 
   nsRefPtr<MemoryOutputStream> stream = new MemoryOutputStream();
 
   char* dummy;
-  uint32_t length = stream->mData.GetMutableData(&dummy, aSize, fallible_t());
+  uint32_t length = stream->mData.GetMutableData(&dummy, aSize, fallible);
   NS_ENSURE_TRUE(length == aSize, nullptr);
 
   return stream.forget();
 }
 
 NS_IMPL_ISUPPORTS(MemoryOutputStream, nsIOutputStream)
 
 NS_IMETHODIMP
--- a/dom/html/HTMLFrameSetElement.cpp
+++ b/dom/html/HTMLFrameSetElement.cpp
@@ -227,17 +227,16 @@ HTMLFrameSetElement::ParseRowCol(const n
                 "Too many frameset specs allowed to allocate");
   int32_t commaX = spec.FindChar(sComma);
   int32_t count = 1;
   while (commaX != kNotFound && count < NS_MAX_FRAMESET_SPEC_COUNT) {
     count++;
     commaX = spec.FindChar(sComma, commaX + 1);
   }
 
-  static const fallible_t fallible = fallible_t();
   nsFramesetSpec* specs = new (fallible) nsFramesetSpec[count];
   if (!specs) {
     *aSpecs = nullptr;
     aNumSpecs = 0;
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   // Pre-grab the compat mode; we may need it later in the loop.
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -1868,18 +1868,16 @@ nsTextEditorState::GetValue(nsAString& a
     }
   }
 }
 
 bool
 nsTextEditorState::SetValue(const nsAString& aValue, bool aUserInput,
                             bool aSetValueChanged)
 {
-  mozilla::fallible_t fallible;
-
   if (mEditor && mBoundFrame) {
     // The InsertText call below might flush pending notifications, which
     // could lead into a scheduled PrepareEditor to be called.  That will
     // lead to crashes (or worse) because we'd be initializing the editor
     // before InsertText returns.  This script blocker makes sure that
     // PrepareEditor cannot be called prematurely.
     nsAutoScriptBlocker scriptBlocker;
 
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -141,18 +141,16 @@ static_assert(kMinorSchemaVersion <= 0xF
 
 const int32_t kSQLiteSchemaVersion =
   int32_t((kMajorSchemaVersion << 4) + kMinorSchemaVersion);
 
 const int32_t kStorageProgressGranularity = 1000;
 
 const char kSavepointClause[] = "SAVEPOINT sp;";
 
-const fallible_t fallible = fallible_t();
-
 const uint32_t kFileCopyBufferSize = 32768;
 
 const char kJournalDirectoryName[] = "journals";
 
 const char kFileManagerDirectoryNameSuffix[] = ".files";
 
 const char kPrefIndexedDBEnabled[] = "dom.indexedDB.enabled";
 
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -459,17 +459,17 @@ StructuredCloneReadString(JSStructuredCl
 {
   uint32_t length;
   if (!JS_ReadBytes(aReader, &length, sizeof(uint32_t))) {
     NS_WARNING("Failed to read length!");
     return false;
   }
   length = NativeEndian::swapFromLittleEndian(length);
 
-  if (!aString.SetLength(length, fallible_t())) {
+  if (!aString.SetLength(length, fallible)) {
     NS_WARNING("Out of memory?");
     return false;
   }
   char* buffer = aString.BeginWriting();
 
   if (!JS_ReadBytes(aReader, buffer, length)) {
     NS_WARNING("Failed to read type!");
     return false;
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -2297,19 +2297,18 @@ TabChild::RecvMouseWheelEvent(const Widg
                               const ScrollableLayerGuid& aGuid,
                               const uint64_t& aInputBlockId)
 {
   if (IsAsyncPanZoomEnabled()) {
     nsCOMPtr<nsIDocument> document(GetDocument());
     if (nsIPresShell* shell = document->GetShell()) {
       if (nsIFrame* rootFrame = shell->GetRootFrame()) {
         nsTArray<ScrollableLayerGuid> targets;
-        nsIntPoint refPoint(aEvent.refPoint.x, aEvent.refPoint.y);
         bool waitForRefresh =
-          PrepareForSetTargetAPZCNotification(aGuid, aInputBlockId, rootFrame, refPoint, &targets);
+          PrepareForSetTargetAPZCNotification(aGuid, aInputBlockId, rootFrame, aEvent.refPoint, &targets);
 
         SendSetTargetAPZCNotification(shell, aInputBlockId, targets, waitForRefresh);
       }
     }
   }
 
   WidgetWheelEvent event(aEvent);
   event.widget = mWidget;
@@ -2536,17 +2535,17 @@ private:
   uint64_t mInputBlockId;
   nsTArray<ScrollableLayerGuid> mTargets;
 };
 
 bool
 TabChild::PrepareForSetTargetAPZCNotification(const ScrollableLayerGuid& aGuid,
                                               const uint64_t& aInputBlockId,
                                               nsIFrame* aRootFrame,
-                                              const nsIntPoint& aRefPoint,
+                                              const LayoutDeviceIntPoint& aRefPoint,
                                               nsTArray<ScrollableLayerGuid>* aTargets)
 {
   ScrollableLayerGuid guid(aGuid.mLayersId, 0, FrameMetrics::NULL_SCROLL_ID);
   nsPoint point =
     nsLayoutUtils::GetEventCoordinatesRelativeTo(WebWidget(), aRefPoint, aRootFrame);
   nsIFrame* target =
     nsLayoutUtils::GetFrameForPoint(aRootFrame, point, nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME);
   nsIScrollableFrame* scrollAncestor = GetScrollableAncestorFrame(target);
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -587,17 +587,17 @@ private:
                                            const ScrollableLayerGuid& aGuid);
 
     // Adds the scrollable layer target to the target list, and returns whether
     // or not the caller should wait for a refresh to send a target
     // notification.
     bool PrepareForSetTargetAPZCNotification(const ScrollableLayerGuid& aGuid,
                                              const uint64_t& aInputBlockId,
                                              nsIFrame* aRootFrame,
-                                             const nsIntPoint& aRefPoint,
+                                             const LayoutDeviceIntPoint& aRefPoint,
                                              nsTArray<ScrollableLayerGuid>* aTargets);
 
     // Sends a SetTarget notification for APZC, given one or more previous
     // calls to PrepareForAPZCSetTargetNotification().
     void SendSetTargetAPZCNotification(nsIPresShell* aShell,
                                        const uint64_t& aInputBlockId,
                                        const nsTArray<ScrollableLayerGuid>& aTargets,
                                        bool aWaitForRefresh);
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1080,17 +1080,17 @@ TabParent::MapEventCoordinatesForChildPr
     aEvent->refPoint = LayoutDeviceIntPoint();
     // Then offset all the touch points by that distance, to put them
     // in the space where top-left is 0,0.
     const WidgetTouchEvent::TouchArray& touches =
       aEvent->AsTouchEvent()->touches;
     for (uint32_t i = 0; i < touches.Length(); ++i) {
       Touch* touch = touches[i];
       if (touch) {
-        touch->mRefPoint += LayoutDeviceIntPoint::ToUntyped(aOffset);
+        touch->mRefPoint += aOffset;
       }
     }
   }
 }
 
 bool TabParent::SendRealMouseEvent(WidgetMouseEvent& event)
 {
   if (mIsDestroyed) {
@@ -1726,17 +1726,17 @@ TabParent::GetChildProcessOffset()
   }
 
   // Find out how far we're offset from the nearest widget.
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return offset;
   }
   nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(widget,
-                                                            nsIntPoint(0, 0),
+                                                            LayoutDeviceIntPoint(0, 0),
                                                             targetFrame);
 
   return LayoutDeviceIntPoint::ToUntyped(LayoutDeviceIntPoint::FromAppUnitsToNearest(
            pt, targetFrame->PresContext()->AppUnitsPerDevPixel()));
 }
 
 bool
 TabParent::RecvReplyKeyEvent(const WidgetKeyboardEvent& event)
@@ -2480,17 +2480,17 @@ TabParent::InjectTouchEvent(const nsAStr
   event.touches.SetCapacity(aCount);
   for (uint32_t i = 0; i < aCount; ++i) {
     LayoutDeviceIntPoint pt =
       LayoutDeviceIntPoint::FromAppUnitsRounded(
         CSSPoint::ToAppUnits(CSSPoint(aXs[i], aYs[i])),
         presContext->AppUnitsPerDevPixel());
 
     nsRefPtr<Touch> t = new Touch(aIdentifiers[i],
-                                  LayoutDeviceIntPoint::ToUntyped(pt),
+                                  pt,
                                   nsIntPoint(aRxs[i], aRys[i]),
                                   aRotationAngles[i],
                                   aForces[i]);
 
     // Consider all injected touch events as changedTouches. For more details
     // about the meaning of changedTouches for each event, see
     // https://developer.mozilla.org/docs/Web/API/TouchEvent.changedTouches
     t->mChanged = true;
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -186,16 +186,22 @@ static const uint64_t ESTIMATED_DURATION
 static TimeDuration UsecsToDuration(int64_t aUsecs) {
   return TimeDuration::FromMicroseconds(aUsecs);
 }
 
 static int64_t DurationToUsecs(TimeDuration aDuration) {
   return static_cast<int64_t>(aDuration.ToSeconds() * USECS_PER_S);
 }
 
+static const uint32_t MIN_VIDEO_QUEUE_SIZE = 3;
+static const uint32_t MAX_VIDEO_QUEUE_SIZE = 10;
+
+static uint32_t sVideoQueueDefaultSize = MAX_VIDEO_QUEUE_SIZE;
+static uint32_t sVideoQueueHWAccelSize = MIN_VIDEO_QUEUE_SIZE;
+
 MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
                                                    MediaDecoderReader* aReader,
                                                    bool aRealTime) :
   mDecoder(aDecoder),
   mScheduler(new MediaDecoderStateMachineScheduler(
       aDecoder->GetReentrantMonitor(),
       &MediaDecoderStateMachine::TimeoutExpired, this, aRealTime)),
   mState(DECODER_STATE_DECODING_NONE),
@@ -211,17 +217,17 @@ MediaDecoderStateMachine::MediaDecoderSt
   mAudioStartTime(-1),
   mAudioEndTime(-1),
   mDecodedAudioEndTime(-1),
   mVideoFrameEndTime(-1),
   mDecodedVideoEndTime(-1),
   mVolume(1.0),
   mPlaybackRate(1.0),
   mPreservesPitch(true),
-  mAmpleVideoFrames(2),
+  mAmpleVideoFrames(MIN_VIDEO_QUEUE_SIZE),
   mLowAudioThresholdUsecs(detail::LOW_AUDIO_USECS),
   mAmpleAudioThresholdUsecs(detail::AMPLE_AUDIO_USECS),
   mQuickBufferingLowDataThresholdUsecs(detail::QUICK_BUFFERING_LOW_DATA_USECS),
   mIsAudioPrerolling(false),
   mIsVideoPrerolling(false),
   mAudioRequestStatus(RequestStatus::Idle),
   mVideoRequestStatus(RequestStatus::Idle),
   mAudioCaptured(false),
@@ -242,18 +248,26 @@ MediaDecoderStateMachine::MediaDecoderSt
   mLastFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED),
   mDecodingFrozenAtStateDecoding(false),
   mSentLoadedMetadataEvent(false),
   mSentFirstFrameLoadedEvent(false)
 {
   MOZ_COUNT_CTOR(MediaDecoderStateMachine);
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
 
-  mAmpleVideoFrames =
-    std::max<uint32_t>(Preferences::GetUint("media.video-queue.default-size", 10), 3);
+  static bool sPrefCacheInit = false;
+  if (!sPrefCacheInit) {
+    sPrefCacheInit = true;
+    Preferences::AddUintVarCache(&sVideoQueueDefaultSize,
+                                 "media.video-queue.default-size",
+                                 MAX_VIDEO_QUEUE_SIZE);
+    Preferences::AddUintVarCache(&sVideoQueueHWAccelSize,
+                                 "media.video-queue.hw-accel-size",
+                                 MIN_VIDEO_QUEUE_SIZE);
+  }
 
   mBufferingWait = IsRealTime() ? 0 : 30;
   mLowDataThresholdUsecs = IsRealTime() ? 0 : detail::LOW_DATA_THRESHOLD_USECS;
 
 #ifdef XP_WIN
   // Ensure high precision timers are enabled on Windows, otherwise the state
   // machine thread isn't woken up at reliable intervals to set the next frame,
   // and we drop frames while painting. Note that multiple calls to this
@@ -2210,26 +2224,37 @@ nsresult MediaDecoderStateMachine::Decod
       mState == DECODER_STATE_DECODING_METADATA &&
       isAwaitingResources) {
     // change state to DECODER_STATE_WAIT_FOR_RESOURCES
     StartWaitForResources();
     // affect values only if ReadMetadata succeeds
     return NS_OK;
   }
 
+  if (NS_FAILED(res) || (!info.HasValidMedia())) {
+    DECODER_WARN("ReadMetadata failed, res=%x HasValidMedia=%d", res, info.HasValidMedia());
+    return NS_ERROR_FAILURE;
+  }
+
   if (NS_SUCCEEDED(res)) {
     mDecoder->SetMediaSeekable(mReader->IsMediaSeekable());
   }
 
   mInfo = info;
 
-  if (NS_FAILED(res) || (!info.HasValidMedia())) {
-    DECODER_WARN("ReadMetadata failed, res=%x HasValidMedia=%d", res, info.HasValidMedia());
-    return NS_ERROR_FAILURE;
+  if (HasVideo()) {
+    mAmpleVideoFrames = (mReader->IsAsync() && mInfo.mVideo.mIsHardwareAccelerated)
+      ? std::max<uint32_t>(sVideoQueueHWAccelSize, MIN_VIDEO_QUEUE_SIZE)
+      : std::max<uint32_t>(sVideoQueueDefaultSize, MIN_VIDEO_QUEUE_SIZE);
+    DECODER_LOG("Video decode isAsync=%d HWAccel=%d videoQueueSize=%d",
+                mReader->IsAsync(),
+                mInfo.mVideo.mIsHardwareAccelerated,
+                mAmpleVideoFrames);
   }
+
   mDecoder->StartProgressUpdates();
   mGotDurationFromMetaData = (GetDuration() != -1) || mDurationSet;
 
   if (mGotDurationFromMetaData) {
     // We have all the information required: duration and size
     // Inform the element that we've loaded the metadata.
     EnqueueLoadedMetadataEvent();
   }
--- a/dom/media/MediaInfo.h
+++ b/dom/media/MediaInfo.h
@@ -36,16 +36,17 @@ struct TrackInfo {
 
 // Stores info relevant to presenting media frames.
 class VideoInfo {
 public:
   VideoInfo()
     : mDisplay(0,0)
     , mStereoMode(StereoMode::MONO)
     , mHasVideo(false)
+    , mIsHardwareAccelerated(false)
   {
     // TODO: TrackInfo should be initialized by its specific codec decoder.
     // This following call should be removed once we have that implemented.
     mTrackInfo.Init(NS_LITERAL_STRING("2"), NS_LITERAL_STRING("main"),
     EmptyString(), EmptyString(), true);
   }
 
   // Size in pixels at which the video is rendered. This is after it has
@@ -54,16 +55,18 @@ public:
 
   // Indicates the frame layout for single track stereo videos.
   StereoMode mStereoMode;
 
   // True if we have an active video bitstream.
   bool mHasVideo;
 
   TrackInfo mTrackInfo;
+
+  bool mIsHardwareAccelerated;
 };
 
 class AudioInfo {
 public:
   AudioInfo()
     : mRate(44100)
     , mChannels(2)
     , mHasAudio(false)
--- a/dom/media/fmp4/MP4Reader.cpp
+++ b/dom/media/fmp4/MP4Reader.cpp
@@ -460,16 +460,17 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo
                                                       mLayersBackendType,
                                                       mDecoder->GetImageContainer(),
                                                       mVideo.mTaskQueue,
                                                       mVideo.mCallback);
     }
     NS_ENSURE_TRUE(mVideo.mDecoder != nullptr, NS_ERROR_FAILURE);
     nsresult rv = mVideo.mDecoder->Init();
     NS_ENSURE_SUCCESS(rv, rv);
+    mInfo.mVideo.mIsHardwareAccelerated = mVideo.mDecoder->IsHardwareAccelerated();
   }
 
   // Get the duration, and report it to the decoder if we have it.
   Microseconds duration;
   {
     MonitorAutoLock lock(mDemuxerMonitor);
     duration = mDemuxer->Duration();
   }
--- a/dom/media/fmp4/MP4Stream.h
+++ b/dom/media/fmp4/MP4Stream.h
@@ -6,17 +6,16 @@
 
 #ifndef MP4_STREAM_H_
 #define MP4_STREAM_H_
 
 #include "mp4_demuxer/mp4_demuxer.h"
 
 #include "MediaResource.h"
 
-#include "mozilla/fallible.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/Monitor.h"
 
 namespace mozilla {
 
 class Monitor;
 
 class MP4Stream : public mp4_demuxer::Stream {
@@ -72,17 +71,17 @@ private:
   struct CacheBlock {
     CacheBlock(int64_t aOffset, size_t aCount)
       : mOffset(aOffset), mCount(aCount), mBuffer(nullptr) {}
     int64_t mOffset;
     size_t mCount;
 
     bool Init()
     {
-      mBuffer = new ((fallible_t())) char[mCount];
+      mBuffer = new (fallible) char[mCount];
       return !!mBuffer;
     }
 
     char* Buffer()
     {
       MOZ_ASSERT(mBuffer.get());
       return mBuffer.get();
     }
--- a/dom/media/fmp4/PlatformDecoderModule.h
+++ b/dom/media/fmp4/PlatformDecoderModule.h
@@ -240,13 +240,14 @@ public:
     return false;
   };
   virtual bool IsDormantNeeded() {
     return false;
   };
   virtual void AllocateMediaResources() {}
   virtual void ReleaseMediaResources() {}
   virtual void ReleaseDecoder() {}
+  virtual bool IsHardwareAccelerated() const { return false; }
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/fmp4/SharedDecoderManager.cpp
+++ b/dom/media/fmp4/SharedDecoderManager.cpp
@@ -232,9 +232,16 @@ SharedDecoderProxy::ReleaseMediaResource
 
 void
 SharedDecoderProxy::ReleaseDecoder()
 {
   if (mManager->mActiveProxy == this) {
     mManager->mDecoder->ReleaseMediaResources();
   }
 }
+
+bool
+SharedDecoderProxy::IsHardwareAccelerated() const
+{
+  return mManager->mDecoder->IsHardwareAccelerated();
 }
+
+}
--- a/dom/media/fmp4/SharedDecoderManager.h
+++ b/dom/media/fmp4/SharedDecoderManager.h
@@ -65,16 +65,17 @@ public:
   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
   virtual nsresult Flush() MOZ_OVERRIDE;
   virtual nsresult Drain() MOZ_OVERRIDE;
   virtual nsresult Shutdown() MOZ_OVERRIDE;
   virtual bool IsWaitingMediaResources() MOZ_OVERRIDE;
   virtual bool IsDormantNeeded() MOZ_OVERRIDE;
   virtual void ReleaseMediaResources() MOZ_OVERRIDE;
   virtual void ReleaseDecoder() MOZ_OVERRIDE;
+  virtual bool IsHardwareAccelerated() const MOZ_OVERRIDE;
 
   friend class SharedDecoderManager;
 
 private:
   nsRefPtr<SharedDecoderManager> mManager;
   MediaDataDecoderCallback* mCallback;
 };
 }
--- a/dom/media/fmp4/wmf/WMFMediaDataDecoder.cpp
+++ b/dom/media/fmp4/wmf/WMFMediaDataDecoder.cpp
@@ -174,9 +174,14 @@ WMFMediaDataDecoder::ReleaseMediaResourc
 }
 
 void
 WMFMediaDataDecoder::ReleaseDecoder()
 {
   ReleaseMediaResources();
 }
 
+bool
+WMFMediaDataDecoder::IsHardwareAccelerated() const {
+  return mMFTManager && mMFTManager->IsHardwareAccelerated();
+}
+
 } // namespace mozilla
--- a/dom/media/fmp4/wmf/WMFMediaDataDecoder.h
+++ b/dom/media/fmp4/wmf/WMFMediaDataDecoder.h
@@ -41,16 +41,19 @@ public:
   // enough data to produce more output. If this returns a failure code other
   // than MF_E_TRANSFORM_NEED_MORE_INPUT, an error will be reported to the
   // MP4Reader.
   virtual HRESULT Output(int64_t aStreamOffset,
                          nsRefPtr<MediaData>& aOutput) = 0;
 
   // Destroys all resources.
   virtual void Shutdown() = 0;
+
+  virtual bool IsHardwareAccelerated() const { return false; }
+
 };
 
 // Decodes audio and video using Windows Media Foundation. Samples are decoded
 // using the MFTDecoder created by the MFTManager. This class implements
 // the higher-level logic that drives mapping the MFT to the async
 // MediaDataDecoder interface. The specifics of decoding the exact stream
 // type are handled by MFTManager and the MFTDecoder it creates.
 class WMFMediaDataDecoder : public MediaDataDecoder {
@@ -70,16 +73,17 @@ public:
 
   virtual nsresult Shutdown() MOZ_OVERRIDE;
 
   virtual bool IsWaitingMediaResources() { return false; };
   virtual bool IsDormantNeeded() { return true; };
   virtual void AllocateMediaResources() MOZ_OVERRIDE;
   virtual void ReleaseMediaResources() MOZ_OVERRIDE;
   virtual void ReleaseDecoder() MOZ_OVERRIDE;
+  virtual bool IsHardwareAccelerated() const MOZ_OVERRIDE;
 
 private:
 
   // Called on the task queue. Inserts the sample into the decoder, and
   // extracts output if available.
   void ProcessDecode(mp4_demuxer::MP4Sample* aSample);
 
   // Called on the task queue. Extracts output if available, and delivers
--- a/dom/media/fmp4/wmf/WMFVideoMFTManager.cpp
+++ b/dom/media/fmp4/wmf/WMFVideoMFTManager.cpp
@@ -490,9 +490,15 @@ WMFVideoMFTManager::Output(int64_t aStre
 
 void
 WMFVideoMFTManager::Shutdown()
 {
   mDecoder = nullptr;
   DeleteOnMainThread(mDXVA2Manager);
 }
 
+bool
+WMFVideoMFTManager::IsHardwareAccelerated() const
+{
+  return mUseHwAccel;
+}
+
 } // namespace mozilla
--- a/dom/media/fmp4/wmf/WMFVideoMFTManager.h
+++ b/dom/media/fmp4/wmf/WMFVideoMFTManager.h
@@ -30,16 +30,18 @@ public:
 
   virtual HRESULT Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
 
   virtual HRESULT Output(int64_t aStreamOffset,
                          nsRefPtr<MediaData>& aOutput) MOZ_OVERRIDE;
 
   virtual void Shutdown() MOZ_OVERRIDE;
 
+  virtual bool IsHardwareAccelerated() const MOZ_OVERRIDE;
+
 private:
 
   bool InitializeDXVA();
 
   HRESULT ConfigureVideoFrameGeometry();
 
   HRESULT CreateBasicVideoFrame(IMFSample* aSample,
                                 int64_t aStreamOffset,
--- a/dom/media/gtest/MockMediaResource.cpp
+++ b/dom/media/gtest/MockMediaResource.cpp
@@ -55,17 +55,18 @@ MockMediaResource::ReadAt(int64_t aOffse
   mEntry--;
 
   return ferror(mFileHandle) ? NS_ERROR_FAILURE : NS_OK;
 }
 
 int64_t
 MockMediaResource::GetLength()
 {
-  return fseek(mFileHandle, 0, SEEK_END);
+  fseek(mFileHandle, 0, SEEK_END);
+  return ftell(mFileHandle);
 }
 
 void
 MockMediaResource::MockClearBufferedRanges()
 {
   mRanges.Clear();
 }
 
--- a/dom/media/gtest/TestMP4Demuxer.cpp
+++ b/dom/media/gtest/TestMP4Demuxer.cpp
@@ -326,8 +326,39 @@ TEST(MP4Demuxer, CENCFrag)
 
   i = 0;
   while (!!(sample = d->DemuxAudioSample())) {
     nsCString text = ToCryptoString(sample->crypto);
     EXPECT_STREQ(audio[i++], text.get());
   }
   EXPECT_EQ(ArrayLength(audio), i);
 }
+
+TEST(MP4Demuxer, GetNextKeyframe)
+{
+  nsRefPtr<MP4DemuxerBinding> b = new MP4DemuxerBinding("gizmo-frag.mp4");
+  MonitorAutoLock mon(b->mMonitor);
+  MP4Demuxer* d = b->demuxer;
+
+  EXPECT_TRUE(d->Init());
+
+  // Insert a [0,end] buffered range, to simulate Moof's being buffered
+  // via MSE.
+  auto len = b->resource->GetLength();
+  b->resource->MockAddBufferedRange(0, len);
+
+  // Rebuild the index so that it can be used to find the keyframes.
+  nsTArray<MediaByteRange> ranges;
+  EXPECT_TRUE(NS_SUCCEEDED(b->resource->GetCachedRanges(ranges)));
+  d->UpdateIndex(ranges);
+
+  // gizmp-frag has two keyframes; one at dts=cts=0, and another at
+  // dts=cts=1000000. Verify we get expected results.
+
+  MP4Sample* sample;
+  size_t i = 0;
+  const int64_t keyframe = 1000000;
+  while (!!(sample = d->DemuxVideoSample())) {
+    int64_t expected = (sample->decode_timestamp < keyframe) ? keyframe : -1;
+    EXPECT_EQ(d->GetNextKeyframeTime(), expected);
+    i++;
+  }
+}
--- a/dom/media/webaudio/AudioDestinationNode.cpp
+++ b/dom/media/webaudio/AudioDestinationNode.cpp
@@ -57,19 +57,18 @@ public:
     *aOutput = aInput;
 
     // The output buffer is allocated lazily, on the rendering thread.
     if (!mBufferAllocated) {
       // These allocations might fail if content provides a huge number of
       // channels or size, but it's OK since we'll deal with the failure
       // gracefully.
       if (mInputChannels.SetLength(mNumberOfChannels)) {
-        static const fallible_t fallible = fallible_t();
         for (uint32_t i = 0; i < mNumberOfChannels; ++i) {
-          mInputChannels[i] = new(fallible) float[mLength];
+          mInputChannels[i] = new (fallible) float[mLength];
           if (!mInputChannels[i]) {
             mInputChannels.Clear();
             break;
           }
         }
       }
 
       mBufferAllocated = true;
--- a/dom/media/webaudio/MediaBufferDecoder.cpp
+++ b/dom/media/webaudio/MediaBufferDecoder.cpp
@@ -328,23 +328,22 @@ MediaDecodeTask::FinishDecode()
                                      SPEEX_RESAMPLER_QUALITY_DEFAULT, nullptr);
     speex_resampler_skip_zeros(resampler);
     resampledFrames += speex_resampler_get_output_latency(resampler);
   }
 
   // Allocate the channel buffers.  Note that if we end up resampling, we may
   // write fewer bytes than mResampledFrames to the output buffer, in which
   // case mWriteIndex will tell us how many valid samples we have.
-  static const fallible_t fallible = fallible_t();
   bool memoryAllocationSuccess = true;
   if (!mDecodeJob.mChannelBuffers.SetLength(channelCount)) {
     memoryAllocationSuccess = false;
   } else {
     for (uint32_t i = 0; i < channelCount; ++i) {
-      mDecodeJob.mChannelBuffers[i] = new(fallible) float[resampledFrames];
+      mDecodeJob.mChannelBuffers[i] = new (fallible) float[resampledFrames];
       if (!mDecodeJob.mChannelBuffers[i]) {
         memoryAllocationSuccess = false;
         break;
       }
     }
   }
   if (!memoryAllocationSuccess) {
     ReportFailureOnMainThread(WebAudioDecodeJob::UnknownError);
--- a/dom/plugins/base/nsPluginTags.cpp
+++ b/dom/plugins/base/nsPluginTags.cpp
@@ -254,17 +254,17 @@ static nsresult ConvertToUTF8(nsIUnicode
                               nsAFlatCString& aString)
 {
   int32_t numberOfBytes = aString.Length();
   int32_t outUnicodeLen;
   nsAutoString buffer;
   nsresult rv = aUnicodeDecoder->GetMaxLength(aString.get(), numberOfBytes,
                                               &outUnicodeLen);
   NS_ENSURE_SUCCESS(rv, rv);
-  if (!buffer.SetLength(outUnicodeLen, fallible_t()))
+  if (!buffer.SetLength(outUnicodeLen, fallible))
     return NS_ERROR_OUT_OF_MEMORY;
   rv = aUnicodeDecoder->Convert(aString.get(), &numberOfBytes,
                                 buffer.BeginWriting(), &outUnicodeLen);
   NS_ENSURE_SUCCESS(rv, rv);
   buffer.SetLength(outUnicodeLen);
   CopyUTF16toUTF8(buffer, aString);
   
   return NS_OK;
--- a/dom/storage/DOMStorage.cpp
+++ b/dom/storage/DOMStorage.cpp
@@ -112,17 +112,17 @@ DOMStorage::SetItem(const nsAString& aKe
   Telemetry::Accumulate(GetType() == LocalStorage
       ? Telemetry::LOCALDOMSTORAGE_KEY_SIZE_BYTES
       : Telemetry::SESSIONDOMSTORAGE_KEY_SIZE_BYTES, aKey.Length());
   Telemetry::Accumulate(GetType() == LocalStorage
       ? Telemetry::LOCALDOMSTORAGE_VALUE_SIZE_BYTES
       : Telemetry::SESSIONDOMSTORAGE_VALUE_SIZE_BYTES, aData.Length());
 
   nsString data;
-  bool ok = data.Assign(aData, fallible_t());
+  bool ok = data.Assign(aData, fallible);
   if (!ok) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
 
   nsString old;
   aRv = mCache->SetItem(this, aKey, data, old);
   if (aRv.Failed()) {
--- a/dom/svg/SVGContentUtils.h
+++ b/dom/svg/SVGContentUtils.h
@@ -5,17 +5,16 @@
 
 #ifndef MOZILLA_SVGCONTENTUTILS_H
 #define MOZILLA_SVGCONTENTUTILS_H
 
 // include math.h to pick up definition of M_ maths defines e.g. M_PI
 #define _USE_MATH_DEFINES
 #include <math.h>
 
-#include "mozilla/fallible.h"
 #include "mozilla/gfx/2D.h" // for StrokeOptions
 #include "mozilla/gfx/Matrix.h"
 #include "mozilla/RangedPtr.h"
 #include "nsError.h"
 #include "nsStringFwd.h"
 #include "gfx2DGlue.h"
 
 class gfxTextContextPaint;
@@ -106,18 +105,17 @@ public:
      * returned to the caller as a non-const pointer (so that the caller can
      * initialize the values in the buffer, since mDashPattern is const).
      */
     Float* InitDashPattern(size_t aDashCount) {
       if (aDashCount <= MOZ_ARRAY_LENGTH(mSmallArray)) {
         mDashPattern = mSmallArray;
         return mSmallArray;
       }
-      static const mozilla::fallible_t fallible = mozilla::fallible_t();
-      Float* nonConstArray = new (fallible) Float[aDashCount];
+      Float* nonConstArray = new (mozilla::fallible) Float[aDashCount];
       mDashPattern = nonConstArray;
       return nonConstArray;
     }
     void DiscardDashPattern() {
       if (mDashPattern && mDashPattern != mSmallArray) {
         delete [] mDashPattern;
       }
       mDashLength = 0;
--- a/dom/svg/SVGFEConvolveMatrixElement.cpp
+++ b/dom/svg/SVGFEConvolveMatrixElement.cpp
@@ -197,17 +197,16 @@ SVGFEConvolveMatrixElement::GetPrimitive
       return failureDescription;
   } else {
     targetY = orderY / 2;
   }
 
   if (orderX > NS_SVG_OFFSCREEN_MAX_DIMENSION ||
       orderY > NS_SVG_OFFSCREEN_MAX_DIMENSION)
     return failureDescription;
-  const fallible_t fallible = fallible_t();
   nsAutoArrayPtr<float> kernel(new (fallible) float[orderX * orderY]);
   if (!kernel)
     return failureDescription;
   for (uint32_t i = 0; i < kmLength; i++) {
     kernel[kmLength - 1 - i] = kernelMatrix[i];
   }
 
   float divisor;
--- a/dom/xslt/base/txDouble.cpp
+++ b/dom/xslt/base/txDouble.cpp
@@ -174,17 +174,17 @@ void txDouble::toString(double aValue, n
     else {
         // trailing zeros, total length given by intDigits
         length = intDigits;
     }
     if (aValue < 0)
         ++length;
     // grow the string
     uint32_t oldlength = aDest.Length();
-    if (!aDest.SetLength(oldlength + length, mozilla::fallible_t()))
+    if (!aDest.SetLength(oldlength + length, mozilla::fallible))
         return; // out of memory
     nsAString::iterator dest;
     aDest.BeginWriting(dest).advance(int32_t(oldlength));
     if (aValue < 0) {
         *dest = '-'; ++dest;
     }
     int i;
     // leading zeros
--- a/dom/xslt/xpath/txMozillaXPathTreeWalker.cpp
+++ b/dom/xslt/xpath/txMozillaXPathTreeWalker.cpp
@@ -509,17 +509,17 @@ txXPathNodeUtils::appendNodeValue(const 
 
         return;
     }
 
     if (aNode.isDocument() ||
         aNode.mNode->IsElement() ||
         aNode.mNode->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT)) {
         nsContentUtils::AppendNodeTextContent(aNode.mNode, true, aResult,
-                                              mozilla::fallible_t());
+                                              mozilla::fallible);
 
         return;
     }
 
     aNode.Content()->AppendTextTo(aResult);
 }
 
 /* static */
--- a/editor/libeditor/nsTextEditRules.cpp
+++ b/editor/libeditor/nsTextEditRules.cpp
@@ -1193,17 +1193,17 @@ nsTextEditRules::TruncateInsertionIfNeed
                                            const nsAString  *aInString,
                                            nsAString  *aOutString,
                                            int32_t          aMaxLength,
                                            bool *aTruncated)
 {
   if (!aSelection || !aInString || !aOutString) {return NS_ERROR_NULL_POINTER;}
   
   nsresult res = NS_OK;
-  if (!aOutString->Assign(*aInString, mozilla::fallible_t())) {
+  if (!aOutString->Assign(*aInString, mozilla::fallible)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   if (aTruncated) {
     *aTruncated = false;
   }
   
   NS_ENSURE_STATE(mEditor);
   if ((-1 != aMaxLength) && IsPlaintextEditor() && !mEditor->IsIMEComposing() )
--- a/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
+++ b/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
@@ -571,17 +571,17 @@ mozInlineSpellWordUtil::BuildSoftText()
       }
 
       if (firstOffsetInNode < lastOffsetInNode) {
         int32_t len = lastOffsetInNode - firstOffsetInNode;
         mSoftTextDOMMapping.AppendElement(
           DOMTextMapping(NodeOffset(node, firstOffsetInNode), mSoftText.Length(), len));
 
         bool ok = textFragment->AppendTo(mSoftText, firstOffsetInNode, len,
-                                         mozilla::fallible_t());
+                                         mozilla::fallible);
         if (!ok) {
             // probably out of memory, remove from mSoftTextDOMMapping
             mSoftTextDOMMapping.RemoveElementAt(mSoftTextDOMMapping.Length() - 1);
             exit = true;
         }
       }
 
       firstOffsetInNode = 0;
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -350,26 +350,25 @@ APZCCallbackHelper::ApplyCallbackTransfo
                 CSSPoint delta = (*static_cast<CSSPoint*>(property));
                 return input + delta;
             }
         }
     }
     return input;
 }
 
-nsIntPoint
-APZCCallbackHelper::ApplyCallbackTransform(const nsIntPoint& aPoint,
+LayoutDeviceIntPoint
+APZCCallbackHelper::ApplyCallbackTransform(const LayoutDeviceIntPoint& aPoint,
                                            const ScrollableLayerGuid& aGuid,
                                            const CSSToLayoutDeviceScale& aScale,
                                            float aPresShellResolution)
 {
     LayoutDevicePoint point = LayoutDevicePoint(aPoint.x, aPoint.y);
     point = ApplyCallbackTransform(point / aScale, aGuid, aPresShellResolution) * aScale;
-    LayoutDeviceIntPoint ret = gfx::RoundedToInt(point);
-    return nsIntPoint(ret.x, ret.y);
+    return gfx::RoundedToInt(point);
 }
 
 nsEventStatus
 APZCCallbackHelper::DispatchWidgetEvent(WidgetGUIEvent& aEvent)
 {
   if (!aEvent.widget)
     return nsEventStatus_eConsumeNoDefault;
 
--- a/gfx/layers/apz/util/APZCCallbackHelper.h
+++ b/gfx/layers/apz/util/APZCCallbackHelper.h
@@ -94,23 +94,24 @@ public:
        method's documentations for details.
        This method additionally adjusts |aInput| by inversely scaling by the provided
        pres shell resolution, to cancel out a compositor-side transform (added in
        bug 1076241) that APZ doesn't unapply. */
     static CSSPoint ApplyCallbackTransform(const CSSPoint& aInput,
                                            const ScrollableLayerGuid& aGuid,
                                            float aPresShellResolution);
 
-    /* Same as above, but operates on nsIntPoint that are assumed to be in LayoutDevice
-       pixel space. Requires an additonal |aScale| parameter to convert between CSS and
+    /* Same as above, but operates on LayoutDeviceIntPoint.
+       Requires an additonal |aScale| parameter to convert between CSS and
        LayoutDevice space. */
-    static nsIntPoint ApplyCallbackTransform(const nsIntPoint& aPoint,
-                                             const ScrollableLayerGuid& aGuid,
-                                             const CSSToLayoutDeviceScale& aScale,
-                                             float aPresShellResolution);
+    static mozilla::LayoutDeviceIntPoint
+    ApplyCallbackTransform(const LayoutDeviceIntPoint& aPoint,
+                           const ScrollableLayerGuid& aGuid,
+                           const CSSToLayoutDeviceScale& aScale,
+                           float aPresShellResolution);
 
     /* Dispatch a widget event via the widget stored in the event, if any.
      * In a child process, allows the TabParent event-capture mechanism to
      * intercept the event. */
     static nsEventStatus DispatchWidgetEvent(WidgetGUIEvent& aEvent);
 
     /* Synthesize a mouse event with the given parameters, and dispatch it
      * via the given widget. */
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -669,18 +669,17 @@ MemoryTextureClient::ToSurfaceDescriptor
                                         GetFormat());
   return true;
 }
 
 bool
 MemoryTextureClient::Allocate(uint32_t aSize)
 {
   MOZ_ASSERT(!mBuffer);
-  static const fallible_t fallible = fallible_t();
-  mBuffer = new(fallible) uint8_t[aSize];
+  mBuffer = new (fallible) uint8_t[aSize];
   if (!mBuffer) {
     NS_WARNING("Failed to allocate buffer");
     return false;
   }
   GfxMemoryImageReporter::DidAlloc(mBuffer);
   mBufSize = aSize;
   return true;
 }
--- a/gfx/thebes/gfxFT2FontList.cpp
+++ b/gfx/thebes/gfxFT2FontList.cpp
@@ -1091,17 +1091,16 @@ gfxFT2FontList::AppendFacesFromOmnijarEn
     }
 
     nsZipItem *item = aArchive->GetItem(aEntryName.get());
     NS_ASSERTION(item, "failed to find zip entry");
 
     uint32_t bufSize = item->RealSize();
     // We use fallible allocation here; if there's not enough RAM, we'll simply
     // ignore the bundled fonts and fall back to the device's installed fonts.
-    static const fallible_t fallible = fallible_t();
     nsAutoArrayPtr<uint8_t> buf(new (fallible) uint8_t[bufSize]);
     if (!buf) {
         return;
     }
 
     nsZipCursor cursor(item, aArchive, buf, bufSize);
     uint8_t* data = cursor.Copy(&bufSize);
     NS_ASSERTION(data && bufSize == item->RealSize(),
--- a/image/decoders/icon/win/nsIconChannel.cpp
+++ b/image/decoders/icon/win/nsIconChannel.cpp
@@ -485,17 +485,17 @@ GetColorTableSize(BITMAPINFOHEADER* aHea
 
 // Given a header and a size, creates a freshly allocated BITMAPINFO structure.
 // It is the caller's responsibility to null-check and delete the structure.
 static BITMAPINFO*
 CreateBitmapInfo(BITMAPINFOHEADER* aHeader, size_t aColorTableSize)
 {
   BITMAPINFO* bmi = (BITMAPINFO*) ::operator new(sizeof(BITMAPINFOHEADER) +
                                                  aColorTableSize,
-                                                 mozilla::fallible_t());
+                                                 mozilla::fallible);
   if (bmi) {
     memcpy(bmi, aHeader, sizeof(BITMAPINFOHEADER));
     memset(bmi->bmiColors, 0, aColorTableSize);
   }
   return bmi;
 }
 
 nsresult
--- a/image/encoders/bmp/nsBMPEncoder.cpp
+++ b/image/encoders/bmp/nsBMPEncoder.cpp
@@ -180,17 +180,16 @@ nsBMPEncoder::AddImageFrame(const uint8_
 
   // validate input format
   if (aInputFormat != INPUT_FORMAT_RGB &&
       aInputFormat != INPUT_FORMAT_RGBA &&
       aInputFormat != INPUT_FORMAT_HOSTARGB) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  static fallible_t fallible = fallible_t();
   nsAutoArrayPtr<uint8_t> row(new (fallible)
                               uint8_t[mBMPInfoHeader.width *
                               BytesPerPixel(mBMPInfoHeader.bpp)]);
   if (!row) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   // write each row: if we add more input formats, we may want to
--- a/image/src/SourceBuffer.h
+++ b/image/src/SourceBuffer.h
@@ -267,17 +267,16 @@ private:
   class Chunk
   {
   public:
     explicit Chunk(size_t aCapacity)
       : mCapacity(aCapacity)
       , mLength(0)
     {
       MOZ_ASSERT(aCapacity > 0, "Creating zero-capacity chunk");
-      static const fallible_t fallible = fallible_t();
       mData = new (fallible) char[mCapacity];
     }
 
     ~Chunk() { delete[] mData; }
 
     Chunk(Chunk&& aOther)
       : mCapacity(aOther.mCapacity)
       , mLength(aOther.mLength)
--- a/intl/uconv/nsScriptableUConv.cpp
+++ b/intl/uconv/nsScriptableUConv.cpp
@@ -60,17 +60,17 @@ NS_IMETHODIMP
 nsScriptableUnicodeConverter::ConvertFromUnicode(const nsAString& aSrc,
                                                  nsACString& _retval)
 {
   int32_t len;
   char* str;
   nsresult rv = ConvertFromUnicodeWithLength(aSrc, &len, &str);
   if (NS_SUCCEEDED(rv)) {
     // No Adopt on nsACString :(
-    if (!_retval.Assign(str, len, mozilla::fallible_t())) {
+    if (!_retval.Assign(str, len, mozilla::fallible)) {
       rv = NS_ERROR_OUT_OF_MEMORY;
     }
     moz_free(str);
   }
   return rv;
 }
 
 nsresult
@@ -109,17 +109,17 @@ nsScriptableUnicodeConverter::Finish(nsA
     _retval.Truncate();
     return NS_OK;
   }
   int32_t len;
   char* str;
   nsresult rv = FinishWithLength(&str, &len);
   if (NS_SUCCEEDED(rv)) {
     // No Adopt on nsACString :(
-    if (!_retval.Assign(str, len, mozilla::fallible_t())) {
+    if (!_retval.Assign(str, len, mozilla::fallible)) {
       rv = NS_ERROR_OUT_OF_MEMORY;
     }
     moz_free(str);
   }
   return rv;
 }
 
 /* AString ConvertToUnicode (in ACString src); */
@@ -155,17 +155,17 @@ nsScriptableUnicodeConverter::ConvertFro
     if (!buf)
       return NS_ERROR_OUT_OF_MEMORY;
 
     rv = mDecoder->Convert(reinterpret_cast<const char*>(aData),
                            &inLength, buf, &outLength);
     if (NS_SUCCEEDED(rv))
     {
       buf[outLength] = 0;
-      if (!_retval.Assign(buf, outLength, mozilla::fallible_t())) {
+      if (!_retval.Assign(buf, outLength, mozilla::fallible)) {
         rv = NS_ERROR_OUT_OF_MEMORY;
       }
     }
     moz_free(buf);
     return rv;
   }
   return NS_ERROR_FAILURE;
 
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -358,16 +358,21 @@ ICStub::trace(JSTracer *trc)
           case 5: propStub->toImpl<5>()->traceShapes(trc); break;
           case 6: propStub->toImpl<6>()->traceShapes(trc); break;
           case 7: propStub->toImpl<7>()->traceShapes(trc); break;
           case 8: propStub->toImpl<8>()->traceShapes(trc); break;
           default: MOZ_CRASH("Invalid proto stub.");
         }
         break;
       }
+      case ICStub::GetProp_Unboxed: {
+        ICGetProp_Unboxed *propStub = toGetProp_Unboxed();
+        MarkTypeObject(trc, &propStub->type(), "baseline-getprop-unboxed-stub-type");
+        break;
+      }
       case ICStub::GetProp_TypedObject: {
         ICGetProp_TypedObject *propStub = toGetProp_TypedObject();
         MarkShape(trc, &propStub->shape(), "baseline-getprop-typedobject-stub-shape");
         break;
       }
       case ICStub::GetProp_CallDOMProxyNative:
       case ICStub::GetProp_CallDOMProxyWithGenerationNative: {
         ICGetPropCallDOMProxyNativeStub *propStub;
@@ -432,16 +437,21 @@ ICStub::trace(JSTracer *trc)
           case 1: propStub->toImpl<1>()->traceShapes(trc); break;
           case 2: propStub->toImpl<2>()->traceShapes(trc); break;
           case 3: propStub->toImpl<3>()->traceShapes(trc); break;
           case 4: propStub->toImpl<4>()->traceShapes(trc); break;
           default: MOZ_CRASH("Invalid proto stub.");
         }
         break;
       }
+      case ICStub::SetProp_Unboxed: {
+        ICSetProp_Unboxed *propStub = toSetProp_Unboxed();
+        MarkTypeObject(trc, &propStub->type(), "baseline-setprop-unboxed-stub-type");
+        break;
+      }
       case ICStub::SetProp_TypedObject: {
         ICSetProp_TypedObject *propStub = toSetProp_TypedObject();
         MarkShape(trc, &propStub->shape(), "baseline-setprop-typedobject-stub-shape");
         MarkTypeObject(trc, &propStub->type(), "baseline-setprop-typedobject-stub-type");
         break;
       }
       case ICStub::SetProp_CallScripted: {
         ICSetProp_CallScripted *callStub = toSetProp_CallScripted();
@@ -1405,18 +1415,19 @@ DoTypeUpdateFallback(JSContext *cx, Base
       case ICStub::SetElem_Dense:
       case ICStub::SetElem_DenseAdd: {
         MOZ_ASSERT(obj->isNative());
         id = JSID_VOID;
         types::AddTypePropertyId(cx, obj, id, value);
         break;
       }
       case ICStub::SetProp_Native:
-      case ICStub::SetProp_NativeAdd: {
-        MOZ_ASSERT(obj->isNative());
+      case ICStub::SetProp_NativeAdd:
+      case ICStub::SetProp_Unboxed: {
+        MOZ_ASSERT(obj->isNative() || obj->is<UnboxedPlainObject>());
         jsbytecode *pc = stub->getChainFallback()->icEntry()->pc(script);
         if (*pc == JSOP_SETALIASEDVAR || *pc == JSOP_INITALIASEDLEXICAL)
             id = NameToId(ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, pc));
         else
             id = NameToId(script->getName(pc));
         types::AddTypePropertyId(cx, obj, id, value);
         break;
       }
@@ -6594,16 +6605,50 @@ TryAttachNativeGetPropStub(JSContext *cx
     if (!newStub)
         return false;
     stub->addNewStub(newStub);
     *attached = true;
     return true;
 }
 
 static bool
+TryAttachUnboxedGetPropStub(JSContext *cx, HandleScript script,
+                            ICGetProp_Fallback *stub, HandlePropertyName name, HandleValue val,
+                            bool *attached)
+{
+    MOZ_ASSERT(!*attached);
+
+    if (!cx->runtime()->jitSupportsFloatingPoint)
+        return true;
+
+    if (!val.isObject() || !val.toObject().is<UnboxedPlainObject>())
+        return true;
+    Rooted<UnboxedPlainObject *> obj(cx, &val.toObject().as<UnboxedPlainObject>());
+
+    const UnboxedLayout::Property *property = obj->layout().lookup(name);
+    if (!property)
+        return true;
+
+    ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
+
+    ICGetProp_Unboxed::Compiler compiler(cx, monitorStub, obj->type(),
+                                         property->offset + UnboxedPlainObject::offsetOfData(),
+                                         property->type);
+    ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
+    if (!newStub)
+        return false;
+    stub->addNewStub(newStub);
+
+    StripPreliminaryObjectStubs(cx, stub);
+
+    *attached = true;
+    return true;
+}
+
+static bool
 TryAttachTypedObjectGetPropStub(JSContext *cx, HandleScript script,
                                 ICGetProp_Fallback *stub, HandlePropertyName name, HandleValue val,
                                 bool *attached)
 {
     MOZ_ASSERT(!*attached);
 
     if (!cx->runtime()->jitSupportsFloatingPoint)
         return true;
@@ -6840,16 +6885,21 @@ DoGetPropFallback(JSContext *cx, Baselin
     RootedScript script(cx, frame->script());
 
     if (!TryAttachNativeGetPropStub(cx, script, pc, stub, name, val, oldShape,
                                     res, &attached, &isTemporarilyUnoptimizable))
         return false;
     if (attached)
         return true;
 
+    if (!TryAttachUnboxedGetPropStub(cx, script, stub, name, val, &attached))
+        return false;
+    if (attached)
+        return true;
+
     if (!TryAttachTypedObjectGetPropStub(cx, script, stub, name, val, &attached))
         return false;
     if (attached)
         return true;
 
     if (val.isString() || val.isNumber() || val.isBoolean()) {
         if (!TryAttachPrimitiveGetPropStub(cx, script, pc, stub, name, val, res, &attached))
             return false;
@@ -7751,16 +7801,49 @@ ICGetProp_Generic::Compiler::generateStu
 
     leaveStubFrame(masm);
     EmitUnstowICValues(masm, 1, /* discard = */ true);
     EmitEnterTypeMonitorIC(masm);
     return true;
 }
 
 bool
+ICGetProp_Unboxed::Compiler::generateStubCode(MacroAssembler &masm)
+{
+    Label failure;
+
+    GeneralRegisterSet regs(availableGeneralRegs(1));
+
+    Register scratch = regs.takeAnyExcluding(BaselineTailCallReg);
+
+    // Object and type guard.
+    masm.branchTestObject(Assembler::NotEqual, R0, &failure);
+    Register object = masm.extractObject(R0, ExtractTemp0);
+    masm.loadPtr(Address(BaselineStubReg, ICGetProp_Unboxed::offsetOfType()), scratch);
+    masm.branchPtr(Assembler::NotEqual, Address(object, JSObject::offsetOfType()), scratch,
+                   &failure);
+
+    // Get the address being read from.
+    masm.load32(Address(BaselineStubReg, ICGetProp_Unboxed::offsetOfFieldOffset()), scratch);
+
+    masm.loadUnboxedProperty(BaseIndex(object, scratch, TimesOne), fieldType_, TypedOrValueRegister(R0));
+
+    // Only monitor the result if its type might change.
+    if (fieldType_ == JSVAL_TYPE_OBJECT)
+        EmitEnterTypeMonitorIC(masm);
+    else
+        EmitReturnFromIC(masm);
+
+    masm.bind(&failure);
+    EmitStubGuardFailure(masm);
+
+    return true;
+}
+
+bool
 ICGetProp_TypedObject::Compiler::generateStubCode(MacroAssembler &masm)
 {
     Label failure;
 
     CheckForNeuteredTypedObject(cx, masm, &failure);
 
     GeneralRegisterSet regs(availableGeneralRegs(1));
 
@@ -8005,16 +8088,50 @@ TryAttachSetAccessorPropStub(JSContext *
         *attached = true;
         return true;
     }
 
     return true;
 }
 
 static bool
+TryAttachUnboxedSetPropStub(JSContext *cx, HandleScript script,
+                            ICSetProp_Fallback *stub, HandleId id,
+                            HandleObject obj, HandleValue rhs, bool *attached)
+{
+    MOZ_ASSERT(!*attached);
+
+    if (!cx->runtime()->jitSupportsFloatingPoint)
+        return true;
+
+    if (!obj->is<UnboxedPlainObject>())
+        return true;
+
+    const UnboxedLayout::Property *property = obj->as<UnboxedPlainObject>().layout().lookup(id);
+    if (!property)
+        return true;
+
+    ICSetProp_Unboxed::Compiler compiler(cx, obj->type(),
+                                         property->offset + UnboxedPlainObject::offsetOfData(),
+                                         property->type);
+    ICUpdatedStub *newStub = compiler.getStub(compiler.getStubSpace(script));
+    if (!newStub)
+        return false;
+    if (compiler.needsUpdateStubs() && !newStub->addUpdateStubForValue(cx, script, obj, id, rhs))
+        return false;
+
+    stub->addNewStub(newStub);
+
+    StripPreliminaryObjectStubs(cx, stub);
+
+    *attached = true;
+    return true;
+}
+
+static bool
 TryAttachTypedObjectSetPropStub(JSContext *cx, HandleScript script,
                                 ICSetProp_Fallback *stub, HandleId id,
                                 HandleObject obj, HandleValue rhs, bool *attached)
 {
     MOZ_ASSERT(!*attached);
 
     if (!cx->runtime()->jitSupportsFloatingPoint)
         return true;
@@ -8149,16 +8266,25 @@ DoSetPropFallback(JSContext *cx, Baselin
     {
         return false;
     }
     if (attached)
         return true;
 
     if (!attached &&
         lhs.isObject() &&
+        !TryAttachUnboxedSetPropStub(cx, script, stub, id, obj, rhs, &attached))
+    {
+        return false;
+    }
+    if (attached)
+        return true;
+
+    if (!attached &&
+        lhs.isObject() &&
         !TryAttachTypedObjectSetPropStub(cx, script, stub, id, obj, rhs, &attached))
     {
         return false;
     }
     if (attached)
         return true;
 
     MOZ_ASSERT(!attached);
@@ -8432,16 +8558,85 @@ ICSetPropNativeAddCompiler::generateStub
     EmitUnstowICValues(masm, 2);
 
     masm.bind(&failure);
     EmitStubGuardFailure(masm);
     return true;
 }
 
 bool
+ICSetProp_Unboxed::Compiler::generateStubCode(MacroAssembler &masm)
+{
+    Label failure;
+
+    // Guard input is an object.
+    masm.branchTestObject(Assembler::NotEqual, R0, &failure);
+
+    GeneralRegisterSet regs(availableGeneralRegs(2));
+    Register scratch = regs.takeAny();
+
+    // Unbox and type guard.
+    Register object = masm.extractObject(R0, ExtractTemp0);
+    masm.loadPtr(Address(BaselineStubReg, ICSetProp_Unboxed::offsetOfType()), scratch);
+    masm.branchPtr(Assembler::NotEqual, Address(object, JSObject::offsetOfType()), scratch,
+                   &failure);
+
+    if (needsUpdateStubs()) {
+        // Stow both R0 and R1 (object and value).
+        masm.push(object);
+        masm.push(BaselineStubReg);
+        EmitStowICValues(masm, 2);
+
+        // Move RHS into R0 for TypeUpdate check.
+        masm.moveValue(R1, R0);
+
+        // Call the type update stub.
+        if (!callTypeUpdateIC(masm, sizeof(Value)))
+            return false;
+
+        // Unstow R0 and R1 (object and key)
+        EmitUnstowICValues(masm, 2);
+        masm.pop(BaselineStubReg);
+        masm.pop(object);
+
+        // Trigger post barriers here on the values being written. Fields which
+        // objects can be written to also need update stubs.
+        GeneralRegisterSet saveRegs;
+        saveRegs.add(R0);
+        saveRegs.add(R1);
+        saveRegs.addUnchecked(object);
+        saveRegs.add(BaselineStubReg);
+        emitPostWriteBarrierSlot(masm, object, R1, scratch, saveRegs);
+    }
+
+    // Compute the address being written to.
+    masm.load32(Address(BaselineStubReg, ICSetProp_Unboxed::offsetOfFieldOffset()), scratch);
+    BaseIndex address(object, scratch, TimesOne);
+
+    if (fieldType_ == JSVAL_TYPE_OBJECT)
+        EmitPreBarrier(masm, address, MIRType_Object);
+    else if (fieldType_ == JSVAL_TYPE_STRING)
+        EmitPreBarrier(masm, address, MIRType_String);
+    else
+        MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(fieldType_));
+
+    masm.storeUnboxedProperty(address, fieldType_,
+                              ConstantOrRegister(TypedOrValueRegister(R1)), &failure);
+
+    // The RHS has to be in R0.
+    masm.moveValue(R1, R0);
+
+    EmitReturnFromIC(masm);
+
+    masm.bind(&failure);
+    EmitStubGuardFailure(masm);
+    return true;
+}
+
+bool
 ICSetProp_TypedObject::Compiler::generateStubCode(MacroAssembler &masm)
 {
     Label failure;
 
     CheckForNeuteredTypedObject(cx, masm, &failure);
 
     // Guard input is an object.
     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
@@ -9061,37 +9256,36 @@ TryAttachCallStub(JSContext *cx, ICCall_
 
         // Keep track of the function's |prototype| property in type
         // information, for use during Ion compilation.
         if (IsIonEnabled(cx))
             types::EnsureTrackPropertyTypes(cx, fun, NameToId(cx->names().prototype));
 
         // Remember the template object associated with any script being called
         // as a constructor, for later use during Ion compilation.
-        RootedPlainObject templateObject(cx);
+        RootedObject templateObject(cx);
         if (constructing) {
             JSObject *thisObject = CreateThisForFunction(cx, fun, MaybeSingletonObject);
             if (!thisObject)
                 return false;
 
-            if (thisObject->is<PlainObject>()) {
-                templateObject = &thisObject->as<PlainObject>();
+            if (thisObject->is<PlainObject>() || thisObject->is<UnboxedPlainObject>()) {
+                templateObject = thisObject;
 
                 // If we are calling a constructor for which the new script
                 // properties analysis has not been performed yet, don't attach a
                 // stub. After the analysis is performed, CreateThisForFunction may
                 // start returning objects with a different type, and the Ion
                 // compiler might get confused.
-                if (templateObject->type()->newScript() &&
-                    !templateObject->type()->newScript()->analyzed())
-                {
+                types::TypeNewScript *newScript = templateObject->type()->newScript();
+                if (newScript && !newScript->analyzed()) {
                     // Clear the object just created from the preliminary objects
                     // on the TypeNewScript, as it will not be used or filled in by
                     // running code.
-                    templateObject->type()->newScript()->unregisterNewObject(templateObject);
+                    newScript->unregisterNewObject(&templateObject->as<PlainObject>());
                     return true;
                 }
             }
         }
 
         JitSpew(JitSpew_BaselineIC,
                 "  Generating Call_Scripted stub (fun=%p, %s:%d, cons=%s, spread=%s)",
                 fun.get(), fun->nonLazyScript()->filename(), fun->nonLazyScript()->lineno(),
@@ -11708,30 +11902,30 @@ ICSetProp_CallNative::Clone(JSContext *c
     RootedShape shape(cx, other.shape_);
     RootedObject holder(cx, other.holder_);
     RootedShape holderShape(cx, other.holderShape_);
     RootedFunction setter(cx, other.setter_);
     return New(space, other.jitCode(), shape, holder, holderShape, setter, other.pcOffset_);
 }
 
 ICCall_Scripted::ICCall_Scripted(JitCode *stubCode, ICStub *firstMonitorStub,
-                                 HandleScript calleeScript, HandleNativeObject templateObject,
+                                 HandleScript calleeScript, HandleObject templateObject,
                                  uint32_t pcOffset)
   : ICMonitoredStub(ICStub::Call_Scripted, stubCode, firstMonitorStub),
     calleeScript_(calleeScript),
     templateObject_(templateObject),
     pcOffset_(pcOffset)
 { }
 
 /* static */ ICCall_Scripted *
 ICCall_Scripted::Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
                        ICCall_Scripted &other)
 {
     RootedScript calleeScript(cx, other.calleeScript_);
-    RootedNativeObject templateObject(cx, other.templateObject_);
+    RootedObject templateObject(cx, other.templateObject_);
     return New(space, other.jitCode(), firstMonitorStub, calleeScript, templateObject,
                other.pcOffset_);
 }
 
 /* static */ ICCall_AnyScripted *
 ICCall_AnyScripted::Clone(JSContext *, ICStubSpace *space, ICStub *firstMonitorStub,
                           ICCall_AnyScripted &other)
 {
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -425,30 +425,32 @@ class ICEntry
                                 \
     _(GetProp_Fallback)         \
     _(GetProp_ArrayLength)      \
     _(GetProp_Primitive)        \
     _(GetProp_StringLength)     \
     _(GetProp_Native)           \
     _(GetProp_NativeDoesNotExist) \
     _(GetProp_NativePrototype)  \
+    _(GetProp_Unboxed)          \
     _(GetProp_TypedObject)      \
     _(GetProp_CallScripted)     \
     _(GetProp_CallNative)       \
     _(GetProp_CallNativePrototype)\
     _(GetProp_CallDOMProxyNative)\
     _(GetProp_CallDOMProxyWithGenerationNative)\
     _(GetProp_DOMProxyShadowed) \
     _(GetProp_ArgumentsLength)  \
     _(GetProp_ArgumentsCallee)  \
     _(GetProp_Generic)          \
                                 \
     _(SetProp_Fallback)         \
     _(SetProp_Native)           \
     _(SetProp_NativeAdd)        \
+    _(SetProp_Unboxed)          \
     _(SetProp_TypedObject)      \
     _(SetProp_CallScripted)     \
     _(SetProp_CallNative)       \
                                 \
     _(TableSwitch)              \
                                 \
     _(IteratorNew_Fallback)     \
     _(IteratorMore_Fallback)    \
@@ -4518,16 +4520,82 @@ class ICGetPropNativeDoesNotExistCompile
     ICStub *getStubSpecific(ICStubSpace *space, const AutoShapeVector *shapes) {
         return ICGetProp_NativeDoesNotExistImpl<ProtoChainDepth>::New(space, getStubCode(),
                                                                       firstMonitorStub_, shapes);
     }
 
     ICStub *getStub(ICStubSpace *space);
 };
 
+class ICGetProp_Unboxed : public ICMonitoredStub
+{
+    friend class ICStubSpace;
+
+    HeapPtrTypeObject type_;
+    uint32_t fieldOffset_;
+
+    ICGetProp_Unboxed(JitCode *stubCode, ICStub *firstMonitorStub, HandleTypeObject type,
+                      uint32_t fieldOffset)
+      : ICMonitoredStub(ICStub::GetProp_Unboxed, stubCode, firstMonitorStub),
+        type_(type), fieldOffset_(fieldOffset)
+    {
+        (void) fieldOffset_; // Silence clang warning
+    }
+
+  public:
+    static inline ICGetProp_Unboxed *New(ICStubSpace *space, JitCode *code,
+                                         ICStub *firstMonitorStub, HandleTypeObject shape,
+                                         uint32_t fieldOffset)
+    {
+        if (!code)
+            return nullptr;
+        return space->allocate<ICGetProp_Unboxed>(code, firstMonitorStub, shape, fieldOffset);
+    }
+
+    HeapPtrTypeObject &type() {
+        return type_;
+    }
+
+    static size_t offsetOfType() {
+        return offsetof(ICGetProp_Unboxed, type_);
+    }
+    static size_t offsetOfFieldOffset() {
+        return offsetof(ICGetProp_Unboxed, fieldOffset_);
+    }
+
+    class Compiler : public ICStubCompiler {
+      protected:
+        ICStub *firstMonitorStub_;
+        RootedTypeObject type_;
+        uint32_t fieldOffset_;
+        JSValueType fieldType_;
+
+        bool generateStubCode(MacroAssembler &masm);
+
+        virtual int32_t getKey() const {
+            return static_cast<int32_t>(kind) | (static_cast<int32_t>(fieldType_)) << 16;
+        }
+
+      public:
+        Compiler(JSContext *cx, ICStub *firstMonitorStub,
+                 types::TypeObject *type, uint32_t fieldOffset, JSValueType fieldType)
+          : ICStubCompiler(cx, ICStub::GetProp_Unboxed),
+            firstMonitorStub_(firstMonitorStub),
+            type_(cx, type),
+            fieldOffset_(fieldOffset),
+            fieldType_(fieldType)
+        {}
+
+        ICStub *getStub(ICStubSpace *space) {
+            return ICGetProp_Unboxed::New(space, getStubCode(), firstMonitorStub_,
+                                          type_, fieldOffset_);
+        }
+    };
+};
+
 static uint32_t
 SimpleTypeDescrKey(SimpleTypeDescr *descr)
 {
     if (descr->is<ScalarTypeDescr>())
         return uint32_t(descr->as<ScalarTypeDescr>().type()) << 1;
     return (uint32_t(descr->as<ReferenceTypeDescr>().type()) << 1) | 1;
 }
 
@@ -5414,16 +5482,87 @@ class ICSetPropNativeAddCompiler : publi
 
         return ICSetProp_NativeAddImpl<ProtoChainDepth>::New(
                     space, getStubCode(), oldType_, shapes, newShape, newType, offset_);
     }
 
     ICUpdatedStub *getStub(ICStubSpace *space);
 };
 
+class ICSetProp_Unboxed : public ICUpdatedStub
+{
+    friend class ICStubSpace;
+
+    HeapPtrTypeObject type_;
+    uint32_t fieldOffset_;
+
+    ICSetProp_Unboxed(JitCode *stubCode, HandleTypeObject type, uint32_t fieldOffset)
+      : ICUpdatedStub(ICStub::SetProp_Unboxed, stubCode),
+        type_(type),
+        fieldOffset_(fieldOffset)
+    {
+        (void) fieldOffset_; // Silence clang warning
+    }
+
+  public:
+    static inline ICSetProp_Unboxed *New(ICStubSpace *space, JitCode *code,
+                                         HandleTypeObject type, uint32_t fieldOffset)
+    {
+        if (!code)
+            return nullptr;
+        return space->allocate<ICSetProp_Unboxed>(code, type, fieldOffset);
+    }
+
+    HeapPtrTypeObject &type() {
+        return type_;
+    }
+
+    static size_t offsetOfType() {
+        return offsetof(ICSetProp_Unboxed, type_);
+    }
+    static size_t offsetOfFieldOffset() {
+        return offsetof(ICSetProp_Unboxed, fieldOffset_);
+    }
+
+    class Compiler : public ICStubCompiler {
+      protected:
+        RootedTypeObject type_;
+        uint32_t fieldOffset_;
+        JSValueType fieldType_;
+
+        bool generateStubCode(MacroAssembler &masm);
+
+        virtual int32_t getKey() const {
+            return static_cast<int32_t>(kind) |
+                   (static_cast<int32_t>(fieldType_) << 16);
+        }
+
+      public:
+        Compiler(JSContext *cx, types::TypeObject *type, uint32_t fieldOffset,
+                 JSValueType fieldType)
+          : ICStubCompiler(cx, ICStub::SetProp_Unboxed),
+            type_(cx, type),
+            fieldOffset_(fieldOffset),
+            fieldType_(fieldType)
+        {}
+
+        ICUpdatedStub *getStub(ICStubSpace *space) {
+            ICUpdatedStub *stub = ICSetProp_Unboxed::New(space, getStubCode(),
+                                                         type_, fieldOffset_);
+            if (!stub || !stub->initUpdatingChain(cx, space))
+                return nullptr;
+            return stub;
+        }
+
+        bool needsUpdateStubs() {
+            return fieldType_ == JSVAL_TYPE_OBJECT;
+        }
+    };
+};
+
 class ICSetProp_TypedObject : public ICUpdatedStub
 {
     friend class ICStubSpace;
 
     HeapPtrShape shape_;
     HeapPtrTypeObject type_;
     uint32_t fieldOffset_;
     bool isObjectReference_;
@@ -5794,42 +5933,42 @@ class ICCall_Scripted : public ICMonitor
   public:
     // The maximum number of inlineable spread call arguments. Keep this small
     // to avoid controllable stack overflows by attackers passing large arrays
     // to spread call. This value is shared with ICCall_Native.
     static const uint32_t MAX_ARGS_SPREAD_LENGTH = 16;
 
   protected:
     HeapPtrScript calleeScript_;
-    HeapPtrNativeObject templateObject_;
+    HeapPtrObject templateObject_;
     uint32_t pcOffset_;
 
     ICCall_Scripted(JitCode *stubCode, ICStub *firstMonitorStub,
-                    HandleScript calleeScript, HandleNativeObject templateObject,
+                    HandleScript calleeScript, HandleObject templateObject,
                     uint32_t pcOffset);
 
   public:
     static inline ICCall_Scripted *New(
             ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub,
-            HandleScript calleeScript, HandleNativeObject templateObject,
+            HandleScript calleeScript, HandleObject templateObject,
             uint32_t pcOffset)
     {
         if (!code)
             return nullptr;
         return space->allocate<ICCall_Scripted>(code, firstMonitorStub,
                                                 calleeScript, templateObject, pcOffset);
     }
 
     static ICCall_Scripted *Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
                                   ICCall_Scripted &other);
 
     HeapPtrScript &calleeScript() {
         return calleeScript_;
     }
-    HeapPtrNativeObject &templateObject() {
+    HeapPtrObject &templateObject() {
         return templateObject_;
     }
 
     static size_t offsetOfCalleeScript() {
         return offsetof(ICCall_Scripted, calleeScript_);
     }
     static size_t offsetOfPCOffset() {
         return offsetof(ICCall_Scripted, pcOffset_);
@@ -5867,28 +6006,28 @@ class ICCall_AnyScripted : public ICMoni
 
 // Compiler for Call_Scripted and Call_AnyScripted stubs.
 class ICCallScriptedCompiler : public ICCallStubCompiler {
   protected:
     ICStub *firstMonitorStub_;
     bool isConstructing_;
     bool isSpread_;
     RootedScript calleeScript_;
-    RootedNativeObject templateObject_;
+    RootedObject templateObject_;
     uint32_t pcOffset_;
     bool generateStubCode(MacroAssembler &masm);
 
     virtual int32_t getKey() const {
         return static_cast<int32_t>(kind) | (static_cast<int32_t>(isConstructing_) << 16) |
                (static_cast<int32_t>(isSpread_) << 17);
     }
 
   public:
     ICCallScriptedCompiler(JSContext *cx, ICStub *firstMonitorStub,
-                           HandleScript calleeScript, HandleNativeObject templateObject,
+                           HandleScript calleeScript, HandleObject templateObject,
                            bool isConstructing, bool isSpread, uint32_t pcOffset)
       : ICCallStubCompiler(cx, ICStub::Call_Scripted),
         firstMonitorStub_(firstMonitorStub),
         isConstructing_(isConstructing),
         isSpread_(isSpread),
         calleeScript_(cx, calleeScript),
         templateObject_(cx, templateObject),
         pcOffset_(pcOffset)
--- a/js/src/jit/BaselineInspector.cpp
+++ b/js/src/jit/BaselineInspector.cpp
@@ -75,68 +75,94 @@ SetElemICInspector::sawTypedArrayWrite()
     for (ICStub *stub = icEntry_->firstStub(); stub; stub = stub->next()) {
         if (stub->isSetElem_TypedArray())
             return true;
     }
     return false;
 }
 
 bool
-BaselineInspector::maybeShapesForPropertyOp(jsbytecode *pc, ShapeVector &shapes)
+BaselineInspector::maybeInfoForPropertyOp(jsbytecode *pc,
+                                          ShapeVector &nativeShapes,
+                                          TypeObjectVector &unboxedTypes)
 {
-    // Return a list of shapes seen by the baseline IC for the current op.
-    // An empty list indicates no shapes are known, or there was an uncacheable
-    // access.
-    MOZ_ASSERT(shapes.empty());
+    // Return lists of native shapes and unboxed objects seen by the baseline
+    // IC for the current op. Empty lists indicate no shapes/types are known,
+    // or there was an uncacheable access.
+    MOZ_ASSERT(nativeShapes.empty());
+    MOZ_ASSERT(unboxedTypes.empty());
 
     if (!hasBaselineScript())
         return true;
 
     MOZ_ASSERT(isValidPC(pc));
     const ICEntry &entry = icEntryFromPC(pc);
 
     ICStub *stub = entry.firstStub();
     while (stub->next()) {
-        Shape *shape;
+        Shape *shape = nullptr;
+        types::TypeObject *type = nullptr;
         if (stub->isGetProp_Native()) {
             shape = stub->toGetProp_Native()->shape();
         } else if (stub->isSetProp_Native()) {
             shape = stub->toSetProp_Native()->shape();
+        } else if (stub->isGetProp_Unboxed()) {
+            type = stub->toGetProp_Unboxed()->type();
+        } else if (stub->isSetProp_Unboxed()) {
+            type = stub->toSetProp_Unboxed()->type();
         } else {
-            shapes.clear();
+            nativeShapes.clear();
+            unboxedTypes.clear();
             return true;
         }
 
-        // Don't add the same shape twice (this can happen if there are multiple
-        // SetProp_Native stubs with different TypeObject's).
-        bool found = false;
-        for (size_t i = 0; i < shapes.length(); i++) {
-            if (shapes[i] == shape) {
-                found = true;
-                break;
+        // Don't add the same shape/type twice (this can happen if there are
+        // multiple SetProp_Native stubs with different TypeObject's).
+        if (shape) {
+            bool found = false;
+            for (size_t i = 0; i < nativeShapes.length(); i++) {
+                if (nativeShapes[i] == shape) {
+                    found = true;
+                    break;
+                }
             }
+            if (!found && !nativeShapes.append(shape))
+                return false;
+        } else {
+            bool found = false;
+            for (size_t i = 0; i < unboxedTypes.length(); i++) {
+                if (unboxedTypes[i] == type) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found && !unboxedTypes.append(type))
+                return false;
         }
 
-        if (!found && !shapes.append(shape))
-            return false;
-
         stub = stub->next();
     }
 
     if (stub->isGetProp_Fallback()) {
-        if (stub->toGetProp_Fallback()->hadUnoptimizableAccess())
-            shapes.clear();
+        if (stub->toGetProp_Fallback()->hadUnoptimizableAccess()) {
+            nativeShapes.clear();
+            unboxedTypes.clear();
+        }
     } else {
-        if (stub->toSetProp_Fallback()->hadUnoptimizableAccess())
-            shapes.clear();
+        if (stub->toSetProp_Fallback()->hadUnoptimizableAccess()) {
+            nativeShapes.clear();
+            unboxedTypes.clear();
+        }
     }
 
-    // Don't inline if there are more than 5 shapes.
-    if (shapes.length() > 5)
-        shapes.clear();
+    // Don't inline if there are more than 5 shapes/types.
+    if (nativeShapes.length() + unboxedTypes.length() > 5) {
+        nativeShapes.clear();
+        unboxedTypes.clear();
+    }
 
     return true;
 }
 
 ICStub *
 BaselineInspector::monomorphicStub(jsbytecode *pc)
 {
     if (!hasBaselineScript())
@@ -408,33 +434,33 @@ BaselineInspector::hasSeenDoubleResult(j
     if (stub->isUnaryArith_Fallback())
         return stub->toUnaryArith_Fallback()->sawDoubleResult();
     else
         return stub->toBinaryArith_Fallback()->sawDoubleResult();
 
     return false;
 }
 
-NativeObject *
+JSObject *
 BaselineInspector::getTemplateObject(jsbytecode *pc)
 {
     if (!hasBaselineScript())
         return nullptr;
 
     const ICEntry &entry = icEntryFromPC(pc);
     for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
         switch (stub->kind()) {
           case ICStub::NewArray_Fallback:
             return stub->toNewArray_Fallback()->templateObject();
           case ICStub::NewObject_Fallback:
             return stub->toNewObject_Fallback()->templateObject();
           case ICStub::Rest_Fallback:
             return stub->toRest_Fallback()->templateObject();
           case ICStub::Call_Scripted:
-            if (NativeObject *obj = stub->toCall_Scripted()->templateObject())
+            if (JSObject *obj = stub->toCall_Scripted()->templateObject())
                 return obj;
             break;
           default:
             break;
         }
     }
 
     return nullptr;
--- a/js/src/jit/BaselineInspector.h
+++ b/js/src/jit/BaselineInspector.h
@@ -88,33 +88,34 @@ class BaselineInspector
         return ICInspectorType(this, pc, ent);
     }
 
     ICStub *monomorphicStub(jsbytecode *pc);
     bool dimorphicStub(jsbytecode *pc, ICStub **pfirst, ICStub **psecond);
 
   public:
     typedef Vector<Shape *, 4, JitAllocPolicy> ShapeVector;
-    bool maybeShapesForPropertyOp(jsbytecode *pc, ShapeVector &shapes);
+    typedef Vector<types::TypeObject *, 4, JitAllocPolicy> TypeObjectVector;
+    bool maybeInfoForPropertyOp(jsbytecode *pc, ShapeVector &nativeShapes, TypeObjectVector &unboxedTypes);
 
     SetElemICInspector setElemICInspector(jsbytecode *pc) {
         return makeICInspector<SetElemICInspector>(pc, ICStub::SetElem_Fallback);
     }
 
     MIRType expectedResultType(jsbytecode *pc);
     MCompare::CompareType expectedCompareType(jsbytecode *pc);
     MIRType expectedBinaryArithSpecialization(jsbytecode *pc);
 
     bool hasSeenNonNativeGetElement(jsbytecode *pc);
     bool hasSeenNegativeIndexGetElement(jsbytecode *pc);
     bool hasSeenAccessedGetter(jsbytecode *pc);
     bool hasSeenDoubleResult(jsbytecode *pc);
     bool hasSeenNonStringIterMore(jsbytecode *pc);
 
-    NativeObject *getTemplateObject(jsbytecode *pc);
+    JSObject *getTemplateObject(jsbytecode *pc);
     JSObject *getTemplateObjectForNative(jsbytecode *pc, Native native);
     JSObject *getTemplateObjectForClassHook(jsbytecode *pc, const Class *clasp);
 
     DeclEnvObject *templateDeclEnvObject();
     CallObject *templateCallObject();
 
     JSObject *commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonGetter,
                                     Shape **globalShape);
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -2228,43 +2228,72 @@ CodeGenerator::visitStoreSlotV(LStoreSlo
     masm.storeValue(value, Address(base, offset));
 }
 
 void
 CodeGenerator::emitGetPropertyPolymorphic(LInstruction *ins, Register obj, Register scratch,
                                           const TypedOrValueRegister &output)
 {
     MGetPropertyPolymorphic *mir = ins->mirRaw()->toGetPropertyPolymorphic();
-    MOZ_ASSERT(mir->numShapes() > 1);
-
-    masm.loadObjShape(obj, scratch);
+
+    size_t total = mir->numUnboxedTypes() + mir->numShapes();
+    MOZ_ASSERT(total > 1);
+
+    bool typeInScratch = mir->numUnboxedTypes() > 1;
+    bool shapeInScratch = mir->numShapes() > 1;
 
     Label done;
-    for (size_t i = 0; i < mir->numShapes(); i++) {
+
+    for (size_t i = 0; i < total; i++) {
+        bool unboxedType = i < mir->numUnboxedTypes();
+
+        ImmGCPtr comparePtr = unboxedType
+                              ? ImmGCPtr(mir->unboxedType(i))
+                              : ImmGCPtr(mir->objShape(i - mir->numUnboxedTypes()));
+        Address addr(obj, unboxedType ? JSObject::offsetOfType() : JSObject::offsetOfShape());
+
+        if ((i == 0 && typeInScratch) || (i == mir->numUnboxedTypes() && shapeInScratch))
+            masm.loadPtr(addr, scratch);
+
+        bool inScratch = unboxedType ? typeInScratch : shapeInScratch;
+
         Label next;
-        if (i == mir->numShapes() - 1) {
-            bailoutCmpPtr(Assembler::NotEqual, scratch, ImmGCPtr(mir->objShape(i)),
-                          ins->snapshot());
+        if (i == total - 1) {
+            if (inScratch)
+                bailoutCmpPtr(Assembler::NotEqual, scratch, comparePtr, ins->snapshot());
+            else
+                bailoutCmpPtr(Assembler::NotEqual, addr, comparePtr, ins->snapshot());
         } else {
-            masm.branchPtr(Assembler::NotEqual, scratch, ImmGCPtr(mir->objShape(i)), &next);
+            if (inScratch)
+                masm.branchPtr(Assembler::NotEqual, scratch, comparePtr, &next);
+            else
+                masm.branchPtr(Assembler::NotEqual, addr, comparePtr, &next);
         }
 
-        Shape *shape = mir->shape(i);
-        if (shape->slot() < shape->numFixedSlots()) {
-            // Fixed slot.
-            masm.loadTypedOrValue(Address(obj, NativeObject::getFixedSlotOffset(shape->slot())),
-                                  output);
+        if (unboxedType) {
+            const UnboxedLayout::Property *property =
+                mir->unboxedType(i)->unboxedLayout().lookup(mir->name());
+            Address propertyAddr(obj, UnboxedPlainObject::offsetOfData() + property->offset);
+
+            masm.loadUnboxedProperty(propertyAddr, property->type, output);
         } else {
-            // Dynamic slot.
-            uint32_t offset = (shape->slot() - shape->numFixedSlots()) * sizeof(js::Value);
-            masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), scratch);
-            masm.loadTypedOrValue(Address(scratch, offset), output);
+            Shape *shape = mir->shape(i - mir->numUnboxedTypes());
+            if (shape->slot() < shape->numFixedSlots()) {
+                // Fixed slot.
+                masm.loadTypedOrValue(Address(obj, NativeObject::getFixedSlotOffset(shape->slot())),
+                                      output);
+            } else {
+                // Dynamic slot.
+                uint32_t offset = (shape->slot() - shape->numFixedSlots()) * sizeof(js::Value);
+                masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), scratch);
+                masm.loadTypedOrValue(Address(scratch, offset), output);
+            }
         }
 
-        if (i != mir->numShapes() - 1)
+        if (i != total - 1)
             masm.jump(&done);
         masm.bind(&next);
     }
 
     masm.bind(&done);
 }
 
 void
@@ -2286,47 +2315,82 @@ CodeGenerator::visitGetPropertyPolymorph
     emitGetPropertyPolymorphic(ins, obj, temp, output);
 }
 
 void
 CodeGenerator::emitSetPropertyPolymorphic(LInstruction *ins, Register obj, Register scratch,
                                           const ConstantOrRegister &value)
 {
     MSetPropertyPolymorphic *mir = ins->mirRaw()->toSetPropertyPolymorphic();
-    MOZ_ASSERT(mir->numShapes() > 1);
-
-    masm.loadObjShape(obj, scratch);
+
+    size_t total = mir->numUnboxedTypes() + mir->numShapes();
+    MOZ_ASSERT(total > 1);
+
+    bool typeInScratch = mir->numUnboxedTypes() > 1;
+    bool shapeInScratch = mir->numShapes() > 1;
 
     Label done;
-    for (size_t i = 0; i < mir->numShapes(); i++) {
+    for (size_t i = 0; i < total; i++) {
+        bool unboxedType = i < mir->numUnboxedTypes();
+
+        ImmGCPtr comparePtr = unboxedType
+                              ? ImmGCPtr(mir->unboxedType(i))
+                              : ImmGCPtr(mir->objShape(i - mir->numUnboxedTypes()));
+        Address addr(obj, unboxedType ? JSObject::offsetOfType() : JSObject::offsetOfShape());
+
+        if ((i == 0 && typeInScratch) || (i == mir->numUnboxedTypes() && shapeInScratch))
+            masm.loadPtr(addr, scratch);
+
+        bool inScratch = unboxedType ? typeInScratch : shapeInScratch;
+
         Label next;
-        if (i == mir->numShapes() - 1) {
-            bailoutCmpPtr(Assembler::NotEqual, scratch, ImmGCPtr(mir->objShape(i)),
-                          ins->snapshot());
+        if (i == total - 1) {
+            if (inScratch)
+                bailoutCmpPtr(Assembler::NotEqual, scratch, comparePtr, ins->snapshot());
+            else
+                bailoutCmpPtr(Assembler::NotEqual, addr, comparePtr, ins->snapshot());
         } else {
-            masm.branchPtr(Assembler::NotEqual, scratch, ImmGCPtr(mir->objShape(i)), &next);
+            if (inScratch)
+                masm.branchPtr(Assembler::NotEqual, scratch, comparePtr, &next);
+            else
+                masm.branchPtr(Assembler::NotEqual, addr, comparePtr, &next);
         }
 
-        Shape *shape = mir->shape(i);
-        if (shape->slot() < shape->numFixedSlots()) {
-            // Fixed slot.
-            Address addr(obj, NativeObject::getFixedSlotOffset(shape->slot()));
-            if (mir->needsBarrier())
-                emitPreBarrier(addr);
-            masm.storeConstantOrRegister(value, addr);
+        if (unboxedType) {
+            const UnboxedLayout::Property *property =
+                mir->unboxedType(i)->unboxedLayout().lookup(mir->name());
+            Address propertyAddr(obj, UnboxedPlainObject::offsetOfData() + property->offset);
+
+            if (property->type == JSVAL_TYPE_OBJECT)
+                masm.patchableCallPreBarrier(propertyAddr, MIRType_Object);
+            else if (property->type == JSVAL_TYPE_STRING)
+                masm.patchableCallPreBarrier(propertyAddr, MIRType_String);
+            else
+                MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(property->type));
+
+            masm.storeUnboxedProperty(propertyAddr, property->type, value, nullptr);
         } else {
-            // Dynamic slot.
-            masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), scratch);
-            Address addr(scratch, (shape->slot() - shape->numFixedSlots()) * sizeof(js::Value));
-            if (mir->needsBarrier())
-                emitPreBarrier(addr);
-            masm.storeConstantOrRegister(value, addr);
+            Shape *shape = mir->shape(i - mir->numUnboxedTypes());
+            if (shape->slot() < shape->numFixedSlots()) {
+                // Fixed slot.
+                Address addr(obj, NativeObject::getFixedSlotOffset(shape->slot()));
+                if (mir->needsBarrier())
+                    emitPreBarrier(addr);
+                masm.storeConstantOrRegister(value, addr);
+            } else {
+                // Dynamic slot.
+                masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), scratch);
+                Address addr(scratch, (shape->slot() - shape->numFixedSlots()) * sizeof(js::Value));
+                if (mir->needsBarrier())
+                    emitPreBarrier(addr);
+                masm.storeConstantOrRegister(value, addr);
+            }
         }
 
-        if (i != mir->numShapes() - 1)
+        if (i != total - 1)
             masm.jump(&done);
         masm.bind(&next);
     }
 
     masm.bind(&done);
 }
 
 void
@@ -4568,17 +4632,17 @@ CodeGenerator::visitCreateThisWithProto(
 typedef JSObject *(*NewGCObjectFn)(JSContext *cx, gc::AllocKind allocKind,
                                    gc::InitialHeap initialHeap, const js::Class *clasp);
 static const VMFunction NewGCObjectInfo =
     FunctionInfo<NewGCObjectFn>(js::jit::NewGCObject);
 
 void
 CodeGenerator::visitCreateThisWithTemplate(LCreateThisWithTemplate *lir)
 {
-    PlainObject *templateObject = lir->mir()->templateObject();
+    JSObject *templateObject = lir->mir()->templateObject();
     gc::AllocKind allocKind = templateObject->asTenured().getAllocKind();
     gc::InitialHeap initialHeap = lir->mir()->initialHeap();
     const js::Class *clasp = templateObject->type()->clasp();
     Register objReg = ToRegister(lir->output());
     Register tempReg = ToRegister(lir->temp());
 
     OutOfLineCode *ool = oolCallVM(NewGCObjectInfo, lir,
                                    (ArgList(), Imm32(allocKind), Imm32(initialHeap),
@@ -4586,17 +4650,18 @@ CodeGenerator::visitCreateThisWithTempla
                                    StoreRegisterTo(objReg));
 
     // Allocate. If the FreeList is empty, call to VM, which may GC.
     masm.newGCThing(objReg, tempReg, templateObject, lir->mir()->initialHeap(), ool->entry());
 
     // Initialize based on the templateObject.
     masm.bind(ool->rejoin());
 
-    bool initFixedSlots = ShouldInitFixedSlots(lir, templateObject);
+    bool initFixedSlots = !templateObject->is<PlainObject>() ||
+                          ShouldInitFixedSlots(lir, &templateObject->as<PlainObject>());
     masm.initGCThing(objReg, tempReg, templateObject, initFixedSlots);
 }
 
 typedef JSObject *(*NewIonArgumentsObjectFn)(JSContext *cx, JitFrameLayout *frame, HandleObject);
 static const VMFunction NewIonArgumentsObjectInfo =
     FunctionInfo<NewIonArgumentsObjectFn>((NewIonArgumentsObjectFn) ArgumentsObject::createForIon);
 
 void
@@ -8368,18 +8433,18 @@ CodeGenerator::visitLoadUnboxedPointerT(
 {
     Register elements = ToRegister(lir->elements());
     const LAllocation *index = lir->index();
     Register out = ToRegister(lir->output());
 
     bool bailOnNull;
     int32_t offsetAdjustment;
     if (lir->mir()->isLoadUnboxedObjectOrNull()) {
-        MOZ_ASSERT(lir->mir()->toLoadUnboxedObjectOrNull()->bailOnNull());
-        bailOnNull = true;
+        bailOnNull = lir->mir()->toLoadUnboxedObjectOrNull()->nullBehavior() !=
+                     MLoadUnboxedObjectOrNull::NullNotPossible;
         offsetAdjustment = lir->mir()->toLoadUnboxedObjectOrNull()->offsetAdjustment();
     } else if (lir->mir()->isLoadUnboxedString()) {
         bailOnNull = false;
         offsetAdjustment = lir->mir()->toLoadUnboxedString()->offsetAdjustment();
     } else {
         MOZ_CRASH();
     }
 
@@ -8406,21 +8471,23 @@ CodeGenerator::visitLoadTypedArrayElemen
     AnyRegister out = ToAnyRegister(lir->output());
 
     Scalar::Type arrayType = lir->mir()->arrayType();
     int width = Scalar::byteSize(arrayType);
 
     Label fail;
     if (lir->index()->isConstant()) {
         Address source(elements, ToInt32(lir->index()) * width + lir->mir()->offsetAdjustment());
-        masm.loadFromTypedArray(arrayType, source, out, temp, &fail);
+        masm.loadFromTypedArray(arrayType, source, out, temp, &fail,
+                                lir->mir()->canonicalizeDoubles());
     } else {
         BaseIndex source(elements, ToRegister(lir->index()), ScaleFromElemWidth(width),
                          lir->mir()->offsetAdjustment());
-        masm.loadFromTypedArray(arrayType, source, out, temp, &fail);
+        masm.loadFromTypedArray(arrayType, source, out, temp, &fail,
+                                lir->mir()->canonicalizeDoubles());
     }
 
     if (fail.used())
         bailoutFrom(&fail, lir->snapshot());
 }
 
 void
 CodeGenerator::visitLoadTypedArrayElementHole(LLoadTypedArrayElementHole *lir)
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -5509,17 +5509,19 @@ MDefinition *
 IonBuilder::createThisScriptedSingleton(JSFunction *target, MDefinition *callee)
 {
     // Get the singleton prototype (if exists)
     JSObject *proto = getSingletonPrototype(target);
     if (!proto)
         return nullptr;
 
     JSObject *templateObject = inspector->getTemplateObject(pc);
-    if (!templateObject || !templateObject->is<PlainObject>())
+    if (!templateObject)
+        return nullptr;
+    if (!templateObject->is<PlainObject>() && !templateObject->is<UnboxedPlainObject>())
         return nullptr;
     if (!templateObject->hasTenuredProto() || templateObject->getProto() != proto)
         return nullptr;
 
     types::TypeObjectKey *templateObjectType = types::TypeObjectKey::get(templateObject->type());
     if (templateObjectType->hasFlags(constraints(), types::OBJECT_FLAG_NEW_SCRIPT_CLEARED))
         return nullptr;
 
@@ -6176,17 +6178,17 @@ IonBuilder::jsop_compare(JSOp op)
     if (ins->isEffectful() && !resumeAfter(ins))
         return false;
     return true;
 }
 
 bool
 IonBuilder::jsop_newarray(uint32_t count)
 {
-    NativeObject *templateObject = inspector->getTemplateObject(pc);
+    JSObject *templateObject = inspector->getTemplateObject(pc);
     if (!templateObject) {
         if (info().analysisMode() == Analysis_ArgumentsUsage) {
             MUnknownValue *unknown = MUnknownValue::New(alloc());
             current->add(unknown);
             current->push(unknown);
             return true;
         }
         return abort("No template object for NEWARRAY");
@@ -6213,19 +6215,19 @@ IonBuilder::jsop_newarray(uint32_t count
                                     NewArray_FullyAllocating);
     current->add(ins);
     current->push(ins);
 
     types::TemporaryTypeSet::DoubleConversion conversion =
         ins->resultTypeSet()->convertDoubleElements(constraints());
 
     if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles)
-        templateObject->setShouldConvertDoubleElements();
+        templateObject->as<ArrayObject>().setShouldConvertDoubleElements();
     else
-        templateObject->clearShouldConvertDoubleElements();
+        templateObject->as<ArrayObject>().clearShouldConvertDoubleElements();
     return true;
 }
 
 bool
 IonBuilder::jsop_newarray_copyonwrite()
 {
     ArrayObject *templateObject = types::GetCopyOnWriteObject(script(), pc);
 
@@ -6806,17 +6808,18 @@ IonBuilder::maybeInsertResume()
     current->add(ins);
 
     return resumeAfter(ins);
 }
 
 static bool
 ClassHasEffectlessLookup(const Class *clasp, PropertyName *name)
 {
-    return clasp->isNative() && !clasp->ops.lookupGeneric;
+    return (clasp == &UnboxedPlainObject::class_) ||
+           (clasp->isNative() && !clasp->ops.lookupGeneric);
 }
 
 static bool
 ClassHasResolveHook(CompileCompartment *comp, const Class *clasp, PropertyName *name)
 {
     // While arrays do not have resolve hooks, the types of their |length|
     // properties are not reflected in type information, so pretend there is a
     // resolve hook for this property.
@@ -7736,19 +7739,23 @@ IonBuilder::pushReferenceLoadFromTypedOb
         load = MLoadElement::New(alloc(), elements, scaledOffset, false, false, adjustment);
         break;
       }
       case ReferenceTypeDescr::TYPE_OBJECT: {
         // Make sure the barrier reflects the possibility of reading null. When
         // there is no other barrier needed we include the null bailout with
         // MLoadUnboxedObjectOrNull, which avoids the need to box the result
         // for a type barrier instruction.
-        bool bailOnNull = barrier == BarrierKind::NoBarrier &&
-                          !observedTypes->hasType(types::Type::NullType());
-        load = MLoadUnboxedObjectOrNull::New(alloc(), elements, scaledOffset, bailOnNull, adjustment);
+        MLoadUnboxedObjectOrNull::NullBehavior nullBehavior;
+        if (barrier == BarrierKind::NoBarrier && !observedTypes->hasType(types::Type::NullType()))
+            nullBehavior = MLoadUnboxedObjectOrNull::BailOnNull;
+        else
+            nullBehavior = MLoadUnboxedObjectOrNull::HandleNull;
+        load = MLoadUnboxedObjectOrNull::New(alloc(), elements, scaledOffset, nullBehavior,
+                                             adjustment);
         break;
       }
       case ReferenceTypeDescr::TYPE_STRING: {
         load = MLoadUnboxedString::New(alloc(), elements, scaledOffset, adjustment);
         observedTypes->addType(types::Type::StringType(), alloc().lifoAlloc());
         break;
       }
     }
@@ -9239,24 +9246,76 @@ IonBuilder::getDefiniteSlot(types::Tempo
             trackOptimizationOutcome(TrackedOutcome::NotFixedSlot);
             return UINT32_MAX;
         }
 
         uint32_t propertySlot = property.maybeTypes()->definiteSlot();
         if (slot == UINT32_MAX) {
             slot = propertySlot;
         } else if (slot != propertySlot) {
-            trackOptimizationOutcome(TrackedOutcome::NotFixedSlot);
+            trackOptimizationOutcome(TrackedOutcome::InconsistentFixedSlot);
             return UINT32_MAX;
         }
     }
 
     return slot;
 }
 
+uint32_t
+IonBuilder::getUnboxedOffset(types::TemporaryTypeSet *types, PropertyName *name, JSValueType *punboxedType)
+{
+    if (!types || types->unknownObject()) {
+        trackOptimizationOutcome(TrackedOutcome::NoTypeInfo);
+        return UINT32_MAX;
+    }
+
+    uint32_t offset = UINT32_MAX;
+
+    for (size_t i = 0; i < types->getObjectCount(); i++) {
+        types::TypeObjectKey *type = types->getObject(i);
+        if (!type)
+            continue;
+
+        if (type->unknownProperties()) {
+            trackOptimizationOutcome(TrackedOutcome::UnknownProperties);
+            return UINT32_MAX;
+        }
+
+        if (type->singleton()) {
+            trackOptimizationOutcome(TrackedOutcome::Singleton);
+            return UINT32_MAX;
+        }
+
+        UnboxedLayout *layout = type->asTypeObject()->maybeUnboxedLayout();
+        if (!layout) {
+            trackOptimizationOutcome(TrackedOutcome::NotUnboxed);
+            return UINT32_MAX;
+        }
+
+        const UnboxedLayout::Property *property = layout->lookup(name);
+        if (!property) {
+            trackOptimizationOutcome(TrackedOutcome::StructNoField);
+            return UINT32_MAX;
+        }
+
+        if (offset == UINT32_MAX) {
+            offset = property->offset;
+            *punboxedType = property->type;
+        } else if (offset != property->offset) {
+            trackOptimizationOutcome(TrackedOutcome::InconsistentFieldOffset);
+            return UINT32_MAX;
+        } else if (*punboxedType != property->type) {
+            trackOptimizationOutcome(TrackedOutcome::InconsistentFieldType);
+            return UINT32_MAX;
+        }
+    }
+
+    return offset;
+}
+
 bool
 IonBuilder::jsop_runonce()
 {
     MRunOncePrologue *ins = MRunOncePrologue::New(alloc());
     current->add(ins);
     return resumeAfter(ins);
 }
 
@@ -9674,16 +9733,21 @@ IonBuilder::jsop_getprop(PropertyName *n
     if (!getPropTryTypedObject(&emitted, obj, name) || emitted)
         return emitted;
 
     // Try to emit loads from definite slots.
     trackOptimizationAttempt(TrackedStrategy::GetProp_DefiniteSlot);
     if (!getPropTryDefiniteSlot(&emitted, obj, name, barrier, types) || emitted)
         return emitted;
 
+    // Try to emit loads from unboxed objects.
+    trackOptimizationAttempt(TrackedStrategy::GetProp_Unboxed);
+    if (!getPropTryUnboxed(&emitted, obj, name, barrier, types) || emitted)
+        return emitted;
+
     // Try to inline a common property getter, or make a call.
     trackOptimizationAttempt(TrackedStrategy::GetProp_CommonGetter);
     if (!getPropTryCommonGetter(&emitted, obj, name, types) || emitted)
         return emitted;
 
     // Try to emit a monomorphic/polymorphic access based on baseline caches.
     trackOptimizationAttempt(TrackedStrategy::GetProp_InlineAccess);
     if (!getPropTryInlineAccess(&emitted, obj, name, barrier, types) || emitted)
@@ -10002,16 +10066,102 @@ IonBuilder::getPropTryDefiniteSlot(bool 
     if (!pushTypeBarrier(load, types, barrier))
         return false;
 
     trackOptimizationSuccess();
     *emitted = true;
     return true;
 }
 
+MInstruction *
+IonBuilder::loadUnboxedProperty(MDefinition *obj, size_t offset, JSValueType unboxedType,
+                                BarrierKind barrier, types::TemporaryTypeSet *types)
+{
+    size_t scaledOffsetConstant = offset / UnboxedTypeSize(unboxedType);
+    MInstruction *scaledOffset = MConstant::New(alloc(), Int32Value(scaledOffsetConstant));
+    current->add(scaledOffset);
+
+    MInstruction *load;
+    switch (unboxedType) {
+      case JSVAL_TYPE_BOOLEAN:
+        load = MLoadTypedArrayElement::New(alloc(), obj, scaledOffset, Scalar::Uint8,
+                                           DoesNotRequireMemoryBarrier,
+                                           UnboxedPlainObject::offsetOfData());
+        load->setResultType(MIRType_Boolean);
+        break;
+
+      case JSVAL_TYPE_INT32:
+        load = MLoadTypedArrayElement::New(alloc(), obj, scaledOffset, Scalar::Int32,
+                                           DoesNotRequireMemoryBarrier,
+                                           UnboxedPlainObject::offsetOfData());
+        load->setResultType(MIRType_Int32);
+        break;
+
+      case JSVAL_TYPE_DOUBLE:
+        load = MLoadTypedArrayElement::New(alloc(), obj, scaledOffset, Scalar::Float64,
+                                           DoesNotRequireMemoryBarrier,
+                                           UnboxedPlainObject::offsetOfData(),
+                                           /* canonicalizeDoubles = */ false);
+        load->setResultType(MIRType_Double);
+        break;
+
+      case JSVAL_TYPE_STRING:
+        load = MLoadUnboxedString::New(alloc(), obj, scaledOffset,
+                                       UnboxedPlainObject::offsetOfData());
+        break;
+
+      case JSVAL_TYPE_OBJECT: {
+        MLoadUnboxedObjectOrNull::NullBehavior nullBehavior;
+        if (types->hasType(types::Type::NullType()) || barrier != BarrierKind::NoBarrier)
+            nullBehavior = MLoadUnboxedObjectOrNull::HandleNull;
+        else
+            nullBehavior = MLoadUnboxedObjectOrNull::NullNotPossible;
+        load = MLoadUnboxedObjectOrNull::New(alloc(), obj, scaledOffset, nullBehavior,
+                                             UnboxedPlainObject::offsetOfData());
+        break;
+      }
+
+      default:
+        MOZ_CRASH();
+    }
+
+    current->add(load);
+    return load;
+}
+
+bool
+IonBuilder::getPropTryUnboxed(bool *emitted, MDefinition *obj, PropertyName *name,
+                              BarrierKind barrier, types::TemporaryTypeSet *types)
+{
+    MOZ_ASSERT(*emitted == false);
+
+    JSValueType unboxedType;
+    uint32_t offset = getUnboxedOffset(obj->resultTypeSet(), name, &unboxedType);
+    if (offset == UINT32_MAX)
+        return true;
+
+    if (obj->type() != MIRType_Object) {
+        MGuardObject *guard = MGuardObject::New(alloc(), obj);
+        current->add(guard);
+        obj = guard;
+    }
+
+    if (unboxedType != JSVAL_TYPE_OBJECT)
+        barrier = BarrierKind::NoBarrier;
+
+    MInstruction *load = loadUnboxedProperty(obj, offset, unboxedType, barrier, types);
+    current->push(load);
+
+    if (!pushTypeBarrier(load, types, barrier))
+        return false;
+
+    *emitted = true;
+    return true;
+}
+
 bool
 IonBuilder::getPropTryCommonGetter(bool *emitted, MDefinition *obj, PropertyName *name,
                                    types::TemporaryTypeSet *types)
 {
     MOZ_ASSERT(*emitted == false);
 
     Shape *lastProperty = nullptr;
     JSFunction *commonGetter = nullptr;
@@ -10130,36 +10280,43 @@ IonBuilder::getPropTryCommonGetter(bool 
     // couldn't inline.
     if (!commonGetter->isInterpreted())
         trackOptimizationSuccess();
 
     *emitted = true;
     return true;
 }
 
-static bool
-CanInlinePropertyOpShapes(const BaselineInspector::ShapeVector &shapes)
-{
-    for (size_t i = 0; i < shapes.length(); i++) {
+bool
+IonBuilder::canInlinePropertyOpShapes(const BaselineInspector::ShapeVector &nativeShapes,
+                                      const BaselineInspector::TypeObjectVector &unboxedTypes)
+{
+    if (nativeShapes.empty() && unboxedTypes.empty()) {
+        trackOptimizationOutcome(TrackedOutcome::NoShapeInfo);
+        return false;
+    }
+
+    for (size_t i = 0; i < nativeShapes.length(); i++) {
         // We inline the property access as long as the shape is not in
         // dictionary mode. We cannot be sure that the shape is still a
         // lastProperty, and calling Shape::search() on dictionary mode
         // shapes that aren't lastProperty is invalid.
-        if (shapes[i]->inDictionary())
+        if (nativeShapes[i]->inDictionary()) {
+            trackOptimizationOutcome(TrackedOutcome::InDictionaryMode);
             return false;
+        }
     }
 
     return true;
 }
 
 static bool
 GetPropertyShapes(jsid id, const BaselineInspector::ShapeVector &shapes,
                   BaselineInspector::ShapeVector &propShapes, bool *sameSlot)
 {
-    MOZ_ASSERT(shapes.length() > 1);
     MOZ_ASSERT(propShapes.empty());
 
     if (!propShapes.reserve(shapes.length()))
         return false;
 
     *sameSlot = true;
     for (size_t i = 0; i < shapes.length(); i++) {
         Shape *objShape = shapes[i];
@@ -10185,88 +10342,111 @@ IonBuilder::getPropTryInlineAccess(bool 
 {
     MOZ_ASSERT(*emitted == false);
 
     if (obj->type() != MIRType_Object) {
         trackOptimizationOutcome(TrackedOutcome::NotObject);
         return true;
     }
 
-    BaselineInspector::ShapeVector shapes(alloc());
-    if (!inspector->maybeShapesForPropertyOp(pc, shapes))
-        return false;
-
-    if (shapes.empty()) {
-        trackOptimizationOutcome(TrackedOutcome::NoShapeInfo);
-        return true;
-    }
-
-    if (!CanInlinePropertyOpShapes(shapes)) {
-        trackOptimizationOutcome(TrackedOutcome::InDictionaryMode);
-        return true;
-    }
+    BaselineInspector::ShapeVector nativeShapes(alloc());
+    BaselineInspector::TypeObjectVector unboxedTypes(alloc());
+    if (!inspector->maybeInfoForPropertyOp(pc, nativeShapes, unboxedTypes))
+        return false;
+
+    if (!canInlinePropertyOpShapes(nativeShapes, unboxedTypes))
+        return true;
 
     MIRType rvalType = types->getKnownMIRType();
     if (barrier != BarrierKind::NoBarrier || IsNullOrUndefined(rvalType))
         rvalType = MIRType_Value;
 
-    if (shapes.length() == 1) {
+    if (nativeShapes.length() == 1 && unboxedTypes.empty()) {
         // In the monomorphic case, use separate ShapeGuard and LoadSlot
         // instructions.
         spew("Inlining monomorphic GETPROP");
 
-        Shape *objShape = shapes[0];
+        Shape *objShape = nativeShapes[0];
         obj = addShapeGuard(obj, objShape, Bailout_ShapeGuard);
 
         Shape *shape = objShape->searchLinear(NameToId(name));
         MOZ_ASSERT(shape);
 
         if (!loadSlot(obj, shape, rvalType, barrier, types))
             return false;
 
         trackOptimizationOutcome(TrackedOutcome::Monomorphic);
         *emitted = true;
         return true;
     }
 
-    MOZ_ASSERT(shapes.length() > 1);
+    if (nativeShapes.empty() && unboxedTypes.length() == 1) {
+        spew("Inlining monomorphic unboxed GETPROP");
+
+        types::TypeObject *unboxedType = unboxedTypes[0];
+
+        // Failures in this type guard should be treated the same as a shape guard failure.
+        obj = MGuardObjectType::New(alloc(), obj, unboxedType, /* bailOnEquality = */ false,
+                                    Bailout_ShapeGuard);
+        current->add(obj->toInstruction());
+
+        if (failedShapeGuard_)
+            obj->toGuardObjectType()->setNotMovable();
+
+        const UnboxedLayout::Property *property = unboxedType->unboxedLayout().lookup(name);
+        MInstruction *load = loadUnboxedProperty(obj, property->offset, property->type, barrier, types);
+        current->push(load);
+
+        if (!pushTypeBarrier(load, types, barrier))
+            return false;
+
+        *emitted = true;
+        return true;
+    }
+
+    MOZ_ASSERT(nativeShapes.length() + unboxedTypes.length() > 1);
     spew("Inlining polymorphic GETPROP");
 
     BaselineInspector::ShapeVector propShapes(alloc());
     bool sameSlot;
-    if (!GetPropertyShapes(NameToId(name), shapes, propShapes, &sameSlot))
-        return false;
-
-    if (sameSlot) {
+    if (!GetPropertyShapes(NameToId(name), nativeShapes, propShapes, &sameSlot))
+        return false;
+
+    if (sameSlot && unboxedTypes.empty()) {
         MGuardShapePolymorphic *guard = MGuardShapePolymorphic::New(alloc(), obj);
         current->add(guard);
         obj = guard;
 
         if (failedShapeGuard_)
             guard->setNotMovable();
 
-        for (size_t i = 0; i < shapes.length(); i++) {
-            if (!guard->addShape(shapes[i]))
+        for (size_t i = 0; i < nativeShapes.length(); i++) {
+            if (!guard->addShape(nativeShapes[i]))
                 return false;
         }
 
         if (!loadSlot(obj, propShapes[0], rvalType, barrier, types))
             return false;
 
         trackOptimizationOutcome(TrackedOutcome::Polymorphic);
         *emitted = true;
         return true;
     }
 
     MGetPropertyPolymorphic *load = MGetPropertyPolymorphic::New(alloc(), obj, name);
     current->add(load);
     current->push(load);
 
-    for (size_t i = 0; i < shapes.length(); i++) {
-        if (!load->addShape(shapes[i], propShapes[i]))
+    for (size_t i = 0; i < nativeShapes.length(); i++) {
+        if (!load->addShape(nativeShapes[i], propShapes[i]))
+            return false;
+    }
+
+    for (size_t i = 0; i < unboxedTypes.length(); i++) {
+        if (!load->addUnboxedType(unboxedTypes[i]))
             return false;
     }
 
     if (failedShapeGuard_)
         load->setNotMovable();
 
     load->setResultType(rvalType);
     if (!pushTypeBarrier(load, types, barrier))
@@ -10442,34 +10622,40 @@ IonBuilder::jsop_setprop(PropertyName *n
     if (info().isAnalysis()) {
         bool strict = IsStrictSetPC(pc);
         MInstruction *ins = MCallSetProperty::New(alloc(), obj, value, name, strict);
         current->add(ins);
         current->push(value);
         return resumeAfter(ins);
     }
 
-    // Add post barrier if needed.
-    if (NeedsPostBarrier(info(), value))
-        current->add(MPostWriteBarrier::New(alloc(), obj, value));
-
     // Try to inline a common property setter, or make a call.
     trackOptimizationAttempt(TrackedStrategy::SetProp_CommonSetter);
     if (!setPropTryCommonSetter(&emitted, obj, name, value) || emitted)
         return emitted;
 
     // Try to emit stores to known binary data blocks
     trackOptimizationAttempt(TrackedStrategy::SetProp_TypedObject);
     if (!setPropTryTypedObject(&emitted, obj, name, value) || emitted)
         return emitted;
 
     types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
     bool barrier = PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current, &obj, name, &value,
                                                  /* canModify = */ true);
 
+    // Try to emit stores to unboxed objects.
+    trackOptimizationAttempt(TrackedStrategy::SetProp_Unboxed);
+    if (!setPropTryUnboxed(&emitted, obj, name, value, barrier, objTypes) || emitted)
+        return emitted;
+
+    // Add post barrier if needed. The instructions above manage any post
+    // barriers they need directly.
+    if (NeedsPostBarrier(info(), value))
+        current->add(MPostWriteBarrier::New(alloc(), obj, value));
+
     // Try to emit store from definite slots.
     trackOptimizationAttempt(TrackedStrategy::SetProp_DefiniteSlot);
     if (!setPropTryDefiniteSlot(&emitted, obj, name, value, barrier, objTypes) || emitted)
         return emitted;
 
     // Try to emit a monomorphic/polymorphic store based on baseline caches.
     trackOptimizationAttempt(TrackedStrategy::SetProp_InlineAccess);
     if (!setPropTryInlineAccess(&emitted, obj, name, value, barrier, objTypes) || emitted)
@@ -10745,106 +10931,207 @@ IonBuilder::setPropTryDefiniteSlot(bool 
     if (!resumeAfter(store))
         return false;
 
     trackOptimizationSuccess();
     *emitted = true;
     return true;
 }
 
+MInstruction *
+IonBuilder::storeUnboxedProperty(MDefinition *obj, size_t offset, JSValueType unboxedType,
+                                 MDefinition *value)
+{
+    size_t scaledOffsetConstant = offset / UnboxedTypeSize(unboxedType);
+    MInstruction *scaledOffset = MConstant::New(alloc(), Int32Value(scaledOffsetConstant));
+    current->add(scaledOffset);
+
+    MInstruction *store;
+    switch (unboxedType) {
+      case JSVAL_TYPE_BOOLEAN:
+        store = MStoreTypedArrayElement::New(alloc(), obj, scaledOffset, value, Scalar::Uint8,
+                                             DoesNotRequireMemoryBarrier,
+                                             UnboxedPlainObject::offsetOfData());
+        break;
+
+      case JSVAL_TYPE_INT32:
+        store = MStoreTypedArrayElement::New(alloc(), obj, scaledOffset, value, Scalar::Int32,
+                                             DoesNotRequireMemoryBarrier,
+                                             UnboxedPlainObject::offsetOfData());
+        break;
+
+      case JSVAL_TYPE_DOUBLE:
+        store = MStoreTypedArrayElement::New(alloc(), obj, scaledOffset, value, Scalar::Float64,
+                                             DoesNotRequireMemoryBarrier,
+                                             UnboxedPlainObject::offsetOfData());
+        break;
+
+      case JSVAL_TYPE_STRING:
+        store = MStoreUnboxedString::New(alloc(), obj, scaledOffset, value,
+                                         UnboxedPlainObject::offsetOfData());
+        break;
+
+      case JSVAL_TYPE_OBJECT:
+        store = MStoreUnboxedObjectOrNull::New(alloc(), obj, scaledOffset, value, obj,
+                                               UnboxedPlainObject::offsetOfData());
+        break;
+
+      default:
+        MOZ_CRASH();
+    }
+
+    current->add(store);
+    return store;
+}
+
+bool
+IonBuilder::setPropTryUnboxed(bool *emitted, MDefinition *obj,
+                              PropertyName *name, MDefinition *value,
+                              bool barrier, types::TemporaryTypeSet *objTypes)
+{
+    MOZ_ASSERT(*emitted == false);
+
+    if (barrier) {
+        trackOptimizationOutcome(TrackedOutcome::NeedsTypeBarrier);
+        return true;
+    }
+
+    JSValueType unboxedType;
+    uint32_t offset = getUnboxedOffset(obj->resultTypeSet(), name, &unboxedType);
+    if (offset == UINT32_MAX)
+        return true;
+
+    if (obj->type() != MIRType_Object) {
+        MGuardObject *guard = MGuardObject::New(alloc(), obj);
+        current->add(guard);
+        obj = guard;
+    }
+
+    MInstruction *store = storeUnboxedProperty(obj, offset, unboxedType, value);
+
+    current->push(value);
+
+    if (!resumeAfter(store))
+        return false;
+
+    *emitted = true;
+    return true;
+}
+
 bool
 IonBuilder::setPropTryInlineAccess(bool *emitted, MDefinition *obj,
                                    PropertyName *name, MDefinition *value,
                                    bool barrier, types::TemporaryTypeSet *objTypes)
 {
     MOZ_ASSERT(*emitted == false);
 
     if (barrier) {
         trackOptimizationOutcome(TrackedOutcome::NeedsTypeBarrier);
         return true;
     }
 
-    BaselineInspector::ShapeVector shapes(alloc());
-    if (!inspector->maybeShapesForPropertyOp(pc, shapes))
-        return false;
-
-    if (shapes.empty()) {
-        trackOptimizationOutcome(TrackedOutcome::NoShapeInfo);
-        return true;
-    }
-
-    if (!CanInlinePropertyOpShapes(shapes)) {
-        trackOptimizationOutcome(TrackedOutcome::InDictionaryMode);
-        return true;
-    }
-
-    if (shapes.length() == 1) {
+    BaselineInspector::ShapeVector nativeShapes(alloc());
+    BaselineInspector::TypeObjectVector unboxedTypes(alloc());
+    if (!inspector->maybeInfoForPropertyOp(pc, nativeShapes, unboxedTypes))
+        return false;
+
+    if (!canInlinePropertyOpShapes(nativeShapes, unboxedTypes))
+        return true;
+
+    if (nativeShapes.length() == 1 && unboxedTypes.empty()) {
         spew("Inlining monomorphic SETPROP");
 
         // The Baseline IC was monomorphic, so we inline the property access as
         // long as the shape is not in dictionary mode. We cannot be sure
         // that the shape is still a lastProperty, and calling Shape::search
         // on dictionary mode shapes that aren't lastProperty is invalid.
-        Shape *objShape = shapes[0];
+        Shape *objShape = nativeShapes[0];
         obj = addShapeGuard(obj, objShape, Bailout_ShapeGuard);
 
         Shape *shape = objShape->searchLinear(NameToId(name));
         MOZ_ASSERT(shape);
 
         bool needsBarrier = objTypes->propertyNeedsBarrier(constraints(), NameToId(name));
         if (!storeSlot(obj, shape, value, needsBarrier))
             return false;
 
         trackOptimizationOutcome(TrackedOutcome::Monomorphic);
         *emitted = true;
         return true;
     }
 
-    MOZ_ASSERT(shapes.length() > 1);
+    if (nativeShapes.empty() && unboxedTypes.length() == 1) {
+        spew("Inlining monomorphic unboxed SETPROP");
+
+        types::TypeObject *unboxedType = unboxedTypes[0];
+
+        // Failures in this type guard should be treated the same as a shape guard failure.
+        obj = MGuardObjectType::New(alloc(), obj, unboxedType, /* bailOnEquality = */ false,
+                                    Bailout_ShapeGuard);
+        current->add(obj->toInstruction());
+
+        if (failedShapeGuard_)
+            obj->toGuardObjectType()->setNotMovable();
+
+        const UnboxedLayout::Property *property = unboxedType->unboxedLayout().lookup(name);
+        storeUnboxedProperty(obj, property->offset, property->type, value);
+
+        current->push(value);
+
+        *emitted = true;
+        return true;
+    }
+
+    MOZ_ASSERT(nativeShapes.length() + unboxedTypes.length() > 1);
     spew("Inlining polymorphic SETPROP");
 
     BaselineInspector::ShapeVector propShapes(alloc());
     bool sameSlot;
-    if (!GetPropertyShapes(NameToId(name), shapes, propShapes, &sameSlot))
-        return false;
-
-    if (sameSlot) {
+    if (!GetPropertyShapes(NameToId(name), nativeShapes, propShapes, &sameSlot))
+        return false;
+
+    if (sameSlot && unboxedTypes.empty()) {
         MGuardShapePolymorphic *guard = MGuardShapePolymorphic::New(alloc(), obj);
         current->add(guard);
         obj = guard;
 
         if (failedShapeGuard_)
             guard->setNotMovable();
 
-        for (size_t i = 0; i < shapes.length(); i++) {
-            if (!guard->addShape(shapes[i]))
+        for (size_t i = 0; i < nativeShapes.length(); i++) {
+            if (!guard->addShape(nativeShapes[i]))
                 return false;
         }
 
         bool needsBarrier = objTypes->propertyNeedsBarrier(constraints(), NameToId(name));
         if (!storeSlot(obj, propShapes[0], value, needsBarrier))
             return false;
 
         trackOptimizationOutcome(TrackedOutcome::Polymorphic);
         *emitted = true;
         return true;
     }
 
-    MSetPropertyPolymorphic *ins = MSetPropertyPolymorphic::New(alloc(), obj, value);
+    MSetPropertyPolymorphic *ins = MSetPropertyPolymorphic::New(alloc(), obj, value, name);
     current->add(ins);
     current->push(value);
 
-    for (size_t i = 0; i < shapes.length(); i++) {
-        Shape *objShape = shapes[i];
+    for (size_t i = 0; i < nativeShapes.length(); i++) {
+        Shape *objShape = nativeShapes[i];
         Shape *shape =  objShape->searchLinear(NameToId(name));
         MOZ_ASSERT(shape);
         if (!ins->addShape(objShape, shape))
             return false;
     }
 
+    for (size_t i = 0; i < unboxedTypes.length(); i++) {
+        if (!ins->addUnboxedType(unboxedTypes[i]))
+            return false;
+    }
+
     if (objTypes->propertyNeedsBarrier(constraints(), NameToId(name)))
         ins->setNeedsBarrier();
 
     if (!resumeAfter(ins))
         return false;
 
     trackOptimizationOutcome(TrackedOutcome::Polymorphic);
     *emitted = true;
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -7,30 +7,30 @@
 #ifndef jit_IonBuilder_h
 #define jit_IonBuilder_h
 
 // This file declares the data structures for building a MIRGraph from a
 // JSScript.
 
 #include "mozilla/LinkedList.h"
 
+#include "jit/BaselineInspector.h"
 #include "jit/BytecodeAnalysis.h"
 #include "jit/IonAnalysis.h"
 #include "jit/IonOptimizationLevels.h"
 #include "jit/MIR.h"
 #include "jit/MIRGenerator.h"
 #include "jit/MIRGraph.h"
 #include "jit/OptimizationTracking.h"
 
 namespace js {
 namespace jit {
 
 class CodeGenerator;
 class CallInfo;
-class BaselineInspector;
 class BaselineFrameInspector;
 
 // Records information about a baseline frame for compilation that is stable
 // when later used off thread.
 BaselineFrameInspector *
 NewBaselineFrameInspector(TempAllocator *temp, BaselineFrame *frame, CompileInfo *info);
 
 class IonBuilder
@@ -418,16 +418,18 @@ class IonBuilder
     bool getPropTryInferredConstant(bool *emitted, MDefinition *obj, PropertyName *name,
                                     types::TemporaryTypeSet *types);
     bool getPropTryArgumentsLength(bool *emitted, MDefinition *obj);
     bool getPropTryArgumentsCallee(bool *emitted, MDefinition *obj, PropertyName *name);
     bool getPropTryConstant(bool *emitted, MDefinition *obj, PropertyName *name,
                             types::TemporaryTypeSet *types);
     bool getPropTryDefiniteSlot(bool *emitted, MDefinition *obj, PropertyName *name,
                                 BarrierKind barrier, types::TemporaryTypeSet *types);
+    bool getPropTryUnboxed(bool *emitted, MDefinition *obj, PropertyName *name,
+                           BarrierKind barrier, types::TemporaryTypeSet *types);
     bool getPropTryCommonGetter(bool *emitted, MDefinition *obj, PropertyName *name,
                                 types::TemporaryTypeSet *types);
     bool getPropTryInlineAccess(bool *emitted, MDefinition *obj, PropertyName *name,
                                 BarrierKind barrier, types::TemporaryTypeSet *types);
     bool getPropTryTypedObject(bool *emitted, MDefinition *obj, PropertyName *name);
     bool getPropTryScalarPropOfTypedObject(bool *emitted, MDefinition *typedObj,
                                            int32_t fieldOffset,
                                            TypedObjectPrediction fieldTypeReprs);
@@ -448,16 +450,19 @@ class IonBuilder
     bool setPropTryCommonSetter(bool *emitted, MDefinition *obj,
                                 PropertyName *name, MDefinition *value);
     bool setPropTryCommonDOMSetter(bool *emitted, MDefinition *obj,
                                    MDefinition *value, JSFunction *setter,
                                    bool isDOM);
     bool setPropTryDefiniteSlot(bool *emitted, MDefinition *obj,
                                 PropertyName *name, MDefinition *value,
                                 bool barrier, types::TemporaryTypeSet *objTypes);
+    bool setPropTryUnboxed(bool *emitted, MDefinition *obj,
+                           PropertyName *name, MDefinition *value,
+                           bool barrier, types::TemporaryTypeSet *objTypes);
     bool setPropTryInlineAccess(bool *emitted, MDefinition *obj,
                                 PropertyName *name, MDefinition *value,
                                 bool barrier, types::TemporaryTypeSet *objTypes);
     bool setPropTryTypedObject(bool *emitted, MDefinition *obj,
                                PropertyName *name, MDefinition *value);
     bool setPropTryReferencePropOfTypedObject(bool *emitted,
                                               MDefinition *obj,
                                               int32_t fieldOffset,
@@ -873,18 +878,26 @@ class IonBuilder
                                   types::TemporaryTypeSet *pushedTypes);
 
     MGetPropertyCache *getInlineableGetPropertyCache(CallInfo &callInfo);
 
     JSObject *testSingletonProperty(JSObject *obj, PropertyName *name);
     bool testSingletonPropertyTypes(MDefinition *obj, JSObject *singleton, PropertyName *name,
                                     bool *testObject, bool *testString);
     uint32_t getDefiniteSlot(types::TemporaryTypeSet *types, PropertyName *name);
+    uint32_t getUnboxedOffset(types::TemporaryTypeSet *types, PropertyName *name,
+                              JSValueType *punboxedType);
+    MInstruction *loadUnboxedProperty(MDefinition *obj, size_t offset, JSValueType unboxedType,
+                                      BarrierKind barrier, types::TemporaryTypeSet *types);
+    MInstruction *storeUnboxedProperty(MDefinition *obj, size_t offset, JSValueType unboxedType,
+                                       MDefinition *value);
     bool freezePropTypeSets(types::TemporaryTypeSet *types,
                             JSObject *foundProto, PropertyName *name);
+    bool canInlinePropertyOpShapes(const BaselineInspector::ShapeVector &nativeShapes,
+                                   const BaselineInspector::TypeObjectVector &unboxedTypes);
 
     types::TemporaryTypeSet *bytecodeTypes(jsbytecode *pc);
 
     // Use one of the below methods for updating the current block, rather than
     // updating |current| directly. setCurrent() should only be used in cases
     // where the block cannot have phis whose type needs to be computed.
 
     bool setCurrentAndSpecializePhis(MBasicBlock *block) {
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -764,33 +764,39 @@ GenerateDOMProxyChecks(JSContext *cx, Ma
 }
 
 static void
 GenerateReadSlot(JSContext *cx, IonScript *ion, MacroAssembler &masm,
                  IonCache::StubAttacher &attacher, JSObject *obj, NativeObject *holder,
                  Shape *shape, Register object, TypedOrValueRegister output,
                  Label *failures = nullptr)
 {
-    MOZ_ASSERT(obj->isNative());
     // If there's a single jump to |failures|, we can patch the shape guard
     // jump directly. Otherwise, jump to the end of the stub, so there's a
     // common point to patch.
     bool multipleFailureJumps = (obj != holder) || (failures != nullptr && failures->used());
 
     // If we have multiple failure jumps but didn't get a label from the
     // outside, make one ourselves.
     Label failures_;
     if (multipleFailureJumps && !failures)
         failures = &failures_;
 
-    // Guard on the shape of the object.
-    attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
-                                   Address(object, JSObject::offsetOfShape()),
-                                   ImmGCPtr(obj->lastProperty()),
-                                   failures);
+    // Guard on the shape or type of the object, depending on whether it is native.
+    if (obj->isNative()) {
+        attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
+                                       Address(object, JSObject::offsetOfShape()),
+                                       ImmGCPtr(obj->lastProperty()),
+                                       failures);
+    } else {
+        attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
+                                       Address(object, JSObject::offsetOfType()),
+                                       ImmGCPtr(obj->type()),
+                                       failures);
+    }
 
     // If we need a scratch register, use either an output register or the
     // object register. After this point, we cannot jump directly to
     // |failures| since we may still have to pop the object register.
     bool restoreScratch = false;
     Register scratchReg = Register::FromCode(0); // Quell compiler warning.
 
     if (obj != holder || !holder->isFixedSlot(shape->slot())) {
@@ -871,16 +877,34 @@ GenerateReadSlot(JSContext *cx, IonScrip
     if (restoreScratch)
         masm.pop(scratchReg);
     masm.bind(failures);
 
     attacher.jumpNextStub(masm);
 
 }
 
+static void
+GenerateReadUnboxed(JSContext *cx, IonScript *ion, MacroAssembler &masm,
+                    IonCache::StubAttacher &attacher, JSObject *obj,
+                    const UnboxedLayout::Property *property,
+                    Register object, TypedOrValueRegister output)
+{
+    // Guard on the type of the object.
+    attacher.branchNextStub(masm, Assembler::NotEqual,
+                            Address(object, JSObject::offsetOfType()),
+                            ImmGCPtr(obj->type()));
+
+    Address address(object, UnboxedPlainObject::offsetOfData() + property->offset);
+
+    masm.loadUnboxedProperty(address, property->type, output);
+
+    attacher.jumpRejoin(masm);
+}
+
 static bool
 EmitGetterCall(JSContext *cx, MacroAssembler &masm,
                IonCache::StubAttacher &attacher, JSObject *obj,
                JSObject *holder, HandleShape shape,
                RegisterSet liveRegs, Register object,
                TypedOrValueRegister output,
                void *returnAddr)
 {
@@ -1165,17 +1189,17 @@ IsCacheableArrayLength(JSContext *cx, Ha
 
 template <class GetPropCache>
 static GetPropertyIC::NativeGetPropCacheability
 CanAttachNativeGetProp(typename GetPropCache::Context cx, const GetPropCache &cache,
                        HandleObject obj, HandlePropertyName name,
                        MutableHandleNativeObject holder, MutableHandleShape shape,
                        bool skipArrayLen = false)
 {
-    if (!obj || !obj->isNative())
+    if (!obj)
         return GetPropertyIC::CanAttachNone;
 
     // The lookup needs to be universally pure, otherwise we risk calling hooks out
     // of turn. We don't mind doing this even when purity isn't required, because we
     // only miss out on shape hashification, which is only a temporary perf cost.
     // The limits were arbitrarily set, anyways.
     JSObject *baseHolder = nullptr;
     if (!LookupPropertyPure(cx, obj, NameToId(name), &baseHolder, shape.address()))
@@ -1301,16 +1325,40 @@ GetPropertyIC::tryAttachNative(JSContext
         break;
       default:
         MOZ_CRASH("Bad NativeGetPropCacheability");
     }
     return linkAndAttachStub(cx, masm, attacher, ion, attachKind);
 }
 
 bool
+GetPropertyIC::tryAttachUnboxed(JSContext *cx, HandleScript outerScript, IonScript *ion,
+                                HandleObject obj, HandlePropertyName name,
+                                void *returnAddr, bool *emitted)
+{
+    MOZ_ASSERT(canAttachStub());
+    MOZ_ASSERT(!*emitted);
+    MOZ_ASSERT(outerScript->ionScript() == ion);
+
+    if (!obj->is<UnboxedPlainObject>())
+        return true;
+    const UnboxedLayout::Property *property = obj->as<UnboxedPlainObject>().layout().lookup(name);
+    if (!property)
+        return true;
+
+    *emitted = true;
+
+    MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
+
+    RepatchStubAppender attacher(*this);
+    GenerateReadUnboxed(cx, ion, masm, attacher, obj, property, object(), output());
+    return linkAndAttachStub(cx, masm, attacher, ion, "read unboxed");
+}
+
+bool
 GetPropertyIC::tryAttachTypedArrayLength(JSContext *cx, HandleScript outerScript, IonScript *ion,
                                          HandleObject obj, HandlePropertyName name, bool *emitted)
 {
     MOZ_ASSERT(canAttachStub());
     MOZ_ASSERT(!*emitted);
 
     if (!IsAnyTypedArray(obj))
         return true;
@@ -1724,19 +1772,25 @@ GetPropertyIC::tryAttachStub(JSContext *
         return false;
 
     if (!*emitted && !tryAttachProxy(cx, outerScript, ion, obj, name, returnAddr, emitted))
         return false;
 
     if (!*emitted && !tryAttachNative(cx, outerScript, ion, obj, name, returnAddr, emitted))
         return false;
 
+    if (!*emitted && !tryAttachUnboxed(cx, outerScript, ion, obj, name, returnAddr, emitted))
+        return false;
+
     if (!*emitted && !tryAttachTypedArrayLength(cx, outerScript, ion, obj, name, emitted))
         return false;
 
+    if (!*emitted)
+        JitSpew(JitSpew_IonIC, "Failed to attach GETPROP cache");
+
     return true;
 }
 
 /* static */ bool
 GetPropertyIC::update(JSContext *cx, size_t cacheIndex,
                       HandleObject obj, MutableHandleValue vp)
 {
     void *returnAddr;
@@ -1831,16 +1885,36 @@ IonCache::reset()
     this->stubCount_ = 0;
 }
 
 void
 IonCache::destroy()
 {
 }
 
+// Jump to failure if a value being written is not a property for obj/id.
+// This might clobber |object|.
+static void
+CheckTypeSetForWrite(MacroAssembler &masm, JSObject *obj, jsid id,
+                     Register object, ConstantOrRegister value, Label *failure)
+{
+    TypedOrValueRegister valReg = value.reg();
+    types::TypeObject *type = obj->type();
+    if (type->unknownProperties())
+        return;
+    types::HeapTypeSet *propTypes = type->maybeGetProperty(id);
+    MOZ_ASSERT(propTypes);
+
+    // guardTypeSet can read from type sets without triggering read barriers.
+    types::TypeSet::readBarrier(propTypes);
+
+    Register scratch = object;
+    masm.guardTypeSet(valReg, propTypes, BarrierKind::TypeSet, scratch, failure);
+}
+
 static void
 GenerateSetSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
                 NativeObject *obj, Shape *shape, Register object, ConstantOrRegister value,
                 bool needsTypeBarrier, bool checkTypeset)
 {
     MOZ_ASSERT(obj->isNative());
 
     Label failures, barrierFailure;
@@ -1856,28 +1930,18 @@ GenerateSetSlot(JSContext *cx, MacroAsse
 
         // Obtain and guard on the TypeObject of the object.
         types::TypeObject *type = obj->type();
         masm.branchPtr(Assembler::NotEqual,
                        Address(object, JSObject::offsetOfType()),
                        ImmGCPtr(type), &failures);
 
         if (checkTypeset) {
-            TypedOrValueRegister valReg = value.reg();
-            types::HeapTypeSet *propTypes = type->maybeGetProperty(shape->propid());
-            MOZ_ASSERT(propTypes);
-            MOZ_ASSERT(!propTypes->unknown());
-
-            // guardTypeSet can read from type sets without triggering read barriers.
-            types::TypeSet::readBarrier(propTypes);
-
-            Register scratchReg = object;
-            masm.push(scratchReg);
-
-            masm.guardTypeSet(valReg, propTypes, BarrierKind::TypeSet, scratchReg, &barrierFailure);
+            masm.push(object);
+            CheckTypeSetForWrite(masm, obj, shape->propid(), object, value, &barrierFailure);
             masm.pop(object);
         }
     }
 
     NativeObject::slotsSizeMustNotOverflow();
     if (obj->isFixedSlot(shape->slot())) {
         Address addr(object, NativeObject::getFixedSlotOffset(shape->slot()));
 
@@ -2415,27 +2479,17 @@ GenerateAddSlot(JSContext *cx, MacroAsse
     masm.branchTestObjShape(Assembler::NotEqual, object, oldShape, &failures);
 
     Label failuresPopObject;
     masm.push(object);    // save object reg because we clobber it
 
     // Guard that the incoming value is in the type set for the property
     // if a type barrier is required.
     if (checkTypeset) {
-        TypedOrValueRegister valReg = value.reg();
-        types::TypeObject *type = obj->type();
-        types::HeapTypeSet *propTypes = type->maybeGetProperty(obj->lastProperty()->propid());
-        MOZ_ASSERT(propTypes);
-        MOZ_ASSERT(!propTypes->unknown());
-
-        // guardTypeSet can read from type sets without triggering read barriers.
-        types::TypeSet::readBarrier(propTypes);
-
-        Register scratchReg = object;
-        masm.guardTypeSet(valReg, propTypes, BarrierKind::TypeSet, scratchReg, &failuresPopObject);
+        CheckTypeSetForWrite(masm, obj, obj->lastProperty()->propid(), object, value, &failuresPopObject);
         masm.loadPtr(Address(StackPointer, 0), object);
     }
 
     JSObject *proto = obj->getProto();
     Register protoReg = object;
     while (proto) {
         Shape *protoShape = proto->lastProperty();
 
@@ -2679,16 +2733,95 @@ CanAttachNativeSetProp(JSContext *cx, Ha
         IsCacheableSetPropCallNative(obj, holder, shape))
     {
         return SetPropertyIC::CanAttachCallSetter;
     }
 
     return SetPropertyIC::CanAttachNone;
 }
 
+static void
+GenerateSetUnboxed(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
+                   JSObject *obj, jsid id, uint32_t unboxedOffset, JSValueType unboxedType,
+                   Register object, ConstantOrRegister value, bool checkTypeset)
+{
+    Label failure, failurePopObject;
+
+    // Guard on the type of the object.
+    masm.branchPtr(Assembler::NotEqual,
+                   Address(object, JSObject::offsetOfType()),
+                   ImmGCPtr(obj->type()), &failure);
+
+    if (checkTypeset) {
+        masm.push(object);
+        CheckTypeSetForWrite(masm, obj, id, object, value, &failurePopObject);
+        masm.pop(object);
+    }
+
+    Address address(object, UnboxedPlainObject::offsetOfData() + unboxedOffset);
+
+    if (cx->zone()->needsIncrementalBarrier()) {
+        if (unboxedType == JSVAL_TYPE_OBJECT)
+            masm.callPreBarrier(address, MIRType_Object);
+        else if (unboxedType == JSVAL_TYPE_STRING)
+            masm.callPreBarrier(address, MIRType_String);
+        else
+            MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(unboxedType));
+    }
+
+    // If the unboxed object's type has known properties, then instances have
+    // never been converted to native objects and the type set check performed
+    // above ensures the value being written can be stored in the unboxed
+    // object.
+    Label *storeFailure = obj->type()->unknownProperties() ? &failure : nullptr;
+
+    masm.storeUnboxedProperty(address, unboxedType, value, storeFailure);
+
+    attacher.jumpRejoin(masm);
+
+    masm.bind(&failurePopObject);
+    masm.pop(object);
+    masm.bind(&failure);
+
+    attacher.jumpNextStub(masm);
+}
+
+bool
+SetPropertyIC::attachSetUnboxed(JSContext *cx, HandleScript outerScript, IonScript *ion,
+                                HandleObject obj, HandleId id,
+                                uint32_t unboxedOffset, JSValueType unboxedType,
+                                bool checkTypeset)
+{
+    MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
+    RepatchStubAppender attacher(*this);
+    GenerateSetUnboxed(cx, masm, attacher, obj, id, unboxedOffset, unboxedType,
+                       object(), value(), needsTypeBarrier());
+    return linkAndAttachStub(cx, masm, attacher, ion, "set_unboxed");
+}
+
+static bool
+CanAttachSetUnboxed(JSContext *cx, HandleObject obj, HandleId id, ConstantOrRegister val,
+                    bool needsTypeBarrier, bool *checkTypeset,
+                    uint32_t *unboxedOffset, JSValueType *unboxedType)
+{
+    if (!obj->is<UnboxedPlainObject>())
+        return false;
+
+    const UnboxedLayout::Property *property = obj->as<UnboxedPlainObject>().layout().lookup(id);
+    if (property) {
+        if (needsTypeBarrier && !CanInlineSetPropTypeCheck(obj, id, val, checkTypeset))
+            return false;
+        *unboxedOffset = property->offset;
+        *unboxedType = property->type;
+        return true;
+    }
+
+    return false;
+}
+
 bool
 SetPropertyIC::update(JSContext *cx, size_t cacheIndex, HandleObject obj,
                       HandleValue value)
 {
     void *returnAddr;
     RootedScript script(cx, GetTopJitJSScript(cx, &returnAddr));
     IonScript *ion = script->ionScript();
     SetPropertyIC &cache = ion->getCache(cacheIndex).toSetProperty();
@@ -2743,16 +2876,31 @@ SetPropertyIC::update(JSContext *cx, siz
             addedSetterStub = true;
         }
 
         if (!addedSetterStub && canCache == CanAttachCallSetter) {
             if (!cache.attachCallSetter(cx, script, ion, obj, holder, shape, returnAddr))
                 return false;
             addedSetterStub = true;
         }
+
+        checkTypeset = false;
+        uint32_t unboxedOffset;
+        JSValueType unboxedType;
+        if (!addedSetterStub && CanAttachSetUnboxed(cx, obj, id, cache.value(),
+                                                    cache.needsTypeBarrier(),
+                                                    &checkTypeset, &unboxedOffset, &unboxedType))
+        {
+            if (!cache.attachSetUnboxed(cx, script, ion, obj, id, unboxedOffset, unboxedType,
+                                        checkTypeset))
+            {
+                return false;
+            }
+            addedSetterStub = true;
+        }
     }
 
     uint32_t oldSlots = obj->is<NativeObject>() ? obj->as<NativeObject>().numDynamicSlots() : 0;
     RootedShape oldShape(cx, obj->lastProperty());
 
     // Set/Add the property on the object, the inlined cache are setup for the next execution.
     if (!SetProperty(cx, obj, name, value, cache.strict(), cache.pc()))
         return false;
@@ -2762,18 +2910,22 @@ SetPropertyIC::update(JSContext *cx, siz
     if (!addedSetterStub && canCache == MaybeCanAttachAddSlot &&
         IsPropertyAddInlineable(&obj->as<NativeObject>(), id,
                                 cache.value(), oldSlots, oldShape, cache.needsTypeBarrier(),
                                 &checkTypeset))
     {
         RootedNativeObject nobj(cx, &obj->as<NativeObject>());
         if (!cache.attachAddSlot(cx, script, ion, nobj, oldShape, oldType, checkTypeset))
             return false;
+        addedSetterStub = true;
     }
 
+    if (!addedSetterStub)
+        JitSpew(JitSpew_IonIC, "Failed to attach SETPROP cache");
+
     return true;
 }
 
 void
 SetPropertyIC::reset()
 {
     RepatchIonCache::reset();
     hasGenericProxyStub_ = false;
--- a/js/src/jit/IonCaches.h
+++ b/js/src/jit/IonCaches.h
@@ -664,16 +664,20 @@ class GetPropertyIC : public RepatchIonC
     bool tryAttachDOMProxyUnshadowed(JSContext *cx, HandleScript outerScript, IonScript *ion,
                                      HandleObject obj, HandlePropertyName name, bool resetNeeded,
                                      void *returnAddr, bool *emitted);
 
     bool tryAttachNative(JSContext *cx, HandleScript outerScript, IonScript *ion,
                          HandleObject obj, HandlePropertyName name,
                          void *returnAddr, bool *emitted);
 
+    bool tryAttachUnboxed(JSContext *cx, HandleScript outerScript, IonScript *ion,
+                          HandleObject obj, HandlePropertyName name,
+                          void *returnAddr, bool *emitted);
+
     bool tryAttachTypedArrayLength(JSContext *cx, HandleScript outerScript, IonScript *ion,
                                    HandleObject obj, HandlePropertyName name, bool *emitted);
 
     bool tryAttachArgumentsLength(JSContext *cx, HandleScript outerScript, IonScript *ion,
                                   HandleObject obj, HandlePropertyName name, bool *emitted);
 
     static bool update(JSContext *cx, size_t cacheIndex, HandleObject obj, MutableHandleValue vp);
 };
@@ -742,16 +746,21 @@ class SetPropertyIC : public RepatchIonC
     bool attachCallSetter(JSContext *cx, HandleScript outerScript, IonScript *ion,
                           HandleObject obj, HandleObject holder, HandleShape shape,
                           void *returnAddr);
 
     bool attachAddSlot(JSContext *cx, HandleScript outerScript, IonScript *ion,
                        HandleNativeObject obj, HandleShape oldShape, HandleTypeObject oldType,
                        bool checkTypeset);
 
+    bool attachSetUnboxed(JSContext *cx, HandleScript outerScript, IonScript *ion,
+                          HandleObject obj, HandleId id,
+                          uint32_t unboxedOffset, JSValueType unboxedType,
+                          bool checkTypeset);
+
     bool attachGenericProxy(JSContext *cx, HandleScript outerScript, IonScript *ion,
                             void *returnAddr);
 
     bool attachDOMProxyShadowed(JSContext *cx, HandleScript outerScript, IonScript *ion,
                                 HandleObject obj, void *returnAddr);
 
     bool attachDOMProxyUnshadowed(JSContext *cx, HandleScript outerScript, IonScript *ion,
                                   HandleObject obj, void *returnAddr);
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -2614,22 +2614,22 @@ void
 LIRGenerator::visitLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull *ins)
 {
     MOZ_ASSERT(IsValidElementsType(ins->elements(), ins->offsetAdjustment()));
     MOZ_ASSERT(ins->index()->type() == MIRType_Int32);
 
     if (ins->type() == MIRType_Object) {
         LLoadUnboxedPointerT *lir = new(alloc()) LLoadUnboxedPointerT(useRegister(ins->elements()),
                                                                       useRegisterOrConstant(ins->index()));
-        if (ins->bailOnNull())
+        if (ins->nullBehavior() == MLoadUnboxedObjectOrNull::BailOnNull)
             assignSnapshot(lir, Bailout_TypeBarrierO);
         define(lir, ins);
     } else {
         MOZ_ASSERT(ins->type() == MIRType_Value);
-        MOZ_ASSERT(!ins->bailOnNull());
+        MOZ_ASSERT(ins->nullBehavior() != MLoadUnboxedObjectOrNull::BailOnNull);
 
         LLoadUnboxedPointerV *lir = new(alloc()) LLoadUnboxedPointerV(useRegister(ins->elements()),
                                                                       useRegisterOrConstant(ins->index()));
         defineBox(lir, ins);
     }
 }
 
 void
@@ -2843,17 +2843,17 @@ void
 LIRGenerator::visitLoadTypedArrayElement(MLoadTypedArrayElement *ins)
 {
     MOZ_ASSERT(IsValidElementsType(ins->elements(), ins->offsetAdjustment()));
     MOZ_ASSERT(ins->index()->type() == MIRType_Int32);
 
     const LUse elements = useRegister(ins->elements());
     const LAllocation index = useRegisterOrConstant(ins->index());
 
-    MOZ_ASSERT(IsNumberType(ins->type()));
+    MOZ_ASSERT(IsNumberType(ins->type()) || ins->type() == MIRType_Boolean);
 
     // We need a temp register for Uint32Array with known double result.
     LDefinition tempDef = LDefinition::BogusTemp();
     if (ins->arrayType() == Scalar::Uint32 && IsFloatingPointType(ins->type()))
         tempDef = temp();
 
     if (ins->requiresMemoryBarrier()) {
         LMemoryBarrier *fence = new(alloc()) LMemoryBarrier(MembarBeforeLoad);
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -3642,31 +3642,32 @@ MNewObject::shouldUseVM() const
 {
     PlainObject *obj = templateObject();
     return obj->hasSingletonType() || obj->hasDynamicSlots();
 }
 
 bool
 MCreateThisWithTemplate::canRecoverOnBailout() const
 {
-    MOZ_ASSERT(!templateObject()->denseElementsAreCopyOnWrite());
-    MOZ_ASSERT(!templateObject()->is<ArrayObject>());
+    MOZ_ASSERT(templateObject()->is<PlainObject>() || templateObject()->is<UnboxedPlainObject>());
+    MOZ_ASSERT_IF(templateObject()->is<PlainObject>(),
+                  !templateObject()->as<PlainObject>().denseElementsAreCopyOnWrite());
     return true;
 }
 
 MObjectState::MObjectState(MDefinition *obj)
 {
     // This instruction is only used as a summary for bailout paths.
     setResultType(MIRType_Object);
     setRecoveredOnBailout();
     NativeObject *templateObject = nullptr;
     if (obj->isNewObject())
         templateObject = obj->toNewObject()->templateObject();
     else if (obj->isCreateThisWithTemplate())
-        templateObject = obj->toCreateThisWithTemplate()->templateObject();
+        templateObject = &obj->toCreateThisWithTemplate()->templateObject()->as<PlainObject>();
     else
         templateObject = obj->toNewCallObject()->templateObject();
     numSlots_ = templateObject->slotSpan();
     numFixedSlots_ = templateObject->numFixedSlots();
 }
 
 bool
 MObjectState::init(TempAllocator &alloc, MDefinition *obj)
@@ -4722,20 +4723,22 @@ TryAddTypeBarrierForWrite(TempAllocator 
 }
 
 static MInstruction *
 AddTypeGuard(TempAllocator &alloc, MBasicBlock *current, MDefinition *obj,
              types::TypeObjectKey *type, bool bailOnEquality)
 {
     MInstruction *guard;
 
-    if (type->isTypeObject())
-        guard = MGuardObjectType::New(alloc, obj, type->asTypeObject(), bailOnEquality);
-    else
+    if (type->isTypeObject()) {
+        guard = MGuardObjectType::New(alloc, obj, type->asTypeObject(), bailOnEquality,
+                                      Bailout_ObjectIdentityOrTypeGuard);
+    } else {
         guard = MGuardObjectIdentity::New(alloc, obj, type->asSingleObject(), bailOnEquality);
+    }
 
     current->add(guard);
 
     // For now, never move type object guards.
     guard->setNotMovable();
 
     return guard;
 }
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -4268,18 +4268,18 @@ class MCreateThisWithTemplate
     INSTRUCTION_HEADER(CreateThisWithTemplate)
     static MCreateThisWithTemplate *New(TempAllocator &alloc, types::CompilerConstraintList *constraints,
                                         MConstant *templateConst, gc::InitialHeap initialHeap)
     {
         return new(alloc) MCreateThisWithTemplate(constraints, templateConst, initialHeap);
     }
 
     // Template for |this|, provided by TI.
-    PlainObject *templateObject() const {
-        return &getOperand(0)->toConstant()->value().toObject().as<PlainObject>();
+    JSObject *templateObject() const {
+        return &getOperand(0)->toConstant()->value().toObject();
     }
 
     gc::InitialHeap initialHeap() const {
         return initialHeap_;
     }
 
     // Although creation of |this| modifies global state, it is safely repeatable.
     AliasSet getAliasSet() const MOZ_OVERRIDE {
@@ -8054,65 +8054,74 @@ class MLoadElementHole
 
     ALLOW_CLONE(MLoadElementHole)
 };
 
 class MLoadUnboxedObjectOrNull
   : public MBinaryInstruction,
     public SingleObjectPolicy::Data
 {
-    bool bailOnNull_;
+  public:
+    enum NullBehavior {
+        HandleNull,
+        BailOnNull,
+        NullNotPossible
+    };
+
+  private:
+    NullBehavior nullBehavior_;
     int32_t offsetAdjustment_;
 
     MLoadUnboxedObjectOrNull(MDefinition *elements, MDefinition *index,
-                             bool bailOnNull, int32_t offsetAdjustment)
+                             NullBehavior nullBehavior, int32_t offsetAdjustment)
       : MBinaryInstruction(elements, index),
-        bailOnNull_(bailOnNull),
+        nullBehavior_(nullBehavior),
         offsetAdjustment_(offsetAdjustment)
     {
-        if (bailOnNull) {
+        if (nullBehavior == BailOnNull) {
             // Don't eliminate loads which bail out on a null pointer, for the
             // same reason as MLoadElement.
             setGuard();
         }
-        setResultType(bailOnNull ? MIRType_Object : MIRType_Value);
+        setResultType(nullBehavior == HandleNull ? MIRType_Value : MIRType_Object);
         setMovable();
         MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
         MOZ_ASSERT(index->type() == MIRType_Int32);
     }
 
   public:
     INSTRUCTION_HEADER(LoadUnboxedObjectOrNull)
 
     static MLoadUnboxedObjectOrNull *New(TempAllocator &alloc,
                                          MDefinition *elements, MDefinition *index,
-                                         bool bailOnNull, int32_t offsetAdjustment) {
-        return new(alloc) MLoadUnboxedObjectOrNull(elements, index, bailOnNull, offsetAdjustment);
+                                         NullBehavior nullBehavior, int32_t offsetAdjustment) {
+        return new(alloc) MLoadUnboxedObjectOrNull(elements, index, nullBehavior,
+                                                   offsetAdjustment);
     }
 
     MDefinition *elements() const {
         return getOperand(0);
     }
     MDefinition *index() const {
         return getOperand(1);
     }
-    bool bailOnNull() const {
-        return bailOnNull_;
+    NullBehavior nullBehavior() const {
+        return nullBehavior_;
     }
     int32_t offsetAdjustment() const {
         return offsetAdjustment_;
     }
     bool fallible() const {
-        return bailOnNull();
+        return nullBehavior() == BailOnNull;
     }
     bool congruentTo(const MDefinition *ins) const MOZ_OVERRIDE {
         if (!ins->isLoadUnboxedObjectOrNull())
             return false;
         const MLoadUnboxedObjectOrNull *other = ins->toLoadUnboxedObjectOrNull();
-        if (bailOnNull() != other->bailOnNull())
+        if (nullBehavior() != other->nullBehavior())
             return false;
         if (offsetAdjustment() != other->offsetAdjustment())
             return false;
         return congruentIfOperandsEqual(other);
     }
     AliasSet getAliasSet() const MOZ_OVERRIDE {
         return AliasSet::Load(AliasSet::Element);
     }
@@ -8135,17 +8144,18 @@ class MLoadUnboxedString
         MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
         MOZ_ASSERT(index->type() == MIRType_Int32);
     }
 
   public:
     INSTRUCTION_HEADER(LoadUnboxedString)
 
     static MLoadUnboxedString *New(TempAllocator &alloc,
-                                   MDefinition *elements, MDefinition *index, int32_t offsetAdjustment) {
+                                   MDefinition *elements, MDefinition *index,
+                                   int32_t offsetAdjustment = 0) {
         return new(alloc) MLoadUnboxedString(elements, index, offsetAdjustment);
     }
 
     MDefinition *elements() const {
         return getOperand(0);
     }
     MDefinition *index() const {
         return getOperand(1);
@@ -8326,17 +8336,17 @@ class MStoreUnboxedObjectOrNull
     }
 
   public:
     INSTRUCTION_HEADER(StoreUnboxedObjectOrNull)
 
     static MStoreUnboxedObjectOrNull *New(TempAllocator &alloc,
                                           MDefinition *elements, MDefinition *index,
                                           MDefinition *value, MDefinition *typedObj,
-                                          int32_t offsetAdjustment) {
+                                          int32_t offsetAdjustment = 0) {
         return new(alloc) MStoreUnboxedObjectOrNull(elements, index, value, typedObj,
                                                     offsetAdjustment);
     }
     MDefinition *elements() const {
         return getOperand(0);
     }
     MDefinition *index() const {
         return getOperand(1);
@@ -8381,17 +8391,17 @@ class MStoreUnboxedString
         MOZ_ASSERT(index->type() == MIRType_Int32);
     }
 
   public:
     INSTRUCTION_HEADER(StoreUnboxedString)
 
     static MStoreUnboxedString *New(TempAllocator &alloc,
                                     MDefinition *elements, MDefinition *index,
-                                    MDefinition *value, int32_t offsetAdjustment) {
+                                    MDefinition *value, int32_t offsetAdjustment = 0) {
         return new(alloc) MStoreUnboxedString(elements, index, value, offsetAdjustment);
     }
     MDefinition *elements() const {
         return getOperand(0);
     }
     MDefinition *index() const {
         return getOperand(1);
     }
@@ -8576,24 +8586,26 @@ enum MemoryBarrierRequirement
 
 class MLoadTypedArrayElement
   : public MBinaryInstruction,
     public SingleObjectPolicy::Data
 {
     Scalar::Type arrayType_;
     bool requiresBarrier_;
     int32_t offsetAdjustment_;
+    bool canonicalizeDoubles_;
 
     MLoadTypedArrayElement(MDefinition *elements, MDefinition *index,
                            Scalar::Type arrayType, MemoryBarrierRequirement requiresBarrier,
-                           int32_t offsetAdjustment)
+                           int32_t offsetAdjustment, bool canonicalizeDoubles)
       : MBinaryInstruction(elements, index),
         arrayType_(arrayType),
         requiresBarrier_(requiresBarrier == DoesRequireMemoryBarrier),
-        offsetAdjustment_(offsetAdjustment)
+        offsetAdjustment_(offsetAdjustment),
+        canonicalizeDoubles_(canonicalizeDoubles)
     {
         setResultType(MIRType_Value);
         if (requiresBarrier_)
             setGuard();         // Not removable or movable
         else
             setMovable();
         MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
         MOZ_ASSERT(index->type() == MIRType_Int32);
@@ -8601,32 +8613,37 @@ class MLoadTypedArrayElement
     }
 
   public:
     INSTRUCTION_HEADER(LoadTypedArrayElement)
 
     static MLoadTypedArrayElement *New(TempAllocator &alloc, MDefinition *elements, MDefinition *index,
                                        Scalar::Type arrayType,
                                        MemoryBarrierRequirement requiresBarrier=DoesNotRequireMemoryBarrier,
-                                       int32_t offsetAdjustment = 0)
+                                       int32_t offsetAdjustment = 0,
+                                       bool canonicalizeDoubles = true)
     {
         return new(alloc) MLoadTypedArrayElement(elements, index, arrayType,
-                                                 requiresBarrier, offsetAdjustment);
+                                                 requiresBarrier, offsetAdjustment,
+                                                 canonicalizeDoubles);
     }
 
     Scalar::Type arrayType() const {
         return arrayType_;
     }
     bool fallible() const {
         // Bailout if the result does not fit in an int32.
         return arrayType_ == Scalar::Uint32 && type() == MIRType_Int32;
     }
     bool requiresMemoryBarrier() const {
         return requiresBarrier_;
     }
+    bool canonicalizeDoubles() const {
+        return canonicalizeDoubles_;
+    }
     MDefinition *elements() const {
         return getOperand(0);
     }
     MDefinition *index() const {
         return getOperand(1);
     }
     int32_t offsetAdjustment() const {
         return offsetAdjustment_;
@@ -8644,16 +8661,18 @@ class MLoadTypedArrayElement
             return false;
         if (!ins->isLoadTypedArrayElement())
             return false;
         const MLoadTypedArrayElement *other = ins->toLoadTypedArrayElement();
         if (arrayType_ != other->arrayType_)
             return false;
         if (offsetAdjustment() != other->offsetAdjustment())
             return false;
+        if (canonicalizeDoubles() != other->canonicalizeDoubles())
+            return false;
         return congruentIfOperandsEqual(other);
     }
 
     void printOpcode(FILE *fp) const MOZ_OVERRIDE;
 
     void computeRange(TempAllocator &alloc) MOZ_OVERRIDE;
 
     bool canProduceFloat32() const MOZ_OVERRIDE { return arrayType_ == Scalar::Float32; }
@@ -9335,47 +9354,45 @@ class MGetPropertyCache
         }
         return AliasSet::Store(AliasSet::Any);
     }
 
     void setBlock(MBasicBlock *block) MOZ_OVERRIDE;
     bool updateForReplacement(MDefinition *ins) MOZ_OVERRIDE;
 };
 
-// Emit code to load a value from an object's slots if its shape matches
-// one of the shapes observed by the baseline IC, else bails out.
+// Emit code to load a value from an object if its shape/type matches one of
+// the shapes/types observed by the baseline IC, else bails out.
 class MGetPropertyPolymorphic
   : public MUnaryInstruction,
     public SingleObjectPolicy::Data
 {
     struct Entry {
         // The shape to guard against.
         Shape *objShape;
 
         // The property to laod.
         Shape *shape;
     };
 
-    Vector<Entry, 4, JitAllocPolicy> shapes_;
+    Vector<Entry, 4, JitAllocPolicy> nativeShapes_;
+    Vector<types::TypeObject *, 4, JitAllocPolicy> unboxedTypes_;
     AlwaysTenuredPropertyName name_;
 
     MGetPropertyPolymorphic(TempAllocator &alloc, MDefinition *obj, PropertyName *name)
       : MUnaryInstruction(obj),
-        shapes_(alloc),
+        nativeShapes_(alloc),
+        unboxedTypes_(alloc),
         name_(name)
     {
         setGuard();
         setMovable();
         setResultType(MIRType_Value);
     }
 
-    PropertyName *name() const {
-        return name_;
-    }
-
   public:
     INSTRUCTION_HEADER(GetPropertyPolymorphic)
 
     static MGetPropertyPolymorphic *New(TempAllocator &alloc, MDefinition *obj, PropertyName *name) {
         return new(alloc) MGetPropertyPolymorphic(alloc, obj, name);
     }
 
     bool congruentTo(const MDefinition *ins) const MOZ_OVERRIDE {
@@ -9385,32 +9402,45 @@ class MGetPropertyPolymorphic
             return false;
         return congruentIfOperandsEqual(ins);
     }
 
     bool addShape(Shape *objShape, Shape *shape) {
         Entry entry;
         entry.objShape = objShape;
         entry.shape = shape;
-        return shapes_.append(entry);
+        return nativeShapes_.append(entry);
+    }
+    bool addUnboxedType(types::TypeObject *type) {
+        return unboxedTypes_.append(type);
     }
     size_t numShapes() const {
-        return shapes_.length();
+        return nativeShapes_.length();
     }
     Shape *objShape(size_t i) const {
-        return shapes_[i].objShape;
+        return nativeShapes_[i].objShape;
     }
     Shape *shape(size_t i) const {
-        return shapes_[i].shape;
+        return nativeShapes_[i].shape;
+    }
+    size_t numUnboxedTypes() const {
+        return unboxedTypes_.length();
+    }
+    types::TypeObject *unboxedType(size_t i) const {
+        return unboxedTypes_[i];
+    }
+    PropertyName *name() const {
+        return name_;
     }
     MDefinition *obj() const {
         return getOperand(0);
     }
     AliasSet getAliasSet() const MOZ_OVERRIDE {
-        return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | AliasSet::DynamicSlot);
+        return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | AliasSet::DynamicSlot |
+                              (unboxedTypes_.empty() ? 0 : (AliasSet::TypedArrayElement | AliasSet::Element)));
     }
 
     bool mightAlias(const MDefinition *store) const MOZ_OVERRIDE;
 };
 
 // Emit code to store a value to an object's slots if its shape matches
 // one of the shapes observed by the baseline IC, else bails out.
 class MSetPropertyPolymorphic
@@ -9420,62 +9450,81 @@ class MSetPropertyPolymorphic
     struct Entry {
         // The shape to guard against.
         Shape *objShape;
 
         // The property to load.
         Shape *shape;
     };
 
-    Vector<Entry, 4, JitAllocPolicy> shapes_;
+    Vector<Entry, 4, JitAllocPolicy> nativeShapes_;
+    Vector<types::TypeObject *, 4, JitAllocPolicy> unboxedTypes_;
+    AlwaysTenuredPropertyName name_;
     bool needsBarrier_;
 
-    MSetPropertyPolymorphic(TempAllocator &alloc, MDefinition *obj, MDefinition *value)
+    MSetPropertyPolymorphic(TempAllocator &alloc, MDefinition *obj, MDefinition *value,
+                            PropertyName *name)
       : MBinaryInstruction(obj, value),
-        shapes_(alloc),
+        nativeShapes_(alloc),
+        unboxedTypes_(alloc),
+        name_(name),
         needsBarrier_(false)
     {
     }
 
   public:
     INSTRUCTION_HEADER(SetPropertyPolymorphic)
 
-    static MSetPropertyPolymorphic *New(TempAllocator &alloc, MDefinition *obj, MDefinition *value) {
-        return new(alloc) MSetPropertyPolymorphic(alloc, obj, value);
+    static MSetPropertyPolymorphic *New(TempAllocator &alloc, MDefinition *obj, MDefinition *value,
+                                        PropertyName *name) {
+        return new(alloc) MSetPropertyPolymorphic(alloc, obj, value, name);
     }
 
     bool addShape(Shape *objShape, Shape *shape) {
         Entry entry;
         entry.objShape = objShape;
         entry.shape = shape;
-        return shapes_.append(entry);
+        return nativeShapes_.append(entry);
+    }
+    bool addUnboxedType(types::TypeObject *type) {
+        return unboxedTypes_.append(type);
     }
     size_t numShapes() const {
-        return shapes_.length();
+        return nativeShapes_.length();
     }
     Shape *objShape(size_t i) const {
-        return shapes_[i].objShape;
+        return nativeShapes_[i].objShape;
     }
     Shape *shape(size_t i) const {
-        return shapes_[i].shape;
+        return nativeShapes_[i].shape;
+    }
+    size_t numUnboxedTypes() const {
+        return unboxedTypes_.length();
+    }
+    types::TypeObject *unboxedType(size_t i) const {
+        return unboxedTypes_[i];
+    }
+    PropertyName *name() const {
+        return name_;
     }
     MDefinition *obj() const {
         return getOperand(0);
     }
     MDefinition *value() const {
         return getOperand(1);
     }
     bool needsBarrier() const {
         return needsBarrier_;
     }
     void setNeedsBarrier() {
         needsBarrier_ = true;
     }
     AliasSet getAliasSet() const MOZ_OVERRIDE {
-        return AliasSet::Store(AliasSet::ObjectFields | AliasSet::FixedSlot | AliasSet::DynamicSlot);
+        return AliasSet::Store(AliasSet::ObjectFields | AliasSet::FixedSlot | AliasSet::DynamicSlot |
+                               (unboxedTypes_.empty() ? 0 : (AliasSet::TypedArrayElement | AliasSet::Element)));
     }
 };
 
 class MDispatchInstruction
   : public MControlInstruction,
     public SingleObjectPolicy::Data
 {
     // Map from JSFunction* -> MBasicBlock.
@@ -9800,51 +9849,59 @@ class MGuardShapePolymorphic
 
 // Guard on an object's type, inclusively or exclusively.
 class MGuardObjectType
   : public MUnaryInstruction,
     public SingleObjectPolicy::Data
 {
     AlwaysTenured<types::TypeObject *> typeObject_;
     bool bailOnEquality_;
-
-    MGuardObjectType(MDefinition *obj, types::TypeObject *typeObject, bool bailOnEquality)
+    BailoutKind bailoutKind_;
+
+    MGuardObjectType(MDefinition *obj, types::TypeObject *typeObject, bool bailOnEquality,
+                     BailoutKind bailoutKind)
       : MUnaryInstruction(obj),
         typeObject_(typeObject),
-        bailOnEquality_(bailOnEquality)
+        bailOnEquality_(bailOnEquality),
+        bailoutKind_(bailoutKind)
     {
         setGuard();
         setMovable();
         setResultType(MIRType_Object);
     }
 
   public:
     INSTRUCTION_HEADER(GuardObjectType)
 
     static MGuardObjectType *New(TempAllocator &alloc, MDefinition *obj, types::TypeObject *typeObject,
-                                 bool bailOnEquality) {
-        return new(alloc) MGuardObjectType(obj, typeObject, bailOnEquality);
+                                 bool bailOnEquality, BailoutKind bailoutKind) {
+        return new(alloc) MGuardObjectType(obj, typeObject, bailOnEquality, bailoutKind);
     }
 
     MDefinition *obj() const {
         return getOperand(0);
     }
     const types::TypeObject *typeObject() const {
         return typeObject_;
     }
     bool bailOnEquality() const {
         return bailOnEquality_;
     }
+    BailoutKind bailoutKind() const {
+        return bailoutKind_;
+    }
     bool congruentTo(const MDefinition *ins) const MOZ_OVERRIDE {
         if (!ins->isGuardObjectType())
             return false;
         if (typeObject() != ins->toGuardObjectType()->typeObject())
             return false;
         if (bailOnEquality() != ins->toGuardObjectType()->bailOnEquality())
             return false;
+        if (bailoutKind() != ins->toGuardObjectType()->bailoutKind())
+            return false;
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const MOZ_OVERRIDE {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
 // Guard on an object's identity, inclusively or exclusively.
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -301,17 +301,17 @@ MacroAssembler::storeToTypedFloatArray(S
                                        const Address &dest)
 {
     StoreToTypedFloatArray(*this, arrayType, value, dest);
 }
 
 template<typename T>
 void
 MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const T &src, AnyRegister dest, Register temp,
-                                   Label *fail)
+                                   Label *fail, bool canonicalizeDoubles)
 {
     switch (arrayType) {
       case Scalar::Int8:
         load8SignExtend(src, dest.gpr());
         break;
       case Scalar::Uint8:
       case Scalar::Uint8Clamped:
         load8ZeroExtend(src, dest.gpr());
@@ -339,27 +339,28 @@ MacroAssembler::loadFromTypedArray(Scala
         }
         break;
       case Scalar::Float32:
         loadFloat32(src, dest.fpu());
         canonicalizeFloat(dest.fpu());
         break;
       case Scalar::Float64:
         loadDouble(src, dest.fpu());
-        canonicalizeDouble(dest.fpu());
+        if (canonicalizeDoubles)
+            canonicalizeDouble(dest.fpu());
         break;
       default:
         MOZ_CRASH("Invalid typed array type");
     }
 }
 
 template void MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const Address &src, AnyRegister dest,
-                                                 Register temp, Label *fail);
+                                                 Register temp, Label *fail, bool canonicalizeDoubles);
 template void MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const BaseIndex &src, AnyRegister dest,
-                                                 Register temp, Label *fail);
+                                                 Register temp, Label *fail, bool canonicalizeDoubles);
 
 template<typename T>
 void
 MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const T &src, const ValueOperand &dest,
                                    bool allowDouble, Register temp, Label *fail)
 {
     switch (arrayType) {
       case Scalar::Int8:
@@ -616,16 +617,224 @@ template void
 MacroAssembler::atomicBinopToTypedIntArray(AtomicOp op, Scalar::Type arrayType,
                                            const Register &value, const Address &mem,
                                            Register temp1, Register temp2, AnyRegister output);
 template void
 MacroAssembler::atomicBinopToTypedIntArray(AtomicOp op, Scalar::Type arrayType,
                                            const Register &value, const BaseIndex &mem,
                                            Register temp1, Register temp2, AnyRegister output);
 
+template <typename T>
+void
+MacroAssembler::loadUnboxedProperty(T address, JSValueType type, TypedOrValueRegister output)
+{
+    switch (type) {
+      case JSVAL_TYPE_BOOLEAN:
+      case JSVAL_TYPE_INT32:
+      case JSVAL_TYPE_STRING: {
+        Register outReg;
+        if (output.hasValue()) {
+            outReg = output.valueReg().scratchReg();
+        } else {
+            MOZ_ASSERT(output.type() == MIRTypeFromValueType(type));
+            outReg = output.typedReg().gpr();
+        }
+
+        switch (type) {
+          case JSVAL_TYPE_BOOLEAN:
+            load8ZeroExtend(address, outReg);
+            break;
+          case JSVAL_TYPE_INT32:
+            load32(address, outReg);
+            break;
+          case JSVAL_TYPE_STRING:
+            loadPtr(address, outReg);
+            break;
+          default:
+            MOZ_CRASH();
+        }
+
+        if (output.hasValue())
+            tagValue(type, outReg, output.valueReg());
+        break;
+      }
+
+      case JSVAL_TYPE_OBJECT:
+        if (output.hasValue()) {
+            Register scratch = output.valueReg().scratchReg();
+            loadPtr(address, scratch);
+
+            Label notNull, done;
+            branchPtr(Assembler::NotEqual, scratch, ImmWord(0), &notNull);
+
+            moveValue(NullValue(), output.valueReg());
+            jump(&done);
+
+            bind(&notNull);
+            tagValue(JSVAL_TYPE_OBJECT, scratch, output.valueReg());
+
+            bind(&done);
+        } else {
+            // Reading null can't be possible here, as otherwise the result
+            // would be a value (either because null has been read before or
+            // because there is a barrier).
+            Register reg = output.typedReg().gpr();
+            loadPtr(address, reg);
+#ifdef DEBUG
+            Label ok;
+            branchTestPtr(Assembler::NonZero, reg, reg, &ok);
+            assumeUnreachable("Null not possible");
+            bind(&ok);
+#endif
+        }
+        break;
+
+      case JSVAL_TYPE_DOUBLE:
+        // Note: doubles in unboxed objects are not accessed through other
+        // views and do not need canonicalization.
+        if (output.hasValue())
+            loadValue(address, output.valueReg());
+        else
+            loadDouble(address, output.typedReg().fpu());
+        break;
+
+      default:
+        MOZ_CRASH();
+    }
+}
+
+template void
+MacroAssembler::loadUnboxedProperty(Address address, JSValueType type,
+                                    TypedOrValueRegister output);
+
+template void
+MacroAssembler::loadUnboxedProperty(BaseIndex address, JSValueType type,
+                                    TypedOrValueRegister output);
+
+template <typename T>
+void
+MacroAssembler::storeUnboxedProperty(T address, JSValueType type,
+                                     ConstantOrRegister value, Label *failure)
+{
+    switch (type) {
+      case JSVAL_TYPE_BOOLEAN:
+        if (value.constant()) {
+            if (value.value().isBoolean())
+                store8(Imm32(value.value().toBoolean()), address);
+            else
+                jump(failure);
+        } else if (value.reg().hasTyped()) {
+            if (value.reg().type() == MIRType_Boolean)
+                store8(value.reg().typedReg().gpr(), address);
+            else
+                jump(failure);
+        } else {
+            if (failure)
+                branchTestBoolean(Assembler::NotEqual, value.reg().valueReg(), failure);
+            storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ 1);
+        }
+        break;
+
+      case JSVAL_TYPE_INT32:
+        if (value.constant()) {
+            if (value.value().isInt32())
+                store32(Imm32(value.value().toInt32()), address);
+            else
+                jump(failure);
+        } else if (value.reg().hasTyped()) {
+            if (value.reg().type() == MIRType_Int32)
+                store32(value.reg().typedReg().gpr(), address);
+            else
+                jump(failure);
+        } else {
+            if (failure)
+                branchTestInt32(Assembler::NotEqual, value.reg().valueReg(), failure);
+            storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ 4);
+        }
+        break;
+
+      case JSVAL_TYPE_DOUBLE:
+        if (value.constant()) {
+            if (value.value().isNumber()) {
+                loadConstantDouble(value.value().toNumber(), ScratchDoubleReg);
+                storeDouble(ScratchDoubleReg, address);
+            } else {
+                jump(failure);
+            }
+        } else if (value.reg().hasTyped()) {
+            if (value.reg().type() == MIRType_Int32) {
+                convertInt32ToDouble(value.reg().typedReg().gpr(), ScratchDoubleReg);
+                storeDouble(ScratchDoubleReg, address);
+            } else if (value.reg().type() == MIRType_Double) {
+                storeDouble(value.reg().typedReg().fpu(), address);
+            } else {
+                jump(failure);
+            }
+        } else {
+            if (failure)
+                branchTestNumber(Assembler::NotEqual, value.reg().valueReg(), failure);
+            unboxValue(value.reg().valueReg(), AnyRegister(ScratchDoubleReg));
+            storeDouble(ScratchDoubleReg, address);
+        }
+        break;
+
+      case JSVAL_TYPE_OBJECT:
+        if (value.constant()) {
+            if (value.value().isObjectOrNull())
+                storePtr(ImmGCPtr(value.value().toObjectOrNull()), address);
+            else
+                jump(failure);
+        } else if (value.reg().hasTyped()) {
+            MOZ_ASSERT(value.reg().type() != MIRType_Null);
+            if (value.reg().type() == MIRType_Object)
+                storePtr(value.reg().typedReg().gpr(), address);
+            else
+                jump(failure);
+        } else {
+            if (failure) {
+                Label ok;
+                branchTestNull(Assembler::Equal, value.reg().valueReg(), &ok);
+                branchTestObject(Assembler::NotEqual, value.reg().valueReg(), failure);
+                bind(&ok);
+            }
+            storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ sizeof(uintptr_t));
+        }
+        break;
+
+      case JSVAL_TYPE_STRING:
+        if (value.constant()) {
+            if (value.value().isString())
+                storePtr(ImmGCPtr(value.value().toString()), address);
+            else
+                jump(failure);
+        } else if (value.reg().hasTyped()) {
+            if (value.reg().type() == MIRType_String)
+                storePtr(value.reg().typedReg().gpr(), address);
+            else
+                jump(failure);
+        } else {
+            if (failure)
+                branchTestString(Assembler::NotEqual, value.reg().valueReg(), failure);
+            storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ sizeof(uintptr_t));
+        }
+        break;
+
+      default:
+        MOZ_CRASH();
+    }
+}
+
+template void
+MacroAssembler::storeUnboxedProperty(Address address, JSValueType type,
+                                     ConstantOrRegister value, Label *failure);
+
+template void
+MacroAssembler::storeUnboxedProperty(BaseIndex address, JSValueType type,
+                                     ConstantOrRegister value, Label *failure);
+
 // Inlined version of gc::CheckAllocatorState that checks the bare essentials
 // and bails for anything that cannot be handled with our jit allocators.
 void
 MacroAssembler::checkAllocatorState(Label *fail)
 {
     // Don't execute the inline path if we are tracing allocations.
     if (js::gc::TraceEnabled())
         jump(fail);
@@ -775,32 +984,32 @@ MacroAssembler::allocateObject(Register 
     pop(slots);
     jump(&success);
 
     bind(&failAlloc);
     pop(slots);
     callFreeStub(slots);
     jump(fail);
 
-    bind(&success);
+    breakpoint();
 }
 
 void
-MacroAssembler::newGCThing(Register result, Register temp, NativeObject *templateObj,
-                            gc::InitialHeap initialHeap, Label *fail)
+MacroAssembler::newGCThing(Register result, Register temp, JSObject *templateObj,
+                           gc::InitialHeap initialHeap, Label *fail)
 {
     // This method does not initialize the object: if external slots get
     // allocated into |temp|, there is no easy way for us to ensure the caller
     // frees them. Instead just assert this case does not happen.
-    MOZ_ASSERT(!templateObj->numDynamicSlots());
+    MOZ_ASSERT_IF(templateObj->isNative(), !templateObj->as<NativeObject>().numDynamicSlots());
 
     gc::AllocKind allocKind = templateObj->asTenured().getAllocKind();
     MOZ_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST);
 
-    allocateObject(result, temp, allocKind, templateObj->numDynamicSlots(), initialHeap, fail);
+    allocateObject(result, temp, allocKind, 0, initialHeap, fail);
 }
 
 void
 MacroAssembler::createGCObject(Register obj, Register temp, JSObject *templateObj,
                                gc::InitialHeap initialHeap, Label *fail, bool initFixedSlots)
 {
     gc::AllocKind allocKind = templateObj->asTenured().getAllocKind();
     MOZ_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST);
@@ -1025,28 +1234,47 @@ MacroAssembler::initGCThing(Register obj
 
             if (ntemplate->hasPrivate()) {
                 uint32_t nfixed = ntemplate->numFixedSlots();
                 storePtr(ImmPtr(ntemplate->getPrivate()),
                          Address(obj, NativeObject::getPrivateDataOffset(nfixed)));
             }
         }
     } else if (templateObj->is<InlineTypedObject>()) {
-        InlineTypedObject *ntemplate = &templateObj->as<InlineTypedObject>();
+        size_t nbytes = templateObj->as<InlineTypedObject>().size();
+        const uint8_t *memory = templateObj->as<InlineTypedObject>().inlineTypedMem();
 
         // Memcpy the contents of the template object to the new object.
-        size_t nbytes = ntemplate->size();
         size_t offset = 0;
         while (nbytes) {
-            uintptr_t value = *(uintptr_t *)(ntemplate->inlineTypedMem() + offset);
+            uintptr_t value = *(uintptr_t *)(memory + offset);
             storePtr(ImmWord(value),
                      Address(obj, InlineTypedObject::offsetOfDataStart() + offset));
             nbytes = (nbytes < sizeof(uintptr_t)) ? 0 : nbytes - sizeof(uintptr_t);
             offset += sizeof(uintptr_t);
         }
+    } else if (templateObj->is<UnboxedPlainObject>()) {
+        const UnboxedLayout &layout = templateObj->as<UnboxedPlainObject>().layout();
+
+        // Initialize reference fields of the object, per UnboxedPlainObject::create.
+        if (const int32_t *list = layout.traceList()) {
+            while (*list != -1) {
+                storePtr(ImmGCPtr(GetJitContext()->runtime->names().empty),
+                         Address(obj, UnboxedPlainObject::offsetOfData() + *list));
+                list++;
+            }
+            list++;
+            while (*list != -1) {
+                storePtr(ImmWord(0),
+                         Address(obj, UnboxedPlainObject::offsetOfData() + *list));
+                list++;
+            }
+            // Unboxed objects don't have Values to initialize.
+            MOZ_ASSERT(*(list + 1) == -1);
+        }
     } else {
         MOZ_CRASH("Unknown object");
     }
 
 #ifdef JS_GC_TRACE
     RegisterSet regs = RegisterSet::Volatile();
     PushRegsInMask(regs);
     regs.takeUnchecked(obj);
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -689,17 +689,18 @@ class MacroAssembler : public MacroAssem
     void canonicalizeFloat(FloatRegister reg) {
         Label notNaN;
         branchFloat(DoubleOrdered, reg, reg, &notNaN);
         loadConstantFloat32(float(JS::GenericNaN()), reg);
         bind(&notNaN);
     }
 
     template<typename T>
-    void loadFromTypedArray(Scalar::Type arrayType, const T &src, AnyRegister dest, Register temp, Label *fail);
+    void loadFromTypedArray(Scalar::Type arrayType, const T &src, AnyRegister dest, Register temp, Label *fail,
+                            bool canonicalizeDoubles = true);
 
     template<typename T>
     void loadFromTypedArray(Scalar::Type arrayType, const T &src, const ValueOperand &dest, bool allowDouble,
                             Register temp, Label *fail);
 
     template<typename S, typename T>
     void storeToTypedIntArray(Scalar::Type arrayType, const S &value, const T &dest) {
         switch (arrayType) {
@@ -727,16 +728,27 @@ class MacroAssembler : public MacroAssem
 
     template<typename S, typename T>
     void atomicBinopToTypedIntArray(AtomicOp op, Scalar::Type arrayType, const S &value,
                                     const T &mem, Register temp1, Register temp2, AnyRegister output);
 
     void storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, const BaseIndex &dest);
     void storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, const Address &dest);
 
+    // Load a property from an UnboxedPlainObject.
+    template <typename T>
+    void loadUnboxedProperty(T address, JSValueType type, TypedOrValueRegister output);
+
+    // Store a property to an UnboxedPlainObject, without triggering barriers.
+    // If failure is null, the value definitely has a type suitable for storing
+    // in the property.
+    template <typename T>
+    void storeUnboxedProperty(T address, JSValueType type,
+                              ConstantOrRegister value, Label *failure);
+
     Register extractString(const Address &address, Register scratch) {
         return extractObject(address, scratch);
     }
     Register extractString(const ValueOperand &value, Register scratch) {
         return extractObject(value, scratch);
     }
 
     using MacroAssemblerSpecific::extractTag;
@@ -799,17 +811,17 @@ class MacroAssembler : public MacroAssem
     void initGCSlots(Register obj, Register temp, NativeObject *templateObj, bool initFixedSlots);
 
   public:
     void callMallocStub(size_t nbytes, Register result, Label *fail);
     void callFreeStub(Register slots);
     void createGCObject(Register result, Register temp, JSObject *templateObj,
                         gc::InitialHeap initialHeap, Label *fail, bool initFixedSlots = true);
 
-    void newGCThing(Register result, Register temp, NativeObject *templateObj,
+    void newGCThing(Register result, Register temp, JSObject *templateObj,
                      gc::InitialHeap initialHeap, Label *fail);
     void initGCThing(Register obj, Register temp, JSObject *templateObj,
                      bool initFixedSlots = true);
 
     void newGCString(Register result, Register temp, Label *fail);
     void newGCFatInlineString(Register result, Register temp, Label *fail);
 
     // Compares two strings for equality based on the JSOP.
--- a/js/src/jit/OptimizationTracking.h
+++ b/js/src/jit/OptimizationTracking.h
@@ -27,31 +27,35 @@ namespace jit {
     _(GetProp_InferredConstant,                         \
       "getprop inferred constant")                      \
     _(GetProp_Constant,                                 \
       "getprop constant")                               \
     _(GetProp_TypedObject,                              \
       "getprop TypedObject")                            \
     _(GetProp_DefiniteSlot,                             \
       "getprop definite slot")                          \
+    _(GetProp_Unboxed,                                  \
+      "getprop unboxed object")                         \
     _(GetProp_CommonGetter,                             \
       "getprop common getter")                          \
     _(GetProp_InlineAccess,                             \
       "getprop inline access")                          \
     _(GetProp_Innerize,                                 \
       "getprop innerize (access on global window)")     \
     _(GetProp_InlineCache,                              \
       "getprop IC")                                     \
                                                         \
     _(SetProp_CommonSetter,                             \
       "setprop common setter")                          \
     _(SetProp_TypedObject,                              \
       "setprop TypedObject")                            \
     _(SetProp_DefiniteSlot,                             \
       "setprop definite slot")                          \
+    _(SetProp_Unboxed,                                  \
+      "setprop unboxed object")                         \
     _(SetProp_InlineAccess,                             \
       "setprop inline access")                          \
                                                         \
     _(GetElem_TypedObject,                              \
       "getprop TypedObject")                            \
     _(GetElem_Dense,                                    \
       "getelem dense")                                  \
     _(GetElem_TypedStatic,                              \
@@ -103,22 +107,30 @@ namespace jit {
     _(UnknownProperties,                                                \
       "unknown properties")                                             \
     _(Singleton,                                                        \
       "is singleton")                                                   \
     _(NotSingleton,                                                     \
       "is not singleton")                                               \
     _(NotFixedSlot,                                                     \
       "property not in fixed slot")                                     \
+    _(InconsistentFixedSlot,                                            \
+      "property not in a consistent fixed slot")                        \
     _(NotObject,                                                        \
       "not definitely an object")                                       \
     _(NotStruct,                                                        \
       "not definitely a TypedObject struct")                            \
+    _(NotUnboxed,                                                       \
+      "not definitely an unboxed object")                               \
     _(StructNoField,                                                    \
       "struct doesn't definitely have field")                           \
+    _(InconsistentFieldType,                                            \
+      "unboxed property does not consistent type")                      \
+    _(InconsistentFieldOffset,                                          \
+      "unboxed property does not consistent offset")                    \
     _(NeedsTypeBarrier,                                                 \
       "needs type barrier")                                             \
     _(InDictionaryMode,                                                 \
       "object in dictionary mode")                                      \
     _(NoProtoFound,                                                     \
       "no proto found")                                                 \
     _(MultiProtoPaths,                                                  \
       "not all paths to property go through same proto")                \
--- a/js/src/jit/ScalarReplacement.cpp
+++ b/js/src/jit/ScalarReplacement.cpp
@@ -107,16 +107,20 @@ IsObjectEscaped(MInstruction *ins, JSObj
         obj = ins->toNewObject()->templateObject();
     else if (ins->isCreateThisWithTemplate())
         obj = ins->toCreateThisWithTemplate()->templateObject();
     else if (ins->isNewCallObject())
         obj = ins->toNewCallObject()->templateObject();
     else
         obj = objDefault;
 
+    // Don't optimize unboxed objects, which aren't handled by MObjectState.
+    if (obj->is<UnboxedPlainObject>())
+        return true;
+
     // Check if the object is escaped. If the object is not the first argument
     // of either a known Store / Load, then we consider it as escaped. This is a
     // cheap and conservative escape analysis.
     for (MUseIterator i(ins->usesBegin()); i != ins->usesEnd(); i++) {
         MNode *consumer = (*i)->consumer();
         if (!consumer->isDefinition()) {
             // Cannot optimize if it is observable from fun.arguments or others.
             if (!consumer->toResumePoint()->isRecoverableOperand(*i)) {
--- a/js/src/jit/arm/Lowering-arm.cpp
+++ b/js/src/jit/arm/Lowering-arm.cpp
@@ -388,17 +388,17 @@ LIRGeneratorARM::visitGuardShape(MGuardS
 
 void
 LIRGeneratorARM::visitGuardObjectType(MGuardObjectType *ins)
 {
     MOZ_ASSERT(ins->obj()->type() == MIRType_Object);
 
     LDefinition tempObj = temp(LDefinition::OBJECT);
     LGuardObjectType *guard = new(alloc()) LGuardObjectType(useRegister(ins->obj()), tempObj);
-    assignSnapshot(guard, Bailout_ObjectIdentityOrTypeGuard);
+    assignSnapshot(guard, ins->bailoutKind());
     add(guard, ins);
     redefine(ins, ins->obj());
 }
 
 void
 LIRGeneratorARM::lowerUrshD(MUrsh *mir)
 {
     MDefinition *lhs = mir->lhs();
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -2681,16 +2681,30 @@ MacroAssemblerARMCompat::cmpPtr(const Ad
 
 void
 MacroAssemblerARMCompat::cmpPtr(const Address &lhs, ImmPtr rhs)
 {
     cmpPtr(lhs, ImmWord(uintptr_t(rhs.value)));
 }
 
 void
+MacroAssemblerARMCompat::cmpPtr(const Address &lhs, ImmGCPtr rhs)
+{
+    loadPtr(lhs, secondScratchReg_);
+    ma_cmp(secondScratchReg_, rhs);
+}
+
+void
+MacroAssemblerARMCompat::cmpPtr(const Address &lhs, Imm32 rhs)
+{
+    loadPtr(lhs, secondScratchReg_);
+    ma_cmp(secondScratchReg_, rhs);
+}
+
+void
 MacroAssemblerARMCompat::setStackArg(Register reg, uint32_t arg)
 {
     ma_dataTransferN(IsStore, 32, true, sp, Imm32(arg * sizeof(intptr_t)), reg);
 
 }
 
 void
 MacroAssemblerARMCompat::subPtr(Imm32 imm, const Register dest)
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -1124,16 +1124,29 @@ class MacroAssemblerARMCompat : public M
         else
             load32(address, dest.gpr());
     }
 
     template <typename T>
     void storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T &dest,
                            MIRType slotType);
 
+    template <typename T>
+    void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) {
+        switch (nbytes) {
+          case 4:
+            storePtr(value.payloadReg(), address);
+            return;
+          case 1:
+            store8(value.payloadReg(), address);
+            return;
+          default: MOZ_CRASH("Bad payload width");
+        }
+    }
+
     void moveValue(const Value &val, const ValueOperand &dest);
 
     void moveValue(const ValueOperand &src, const ValueOperand &dest) {
         Register s0 = src.typeReg(), d0 = dest.typeReg(),
                  s1 = src.payloadReg(), d1 = dest.payloadReg();
 
         // Either one or both of the source registers could be the same as a
         // destination register.
@@ -1617,24 +1630,26 @@ class MacroAssemblerARMCompat : public M
         add32(Imm32(1), ToPayload(addr));
     }
 
     void cmp32(Register lhs, Imm32 rhs);
     void cmp32(Register lhs, Register rhs);
     void cmp32(const Operand &lhs, Imm32 rhs);
     void cmp32(const Operand &lhs, Register rhs);
 
+    void cmpPtr(Register lhs, Register rhs);
     void cmpPtr(Register lhs, ImmWord rhs);
     void cmpPtr(Register lhs, ImmPtr rhs);
-    void cmpPtr(Register lhs, Register rhs);
     void cmpPtr(Register lhs, ImmGCPtr rhs);
     void cmpPtr(Register lhs, Imm32 rhs);
     void cmpPtr(const Address &lhs, Register rhs);
     void cmpPtr(const Address &lhs, ImmWord rhs);
     void cmpPtr(const Address &lhs, ImmPtr rhs);
+    void cmpPtr(const Address &lhs, ImmGCPtr rhs);
+    void cmpPtr(const Address &lhs, Imm32 rhs);
 
     void subPtr(Imm32 imm, const Register dest);
     void subPtr(const Address &addr, const Register dest);
     void subPtr(Register src, Register dest);
     void subPtr(Register src, const Address &dest);
     void addPtr(Imm32 imm, const Register dest);
     void addPtr(Imm32 imm, const Address &dest);
     void addPtr(ImmWord imm, const Register dest) {
--- a/js/src/jit/mips/Lowering-mips.cpp
+++ b/js/src/jit/mips/Lowering-mips.cpp
@@ -379,17 +379,17 @@ LIRGeneratorMIPS::visitGuardShape(MGuard
 
 void
 LIRGeneratorMIPS::visitGuardObjectType(MGuardObjectType *ins)
 {
     MOZ_ASSERT(ins->obj()->type() == MIRType_Object);
 
     LDefinition tempObj = temp(LDefinition::OBJECT);
     LGuardObjectType *guard = new(alloc()) LGuardObjectType(useRegister(ins->obj()), tempObj);
-    assignSnapshot(guard, Bailout_ObjectIdentityOrTypeGuard);
+    assignSnapshot(guard, ins->bailoutKind());
     add(guard, ins);
     redefine(ins, ins->obj());
 }
 
 void
 LIRGeneratorMIPS::lowerUrshD(MUrsh *mir)
 {
     MDefinition *lhs = mir->lhs();
--- a/js/src/jit/mips/MacroAssembler-mips.h
+++ b/js/src/jit/mips/MacroAssembler-mips.h
@@ -864,16 +864,29 @@ public:
         else
             load32(address, dest.gpr());
     }
 
     template <typename T>
     void storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T &dest,
                            MIRType slotType);
 
+    template <typename T>
+    void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) {
+        switch (nbytes) {
+          case 4:
+            storePtr(value.payloadReg(), address);
+            return;
+          case 1:
+            store8(value.payloadReg(), address);
+            return;
+          default: MOZ_CRASH("Bad payload width");
+        }
+    }
+
     void moveValue(const Value &val, const ValueOperand &dest);
 
     void moveValue(const ValueOperand &src, const ValueOperand &dest) {
         Register s0 = src.typeReg(), d0 = dest.typeReg(),
                  s1 = src.payloadReg(), d1 = dest.payloadReg();
 
         // Either one or both of the source registers could be the same as a
         // destination register.
--- a/js/src/jit/none/MacroAssembler-none.h
+++ b/js/src/jit/none/MacroAssembler-none.h
@@ -395,16 +395,17 @@ class MacroAssemblerNone : public Assemb
     Condition testStringTruthy(bool, ValueOperand) { MOZ_CRASH(); }
     void branchTestInt32Truthy(bool, ValueOperand, Label *) { MOZ_CRASH(); }
     void branchTestBooleanTruthy(bool, ValueOperand, Label *) { MOZ_CRASH(); }
     void branchTestStringTruthy(bool, ValueOperand, Label *) { MOZ_CRASH(); }
     void branchTestDoubleTruthy(bool, FloatRegister, Label *) { MOZ_CRASH(); }
 
     template <typename T> void loadUnboxedValue(T, MIRType, AnyRegister) { MOZ_CRASH(); }
     template <typename T> void storeUnboxedValue(ConstantOrRegister, MIRType, T, MIRType) { MOZ_CRASH(); }
+    template <typename T> void storeUnboxedPayload(ValueOperand value, T, size_t) { MOZ_CRASH(); }
 
     void rshiftPtr(Imm32, Register) { MOZ_CRASH(); }
     void rshiftPtrArithmetic(Imm32, Register) { MOZ_CRASH(); }
     void lshiftPtr(Imm32, Register) { MOZ_CRASH(); }
     template <typename T, typename S> void xorPtr(T, S) { MOZ_CRASH(); }
     template <typename T, typename S> void xor32(T, S) { MOZ_CRASH(); }
     template <typename T, typename S> void orPtr(T, S) { MOZ_CRASH(); }
     template <typename T, typename S> void or32(T, S) { MOZ_CRASH(); }
--- a/js/src/jit/shared/Lowering-x86-shared.cpp
+++ b/js/src/jit/shared/Lowering-x86-shared.cpp
@@ -44,17 +44,17 @@ LIRGeneratorX86Shared::visitGuardShape(M
 }
 
 void
 LIRGeneratorX86Shared::visitGuardObjectType(MGuardObjectType *ins)
 {
     MOZ_ASSERT(ins->obj()->type() == MIRType_Object);
 
     LGuardObjectType *guard = new(alloc()) LGuardObjectType(useRegisterAtStart(ins->obj()));
-    assignSnapshot(guard, Bailout_ObjectIdentityOrTypeGuard);
+    assignSnapshot(guard, ins->bailoutKind());
     add(guard, ins);
     redefine(ins, ins->obj());
 }
 
 void
 LIRGeneratorX86Shared::visitPowHalf(MPowHalf *ins)
 {
     MDefinition *input = ins->input();
--- a/js/src/jit/shared/MacroAssembler-x86-shared.h
+++ b/js/src/jit/shared/MacroAssembler-x86-shared.h
@@ -645,33 +645,76 @@ class MacroAssemblerX86Shared : public A
         zeroDouble(ScratchDoubleReg);
         vucomisd(reg, ScratchDoubleReg);
         return truthy ? NonZero : Zero;
     }
     void branchTestDoubleTruthy(bool truthy, FloatRegister reg, Label *label) {
         Condition cond = testDoubleTruthy(truthy, reg);
         j(cond, label);
     }
+
+    // Class which ensures that registers used in byte ops are compatible with
+    // such instructions, even if the original register passed in wasn't. This
+    // only applies to x86, as on x64 all registers are valid single byte regs.
+    // This doesn't lead to great code but helps to simplify code generation.
+    class AutoEnsureByteRegister {
+        MacroAssemblerX86Shared *masm;
+        Register reg_;
+        bool read_;
+
+      public:
+        template <typename T>
+        AutoEnsureByteRegister(MacroAssemblerX86Shared *masm, T address, Register reg, bool read)
+          : masm(masm), reg_(reg), read_(read)
+        {
+            if (!GeneralRegisterSet(Registers::SingleByteRegs).has(reg_)) {
+                MOZ_ASSERT(address.base != StackPointer);
+                masm->push(eax);
+                if (read)
+                    masm->mov(reg_, eax);
+            }
+        }
+
+        ~AutoEnsureByteRegister() {
+            if (!GeneralRegisterSet(Registers::SingleByteRegs).has(reg_)) {
+                if (!read_)
+                    masm->mov(eax, reg_);
+                masm->pop(eax);
+            }
+        }
+
+        Register reg() {
+            if (!GeneralRegisterSet(Registers::SingleByteRegs).has(reg_))
+                return eax;
+            return reg_;
+        }
+    };
+
     void load8ZeroExtend(const Address &src, Register dest) {
         movzbl(Operand(src), dest);
     }
     void load8ZeroExtend(const BaseIndex &src, Register dest) {
         movzbl(Operand(src), dest);
     }
     void load8SignExtend(const Address &src, Register dest) {
         movsbl(Operand(src), dest);
     }
     void load8SignExtend(const BaseIndex &src, Register dest) {
         movsbl(Operand(src), dest);
     }
-    template <typename S, typename T>
-    void store8(const S &src, const T &dest) {
+    template <typename T>
+    void store8(Imm32 src, const T &dest) {
         movb(src, Operand(dest));
     }
     template <typename T>
+    void store8(Register src, const T &dest) {
+        AutoEnsureByteRegister ensure(this, dest, src, /* read = */ true);
+        movb(ensure.reg(), Operand(dest));
+    }
+    template <typename T>
     void compareExchange8ZeroExtend(const T &mem, Register oldval, Register newval, Register output) {
         MOZ_ASSERT(output == eax);
         MOZ_ASSERT(newval == ebx || newval == ecx || newval == edx);
         if (oldval != output)
             movl(oldval, output);
         lock_cmpxchg8(newval, Operand(mem));
         movzbl(output, output);
     }
--- a/js/src/jit/x64/MacroAssembler-x64.h
+++ b/js/src/jit/x64/MacroAssembler-x64.h
@@ -1337,16 +1337,33 @@ class MacroAssemblerX64 : public MacroAs
             movl(Operand(src), dest.gpr());
         else
             unboxNonDouble(Operand(src), dest.gpr());
     }
 
     template <typename T>
     void storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T &dest, MIRType slotType);
 
+    template <typename T>
+    void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) {
+        switch (nbytes) {
+          case 8:
+            unboxNonDouble(value, ScratchReg);
+            storePtr(ScratchReg, address);
+            return;
+          case 4:
+            store32(value.valueReg(), address);
+            return;
+          case 1:
+            store8(value.valueReg(), address);
+            return;
+          default: MOZ_CRASH("Bad payload width");
+        }
+    }
+
     void loadInstructionPointerAfterCall(Register dest) {
         loadPtr(Address(StackPointer, 0x0), dest);
     }
 
     void convertUInt32ToDouble(Register src, FloatRegister dest) {
         vcvtsq2sd(src, dest, dest);
     }
 
--- a/js/src/jit/x86/MacroAssembler-x86.h
+++ b/js/src/jit/x86/MacroAssembler-x86.h
@@ -545,16 +545,19 @@ class MacroAssemblerX86 : public MacroAs
         cmp32(lhs, rhs);
     }
     void cmpPtr(const Address &lhs, const ImmWord rhs) {
         cmpPtr(Operand(lhs), rhs);
     }
     void cmpPtr(const Address &lhs, const ImmPtr rhs) {
         cmpPtr(lhs, ImmWord(uintptr_t(rhs.value)));
     }
+    void cmpPtr(const Address &lhs, const ImmGCPtr rhs) {
+        cmpPtr(Operand(lhs), rhs);
+    }
     void cmpPtr(Register lhs, Register rhs) {
         cmp32(lhs, rhs);
     }
     void cmpPtr(const Operand &lhs, ImmMaybeNurseryPtr rhs) {
         cmpl(rhs, lhs);
     }
     void testPtr(Register lhs, Register rhs) {
         test32(lhs, rhs);
@@ -1060,16 +1063,29 @@ class MacroAssemblerX86 : public MacroAs
         else
             movl(Operand(src), dest.gpr());
     }
 
     template <typename T>
     void storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T &dest,
                            MIRType slotType);
 
+    template <typename T>
+    void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) {
+        switch (nbytes) {
+          case 4:
+            storePtr(value.payloadReg(), address);
+            return;
+          case 1:
+            store8(value.payloadReg(), address);
+            return;
+          default: MOZ_CRASH("Bad payload width");
+        }
+    }
+
     void rshiftPtr(Imm32 imm, Register dest) {
         shrl(imm, dest);
     }
     void rshiftPtrArithmetic(Imm32 imm, Register dest) {
         sarl(imm, dest);
     }
     void lshiftPtr(Imm32 imm, Register dest) {
         shll(imm, dest);
--- a/layout/base/SelectionCarets.cpp
+++ b/layout/base/SelectionCarets.cpp
@@ -156,17 +156,17 @@ nsEventStatus
 SelectionCarets::HandleEvent(WidgetEvent* aEvent)
 {
   WidgetMouseEvent *mouseEvent = aEvent->AsMouseEvent();
   if (mouseEvent && mouseEvent->reason == WidgetMouseEvent::eSynthesized) {
     return nsEventStatus_eIgnore;
   }
 
   WidgetTouchEvent *touchEvent = aEvent->AsTouchEvent();
-  nsIntPoint movePoint;
+  LayoutDeviceIntPoint movePoint;
   int32_t nowTouchId = -1;
   if (touchEvent && !touchEvent->touches.IsEmpty()) {
     // If touch happened, just grab event with same identifier
     if (mActiveTouchId >= 0) {
       for (uint32_t i = 0; i < touchEvent->touches.Length(); ++i) {
         if (touchEvent->touches[i]->Identifier() == mActiveTouchId) {
           movePoint = touchEvent->touches[i]->mRefPoint;
           nowTouchId = touchEvent->touches[i]->Identifier();
@@ -178,17 +178,17 @@ SelectionCarets::HandleEvent(WidgetEvent
       if (nowTouchId == -1) {
         return nsEventStatus_eConsumeNoDefault;
       }
     } else {
       movePoint = touchEvent->touches[0]->mRefPoint;
       nowTouchId = touchEvent->touches[0]->Identifier();
     }
   } else if (mouseEvent) {
-    movePoint = LayoutDeviceIntPoint::ToUntyped(mouseEvent->AsGUIEvent()->refPoint);
+    movePoint = mouseEvent->AsGUIEvent()->refPoint;
   }
 
   // Get event coordinate relative to root frame
   nsIFrame* rootFrame = mPresShell->GetRootFrame();
   if (!rootFrame) {
     return nsEventStatus_eIgnore;
   }
   nsPoint ptInRoot =
--- a/layout/base/TouchCaret.cpp
+++ b/layout/base/TouchCaret.cpp
@@ -624,32 +624,31 @@ TouchCaret::HandleEvent(WidgetEvent* aEv
 
 nsPoint
 TouchCaret::GetEventPosition(WidgetTouchEvent* aEvent, int32_t aIdentifier)
 {
   for (size_t i = 0; i < aEvent->touches.Length(); i++) {
     if (aEvent->touches[i]->mIdentifier == aIdentifier) {
       // Get event coordinate relative to canvas frame.
       nsIFrame* canvasFrame = GetCanvasFrame();
-      nsIntPoint touchIntPoint = aEvent->touches[i]->mRefPoint;
+      LayoutDeviceIntPoint touchIntPoint = aEvent->touches[i]->mRefPoint;
       return nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
                                                           touchIntPoint,
                                                           canvasFrame);
     }
   }
   return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
 }
 
 nsPoint
 TouchCaret::GetEventPosition(WidgetMouseEvent* aEvent)
 {
   // Get event coordinate relative to canvas frame.
   nsIFrame* canvasFrame = GetCanvasFrame();
-  nsIntPoint mouseIntPoint =
-    LayoutDeviceIntPoint::ToUntyped(aEvent->AsGUIEvent()->refPoint);
+  LayoutDeviceIntPoint mouseIntPoint = aEvent->AsGUIEvent()->refPoint;
   return nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
                                                       mouseIntPoint,
                                                       canvasFrame);
 }
 
 nsEventStatus
 TouchCaret::HandleMouseMoveEvent(WidgetMouseEvent* aEvent)
 {
--- a/layout/base/nsBidiPresUtils.cpp
+++ b/layout/base/nsBidiPresUtils.cpp
@@ -2215,17 +2215,17 @@ void nsBidiPresUtils::CopyLogicalToVisua
                                           nsAString& aDest,
                                           nsBidiLevel aBaseDirection,
                                           bool aOverride)
 {
   aDest.SetLength(0);
   uint32_t srcLength = aSource.Length();
   if (srcLength == 0)
     return;
-  if (!aDest.SetLength(srcLength, fallible_t())) {
+  if (!aDest.SetLength(srcLength, fallible)) {
     return;
   }
   nsAString::const_iterator fromBegin, fromEnd;
   nsAString::iterator toBegin;
   aSource.BeginReading(fromBegin);
   aSource.EndReading(fromEnd);
   aDest.BeginWriting(toBegin);
 
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -5202,21 +5202,23 @@ nsDisplayTransform::GetResultingTransfor
     // parent transform however *is* the reference frame, so we pass true for
     // aOffsetByOrigin to convert into the correct coordinate space.
     gfx3DMatrix parent =
       GetResultingTransformMatrixInternal(props,
                                           aOrigin - frame->GetPosition(),
                                           aAppUnitsPerPixel, nullptr,
                                           aOutAncestor, !frame->IsTransformed());
 
-    result.ChangeBasis(offsetBetweenOrigins);
+    if (aOffsetByOrigin) {
+      result.Translate(-aProperties.mToTransformOrigin);
+      result.TranslatePost(offsetBetweenOrigins);
+    } else {
+      result.ChangeBasis(offsetBetweenOrigins);
+    }
     result = result * parent;
-    if (aOffsetByOrigin) {
-      result.Translate(roundedOrigin);
-    }
     return result;
   }
 
   if (aOffsetByOrigin) {
     // We can fold the final translation by roundedOrigin into the first matrix
     // basis change translation. This is more stable against variation due to
     // insufficient floating point precision than reversing the translation
     // afterwards.
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1907,40 +1907,40 @@ nsLayoutUtils::GetEventCoordinatesRelati
                   aEvent->mClass != eSimpleGestureEventClass &&
                   aEvent->mClass != ePointerEventClass &&
                   aEvent->mClass != eGestureNotifyEventClass &&
                   aEvent->mClass != eTouchEventClass &&
                   aEvent->mClass != eQueryContentEventClass))
     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
 
   return GetEventCoordinatesRelativeTo(aEvent,
-           LayoutDeviceIntPoint::ToUntyped(aEvent->AsGUIEvent()->refPoint),
+           aEvent->AsGUIEvent()->refPoint,
            aFrame);
 }
 
 nsPoint
 nsLayoutUtils::GetEventCoordinatesRelativeTo(const WidgetEvent* aEvent,
-                                             const nsIntPoint aPoint,
+                                             const LayoutDeviceIntPoint& aPoint,
                                              nsIFrame* aFrame)
 {
   if (!aFrame) {
     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
   }
 
   nsIWidget* widget = aEvent->AsGUIEvent()->widget;
   if (!widget) {
     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
   }
 
   return GetEventCoordinatesRelativeTo(widget, aPoint, aFrame);
 }
 
 nsPoint
 nsLayoutUtils::GetEventCoordinatesRelativeTo(nsIWidget* aWidget,
-                                             const nsIntPoint aPoint,
+                                             const LayoutDeviceIntPoint& aPoint,
                                              nsIFrame* aFrame)
 {
   if (!aFrame || !aWidget) {
     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
   }
 
   nsView* view = aFrame->GetView();
   if (view) {
@@ -2653,26 +2653,27 @@ static nsIntPoint WidgetToWidgetOffset(n
   if (fromRoot == toRoot) {
     return fromOffset - toOffset;
   }
   return aFrom->WidgetToScreenOffset() - aTo->WidgetToScreenOffset();
 }
 
 nsPoint
 nsLayoutUtils::TranslateWidgetToView(nsPresContext* aPresContext,
-                                     nsIWidget* aWidget, nsIntPoint aPt,
+                                     nsIWidget* aWidget, const LayoutDeviceIntPoint& aPt,
                                      nsView* aView)
 {
   nsPoint viewOffset;
   nsIWidget* viewWidget = aView->GetNearestWidget(&viewOffset);
   if (!viewWidget) {
     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
   }
 
-  nsIntPoint widgetPoint = aPt + WidgetToWidgetOffset(aWidget, viewWidget);
+  LayoutDeviceIntPoint widgetPoint = aPt +
+    LayoutDeviceIntPoint::FromUntyped(WidgetToWidgetOffset(aWidget, viewWidget));
   nsPoint widgetAppUnits(aPresContext->DevPixelsToAppUnits(widgetPoint.x),
                          aPresContext->DevPixelsToAppUnits(widgetPoint.y));
   return widgetAppUnits - viewOffset;
 }
 
 nsIntPoint
 nsLayoutUtils::TranslateViewToWidget(nsPresContext* aPresContext,
                                      nsView* aView, nsPoint aPt,
@@ -7641,25 +7642,18 @@ nsLayoutUtils::CalculateExpandedScrollab
     scrollableRect.height = compSize.height;
   }
   return scrollableRect;
 }
 
 /* static */ bool
 nsLayoutUtils::WantSubAPZC()
 {
-  // TODO Turn this on for inprocess OMTC on all platforms
-  bool wantSubAPZC = gfxPrefs::AsyncPanZoomEnabled() &&
-                     gfxPrefs::APZSubframeEnabled();
-#ifdef MOZ_WIDGET_GONK
-  if (XRE_GetProcessType() != GeckoProcessType_Content) {
-    wantSubAPZC = false;
-  }
-#endif
-  return wantSubAPZC;
+  return gfxPrefs::AsyncPanZoomEnabled() &&
+         gfxPrefs::APZSubframeEnabled();
 }
 
 /* static */ bool
 nsLayoutUtils::UsesAsyncScrolling()
 {
 #ifdef MOZ_WIDGET_ANDROID
   // We always have async scrolling for android
   return true;
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -674,31 +674,31 @@ public:
    * @param aPoint the point to get the coordinates relative to
    * @param aFrame the frame to make coordinates relative to
    * @return the point, or (NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) if
    * for some reason the coordinates for the mouse are not known (e.g.,
    * the event is not a GUI event).
    */
   static nsPoint GetEventCoordinatesRelativeTo(
                    const mozilla::WidgetEvent* aEvent,
-                   const nsIntPoint aPoint,
+                   const mozilla::LayoutDeviceIntPoint& aPoint,
                    nsIFrame* aFrame);
 
   /**
    * Get the coordinates of a given point relative to a widget and a
    * given frame.
    * @param aWidget the event src widget
    * @param aPoint the point to get the coordinates relative to
    * @param aFrame the frame to make coordinates relative to
    * @return the point, or (NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) if
    * for some reason the coordinates for the mouse are not known (e.g.,
    * the event is not a GUI event).
    */
   static nsPoint GetEventCoordinatesRelativeTo(nsIWidget* aWidget,
-                                               const nsIntPoint aPoint,
+                                               const mozilla::LayoutDeviceIntPoint& aPoint,
                                                nsIFrame* aFrame);
 
   /**
    * Get the popup frame of a given native mouse event.
    * @param aPresContext only check popups within aPresContext or a descendant
    * @param aEvent  the event.
    * @return        Null, if there is no popup frame at the point, otherwise,
    *                returns top-most popup frame at the point.
@@ -711,17 +711,18 @@ public:
    * Translate from widget coordinates to the view's coordinates
    * @param aPresContext the PresContext for the view
    * @param aWidget the widget
    * @param aPt the point relative to the widget
    * @param aView  view to which returned coordinates are relative
    * @return the point in the view's coordinates
    */
   static nsPoint TranslateWidgetToView(nsPresContext* aPresContext,
-                                       nsIWidget* aWidget, nsIntPoint aPt,
+                                       nsIWidget* aWidget,
+                                       const mozilla::LayoutDeviceIntPoint& aPt,
                                        nsView* aView);
 
   /**
    * Translate from view coordinates to the widget's coordinates.
    * @param aPresContext the PresContext for the view
    * @param aView the view
    * @param aPt the point relative to the view
    * @param aWidget the widget to which returned coordinates are relative
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -6748,18 +6748,17 @@ PresShell::RecordMouseLocation(WidgetGUI
        aEvent->AsMouseEvent()->reason == WidgetMouseEvent::eReal) ||
       aEvent->message == NS_MOUSE_ENTER ||
       aEvent->message == NS_MOUSE_BUTTON_DOWN ||
       aEvent->message == NS_MOUSE_BUTTON_UP) {
     nsIFrame* rootFrame = GetRootFrame();
     if (!rootFrame) {
       nsView* rootView = mViewManager->GetRootView();
       mMouseLocation = nsLayoutUtils::TranslateWidgetToView(mPresContext,
-        aEvent->widget, LayoutDeviceIntPoint::ToUntyped(aEvent->refPoint),
-        rootView);
+        aEvent->widget, aEvent->refPoint, rootView);
     } else {
       mMouseLocation =
         nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, rootFrame);
     }
 #ifdef DEBUG_MOUSE_LOCATION
     if (aEvent->message == NS_MOUSE_ENTER)
       printf("[ps=%p]got mouse enter for %p\n",
              this, aEvent->widget);
@@ -8513,22 +8512,22 @@ PresShell::AdjustContextMenuKeyEvent(Wid
           LayoutDeviceIntPoint::FromAppUnitsToNearest(offset, mPresContext->AppUnitsPerDevPixel());
       }
     }
   } else {
     aEvent->widget = nullptr;
   }
 
   // see if we should use the caret position for the popup
-  nsIntPoint caretPoint;
+  LayoutDeviceIntPoint caretPoint;
   // Beware! This may flush notifications via synchronous
   // ScrollSelectionIntoView.
   if (PrepareToUseCaretPosition(aEvent->widget, caretPoint)) {
     // caret position is good
-    aEvent->refPoint = LayoutDeviceIntPoint::FromUntyped(caretPoint);
+    aEvent->refPoint = caretPoint;
     return true;
   }
 
   // If we're here because of the key-equiv for showing context menus, we
   // have to reset the event target to the currently focused element. Get it
   // from the focus controller.
   nsCOMPtr<nsIDOMElement> currentFocus;
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
@@ -8559,17 +8558,18 @@ PresShell::AdjustContextMenuKeyEvent(Wid
 //    coordinates of that position is returned in aTargetPt. This function
 //    will also scroll the window as needed to make the caret visible.
 //
 //    The event widget should be the widget that generated the event, and
 //    whose coordinate system the resulting event's refPoint should be
 //    relative to.  The returned point is in device pixels realtive to the
 //    widget passed in.
 bool
-PresShell::PrepareToUseCaretPosition(nsIWidget* aEventWidget, nsIntPoint& aTargetPt)
+PresShell::PrepareToUseCaretPosition(nsIWidget* aEventWidget,
+                                     LayoutDeviceIntPoint& aTargetPt)
 {
   nsresult rv;
 
   // check caret visibility
   nsRefPtr<nsCaret> caret = GetCaret();
   NS_ENSURE_TRUE(caret, false);
 
   bool caretVisible = caret->IsVisible();
--- a/layout/base/nsPresShell.h
+++ b/layout/base/nsPresShell.h
@@ -685,17 +685,18 @@ protected:
    * view.
    *
    * Returns true if the context menu event should fire and false if it should
    * not.
    */
   bool AdjustContextMenuKeyEvent(mozilla::WidgetMouseEvent* aEvent);
 
   //
-  bool PrepareToUseCaretPosition(nsIWidget* aEventWidget, nsIntPoint& aTargetPt);
+  bool PrepareToUseCaretPosition(nsIWidget* aEventWidget,
+                                 mozilla::LayoutDeviceIntPoint& aTargetPt);
 
   // Get the selected item and coordinates in device pixels relative to root
   // document's root view for element, first ensuring the element is onscreen
   void GetCurrentItemAndPositionForElement(nsIDOMElement *aCurrentEl,
                                            nsIContent **aTargetToUse,
                                            mozilla::LayoutDeviceIntPoint& aTargetPt,
                                            nsIWidget *aRootWidget);
 
--- a/layout/forms/nsNumberControlFrame.cpp
+++ b/layout/forms/nsNumberControlFrame.cpp
@@ -580,18 +580,17 @@ nsNumberControlFrame::GetSpinButtonForPo
     // In the case that the up/down buttons are hidden (display:none) we use
     // just the spin box element, spinning up if the pointer is over the top
     // half of the element, or down if it's over the bottom half. This is
     // important to handle since this is the state things are in for the
     // default UA style sheet. See the comment in forms.css for why.
     LayoutDeviceIntPoint absPoint = aEvent->refPoint;
     nsPoint point =
       nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
-                       LayoutDeviceIntPoint::ToUntyped(absPoint),
-                       mSpinBox->GetPrimaryFrame());
+                       absPoint, mSpinBox->GetPrimaryFrame());
     if (point != nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)) {
       if (point.y < mSpinBox->GetPrimaryFrame()->GetSize().height / 2) {
         return eSpinButtonUp;
       }
       return eSpinButtonDown;
     }
   }
   return eSpinButtonNone;
--- a/layout/forms/nsRangeFrame.cpp
+++ b/layout/forms/nsRangeFrame.cpp
@@ -487,24 +487,22 @@ nsRangeFrame::GetValueAtEventPoint(Widge
     return minimum;
   }
   Decimal range = maximum - minimum;
 
   LayoutDeviceIntPoint absPoint;
   if (aEvent->mClass == eTouchEventClass) {
     MOZ_ASSERT(aEvent->AsTouchEvent()->touches.Length() == 1,
                "Unexpected number of touches");
-    absPoint = LayoutDeviceIntPoint::FromUntyped(
-      aEvent->AsTouchEvent()->touches[0]->mRefPoint);
+    absPoint = aEvent->AsTouchEvent()->touches[0]->mRefPoint;
   } else {
     absPoint = aEvent->refPoint;
   }
   nsPoint point =
-    nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, 
-      LayoutDeviceIntPoint::ToUntyped(absPoint), this);
+    nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, absPoint, this);
 
   if (point == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)) {
     // We don't want to change the current value for this error state.
     return static_cast<dom::HTMLInputElement*>(mContent)->GetValueAsDecimal();
   }
 
   nsRect rangeContentRect = GetContentRectRelativeToSelf();
   nsSize thumbSize;
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -966,17 +966,17 @@ fails == 413027-3.html 413027-3-ref.html
 == 413286-2b.html 413286-2-ref.html
 == 413286-2c.html 413286-2-ref.html
 == 413286-3.html 413286-3-ref.html
 == 413286-4a.html 413286-4-ref.html
 == 413286-4b.html 413286-4-ref.html
 == 413286-5.html 413286-5-ref.html
 == 413286-6.html 413286-6-ref.html
 skip-if(cocoaWidget) == 413292-1.html 413292-1-ref.html # disabling due to failure loading on some mac tinderboxes. See bug 432954
-fuzzy-if(Android&&AndroidVersion>=15,11,15) == 413361-1.html 413361-1-ref.html
+fuzzy-if(B2G||Android,11,15) == 413361-1.html 413361-1-ref.html # bug 1128229
 == 413840-background-unchanged.html 413840-background-unchanged-ref.html
 == 413840-ltr-offsets.html 413840-ltr-offsets-ref.html
 == 413840-rtl-offsets.html 413840-rtl-offsets-ref.html
 == 413840-pushed-line-bullet.html 413840-pushed-line-bullet-ref.html
 == 413840-bullet-first-line.html 413840-bullet-first-line-ref.html
 == 413982.html 413982-ref.html
 == 414123.xhtml 414123-ref.xhtml
 == 414638.html 414638-ref.html
@@ -1843,17 +1843,17 @@ test-pref(layout.css.grid.enabled,true) 
 == 1059498-3.html 1059498-1-ref.html
 == 1062108-1.html 1062108-1-ref.html
 fails-if(Android) == 1062792-1.html 1062792-1-ref.html
 == 1062963-floatmanager-reflow.html 1062963-floatmanager-reflow-ref.html
 test-pref(dom.webcomponents.enabled,true) == 1066554-1.html 1066554-1-ref.html
 == 1069716-1.html 1069716-1-ref.html
 == 1078262-1.html about:blank
 test-pref(layout.testing.overlay-scrollbars.always-visible,false) == 1081072-1.html 1081072-1-ref.html
-fuzzy-if(winWidget&&!layersGPUAccelerated,1,31) fuzzy-if(B2G,128,75) == 1081185-1.html 1081185-1-ref.html   # fuzzy with event-regions, see bug 1107843
+fuzzy-if(B2G,128,75) == 1081185-1.html 1081185-1-ref.html   # fuzzy with event-regions, see bug 1107843
 == 1097437-1.html 1097437-1-ref.html
 == 1103258-1.html 1103258-1-ref.html # assertion crash test with layers culling test
 == 1105137-1.html 1105137-1-ref.html
 fuzzy-if(d2d,36,304) HTTP(..) == 1116480-1-fakeitalic-overflow.html 1116480-1-fakeitalic-overflow-ref.html
 == 1111753-1.html about:blank
 == 1119117-1a.html 1119117-1-ref.html
 == 1119117-1b.html 1119117-1-ref.html
 == 1120431-1.html 1120431-1-ref.html
--- a/layout/xul/nsBoxFrame.cpp
+++ b/layout/xul/nsBoxFrame.cpp
@@ -2090,36 +2090,37 @@ nsBoxFrame::WrapListsInRedirector(nsDisp
                                   const nsDisplayListSet& aOut)
 {
   nsXULEventRedirectorWrapper wrapper(this);
   wrapper.WrapLists(aBuilder, this, aIn, aOut);
 }
 
 bool
 nsBoxFrame::GetEventPoint(WidgetGUIEvent* aEvent, nsPoint &aPoint) {
-  nsIntPoint refPoint;
+  LayoutDeviceIntPoint refPoint;
   bool res = GetEventPoint(aEvent, refPoint);
-  aPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, refPoint, this);
+  aPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(
+    aEvent, refPoint, this);
   return res;
 }
 
 bool
-nsBoxFrame::GetEventPoint(WidgetGUIEvent* aEvent, nsIntPoint &aPoint) {
+nsBoxFrame::GetEventPoint(WidgetGUIEvent* aEvent, LayoutDeviceIntPoint& aPoint) {
   NS_ENSURE_TRUE(aEvent, false);
 
   WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
   if (touchEvent) {
     // return false if there is more than one touch on the page, or if
     // we can't find a touch point
     if (touchEvent->touches.Length() != 1) {
       return false;
     }
 
     dom::Touch* touch = touchEvent->touches.SafeElementAt(0);
     if (!touch) {
       return false;
     }
     aPoint = touch->mRefPoint;
   } else {
-    aPoint = LayoutDeviceIntPoint::ToUntyped(aEvent->refPoint);
+    aPoint = aEvent->refPoint;
   }
   return true;
 }
--- a/layout/xul/nsBoxFrame.h
+++ b/layout/xul/nsBoxFrame.h
@@ -204,17 +204,18 @@ protected:
 
     nsCOMPtr<nsBoxLayout> mLayoutManager;
 
     // Get the point associated with this event. Returns true if a single valid
     // point was found. Otherwise false.
     bool GetEventPoint(mozilla::WidgetGUIEvent* aEvent, nsPoint& aPoint);
     // Gets the event coordinates relative to the widget offset associated with
     // this frame. Return true if a single valid point was found.
-    bool GetEventPoint(mozilla::WidgetGUIEvent* aEvent, nsIntPoint& aPoint);
+    bool GetEventPoint(mozilla::WidgetGUIEvent* aEvent,
+                       mozilla::LayoutDeviceIntPoint& aPoint);
 
 protected:
     void RegUnregAccessKey(bool aDoReg);
 
   void CheckBoxOrder();
 
 private: 
 
--- a/layout/xul/nsMenuPopupFrame.cpp
+++ b/layout/xul/nsMenuPopupFrame.cpp
@@ -1472,17 +1472,19 @@ nsMenuPopupFrame::GetConstraintRect(cons
   if (mInContentShell) {
     // for content shells, clip to the client area rather than the screen area
     screenRect.IntersectRect(screenRect, aRootScreenRect);
   }
 
   return screenRect;
 }
 
-void nsMenuPopupFrame::CanAdjustEdges(int8_t aHorizontalSide, int8_t aVerticalSide, nsIntPoint& aChange)
+void nsMenuPopupFrame::CanAdjustEdges(int8_t aHorizontalSide,
+                                      int8_t aVerticalSide,
+                                      LayoutDeviceIntPoint& aChange)
 {
   int8_t popupAlign(mPopupAlignment);
   if (IsDirectionRTL()) {
     popupAlign = -popupAlign;
   }
 
   if (aHorizontalSide == (mHFlip ? NS_SIDE_RIGHT : NS_SIDE_LEFT)) {
     if (popupAlign == POPUPALIGNMENT_TOPLEFT || popupAlign == POPUPALIGNMENT_BOTTOMLEFT) {
--- a/layout/xul/nsMenuPopupFrame.h
+++ b/layout/xul/nsMenuPopupFrame.h
@@ -361,17 +361,19 @@ public:
   // 0 for no movement in that direction. aChange is the distance to move on
   // those sides. If will be reset to 0 if the side cannot be adjusted at all
   // in that direction. For example, a popup cannot be moved if it is anchored
   // on a particular side.
   //
   // Later, when bug 357725 is implemented, we can make this adjust aChange by
   // the amount that the side can be resized, so that minimums and maximums
   // can be taken into account.
-  void CanAdjustEdges(int8_t aHorizontalSide, int8_t aVerticalSide, nsIntPoint& aChange);
+  void CanAdjustEdges(int8_t aHorizontalSide,
+                      int8_t aVerticalSide,
+                      mozilla::LayoutDeviceIntPoint& aChange);
 
   // Return true if the popup is positioned relative to an anchor.
   bool IsAnchored() const { return mScreenXPos == -1 && mScreenYPos == -1; }
 
   // Return the anchor if there is one.
   nsIContent* GetAnchor() const { return mAnchorContent; }
 
   // Return the screen coordinates of the popup, or (-1, -1) if anchored.
--- a/layout/xul/nsResizerFrame.cpp
+++ b/layout/xul/nsResizerFrame.cpp
@@ -109,20 +109,21 @@ nsResizerFrame::HandleEvent(nsPresContex
              
           // if there's no native resize support, we need to do window
           // resizing ourselves
           window->GetPositionAndSize(&mMouseDownRect.x, &mMouseDownRect.y,
                                      &mMouseDownRect.width, &mMouseDownRect.height);
         }
 
         // remember current mouse coordinates
-        nsIntPoint refPoint;
+        LayoutDeviceIntPoint refPoint;
         if (!GetEventPoint(aEvent, refPoint))
           return NS_OK;
-        mMouseDownPoint = refPoint + aEvent->widget->WidgetToScreenOffset();
+        mMouseDownPoint = refPoint +
+          LayoutDeviceIntPoint::FromUntyped(aEvent->widget->WidgetToScreenOffset());
 
         // we're tracking
         mTrackingMouseMove = true;
 
         nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED);
       }
     }
     break;
@@ -157,21 +158,22 @@ nsResizerFrame::HandleEvent(nsPresContex
         menuPopupFrame = do_QueryFrame(contentToResize->GetPrimaryFrame());
       }
 
       // both MouseMove and direction are negative when pointing to the
       // top and left, and positive when pointing to the bottom and right
 
       // retrieve the offset of the mousemove event relative to the mousedown.
       // The difference is how much the resize needs to be
-      nsIntPoint refPoint;
+      LayoutDeviceIntPoint refPoint;
       if (!GetEventPoint(aEvent, refPoint))
         return NS_OK;
-      nsIntPoint screenPoint(refPoint + aEvent->widget->WidgetToScreenOffset());
-      nsIntPoint mouseMove(screenPoint - mMouseDownPoint);
+      LayoutDeviceIntPoint screenPoint = refPoint +
+        LayoutDeviceIntPoint::FromUntyped(aEvent->widget->WidgetToScreenOffset());
+      LayoutDeviceIntPoint mouseMove(screenPoint - mMouseDownPoint);
 
       // Determine which direction to resize by checking the dir attribute.
       // For windows and menus, ensure that it can be resized in that direction.
       Direction direction = GetDirection();
       if (window || menuPopupFrame) {
         if (menuPopupFrame) {
           menuPopupFrame->CanAdjustEdges(
             (direction.mHorizontal == -1) ? NS_SIDE_LEFT : NS_SIDE_RIGHT,
--- a/layout/xul/nsResizerFrame.h
+++ b/layout/xul/nsResizerFrame.h
@@ -61,13 +61,13 @@ protected:
   static void SizeInfoDtorFunc(void *aObject, nsIAtom *aPropertyName,
                                void *aPropertyValue, void *aData);
   static void ResizeContent(nsIContent* aContent, const Direction& aDirection,
                             const SizeInfo& aSizeInfo, SizeInfo* aOriginalSizeInfo);
   static void MaybePersistOriginalSize(nsIContent* aContent, const SizeInfo& aSizeInfo);
   static void RestoreOriginalSize(nsIContent* aContent);
 
 protected:
-	nsIntRect mMouseDownRect;
-	nsIntPoint mMouseDownPoint;
+  nsIntRect mMouseDownRect;
+  LayoutDeviceIntPoint mMouseDownPoint;
 }; // class nsResizerFrame
 
 #endif /* nsResizerFrame_h___ */
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
@@ -1004,17 +1004,16 @@ void MediaPipelineTransmit::PipelineList
   if (!enabled_ || chunk.mFrame.GetForceBlack()) {
     gfx::IntSize size = img->GetSize();
     uint32_t yPlaneLen = YSIZE(size.width, size.height);
     uint32_t cbcrPlaneLen = 2 * CRSIZE(size.width, size.height);
     uint32_t length = yPlaneLen + cbcrPlaneLen;
 
     // Send a black image.
     nsAutoArrayPtr<uint8_t> pixelData;
-    static const fallible_t fallible = fallible_t();
     pixelData = new (fallible) uint8_t[length];
     if (pixelData) {
       // YCrCb black = 0x10 0x80 0x80
       memset(pixelData, 0x10, yPlaneLen);
       // Fill Cb/Cr planes
       memset(pixelData + yPlaneLen, 0x80, cbcrPlaneLen);
 
       MOZ_MTLOG(ML_DEBUG, "Sending a black video frame");
new file mode 100644
--- /dev/null
+++ b/memory/fallible/fallible.cpp
@@ -0,0 +1,11 @@
+/* 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 "fallible.h"
+
+namespace mozilla {
+
+const fallible_t fallible = {};
+
+}
rename from memory/mozalloc/fallible.h
rename to memory/fallible/fallible.h
--- a/memory/mozalloc/fallible.h
+++ b/memory/fallible/fallible.h
@@ -1,14 +1,67 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_fallible_h
 #define mozilla_fallible_h
 
+#if defined(__cplusplus)
+
+/* Explicit fallible allocation
+ *
+ * Memory allocation (normally) defaults to abort in case of failed
+ * allocation. That is, it never returns NULL, and crashes instead.
+ *
+ * Code can explicitely request for fallible memory allocation thanks
+ * to the declarations below.
+ *
+ * The typical use of the mozilla::fallible const is with placement new,
+ * like the following:
+ *
+ *     foo = new (mozilla::fallible) Foo();
+ *
+ * The following forms, or derivatives, are also possible but deprecated:
+ *
+ *     foo = new ((mozilla::fallible_t())) Foo();
+ *
+ *     const mozilla::fallible_t fallible = mozilla::fallible_t();
+ *     bar = new (f) Bar();
+ *
+ * It is also possible to declare method overloads with fallible allocation
+ * alternatives, like so:
+ *
+ *     class Foo {
+ *     public:
+ *       void Method(void *);
+ *       void Method(void *, const mozilla::fallible_t&);
+ *     };
+ *
+ *     Foo foo;
+ *     foo.Method(nullptr, mozilla::fallible);
+ *
+ * If that last method call is in a method that itself takes a const
+ * fallible_t& argument, it is recommended to propagate that argument
+ * instead of using mozilla::fallible:
+ *
+ *     void Func(Foo &foo, const mozilla::fallible_t& aFallible) {
+ *         foo.Method(nullptr, aFallible);
+ *     }
+ *
+ */
 namespace mozilla {
 
 struct fallible_t { };
 
+/* This symbol is kept unexported, such that in corner cases where the
+ * compiler can't remove its use (essentially, cross compilation-unit
+ * calls), the smallest machine code is used.
+ * Depending how the linker packs symbols, it will consume between 1 and
+ * 8 bytes of read-only data in each executable or shared library, but
+ * only in those where it's actually not optimized out by the compiler.
+ */
+extern const fallible_t fallible;
+
 } // namespace mozilla
+#endif
 
 #endif // mozilla_fallible_h
new file mode 100644
--- /dev/null
+++ b/memory/fallible/moz.build
@@ -0,0 +1,30 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+EXPORTS.mozilla += [
+    'fallible.h',
+]
+
+Library('fallible')
+
+SOURCES += [
+    'fallible.cpp',
+]
+
+if CONFIG['_MSC_VER']:
+    # MSVC normally adds linker directives relative to the CRT in a .drectve
+    # section in .obj files. Then, when linking objects, it adds those
+    # directives as if they were given as command line arguments. This can
+    # lead to trying to include link CRTs because different objects are
+    # compiled with different CRT options (i.e. -MT vs. -MD), and failing.
+    # The only source in this directory doesn't expose anything that depends
+    # on a CRT, so it doesn't need to be bound to a specific one.
+    # Adding the -Zl option makes MSVC not store linker directives in the
+    # object. This allows to link fallible.obj to binaries independently of
+    # the CRT they use.
+    CXXFLAGS += [
+        '-Zl',
+    ]
--- a/memory/mozalloc/moz.build
+++ b/memory/mozalloc/moz.build
@@ -1,17 +1,16 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 NO_VISIBILITY_FLAGS = True
 
 EXPORTS.mozilla += [
-    'fallible.h',
     'mozalloc.h',
     'mozalloc_abort.h',
     'mozalloc_oom.h',
 ]
 
 if CONFIG['MOZ_MSVC_STL_WRAP__RAISE'] or CONFIG['MOZ_MSVC_STL_WRAP__Throw']:
     build_msvc_wrappers = 1
 else:
--- a/modules/libjar/nsZipArchive.cpp
+++ b/modules/libjar/nsZipArchive.cpp
@@ -1152,17 +1152,17 @@ nsZipItemPtr_base::nsZipItemPtr_base(nsZ
 
   nsZipItem* item = aZip->GetItem(aEntryName);
   if (!item)
     return;
 
   uint32_t size = 0;
   if (item->Compression() == DEFLATED) {
     size = item->RealSize();
-    mAutoBuf = new ((fallible_t())) uint8_t[size];
+    mAutoBuf = new (fallible) uint8_t[size];
     if (!mAutoBuf) {
       return;
     }
   }
 
   nsZipCursor cursor(item, aZip, mAutoBuf, size, doCRC);
   mReturnBuf = cursor.Read(&mReadlen);
   if (!mReturnBuf) {
--- a/modules/libpref/nsPrefBranch.cpp
+++ b/modules/libpref/nsPrefBranch.cpp
@@ -325,17 +325,17 @@ NS_IMETHODIMP nsPrefBranch::GetComplexVa
 
   if (aType.Equals(NS_GET_IID(nsISupportsString))) {
     nsCOMPtr<nsISupportsString> theString(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv));
 
     if (NS_SUCCEEDED(rv)) {
       // Debugging to see why we end up with very long strings here with
       // some addons, see bug 836263.
       nsAutoString wdata;
-      if (!AppendUTF8toUTF16(utf8String, wdata, mozilla::fallible_t())) {
+      if (!AppendUTF8toUTF16(utf8String, wdata, mozilla::fallible)) {
 #ifdef MOZ_CRASHREPORTER
         nsCOMPtr<nsICrashReporter> cr =
           do_GetService("@mozilla.org/toolkit/crash-reporter;1");
         if (cr) {
           cr->AnnotateCrashReport(NS_LITERAL_CSTRING("bug836263-size"),
                                   nsPrintfCString("%x", utf8String.Length()));
           cr->RegisterAppMemory(uint64_t(utf8String.BeginReading()),
                                 std::min(0x1000U, utf8String.Length()));
--- a/modules/libpref/prefapi.cpp
+++ b/modules/libpref/prefapi.cpp
@@ -142,17 +142,17 @@ enum {
 static nsresult pref_HashPref(const char *key, PrefValue value, PrefType type, uint32_t flags);
 
 #define PREF_HASHTABLE_INITIAL_LENGTH   1024
 
 nsresult PREF_Init()
 {
     if (!gHashTable.IsInitialized()) {
         if (!PL_DHashTableInit(&gHashTable, &pref_HashTableOps,
-                               sizeof(PrefHashEntry), fallible_t(),
+                               sizeof(PrefHashEntry), fallible,
                                PREF_HASHTABLE_INITIAL_LENGTH)) {
             return NS_ERROR_OUT_OF_MEMORY;
         }
 
         PL_INIT_ARENA_POOL(&gPrefNameArena, "PrefNameArena",
                            PREFNAME_ARENA_SIZE);
     }
     return NS_OK;
--- a/moz.build
+++ b/moz.build
@@ -38,16 +38,17 @@ if not CONFIG['LIBXUL_SDK']:
         if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
             DIRS += ['other-licenses/android']
 
         if CONFIG['MOZ_MEMORY']:
             DIRS += ['memory']
 
         DIRS += [
             'mozglue',
+            'memory/fallible',
             'memory/mozalloc',
             'memory/volatile',
         ]
 
 if not CONFIG['JS_STANDALONE']:
     DIRS += ['xpcom/xpidl']
 
 if CONFIG['COMPILE_ENVIRONMENT'] and not CONFIG['LIBXUL_SDK']:
--- a/netwerk/base/nsBufferedStreams.cpp
+++ b/netwerk/base/nsBufferedStreams.cpp
@@ -66,18 +66,17 @@ nsBufferedStream::Init(nsISupports* stre
 {
     NS_ASSERTION(stream, "need to supply a stream");
     NS_ASSERTION(mStream == nullptr, "already inited");
     mStream = stream;
     NS_IF_ADDREF(mStream);
     mBufferSize = bufferSize;
     mBufferStartOffset = 0;
     mCursor = 0;
-    const mozilla::fallible_t fallible = mozilla::fallible_t();
-    mBuffer = new (fallible) char[bufferSize];
+    mBuffer = new (mozilla::fallible) char[bufferSize];
     if (mBuffer == nullptr)
         return NS_ERROR_OUT_OF_MEMORY;
     return NS_OK;
 }
 
 nsresult
 nsBufferedStream::Close()
 {
--- a/netwerk/base/nsNetUtil.h
+++ b/netwerk/base/nsNetUtil.h
@@ -1541,17 +1541,17 @@ NS_ReadInputStreamToBuffer(nsIInputStrea
 // external code can't see fallible_t
 #ifdef MOZILLA_INTERNAL_API
 
 inline nsresult
 NS_ReadInputStreamToString(nsIInputStream *aInputStream, 
                            nsACString &aDest,
                            uint32_t aCount)
 {
-    if (!aDest.SetLength(aCount, mozilla::fallible_t()))
+    if (!aDest.SetLength(aCount, mozilla::fallible))
         return NS_ERROR_OUT_OF_MEMORY;
     void* dest = aDest.BeginWriting();
     return NS_ReadInputStreamToBuffer(aInputStream, &dest, aCount);
 }
 
 #endif
 
 inline nsresult
--- a/netwerk/base/nsStandardURL.cpp
+++ b/netwerk/base/nsStandardURL.cpp
@@ -583,17 +583,17 @@ nsStandardURL::BuildNormalizedSpec(const
         else
             approxLen += mHost.mLen;
     }
 
     //
     // generate the normalized URL string
     //
     // approxLen should be correct or 1 high
-    if (!mSpec.SetLength(approxLen+1, mozilla::fallible_t())) // buf needs a trailing '\0' below
+    if (!mSpec.SetLength(approxLen+1, mozilla::fallible)) // buf needs a trailing '\0' below
         return NS_ERROR_OUT_OF_MEMORY;
     char *buf;
     mSpec.BeginWriting(buf);
     uint32_t i = 0;
 
     if (mScheme.mLen > 0) {
         i = AppendSegmentToBuf(buf, i, spec, mScheme);
         net_ToLowerCase(buf + mScheme.mPos, mScheme.mLen);
--- a/netwerk/base/nsUnicharStreamLoader.cpp
+++ b/netwerk/base/nsUnicharStreamLoader.cpp
@@ -21,17 +21,17 @@ using mozilla::dom::EncodingUtils;
 
 NS_IMETHODIMP
 nsUnicharStreamLoader::Init(nsIUnicharStreamLoaderObserver *aObserver)
 {
   NS_ENSURE_ARG_POINTER(aObserver);
 
   mObserver = aObserver;
 
-  if (!mRawData.SetCapacity(SNIFFING_BUFFER_SIZE, fallible_t()))
+  if (!mRawData.SetCapacity(SNIFFING_BUFFER_SIZE, fallible))
     return NS_ERROR_OUT_OF_MEMORY;
 
   return NS_OK;
 }
 
 nsresult
 nsUnicharStreamLoader::Create(nsISupports *aOuter,
                               REFNSIID aIID,
@@ -209,17 +209,17 @@ nsUnicharStreamLoader::WriteSegmentFun(n
   nsUnicharStreamLoader* self = static_cast<nsUnicharStreamLoader*>(aClosure);
 
   uint32_t haveRead = self->mBuffer.Length();
   int32_t srcLen = aCount;
   int32_t dstLen;
   self->mDecoder->GetMaxLength(aSegment, srcLen, &dstLen);
 
   uint32_t capacity = haveRead + dstLen;
-  if (!self->mBuffer.SetCapacity(capacity, fallible_t())) {
+  if (!self->mBuffer.SetCapacity(capacity, fallible)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   DebugOnly<nsresult> rv =
     self->mDecoder->Convert(aSegment,
                             &srcLen,
                             self->mBuffer.BeginWriting() + haveRead,
                             &dstLen);
--- a/netwerk/cache/nsCacheEntry.cpp
+++ b/netwerk/cache/nsCacheEntry.cpp
@@ -400,17 +400,17 @@ nsCacheEntryHashTable::~nsCacheEntryHash
 
 
 nsresult
 nsCacheEntryHashTable::Init()
 {
     nsresult rv = NS_OK;
     initialized = PL_DHashTableInit(&table, &ops,
                                     sizeof(nsCacheEntryHashTableEntry),
-                                    fallible_t(), 256);
+                                    fallible, 256);
 
     if (!initialized) rv = NS_ERROR_OUT_OF_MEMORY;
 
     return rv;
 }
 
 void
 nsCacheEntryHashTable::Shutdown()
--- a/netwerk/cache/nsDiskCacheDeviceSQL.cpp
+++ b/netwerk/cache/nsDiskCacheDeviceSQL.cpp
@@ -961,17 +961,17 @@ nsOfflineCacheDevice::UpdateEntry(nsCach
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = entry->SetMetaDataElement("security-info", info.get());
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsCString metaDataBuf;
   uint32_t mdSize = entry->MetaDataSize();
-  if (!metaDataBuf.SetLength(mdSize, fallible_t()))
+  if (!metaDataBuf.SetLength(mdSize, fallible))
     return NS_ERROR_OUT_OF_MEMORY;
   char *md = metaDataBuf.BeginWriting();
   entry->FlattenMetaData(md, mdSize);
 
   nsOfflineCacheRecord rec;
   rec.metaData = (const uint8_t *) md;
   rec.metaDataLen = mdSize;
   rec.dataSize = entry->DataSize();
--- a/netwerk/protocol/http/nsHttp.cpp
+++ b/netwerk/protocol/http/nsHttp.cpp
@@ -101,17 +101,17 @@ nsHttp::CreateAtomTable()
     if (!sLock) {
         sLock = new Mutex("nsHttp.sLock");
     }
 
     // The initial length for this table is a value greater than the number of
     // known atoms (NUM_HTTP_ATOMS) because we expect to encounter a few random
     // headers right off the bat.
     if (!PL_DHashTableInit(&sAtomTable, &ops, sizeof(PLDHashEntryStub),
-                           fallible_t(), NUM_HTTP_ATOMS + 10)) {
+                           fallible, NUM_HTTP_ATOMS + 10)) {
         return NS_ERROR_OUT_OF_MEMORY;
     }
 
     // fill the table with our known atoms
     const char *const atoms[] = {
 #define HTTP_ATOM(_name, _value) nsHttp::_name._val,
 #include "nsHttpAtomList.h"
 #undef HTTP_ATOM
--- a/netwerk/protocol/websocket/WebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannel.cpp
@@ -1604,17 +1604,17 @@ WebSocketChannel::ProcessInput(uint8_t *
           if (NS_FAILED(rv)) {
             return rv;
           }
           LOG(("WebSocketChannel:: message successfully inflated "
                "[origLength=%d, newLength=%d]\n", payloadLength,
                utf8Data.Length()));
         } else {
           if (!utf8Data.Assign((const char *)payload, payloadLength,
-                               mozilla::fallible_t())) {
+                               mozilla::fallible)) {
             return NS_ERROR_OUT_OF_MEMORY;
           }
         }
 
         // Section 8.1 says to fail connection if invalid utf-8 in text message
         if (!IsUTF8(utf8Data, false)) {
           LOG(("WebSocketChannel:: text frame invalid utf-8\n"));
           return NS_ERROR_CANNOT_CONVERT_DATA;
@@ -1714,17 +1714,17 @@ WebSocketChannel::ProcessInput(uint8_t *
           if (NS_FAILED(rv)) {
             return rv;
           }
           LOG(("WebSocketChannel:: message successfully inflated "
                "[origLength=%d, newLength=%d]\n", payloadLength,
                binaryData.Length()));
         } else {
           if (!binaryData.Assign((const char *)payload, payloadLength,
-                                 mozilla::fallible_t())) {
+                                 mozilla::fallible)) {
             return NS_ERROR_OUT_OF_MEMORY;
           }
         }
 
         mTargetThread->Dispatch(
           new CallOnMessageAvailable(this, binaryData, binaryData.Length()),
           NS_DISPATCH_NORMAL);
         // To add the header to 'Networking Dashboard' log
--- a/netwerk/streamconv/converters/nsDirIndexParser.cpp
+++ b/netwerk/streamconv/converters/nsDirIndexParser.cpp
@@ -328,17 +328,17 @@ nsDirIndexParser::OnDataAvailable(nsIReq
                                   uint32_t aCount) {
   if (aCount < 1)
     return NS_OK;
   
   int32_t len = mBuf.Length();
   
   // Ensure that our mBuf has capacity to hold the data we're about to
   // read.
-  if (!mBuf.SetLength(len + aCount, fallible_t()))
+  if (!mBuf.SetLength(len + aCount, fallible))
     return NS_ERROR_OUT_OF_MEMORY;
 
   // Now read the data into our buffer.
   nsresult rv;
   uint32_t count;
   rv = aStream->Read(mBuf.BeginWriting() + len, aCount, &count);
   if (NS_FAILED(rv)) return rv;
 
--- a/parser/html/nsHtml5OwningUTF16Buffer.cpp
+++ b/parser/html/nsHtml5OwningUTF16Buffer.cpp
@@ -34,23 +34,22 @@ nsHtml5OwningUTF16Buffer::~nsHtml5Owning
     tail.swap(tmp);
   }
 }
 
 // static
 already_AddRefed<nsHtml5OwningUTF16Buffer>
 nsHtml5OwningUTF16Buffer::FalliblyCreate(int32_t aLength)
 {
-  const mozilla::fallible_t fallible = mozilla::fallible_t();
-  char16_t* newBuf = new (fallible) char16_t[aLength];
+  char16_t* newBuf = new (mozilla::fallible) char16_t[aLength];
   if (!newBuf) {
     return nullptr;
   }
   nsRefPtr<nsHtml5OwningUTF16Buffer> newObj =
-    new (fallible) nsHtml5OwningUTF16Buffer(newBuf);
+    new (mozilla::fallible) nsHtml5OwningUTF16Buffer(newBuf);
   if (!newObj) {
     delete[] newBuf;
     return nullptr;
   }
   return newObj.forget();
 }
 
 void
--- a/parser/html/nsHtml5StreamParser.cpp
+++ b/parser/html/nsHtml5StreamParser.cpp
@@ -766,18 +766,17 @@ nsHtml5StreamParser::SniffStreamBytes(co
       mFeedChardet = false;
       mTreeBuilder->SetDocumentCharset(mCharset, mCharsetSource);
       return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(aFromSegment,
         aCount, aWriteCount);
     }
   }
 
   if (!mSniffingBuffer) {
-    const mozilla::fallible_t fallible = mozilla::fallible_t();
-    mSniffingBuffer = new (fallible)
+    mSniffingBuffer = new (mozilla::fallible)
       uint8_t[NS_HTML5_STREAM_PARSER_SNIFFING_BUFFER_SIZE];
     if (!mSniffingBuffer) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
   memcpy(mSniffingBuffer + mSniffingLength, aFromSegment, aCount);
   mSniffingLength += aCount;
   *aWriteCount = aCount;
@@ -1141,18 +1140,17 @@ nsHtml5StreamParser::OnDataAvailable(nsI
   if (NS_FAILED(rv = mExecutor->IsBroken())) {
     return rv;
   }
 
   NS_ASSERTION(mRequest == aRequest, "Got data on wrong stream.");
   uint32_t totalRead;
   // Main thread to parser thread dispatch requires copying to buffer first.
   if (NS_IsMainThread()) {
-    const mozilla::fallible_t fallible = mozilla::fallible_t();
-    nsAutoArrayPtr<uint8_t> data(new (fallible) uint8_t[aLength]);
+    nsAutoArrayPtr<uint8_t> data(new (mozilla::fallible) uint8_t[aLength]);
     if (!data) {
       return mExecutor->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY);
     }
     rv = aInStream->Read(reinterpret_cast<char*>(data.get()),
                          aLength, &totalRead);
     NS_ENSURE_SUCCESS(rv, rv);
     NS_ASSERTION(totalRead <= aLength, "Read more bytes than were available?");
 
--- a/parser/htmlparser/nsHTMLEntities.cpp
+++ b/parser/htmlparser/nsHTMLEntities.cpp
@@ -80,22 +80,22 @@ static const EntityNode gEntityArray[] =
 #define NS_HTML_ENTITY_COUNT ((int32_t)ArrayLength(gEntityArray))
 
 nsresult
 nsHTMLEntities::AddRefTable(void)
 {
   if (!gTableRefCnt) {
     if (!PL_DHashTableInit(&gEntityToUnicode, &EntityToUnicodeOps,
                            sizeof(EntityNodeEntry),
-                           fallible_t(), NS_HTML_ENTITY_COUNT)) {
+                           fallible, NS_HTML_ENTITY_COUNT)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
     if (!PL_DHashTableInit(&gUnicodeToEntity, &UnicodeToEntityOps,
                            sizeof(EntityNodeEntry),
-                           fallible_t(), NS_HTML_ENTITY_COUNT)) {
+                           fallible, NS_HTML_ENTITY_COUNT)) {
       PL_DHashTableFinish(&gEntityToUnicode);
       return NS_ERROR_OUT_OF_MEMORY;
     }
     for (const EntityNode *node = gEntityArray,
                  *node_end = ArrayEnd(gEntityArray);
          node < node_end; ++node) {
 
       // add to Entity->Unicode table
--- a/parser/htmlparser/nsScannerString.cpp
+++ b/parser/htmlparser/nsScannerString.cpp
@@ -467,17 +467,17 @@ copy_multifragment_string( nsScannerIter
   }
 
 void
 CopyUnicodeTo( const nsScannerIterator& aSrcStart,
                const nsScannerIterator& aSrcEnd,
                nsAString& aDest )
   {
     nsAString::iterator writer;
-    if (!aDest.SetLength(Distance(aSrcStart, aSrcEnd), mozilla::fallible_t())) {
+    if (!aDest.SetLength(Distance(aSrcStart, aSrcEnd), mozilla::fallible)) {
       aDest.Truncate();
       return; // out of memory
     }
     aDest.BeginWriting(writer);
     nsScannerIterator fromBegin(aSrcStart);
     
     copy_multifragment_string(fromBegin, aSrcEnd, writer);
   }
@@ -500,17 +500,17 @@ AppendUnicodeTo( const nsScannerIterator
 
 void
 AppendUnicodeTo( const nsScannerIterator& aSrcStart,
                  const nsScannerIterator& aSrcEnd,
                  nsAString& aDest )
   {
     nsAString::iterator writer;
     uint32_t oldLength = aDest.Length();
-    if (!aDest.SetLength(oldLength + Distance(aSrcStart, aSrcEnd), mozilla::fallible_t()))
+    if (!aDest.SetLength(oldLength + Distance(aSrcStart, aSrcEnd), mozilla::fallible))
       return; // out of memory
     aDest.BeginWriting(writer).advance(oldLength);
     nsScannerIterator fromBegin(aSrcStart);
     
     copy_multifragment_string(fromBegin, aSrcEnd, writer);
   }
 
 bool
--- a/security/manager/ssl/src/nsCertTree.cpp
+++ b/security/manager/ssl/src/nsCertTree.cpp
@@ -177,17 +177,17 @@ void nsCertTree::ClearCompareHash()
     PL_DHashTableFinish(&mCompareCache);
   }
 }
 
 nsresult nsCertTree::InitCompareHash()
 {
   ClearCompareHash();
   if (!PL_DHashTableInit(&mCompareCache, &gMapOps,
-                         sizeof(CompareCacheHashEntryPtr), fallible_t(), 64)) {
+                         sizeof(CompareCacheHashEntryPtr), fallible, 64)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   return NS_OK;
 }
 
 nsCertTree::~nsCertTree()
 {
   ClearCompareHash();
--- a/services/crypto/component/nsSyncJPAKE.cpp
+++ b/services/crypto/component/nsSyncJPAKE.cpp
@@ -11,17 +11,17 @@
 #include <secmodt.h>
 #include <secport.h>
 #include <secerr.h>
 #include <nsDebug.h>
 #include <nsError.h>
 #include <base64.h>
 #include <nsString.h>
 
-using mozilla::fallible_t;
+using mozilla::fallible;
 
 static bool
 hex_from_2char(const unsigned char *c2, unsigned char *byteval)
 {
   int i;
   unsigned char offset;
   *byteval = 0;
   for (i=0; i<2; i++) {
@@ -68,17 +68,17 @@ fromHexString(const nsACString & str, un
   }
   return NS_OK;
 }
 
 static bool
 toHexString(const unsigned char * str, unsigned len, nsACString & out)
 {
   static const char digits[] = "0123456789ABCDEF";
-  if (!out.SetCapacity(2 * len, fallible_t()))
+  if (!out.SetCapacity(2 * len, fallible))
     return false;
   out.SetLength(0);
   for (unsigned i = 0; i < len; ++i) {
     out.Append(digits[str[i] >> 4]);
     out.Append(digits[str[i] & 0x0f]);
   }
   return true;
 }
@@ -296,17 +296,17 @@ NS_IMETHODIMP nsSyncJPAKE::Round2(const 
 static nsresult
 setBase64(const unsigned char * data, unsigned len, nsACString & out)
 {
   nsresult rv = NS_OK;
   const char * base64 = BTOA_DataToAscii(data, len);
   
   if (base64 != nullptr) {
     size_t len = PORT_Strlen(base64);
-    if (out.SetCapacity(len, fallible_t())) {
+    if (out.SetCapacity(len, fallible)) {
       out.SetLength(0);
       out.Append(base64, len);
       PORT_Free((void*) base64);
     } else {
       rv = NS_ERROR_OUT_OF_MEMORY;
     }
   } else {
     rv = NS_ERROR_OUT_OF_MEMORY;
--- a/toolkit/components/downloads/SQLFunctions.cpp
+++ b/toolkit/components/downloads/SQLFunctions.cpp
@@ -56,17 +56,17 @@ Base64urlEncode(const uint8_t* aBytes,
                 uint32_t aNumBytes,
                 nsCString& _result)
 {
   // SetLength does not set aside space for null termination.  PL_Base64Encode
   // will not null terminate, however, nsCStrings must be null terminated.  As a
   // result, we set the capacity to be one greater than what we need, and the
   // length to our desired length.
   uint32_t length = (aNumBytes + 2) / 3 * 4; // +2 due to integer math.
-  NS_ENSURE_TRUE(_result.SetCapacity(length + 1, mozilla::fallible_t()),
+  NS_ENSURE_TRUE(_result.SetCapacity(length + 1, mozilla::fallible),
                  NS_ERROR_OUT_OF_MEMORY);
   _result.SetLength(length);
   (void)PL_Base64Encode(reinterpret_cast<const char*>(aBytes), aNumBytes,
                         _result.BeginWriting());
 
   // base64url encoding is defined in RFC 4648.  It replaces the last two
   // alphabet characters of base64 encoding with '-' and '_' respectively.
   _result.ReplaceChar('+', '-');
--- a/toolkit/components/places/Helpers.cpp
+++ b/toolkit/components/places/Helpers.cpp
@@ -207,17 +207,17 @@ Base64urlEncode(const uint8_t* aBytes,
                 uint32_t aNumBytes,
                 nsCString& _result)
 {
   // SetLength does not set aside space for null termination.  PL_Base64Encode
   // will not null terminate, however, nsCStrings must be null terminated.  As a
   // result, we set the capacity to be one greater than what we need, and the
   // length to our desired length.
   uint32_t length = (aNumBytes + 2) / 3 * 4; // +2 due to integer math.
-  NS_ENSURE_TRUE(_result.SetCapacity(length + 1, fallible_t()),
+  NS_ENSURE_TRUE(_result.SetCapacity(length + 1, fallible),
                  NS_ERROR_OUT_OF_MEMORY);
   _result.SetLength(length);
   (void)PL_Base64Encode(reinterpret_cast<const char*>(aBytes), aNumBytes,
                         _result.BeginWriting());
 
   // base64url encoding is defined in RFC 4648.  It replaces the last two
   // alphabet characters of base64 encoding with '-' and '_' respectively.
   _result.ReplaceChar('+', '-');
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -4331,16 +4331,42 @@
     "description": "a testing histogram; not meant to be touched"
   },
   "TELEMETRY_TEST_KEYED_COUNT": {
     "expires_in_version": "default",
     "kind": "count",
     "keyed": true,
     "description": "a testing histogram; not meant to be touched"
   },
+  "TELEMETRY_TEST_RELEASE_OPTOUT": {
+    "expires_in_version": "default",
+    "kind": "flag",
+    "releaseChannelCollection": "opt-out",
+    "description": "a testing histogram; not meant to be touched"
+  },
+  "TELEMETRY_TEST_RELEASE_OPTIN": {
+    "expires_in_version": "default",
+    "kind": "flag",
+    "releaseChannelCollection": "opt-in",
+    "description": "a testing histogram; not meant to be touched"
+  },
+  "TELEMETRY_TEST_KEYED_RELEASE_OPTIN": {
+    "expires_in_version": "default",
+    "kind": "flag",
+    "keyed": true,
+    "releaseChannelCollection": "opt-in",
+    "description": "a testing histogram; not meant to be touched"
+  },
+  "TELEMETRY_TEST_KEYED_RELEASE_OPTOUT": {
+    "expires_in_version": "default",
+    "kind": "flag",
+    "keyed": true,
+    "releaseChannelCollection": "opt-out",
+    "description": "a testing histogram; not meant to be touched"
+  },
   "STARTUP_CRASH_DETECTED": {
     "expires_in_version": "never",
     "kind": "flag",
     "description": "Whether there was a crash during the last startup"
   },
   "SAFE_MODE_USAGE": {
     "expires_in_version": "never",
     "kind": "enumerated",
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -621,194 +621,17 @@ ClearIOReporting()
   if (!sTelemetryIOObserver) {
     return;
   }
   IOInterposer::Unregister(IOInterposeObserver::OpAllWithStaging,
                            sTelemetryIOObserver);
   sTelemetryIOObserver = nullptr;
 }
 
-class KeyedHistogram {
-public:
-  KeyedHistogram(const nsACString &name, const nsACString &expiration,
-                 uint32_t histogramType, uint32_t min, uint32_t max,
-                 uint32_t bucketCount);
-  nsresult GetHistogram(const nsCString& name, Histogram** histogram);
-  Histogram* GetHistogram(const nsCString& name);
-  uint32_t GetHistogramType() const { return mHistogramType; }
-  nsresult GetJSKeys(JSContext* cx, JS::CallArgs& args);
-  nsresult GetJSSnapshot(JSContext* cx, JS::Handle<JSObject*> obj);
-  void Clear();
-
-private:
-  typedef nsBaseHashtableET<nsCStringHashKey, Histogram*> KeyedHistogramEntry;
-  typedef AutoHashtable<KeyedHistogramEntry> KeyedHistogramMapType;
-  KeyedHistogramMapType mHistogramMap;
-
-  struct ReflectKeysArgs {
-    JSContext* jsContext;
-    JS::AutoValueVector* vector;
-  };
-  static PLDHashOperator ReflectKeys(KeyedHistogramEntry* entry, void* arg);
-
-  static bool ReflectKeyedHistogram(KeyedHistogramEntry* entry,
-                                    JSContext* cx,
-                                    JS::Handle<JSObject*> obj);
-
-  static PLDHashOperator ClearHistogramEnumerator(KeyedHistogramEntry*, void*);
-
-  const nsCString mName;
-  const nsCString mExpiration;
-  const uint32_t mHistogramType;
-  const uint32_t mMin;
-  const uint32_t mMax;
-  const uint32_t mBucketCount;
-};
-
-KeyedHistogram::KeyedHistogram(const nsACString &name, const nsACString &expiration,
-                               uint32_t histogramType, uint32_t min, uint32_t max,
-                               uint32_t bucketCount)
-  : mHistogramMap()
-  , mName(name)
-  , mExpiration(expiration)
-  , mHistogramType(histogramType)
-  , mMin(min)
-  , mMax(max)
-  , mBucketCount(bucketCount)
-{
-}
-
-nsresult
-KeyedHistogram::GetHistogram(const nsCString& key, Histogram** histogram)
-{
-  KeyedHistogramEntry* entry = mHistogramMap.GetEntry(key);
-  if (entry) {
-    *histogram = entry->mData;
-    return NS_OK;
-  }
-
-  nsCString histogramName = mName;
-  histogramName.Append(KEYED_HISTOGRAM_NAME_SEPARATOR);
-  histogramName.Append(key);
-
-  Histogram* h;
-  nsresult rv = HistogramGet(histogramName.get(), mExpiration.get(),
-                             mHistogramType, mMin, mMax, mBucketCount,
-                             true, &h);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  h->ClearFlags(Histogram::kUmaTargetedHistogramFlag);
-  h->SetFlags(Histogram::kExtendedStatisticsFlag);
-  *histogram = h;
-
-  entry = mHistogramMap.PutEntry(key);
-  if (MOZ_UNLIKELY(!entry)) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  entry->mData = h;
-  return NS_OK;
-}
-
-Histogram*
-KeyedHistogram::GetHistogram(const nsCString& key)
-{
-  Histogram* h = nullptr;
-  if (NS_FAILED(GetHistogram(key, &h))) {
-    return nullptr;
-  }
-  return h;
-}
-
-/* static */
-PLDHashOperator
-KeyedHistogram::ClearHistogramEnumerator(KeyedHistogramEntry* entry, void*)
-{
-  entry->mData->Clear();
-  return PL_DHASH_NEXT;
-}
-
-void
-KeyedHistogram::Clear()
-{
-  mHistogramMap.EnumerateEntries(&KeyedHistogram::ClearHistogramEnumerator, nullptr);
-  mHistogramMap.Clear();
-}
-
-/* static */
-PLDHashOperator
-KeyedHistogram::ReflectKeys(KeyedHistogramEntry* entry, void* arg)
-{
-  ReflectKeysArgs* args = static_cast<ReflectKeysArgs*>(arg);
-
-  JS::RootedValue jsKey(args->jsContext);
-  const NS_ConvertUTF8toUTF16 key(entry->GetKey());
-  jsKey.setString(JS_NewUCStringCopyN(args->jsContext, key.Data(), key.Length()));
-  args->vector->append(jsKey);
-
-  return PL_DHASH_NEXT;
-}
-
-nsresult
-KeyedHistogram::GetJSKeys(JSContext* cx, JS::CallArgs& args)
-{
-  JS::AutoValueVector keys(cx);
-  if (!keys.reserve(mHistogramMap.Count())) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  ReflectKeysArgs reflectArgs = { cx, &keys };
-  const uint32_t num = mHistogramMap.EnumerateEntries(&KeyedHistogram::ReflectKeys,
-                                                      static_cast<void*>(&reflectArgs));
-  if (num != mHistogramMap.Count()) {
-    return NS_ERROR_FAILURE;
-  }
-
-  JS::RootedObject jsKeys(cx, JS_NewArrayObject(cx, keys));
-  if (!jsKeys) {
-    return NS_ERROR_FAILURE;
-  }
-
-  args.rval().setObject(*jsKeys);
-  return NS_OK;
-}
-
-/* static */
-bool
-KeyedHistogram::ReflectKeyedHistogram(KeyedHistogramEntry* entry, JSContext* cx, JS::Handle<JSObject*> obj)
-{
-  JS::RootedObject histogramSnapshot(cx, JS_NewPlainObject(cx));
-  if (!histogramSnapshot) {
-    return false;
-  }
-
-  if (ReflectHistogramSnapshot(cx, histogramSnapshot, entry->mData) != REFLECT_OK) {
-    return false;
-  }
-
-  const NS_ConvertUTF8toUTF16 key(entry->GetKey());
-  if (!JS_DefineUCProperty(cx, obj, key.Data(), key.Length(),
-                           histogramSnapshot, JSPROP_ENUMERATE)) {
-    return false;
-  }
-
-  return true;
-}
-
-nsresult
-KeyedHistogram::GetJSSnapshot(JSContext* cx, JS::Handle<JSObject*> obj)
-{
-  if (!mHistogramMap.ReflectIntoJS(&KeyedHistogram::ReflectKeyedHistogram, cx, obj)) {
-    return NS_ERROR_FAILURE;
-  }
-
-  return NS_OK;
-}
+class KeyedHistogram;
 
 class TelemetryImpl MOZ_FINAL
   : public nsITelemetry
   , public nsIMemoryReporter
 {
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSITELEMETRY
   NS_DECL_NSIMEMORYREPORTER
@@ -935,27 +758,66 @@ TelemetryImpl::CollectReports(nsIHandleR
                               nsISupports* aData, bool aAnonymize)
 {
   return MOZ_COLLECT_REPORT(
     "explicit/telemetry", KIND_HEAP, UNITS_BYTES,
     SizeOfIncludingThis(TelemetryMallocSizeOf),
     "Memory used by the telemetry system.");
 }
 
+class KeyedHistogram {
+public:
+  KeyedHistogram(const nsACString &name, const nsACString &expiration,
+                 uint32_t histogramType, uint32_t min, uint32_t max,
+                 uint32_t bucketCount);
+  nsresult GetHistogram(const nsCString& name, Histogram** histogram);
+  Histogram* GetHistogram(const nsCString& name);
+  uint32_t GetHistogramType() const { return mHistogramType; }
+  nsresult GetDataset(uint32_t* dataset) const;
+  nsresult GetJSKeys(JSContext* cx, JS::CallArgs& args);
+  nsresult GetJSSnapshot(JSContext* cx, JS::Handle<JSObject*> obj);
+  void Clear();
+
+private:
+  typedef nsBaseHashtableET<nsCStringHashKey, Histogram*> KeyedHistogramEntry;
+  typedef AutoHashtable<KeyedHistogramEntry> KeyedHistogramMapType;
+  KeyedHistogramMapType mHistogramMap;
+
+  struct ReflectKeysArgs {
+    JSContext* jsContext;
+    JS::AutoValueVector* vector;
+  };
+  static PLDHashOperator ReflectKeys(KeyedHistogramEntry* entry, void* arg);
+
+  static bool ReflectKeyedHistogram(KeyedHistogramEntry* entry,
+                                    JSContext* cx,
+                                    JS::Handle<JSObject*> obj);
+
+  static PLDHashOperator ClearHistogramEnumerator(KeyedHistogramEntry*, void*);
+
+  const nsCString mName;
+  const nsCString mExpiration;
+  const uint32_t mHistogramType;
+  const uint32_t mMin;
+  const uint32_t mMax;
+  const uint32_t mBucketCount;
+};
+
 // A initializer to initialize histogram collection
 StatisticsRecorder gStatisticsRecorder;
 
 // Hardcoded probes
 struct TelemetryHistogram {
   uint32_t min;
   uint32_t max;
   uint32_t bucketCount;
   uint32_t histogramType;
   uint32_t id_offset;
   uint32_t expiration_offset;
+  uint32_t dataset;
   bool extendedStatisticsOK;
   bool keyed;
 
   const char *id() const;
   const char *expiration() const;
 };
 
 #include "TelemetryHistogramData.inc"
@@ -987,16 +849,33 @@ IsExpired(const Histogram *histogram){
 }
 
 bool
 IsValidHistogramName(const nsACString& name)
 {
   return !FindInReadable(nsCString(KEYED_HISTOGRAM_NAME_SEPARATOR), name);
 }
 
+bool
+IsInDataset(const TelemetryHistogram& h, uint32_t dataset)
+{
+  if (h.dataset == dataset) {
+    return true;
+  }
+
+  // The "optin on release channel" dataset is a superset of the
+  // "optout on release channel one".
+  if (dataset == nsITelemetry::DATASET_RELEASE_CHANNEL_OPTIN
+      && h.dataset == nsITelemetry::DATASET_RELEASE_CHANNEL_OPTOUT) {
+    return true;
+  }
+
+  return false;
+}
+
 nsresult
 CheckHistogramArguments(uint32_t histogramType, uint32_t min, uint32_t max,
                         uint32_t bucketCount, bool haveOptArgs)
 {
   if (histogramType != nsITelemetry::HISTOGRAM_BOOLEAN
       && histogramType != nsITelemetry::HISTOGRAM_FLAG
       && histogramType != nsITelemetry::HISTOGRAM_COUNT) {
     // The min, max & bucketCount arguments are not optional for this type.
@@ -1267,30 +1146,51 @@ JSHistogram_Clear(JSContext *cx, unsigne
     return false;
   }
 
   Histogram *h = static_cast<Histogram*>(JS_GetPrivate(obj));
   h->Clear();
   return true;
 }
 
+bool
+JSHistogram_Dataset(JSContext *cx, unsigned argc, JS::Value *vp)
+{
+  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  JSObject *obj = JS_THIS_OBJECT(cx, vp);
+  if (!obj) {
+    return false;
+  }
+
+  Histogram *h = static_cast<Histogram*>(JS_GetPrivate(obj));
+  Telemetry::ID id;
+  nsresult rv = TelemetryImpl::GetHistogramEnumId(h->histogram_name().c_str(), &id);
+  if (NS_SUCCEEDED(rv)) {
+    args.rval().setNumber(gHistograms[id].dataset);
+    return true;
+  }
+
+  return false;
+}
+
 nsresult
 WrapAndReturnHistogram(Histogram *h, JSContext *cx, JS::MutableHandle<JS::Value> ret)
 {
   static const JSClass JSHistogram_class = {
     "JSHistogram",  /* name */
     JSCLASS_HAS_PRIVATE  /* flags */
   };
 
   JS::Rooted<JSObject*> obj(cx, JS_NewObject(cx, &JSHistogram_class));
   if (!obj)
     return NS_ERROR_FAILURE;
   if (!(JS_DefineFunction(cx, obj, "add", JSHistogram_Add, 1, 0)
         && JS_DefineFunction(cx, obj, "snapshot", JSHistogram_Snapshot, 0, 0)
-        && JS_DefineFunction(cx, obj, "clear", JSHistogram_Clear, 0, 0))) {
+        && JS_DefineFunction(cx, obj, "clear", JSHistogram_Clear, 0, 0)
+        && JS_DefineFunction(cx, obj, "dataset", JSHistogram_Dataset, 0, 0))) {
     return NS_ERROR_FAILURE;
   }
   JS_SetPrivate(obj, h);
   ret.setObject(*obj);
   return NS_OK;
 }
 
 bool
@@ -1443,31 +1343,56 @@ JSKeyedHistogram_Clear(JSContext *cx, un
   if (!keyed) {
     return false;
   }
 
   keyed->Clear();
   return true;
 }
 
+bool
+JSKeyedHistogram_Dataset(JSContext *cx, unsigned argc, JS::Value *vp)
+{
+  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  JSObject *obj = JS_THIS_OBJECT(cx, vp);
+  if (!obj) {
+    return false;
+  }
+
+  KeyedHistogram* keyed = static_cast<KeyedHistogram*>(JS_GetPrivate(obj));
+  if (!keyed) {
+    return false;
+  }
+
+  uint32_t dataset = nsITelemetry::DATASET_RELEASE_CHANNEL_OPTIN;
+  nsresult rv = keyed->GetDataset(&dataset);;
+  if (NS_FAILED(rv)) {
+    return false;
+  }
+
+  args.rval().setNumber(dataset);
+  return true;
+}
+
 nsresult
 WrapAndReturnKeyedHistogram(KeyedHistogram *h, JSContext *cx, JS::MutableHandle<JS::Value> ret)
 {
   static const JSClass JSHistogram_class = {
     "JSKeyedHistogram",  /* name */
     JSCLASS_HAS_PRIVATE  /* flags */
   };
 
   JS::Rooted<JSObject*> obj(cx, JS_NewObject(cx, &JSHistogram_class));
   if (!obj)
     return NS_ERROR_FAILURE;
   if (!(JS_DefineFunction(cx, obj, "add", JSKeyedHistogram_Add, 2, 0)
         && JS_DefineFunction(cx, obj, "snapshot", JSKeyedHistogram_Snapshot, 1, 0)
         && JS_DefineFunction(cx, obj, "keys", JSKeyedHistogram_Keys, 0, 0)
-        && JS_DefineFunction(cx, obj, "clear", JSKeyedHistogram_Clear, 0, 0))) {
+        && JS_DefineFunction(cx, obj, "clear", JSKeyedHistogram_Clear, 0, 0)
+        && JS_DefineFunction(cx, obj, "dataset", JSKeyedHistogram_Dataset, 0, 0))) {
     return NS_ERROR_FAILURE;
   }
 
   JS_SetPrivate(obj, h);
   ret.setObject(*obj);
   return NS_OK;
 }
 
@@ -1788,17 +1713,17 @@ TelemetryImpl::NewKeyedHistogram(const n
 
   nsresult rv = CheckHistogramArguments(histogramType, min, max, bucketCount, optArgCount == 3);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   KeyedHistogram* keyed = new KeyedHistogram(name, expiration, histogramType,
                                              min, max, bucketCount);
-  if (MOZ_UNLIKELY(!mKeyedHistograms.Put(name, keyed, fallible_t()))) {
+  if (MOZ_UNLIKELY(!mKeyedHistograms.Put(name, keyed, fallible))) {
     delete keyed;
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   return WrapAndReturnKeyedHistogram(keyed, cx, ret);
 }
 
 
@@ -2882,23 +2807,25 @@ TelemetryImpl::GetLateWrites(JSContext *
     return NS_ERROR_FAILURE;
   }
 
   ret.setObject(*report);
   return NS_OK;
 }
 
 nsresult
-GetRegisteredHistogramIds(bool keyed, uint32_t *aCount, char*** aHistograms)
+GetRegisteredHistogramIds(bool keyed, uint32_t dataset, uint32_t *aCount,
+                          char*** aHistograms)
 {
   nsTArray<char*> collection;
 
   for (size_t i = 0; i < ArrayLength(gHistograms); ++i) {
     const TelemetryHistogram& h = gHistograms[i];
-    if (IsExpired(h.expiration()) || h.keyed != keyed) {
+    if (IsExpired(h.expiration()) || h.keyed != keyed ||
+        !IsInDataset(h, dataset)) {
       continue;
     }
 
     const char* id = h.id();
     const size_t len = strlen(id);
     collection.AppendElement(static_cast<char*>(nsMemory::Clone(id, len+1)));
   }
 
@@ -2907,25 +2834,27 @@ GetRegisteredHistogramIds(bool keyed, ui
   memcpy(histograms, collection.Elements(), bytes);
   *aHistograms = histograms;
   *aCount = collection.Length();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-TelemetryImpl::RegisteredHistograms(uint32_t *aCount, char*** aHistograms)
+TelemetryImpl::RegisteredHistograms(uint32_t aDataset, uint32_t *aCount,
+                                    char*** aHistograms)
 {
-  return GetRegisteredHistogramIds(false, aCount, aHistograms);
+  return GetRegisteredHistogramIds(false, aDataset, aCount, aHistograms);
 }
 
 NS_IMETHODIMP
-TelemetryImpl::RegisteredKeyedHistograms(uint32_t *aCount, char*** aHistograms)
+TelemetryImpl::RegisteredKeyedHistograms(uint32_t aDataset, uint32_t *aCount,
+                                         char*** aHistograms)
 {
-  return GetRegisteredHistogramIds(true, aCount, aHistograms);
+  return GetRegisteredHistogramIds(true, aDataset, aCount, aHistograms);
 }
 
 NS_IMETHODIMP
 TelemetryImpl::GetHistogramById(const nsACString &name, JSContext *cx,
                                 JS::MutableHandle<JS::Value> ret)
 {
   Histogram *h;
   nsresult rv = GetHistogramByName(name, &h);
@@ -3831,8 +3760,165 @@ NSMODULE_DEFN(nsTelemetryModule) = &kTel
  * The XRE_TelemetryAdd function is to be used by embedding applications
  * that can't use mozilla::Telemetry::Accumulate() directly.
  */
 void
 XRE_TelemetryAccumulate(int aID, uint32_t aSample)
 {
   mozilla::Telemetry::Accumulate((mozilla::Telemetry::ID) aID, aSample);
 }
+
+KeyedHistogram::KeyedHistogram(const nsACString &name, const nsACString &expiration,
+                               uint32_t histogramType, uint32_t min, uint32_t max,
+                               uint32_t bucketCount)
+  : mHistogramMap()
+  , mName(name)
+  , mExpiration(expiration)
+  , mHistogramType(histogramType)
+  , mMin(min)
+  , mMax(max)
+  , mBucketCount(bucketCount)
+{
+}
+
+nsresult
+KeyedHistogram::GetHistogram(const nsCString& key, Histogram** histogram)
+{
+  KeyedHistogramEntry* entry = mHistogramMap.GetEntry(key);
+  if (entry) {
+    *histogram = entry->mData;
+    return NS_OK;
+  }
+
+  nsCString histogramName = mName;
+  histogramName.Append(KEYED_HISTOGRAM_NAME_SEPARATOR);
+  histogramName.Append(key);
+
+  Histogram* h;
+  nsresult rv = HistogramGet(histogramName.get(), mExpiration.get(),
+                             mHistogramType, mMin, mMax, mBucketCount,
+                             true, &h);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  h->ClearFlags(Histogram::kUmaTargetedHistogramFlag);
+  h->SetFlags(Histogram::kExtendedStatisticsFlag);
+  *histogram = h;
+
+  entry = mHistogramMap.PutEntry(key);
+  if (MOZ_UNLIKELY(!entry)) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  entry->mData = h;
+  return NS_OK;
+}
+
+Histogram*
+KeyedHistogram::GetHistogram(const nsCString& key)
+{
+  Histogram* h = nullptr;
+  if (NS_FAILED(GetHistogram(key, &h))) {
+    return nullptr;
+  }
+  return h;
+}
+
+nsresult
+KeyedHistogram::GetDataset(uint32_t* dataset) const
+{
+  MOZ_ASSERT(dataset);
+
+  Telemetry::ID id;
+  nsresult rv = TelemetryImpl::GetHistogramEnumId(mName.get(), &id);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  *dataset = gHistograms[id].dataset;
+  return NS_OK;
+}
+
+/* static */
+PLDHashOperator
+KeyedHistogram::ClearHistogramEnumerator(KeyedHistogramEntry* entry, void*)
+{
+  entry->mData->Clear();
+  return PL_DHASH_NEXT;
+}
+
+void
+KeyedHistogram::Clear()
+{
+  mHistogramMap.EnumerateEntries(&KeyedHistogram::ClearHistogramEnumerator, nullptr);
+  mHistogramMap.Clear();
+}
+
+/* static */
+PLDHashOperator
+KeyedHistogram::ReflectKeys(KeyedHistogramEntry* entry, void* arg)
+{
+  ReflectKeysArgs* args = static_cast<ReflectKeysArgs*>(arg);
+
+  JS::RootedValue jsKey(args->jsContext);
+  const NS_ConvertUTF8toUTF16 key(entry->GetKey());
+  jsKey.setString(JS_NewUCStringCopyN(args->jsContext, key.Data(), key.Length()));
+  args->vector->append(jsKey);
+
+  return PL_DHASH_NEXT;
+}
+
+nsresult
+KeyedHistogram::GetJSKeys(JSContext* cx, JS::CallArgs& args)
+{
+  JS::AutoValueVector keys(cx);
+  if (!keys.reserve(mHistogramMap.Count())) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  ReflectKeysArgs reflectArgs = { cx, &keys };
+  const uint32_t num = mHistogramMap.EnumerateEntries(&KeyedHistogram::ReflectKeys,
+                                                      static_cast<void*>(&reflectArgs));
+  if (num != mHistogramMap.Count()) {
+    return NS_ERROR_FAILURE;
+  }
+
+  JS::RootedObject jsKeys(cx, JS_NewArrayObject(cx, keys));
+  if (!jsKeys) {
+    return NS_ERROR_FAILURE;
+  }
+
+  args.rval().setObject(*jsKeys);
+  return NS_OK;
+}
+
+/* static */
+bool
+KeyedHistogram::ReflectKeyedHistogram(KeyedHistogramEntry* entry, JSContext* cx, JS::Handle<JSObject*> obj)
+{
+  JS::RootedObject histogramSnapshot(cx, JS_NewPlainObject(cx));
+  if (!histogramSnapshot) {
+    return false;
+  }
+
+  if (ReflectHistogramSnapshot(cx, histogramSnapshot, entry->mData) != REFLECT_OK) {
+    return false;
+  }
+
+  const NS_ConvertUTF8toUTF16 key(entry->GetKey());
+  if (!JS_DefineUCProperty(cx, obj, key.Data(), key.Length(),
+                           histogramSnapshot, JSPROP_ENUMERATE)) {
+    return false;
+  }
+
+  return true;
+}
+
+nsresult
+KeyedHistogram::GetJSSnapshot(JSContext* cx, JS::Handle<JSObject*> obj)
+{
+  if (!mHistogramMap.ReflectIntoJS(&KeyedHistogram::ReflectKeyedHistogram, cx, obj)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
+}
--- a/toolkit/components/telemetry/TelemetrySession.jsm
+++ b/toolkit/components/telemetry/TelemetrySession.jsm
@@ -455,17 +455,17 @@ let Impl = {
     if (last && last < c.length)
       retgram.values[r[last]] = 0;
     return retgram;
   },
 
   getHistograms: function getHistograms(hls) {
     this._log.trace("getHistograms");
 
-    let registered = Telemetry.registeredHistograms([]);
+    let registered = Telemetry.registeredHistograms(Ci.nsITelemetry.DATASET_EXTENDED, []);
     let ret = {};
 
     for (let name of registered) {
       for (let n of [name, "STARTUP_" + name]) {
         if (n in hls) {
           ret[n] = this.packHistogram(hls[n]);
         }
       }
@@ -491,17 +491,17 @@ let Impl = {
     }
 
     return ret;
   },
 
   getKeyedHistograms: function() {
     this._log.trace("getKeyedHistograms");
 
-    let registered = Telemetry.registeredKeyedHistograms([]);
+    let registered = Telemetry.registeredKeyedHistograms(Ci.nsITelemetry.DATASET_EXTENDED, []);
     let ret = {};
 
     for (let id of registered) {
       ret[id] = {};
       let keyed = Telemetry.getKeyedHistogramById(id);
       let snapshot = keyed.snapshot();
       for (let key of Object.keys(snapshot)) {
         ret[id][key] = this.packHistogram(snapshot[key]);
@@ -766,17 +766,17 @@ let Impl = {
   },
 
   /**
    * Make a copy of interesting histograms at startup.
    */
   gatherStartupHistograms: function gatherStartupHistograms() {
     this._log.trace("gatherStartupHistograms");
 
-    let info = Telemetry.registeredHistograms([]);
+    let info = Telemetry.registeredHistograms(Ci.nsITelemetry.DATASET_EXTENDED, []);
     let snapshots = Telemetry.histogramSnapshots;
     for (let name of info) {
       // Only duplicate histograms with actual data.
       if (this.isInterestingStartupHistogram(name) && name in snapshots) {
         Telemetry.histogramFrom("STARTUP_" + name, name);
       }
     }
   },
--- a/toolkit/components/telemetry/gen-histogram-data.py
+++ b/toolkit/components/telemetry/gen-histogram-data.py
@@ -55,20 +55,20 @@ class StringTable:
                 f.write("  /* %5d */ '\\0',\n" % offset)
         f.write("  /* %5d */ %s, '\\0' };\n\n"
                 % (entries[-1][1], explodeToCharArray(entries[-1][0])))
 
 def print_array_entry(histogram, name_index, exp_index):
     cpp_guard = histogram.cpp_guard()
     if cpp_guard:
         print "#if defined(%s)" % cpp_guard
-    print "  { %s, %s, %s, %s, %d, %d, %s, %s }," \
+    print "  { %s, %s, %s, %s, %d, %d, %s, %s, %s }," \
         % (histogram.low(), histogram.high(),
            histogram.n_buckets(), histogram.nsITelemetry_kind(),
-           name_index, exp_index,
+           name_index, exp_index, histogram.dataset(),
            "true" if histogram.extended_statistics_ok() else "false",
            "true" if histogram.keyed() else "false")
     if cpp_guard:
         print "#endif"
 
 def write_histogram_table(histograms):
     table = StringTable()
 
--- a/toolkit/components/telemetry/histogram_tools.py
+++ b/toolkit/components/telemetry/histogram_tools.py
@@ -50,17 +50,18 @@ def exponential_buckets(dmin, dmax, n_bu
         next_value = int(math.floor(math.exp(log_next) + 0.5))
         if next_value > current:
             current = next_value
         else:
             current = current + 1
         ret_array[bucket_index] = current
     return ret_array
 
-always_allowed_keys = ['kind', 'description', 'cpp_guard', 'expires_in_version', "alert_emails", 'keyed']
+always_allowed_keys = ['kind', 'description', 'cpp_guard', 'expires_in_version',
+                       'alert_emails', 'keyed', 'releaseChannelCollection']
 
 class Histogram:
     """A class for representing a histogram definition."""
 
     def __init__(self, name, definition):
         """Initialize a histogram named name with the given definition.
 definition is a dict-like object that must contain at least the keys:
 
@@ -83,16 +84,22 @@ symbol that should guard C/C++ definitio
         table = { 'boolean': 'BOOLEAN',
                   'flag': 'FLAG',
                   'count': 'COUNT',
                   'enumerated': 'LINEAR',
                   'linear': 'LINEAR',
                   'exponential': 'EXPONENTIAL' }
         table_dispatch(self.kind(), table,
                        lambda k: self._set_nsITelemetry_kind(k))
+        datasets = { 'opt-in': 'DATASET_RELEASE_CHANNEL_OPTIN',
+                     'opt-out': 'DATASET_RELEASE_CHANNEL_OPTOUT' }
+        value = definition.get('releaseChannelCollection', 'opt-in')
+        if not value in datasets:
+            raise DefinitionException, "unknown release channel collection policy for " + name
+        self._dataset = "nsITelemetry::" + datasets[value]
 
     def name(self):
         """Return the name of the histogram."""
         return self._name
 
     def description(self):
         """Return the description of the histogram."""
         return self._description
@@ -130,16 +137,20 @@ the histogram."""
         """Return the preprocessor symbol that should guard C/C++ definitions
 associated with the histogram.  Returns None if no guarding is necessary."""
         return self._cpp_guard
 
     def keyed(self):
         """Returns True if this a keyed histogram, false otherwise."""
         return self._keyed
 
+    def dataset(self):
+        """Returns the dataset this histogram belongs into."""
+        return self._dataset
+
     def extended_statistics_ok(self):
         """Return True if gathering extended statistics for this histogram
 is enabled."""
         return self._extended_statistics_ok
 
     def ranges(self):
         """Return an array of lower bounds for each bucket in the histogram."""
         table = { 'boolean': linear_buckets,
--- a/toolkit/components/telemetry/nsITelemetry.idl
+++ b/toolkit/components/telemetry/nsITelemetry.idl
@@ -24,16 +24,26 @@ interface nsITelemetry : nsISupports
    * HISTOGRAM_COUNT - For storing counter values without bucketing.
    */
   const unsigned long HISTOGRAM_EXPONENTIAL = 0;
   const unsigned long HISTOGRAM_LINEAR = 1;
   const unsigned long HISTOGRAM_BOOLEAN = 2;
   const unsigned long HISTOGRAM_FLAG = 3;
   const unsigned long HISTOGRAM_COUNT = 4;
 
+  /**
+   * Dataset types:
+   * DATASET_RELEASE_CHANNEL_OPTOUT - the basic dataset that is on-by-default on all channels
+   * DATASET_RELEASE_CHANNEL_OPTIN - the extended dataset that is opt-in on release,
+   *                                 opt-out on pre-release channels.
+   */
+  const unsigned long DATASET_RELEASE_CHANNEL_OPTOUT = 0;
+  const unsigned long DATASET_RELEASE_CHANNEL_OPTIN = 1;
+
+
   /*
    * An object containing a snapshot from all of the currently registered histograms.
    * { name1: {data1}, name2:{data2}...}
    * where data is consists of the following properties:
    *   min - Minimal bucket size
    *   max - Maximum bucket size
    *   histogram_type - HISTOGRAM_EXPONENTIAL, HISTOGRAM_LINEAR, HISTOGRAM_BOOLEAN
    *                    or HISTOGRAM_COUNT
@@ -129,33 +139,37 @@ interface nsITelemetry : nsISupports
    * symbolication server.
    */
   [implicit_jscontext]
   readonly attribute jsval lateWrites;
 
   /**
    * Returns an array whose values are the names of histograms defined
    * in Histograms.json.
+   *
+   * @param dataset - DATASET_RELEASE_CHANNEL_OPTOUT or DATASET_RELEASE_CHANNEL_OPTIN
    */
-  void registeredHistograms(out uint32_t count,
+  void registeredHistograms(in uint32_t dataset,
+                            out uint32_t count,
                             [retval, array, size_is(count)] out string histograms);
 
   /**
    * Create and return a histogram.  Parameters:
    *
    * @param name Unique histogram name
    * @param expiration Expiration version
    * @param type - HISTOGRAM_EXPONENTIAL, HISTOGRAM_LINEAR or HISTOGRAM_BOOLEAN
    * @param min - Minimal bucket size
    * @param max - Maximum bucket size
    * @param bucket_count - number of buckets in the histogram.
    * The returned object has the following functions:
    *   add(int) - Adds an int value to the appropriate bucket
    *   snapshot() - Returns a snapshot of the histogram with the same data fields as in histogramSnapshots()
    *   clear() - Zeros out the histogram's buckets and sum
+   *   dataset() - identifies what dataset this is in: DATASET_RELEASE_CHANNEL_OPTOUT or ...OPTIN
    */
   [implicit_jscontext, optional_argc]
   jsval newHistogram(in ACString name, in ACString expiration,
                      in unsigned long histogram_type,
                      [optional] in uint32_t min,
                      [optional] in uint32_t max,
                      [optional] in uint32_t bucket_count);
 
@@ -195,30 +209,33 @@ interface nsITelemetry : nsISupports
    * @param min - Minimal bucket size
    * @param max - Maximum bucket size
    * @param bucket_count - number of buckets in the histogram.
    * The returned object has the following functions:
    *   add(string key, [optional] int) - Add an int value to the histogram for that key. If no histogram for that key exists yet, it is created.
    *   snapshot([optional] string key) - If key is provided, returns a snapshot for the histogram with that key or null. If key is not provided, returns the snapshots of all the registered keys in the form {key1: snapshot1, key2: snapshot2, ...}.
    *   keys() - Returns an array with the string keys of the currently registered histograms
    *   clear() - Clears the registered histograms from this.
+   *   dataset() - identifies what dataset this is in: DATASET_RELEASE_CHANNEL_OPTOUT or ...OPTIN
    */
   [implicit_jscontext, optional_argc]
   jsval newKeyedHistogram(in ACString name,
                           in ACString expiration,
                           in unsigned long histogram_type,
                           [optional] in uint32_t min,
                           [optional] in uint32_t max,
                           [optional] in uint32_t bucket_count);
 
   /**
    * Returns an array whose values are the names of histograms defined
    * in Histograms.json.
+   *
+   * @param dataset - DATASET_RELEASE_CHANNEL_OPTOUT or ...OPTIN
    */
-  void registeredKeyedHistograms(out uint32_t count,
+  void registeredKeyedHistograms(in uint32_t dataset, out uint32_t count,
                                  [retval, array, size_is(count)] out string histograms);
 
   /**
    * Same as newKeyedHistogram above, but for histograms registered in TelemetryHistograms.h.
    *
    * @param id - unique identifier from TelemetryHistograms.h
    * The returned object has the same functions as a histogram returned from newKeyedHistogram.
    */
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryPing.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryPing.js
@@ -254,17 +254,17 @@ function checkPayload(request, reason, s
   const TELEMETRY_TEST_KEYED_COUNT = "TELEMETRY_TEST_KEYED_COUNT";
   const READ_SAVED_PING_SUCCESS = "READ_SAVED_PING_SUCCESS";
 
   do_check_true(TELEMETRY_PING in payload.histograms);
   do_check_true(READ_SAVED_PING_SUCCESS in payload.histograms);
   do_check_true(TELEMETRY_TEST_FLAG in payload.histograms);
   do_check_true(TELEMETRY_TEST_COUNT in payload.histograms);
 
-  let rh = Telemetry.registeredHistograms([]);
+  let rh = Telemetry.registeredHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, []);
   for (let name of rh) {
     if (/SQLITE/.test(name) && name in payload.histograms) {
       do_check_true(("STARTUP_" + name) in payload.histograms); 
     }
   }
   do_check_false(IGNORE_HISTOGRAM in payload.histograms);
   do_check_false(IGNORE_CLONED_HISTOGRAM in payload.histograms);
 
--- a/toolkit/components/telemetry/tests/unit/test_nsITelemetry.js
+++ b/toolkit/components/telemetry/tests/unit/test_nsITelemetry.js
@@ -10,17 +10,18 @@ const Telemetry = Cc["@mozilla.org/base/
 Cu.import("resource://gre/modules/Services.jsm", this);
 
 function test_expired_histogram() {
   var histogram_id = "FOOBAR";
   var test_expired_id = "TELEMETRY_TEST_EXPIRED";
   var clone_id = "ExpiredClone";
   var dummy = Telemetry.newHistogram(histogram_id, "28.0a1", Telemetry.HISTOGRAM_EXPONENTIAL, 1, 2, 3);
   var dummy_clone = Telemetry.histogramFrom(clone_id, test_expired_id);
-  var rh = Telemetry.registeredHistograms([]);
+  var rh = Telemetry.registeredHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, []);
+  Assert.ok(!!rh);
 
   dummy.add(1);
   dummy_clone.add(1);
 
   do_check_eq(Telemetry.histogramSnapshots["__expired__"], undefined);
   do_check_eq(Telemetry.histogramSnapshots[histogram_id], undefined);
   do_check_eq(Telemetry.histogramSnapshots[test_expired_id], undefined);
   do_check_eq(Telemetry.histogramSnapshots[clone_id], undefined);
@@ -553,16 +554,62 @@ function test_keyed_histogram() {
 
   // Check specific keyed histogram types working properly.
 
   test_keyed_boolean_histogram();
   test_keyed_count_histogram();
   test_keyed_flag_histogram();
 }
 
+function test_datasets()
+{
+  // Check that datasets work as expected.
+
+  const RELEASE_CHANNEL_OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
+  const RELEASE_CHANNEL_OPTIN  = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN;
+
+  // Histograms should default to the extended dataset
+  let h = Telemetry.getHistogramById("TELEMETRY_TEST_FLAG");
+  Assert.equal(h.dataset(), RELEASE_CHANNEL_OPTIN);
+  h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_FLAG");
+  Assert.equal(h.dataset(), RELEASE_CHANNEL_OPTIN);
+
+  // Check test histograms with explicit dataset definitions
+  h = Telemetry.getHistogramById("TELEMETRY_TEST_RELEASE_OPTIN");
+  Assert.equal(h.dataset(), RELEASE_CHANNEL_OPTIN);
+  h = Telemetry.getHistogramById("TELEMETRY_TEST_RELEASE_OPTOUT");
+  Assert.equal(h.dataset(), RELEASE_CHANNEL_OPTOUT);
+  h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_RELEASE_OPTIN");
+  Assert.equal(h.dataset(), RELEASE_CHANNEL_OPTIN);
+  h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT");
+  Assert.equal(h.dataset(), RELEASE_CHANNEL_OPTOUT);
+
+  // Check that registeredHistogram works properly
+  let registered = Telemetry.registeredHistograms(RELEASE_CHANNEL_OPTIN, []);
+  registered = new Set(registered);
+  Assert.ok(registered.has("TELEMETRY_TEST_FLAG"));
+  Assert.ok(registered.has("TELEMETRY_TEST_RELEASE_OPTIN"));
+  Assert.ok(registered.has("TELEMETRY_TEST_RELEASE_OPTOUT"));
+  registered = Telemetry.registeredHistograms(RELEASE_CHANNEL_OPTOUT, []);
+  registered = new Set(registered);
+  Assert.ok(!registered.has("TELEMETRY_TEST_FLAG"));
+  Assert.ok(!registered.has("TELEMETRY_TEST_RELEASE_OPTIN"));
+  Assert.ok(registered.has("TELEMETRY_TEST_RELEASE_OPTOUT"));
+
+  // Check that registeredKeyedHistograms works properly
+  registered = Telemetry.registeredKeyedHistograms(RELEASE_CHANNEL_OPTIN, []);
+  registered = new Set(registered);
+  Assert.ok(registered.has("TELEMETRY_TEST_KEYED_FLAG"));
+  Assert.ok(registered.has("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT"));
+  registered = Telemetry.registeredKeyedHistograms(RELEASE_CHANNEL_OPTOUT, []);
+  registered = new Set(registered);
+  Assert.ok(!registered.has("TELEMETRY_TEST_KEYED_FLAG"));
+  Assert.ok(registered.has("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT"));
+}
+
 function generateUUID() {
   let str = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID().toString();
   // strip {}
   return str.substring(1, str.length - 1);
 }
 
 function run_test()
 {
@@ -587,9 +634,10 @@ function run_test()
   test_getHistogramById();
   test_histogramFrom();
   test_getSlowSQL();
   test_privateMode();
   test_addons();
   test_extended_stats();
   test_expired_histogram();
   test_keyed_histogram();
+  test_datasets();
 }
--- a/widget/ContentHelper.cpp
+++ b/widget/ContentHelper.cpp
@@ -70,17 +70,19 @@ ContentHelper::UpdateAllowedBehavior(uin
 }
 
 ContentHelper::TouchBehaviorFlags
 ContentHelper::GetAllowedTouchBehavior(nsIWidget* aWidget, const nsIntPoint& aPoint)
 {
   nsView *view = nsView::GetViewFor(aWidget);
   nsIFrame *viewFrame = view->GetFrame();
 
-  nsPoint relativePoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aWidget, aPoint, viewFrame);
+  nsPoint relativePoint =
+    nsLayoutUtils::GetEventCoordinatesRelativeTo(
+      aWidget, LayoutDeviceIntPoint::FromUntyped(aPoint), viewFrame);
 
   nsIFrame *target = nsLayoutUtils::GetFrameForPoint(viewFrame, relativePoint, nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME);
   nsIScrollableFrame *nearestScrollableParent = nsLayoutUtils::GetNearestScrollableFrame(target, 0);
   nsIFrame* nearestScrollableFrame = do_QueryFrame(nearestScrollableParent);
 
   // We're walking up the DOM tree until we meet the element with touch behavior and accumulating
   // touch-action restrictions of all elements in this chain.
   // The exact quote from the spec, that clarifies more:
--- a/widget/InputData.cpp
+++ b/widget/InputData.cpp
@@ -16,17 +16,17 @@ namespace mozilla {
 
 using namespace dom;
 
 already_AddRefed<Touch> SingleTouchData::ToNewDOMTouch() const
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(),
                     "Can only create dom::Touch instances on main thread");
   nsRefPtr<Touch> touch = new Touch(mIdentifier,
-                                    nsIntPoint(mScreenPoint.x, mScreenPoint.y),
+                                    LayoutDeviceIntPoint(mScreenPoint.x, mScreenPoint.y),
                                     nsIntPoint(mRadius.width, mRadius.height),
                                     mRotationAngle,
                                     mForce);
   return touch.forget();
 }
 
 MultiTouchInput::MultiTouchInput(const WidgetTouchEvent& aTouchEvent)
   : InputData(MULTITOUCH_INPUT, aTouchEvent.time, aTouchEvent.timeStamp,
--- a/widget/android/AndroidJavaWrappers.cpp
+++ b/widget/android/AndroidJavaWrappers.cpp
@@ -733,17 +733,17 @@ AndroidGeckoEvent::MakeTouchEvent(nsIWid
     const nsIntPoint& offset = widget->WidgetToScreenOffset();
     event.touches.SetCapacity(endIndex - startIndex);
     for (int i = startIndex; i < endIndex; i++) {
         // In this code branch, we are dispatching this event directly
         // into Gecko (as opposed to going through the AsyncPanZoomController),
         // and the Points() array has points in CSS pixels, which we need
         // to convert.
         CSSToLayoutDeviceScale scale = widget->GetDefaultScale();
-        nsIntPoint pt(
+        LayoutDeviceIntPoint pt(
             (Points()[i].x * scale.scale) - offset.x,
             (Points()[i].y * scale.scale) - offset.y);
         nsIntPoint radii(
             PointRadii()[i].x * scale.scale,
             PointRadii()[i].y * scale.scale);
         nsRefPtr<Touch> t = new Touch(PointIndicies()[i],
                                       pt,
                                       radii,
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -1090,17 +1090,17 @@ bool nsWindow::OnMultitouchEvent(Android
     }
 
     if (isDownEvent && event.touches.Length() == 1) {
         // Since touch events don't get retargeted by PositionedEventTargeting.cpp
         // code on Fennec, we dispatch a dummy mouse event that *does* get
         // retargeted. The Fennec browser.js code can use this to activate the
         // highlight element in case the this touchstart is the start of a tap.
         WidgetMouseEvent hittest(true, NS_MOUSE_MOZHITTEST, this, WidgetMouseEvent::eReal);
-        hittest.refPoint = LayoutDeviceIntPoint::FromUntyped(event.touches[0]->mRefPoint);
+        hittest.refPoint = event.touches[0]->mRefPoint;
         hittest.ignoreRootScrollFrame = true;
         hittest.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
         nsEventStatus status;
         DispatchEvent(&hittest, status);
     }
 
     // if the last event we got was a down event, then by now we know for sure whether
     // this block has been default-prevented or not. if we haven't already sent the
@@ -1135,18 +1135,18 @@ bool nsWindow::OnMultitouchEvent(Android
     sLastWasDownEvent = isDownEvent;
 
     return preventDefaultActions;
 }
 
 void
 nsWindow::OnNativeGestureEvent(AndroidGeckoEvent *ae)
 {
-  nsIntPoint pt(ae->Points()[0].x,
-                ae->Points()[0].y);
+  LayoutDeviceIntPoint pt(ae->Points()[0].x,
+                          ae->Points()[0].y);
   double delta = ae->X();
   int msg = 0;
 
   switch (ae->Action()) {
       case AndroidMotionEvent::ACTION_MAGNIFY_START:
           msg = NS_SIMPLE_GESTURE_MAGNIFY_START;
           mStartDist = delta;
           mLastDist = delta;
@@ -1165,25 +1165,25 @@ nsWindow::OnNativeGestureEvent(AndroidGe
   }
 
   nsRefPtr<nsWindow> kungFuDeathGrip(this);
   DispatchGestureEvent(msg, 0, delta, pt, ae->Time());
 }
 
 void
 nsWindow::DispatchGestureEvent(uint32_t msg, uint32_t direction, double delta,
-                               const nsIntPoint &refPoint, uint64_t time)
+                               const LayoutDeviceIntPoint &refPoint, uint64_t time)
 {
     WidgetSimpleGestureEvent event(true, msg, this);
 
     event.direction = direction;
     event.delta = delta;
     event.modifiers = 0;
     event.time = time;
-    event.refPoint = LayoutDeviceIntPoint::FromUntyped(refPoint);
+    event.refPoint = refPoint;
 
     DispatchEvent(&event);
 }
 
 
 static unsigned int ConvertAndroidKeyCodeToDOMKeyCode(int androidKeyCode)
 {
     // Special-case alphanumeric keycodes because they are most common.
--- a/widget/android/nsWindow.h
+++ b/widget/android/nsWindow.h
@@ -234,17 +234,17 @@ protected:
     static void DumpWindows(const nsTArray<nsWindow*>& wins, int indent = 0);
     static void LogWindow(nsWindow *win, int index, int indent);
 
 private:
     void InitKeyEvent(mozilla::WidgetKeyboardEvent& event,
                       mozilla::AndroidGeckoEvent& key,
                       ANPEvent* pluginEvent);
     void DispatchGestureEvent(uint32_t msg, uint32_t direction, double delta,
-                              const nsIntPoint &refPoint, uint64_t time);
+                              const mozilla::LayoutDeviceIntPoint &refPoint, uint64_t time);
     void HandleSpecialKey(mozilla::AndroidGeckoEvent *ae);
     void CreateLayerManager(int aCompositorWidth, int aCompositorHeight);
     void RedrawAll();
 
     mozilla::AndroidLayerRendererFrame mLayerRendererFrame;
 
     static mozilla::StaticRefPtr<mozilla::layers::APZCTreeManager> sApzcTreeManager;
     static mozilla::StaticRefPtr<mozilla::layers::LayerManager> sLayerManager;
--- a/widget/gonk/nsWindow.cpp
+++ b/widget/gonk/nsWindow.cpp
@@ -276,33 +276,16 @@ nsWindow::DispatchTouchInputViaAPZ(Multi
         }
     }
 
     // If it didn't get captured, dispatch the event into the gecko root process
     // for "normal" flow. The event might get sent to the child process still,
     // but if it doesn't we need to notify the APZ of various things. All of
     // that happens in DispatchEventForAPZ
     rv = DispatchEventForAPZ(&event, guid, inputBlockId);
-
-    // Finally, if the touch event had only one touch point, generate a mouse
-    // event for it and send it through the gecko root process.
-    // Technically we should not need to do this if the touch event was routed
-    // to the child process, but that seems to expose a bug in B2G where the
-    // keyboard doesn't go away in some cases.
-    // Also for now we're dispatching mouse events from all touch events because
-    // we need this for click events to work in the chrome process. Once we have
-    // APZ and ChromeProcessController::HandleSingleTap working for the chrome
-    // process we shouldn't need to do this at all.
-    if (event.touches.Length() == 1) {
-        WidgetMouseEvent mouseEvent = aInput.ToWidgetMouseEvent(this);
-        if (mouseEvent.message != NS_EVENT_NULL) {
-            mouseEvent.mFlags.mNoCrossProcessBoundaryForwarding = (rv == nsEventStatus_eConsumeNoDefault);
-            DispatchEvent(&mouseEvent, rv);
-        }
-    }
 }
 
 
 nsresult
 nsWindow::SynthesizeNativeTouchPoint(uint32_t aPointerId,
                                      TouchPointerState aPointerState,
                                      nsIntPoint aPointerScreenPoint,
                                      double aPointerPressure,
--- a/widget/nsGUIEventIPC.h
+++ b/widget/nsGUIEventIPC.h
@@ -281,18 +281,17 @@ struct ParamTraits<mozilla::WidgetTouchE
             !ReadParam(aMsg, aIter, &refPoint) ||
             !ReadParam(aMsg, aIter, &radius) ||
             !ReadParam(aMsg, aIter, &rotationAngle) ||
             !ReadParam(aMsg, aIter, &force)) {
           return false;
         }
         aResult->touches.AppendElement(
           new mozilla::dom::Touch(
-            identifier, mozilla::LayoutDeviceIntPoint::ToUntyped(refPoint),
-            radius, rotationAngle, force));
+            identifier, refPoint, radius, rotationAngle, force));
     }
     return true;
   }
 };
 
 template<>
 struct ParamTraits<mozilla::AlternativeCharCode>
 {
--- a/widget/windows/nsIMM32Handler.cpp
+++ b/widget/windows/nsIMM32Handler.cpp
@@ -1684,17 +1684,17 @@ nsIMM32Handler::GetCompositionString(con
                                      nsAString& aCompositionString) const
 {
   aCompositionString.Truncate();
 
   // Retrieve the size of the required output buffer.
   long lRtn = ::ImmGetCompositionStringW(aIMEContext.get(), aIndex, nullptr, 0);
   if (lRtn < 0 ||
       !aCompositionString.SetLength((lRtn / sizeof(WCHAR)) + 1,
-                                    mozilla::fallible_t())) {
+                                    mozilla::fallible)) {
     PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
       ("IMM32: GetCompositionString, FAILED by OOM\n"));
     return; // Error or out of memory.
   }
 
   // Actually retrieve the composition string information.
   lRtn = ::ImmGetCompositionStringW(aIMEContext.get(), aIndex,
                                     (LPVOID)aCompositionString.BeginWriting(),
@@ -1751,17 +1751,17 @@ bool
 nsIMM32Handler::ConvertToANSIString(const nsAFlatString& aStr, UINT aCodePage,
                                    nsACString& aANSIStr)
 {
   int len = ::WideCharToMultiByte(aCodePage, 0,
                                   (LPCWSTR)aStr.get(), aStr.Length(),
                                   nullptr, 0, nullptr, nullptr);
   NS_ENSURE_TRUE(len >= 0, false);
 
-  if (!aANSIStr.SetLength(len, mozilla::fallible_t())) {
+  if (!aANSIStr.SetLength(len, mozilla::fallible)) {
     PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
       ("IMM32: ConvertToANSIString, FAILED by OOM\n"));
     return false;
   }
   ::WideCharToMultiByte(aCodePage, 0, (LPCWSTR)aStr.get(), aStr.Length(),
                         (LPSTR)aANSIStr.BeginWriting(), len, nullptr, nullptr);
   return true;
 }
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -6199,17 +6199,17 @@ bool nsWindow::OnTouch(WPARAM wParam, LP
 
       // Setup the touch point we'll append to the touch event array
       nsPointWin touchPoint;
       touchPoint.x = TOUCH_COORD_TO_PIXEL(pInputs[i].x);
       touchPoint.y = TOUCH_COORD_TO_PIXEL(pInputs[i].y);
       touchPoint.ScreenToClient(mWnd);
       nsRefPtr<Touch> touch =
         new Touch(pInputs[i].dwID,
-                  touchPoint,
+                  LayoutDeviceIntPoint::FromUntyped(touchPoint),
                   /* radius, if known */
                   pInputs[i].dwFlags & TOUCHINPUTMASKF_CONTACTAREA ?
                     nsIntPoint(
                       TOUCH_COORD_TO_PIXEL(pInputs[i].cxContact) / 2,
                       TOUCH_COORD_TO_PIXEL(pInputs[i].cyContact) / 2) :
                     nsIntPoint(1,1),
                   /* rotation angle and force */
                   0.0f, 0.0f);
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -1352,17 +1352,17 @@ private:
 
   void DoWalk(nsDeque& aQueue);
 
   void CheckedPush(nsDeque& aQueue, PtrInfo* aPi)
   {
     if (!aPi) {
       MOZ_CRASH();
     }
-    if (!aQueue.Push(aPi, fallible_t())) {
+    if (!aQueue.Push(aPi, fallible)) {
       mVisitor.Failed();
     }
   }
 
 public:
   void Walk(PtrInfo* aPi);
   void WalkFromRoots(CCGraph& aGraph);
   // copy-constructing the visitor should be cheap, and less
--- a/xpcom/ds/nsStaticNameTable.cpp
+++ b/xpcom/ds/nsStaticNameTable.cpp
@@ -134,17 +134,17 @@ nsStaticCaseInsensitiveNameTable::Init(c
 
   mNameArray = (nsDependentCString*)
     nsMemory::Alloc(aLength * sizeof(nsDependentCString));
   if (!mNameArray) {
     return false;
   }
 
   if (!PL_DHashTableInit(&mNameTable, &nametable_CaseInsensitiveHashTableOps,
-                         sizeof(NameTableEntry), fallible_t(),
+                         sizeof(NameTableEntry), fallible,
                          aLength)) {
     return false;
   }
 
   for (int32_t index = 0; index < aLength; ++index) {
     const char* raw = aNames[index];
 #ifdef DEBUG
     {
--- a/xpcom/ds/nsSupportsPrimitives.cpp
+++ b/xpcom/ds/nsSupportsPrimitives.cpp
@@ -2,18 +2,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsSupportsPrimitives.h"
 #include "nsMemory.h"
 #include "prprf.h"
 
-using mozilla::fallible_t;
-
 /***************************************************************************/
 
 NS_IMPL_ISUPPORTS(nsSupportsIDImpl, nsISupportsID, nsISupportsPrimitive)
 
 nsSupportsIDImpl::nsSupportsIDImpl()
   : mData(nullptr)
 {
 }
@@ -102,17 +100,17 @@ nsSupportsCStringImpl::ToString(char** a
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSupportsCStringImpl::SetData(const nsACString& aData)
 {
-  bool ok = mData.Assign(aData, fallible_t());
+  bool ok = mData.Assign(aData, mozilla::fallible);
   if (!ok) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   return NS_OK;
 }
 
 /*****************************************************************************
  * nsSupportsStringImpl
@@ -147,17 +145,17 @@ nsSupportsStringImpl::ToString(char16_t*
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSupportsStringImpl::SetData(const nsAString& aData)
 {
-  bool ok = mData.Assign(aData, fallible_t());
+  bool ok = mData.Assign(aData, mozilla::fallible);
   if (!ok) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   return NS_OK;
 }
 
 /***************************************************************************/
 
--- a/xpcom/glue/moz.build
+++ b/xpcom/glue/moz.build
@@ -109,8 +109,13 @@ if CONFIG['_MSC_VER']:
 LOCAL_INCLUDES += [
     '../build',
 ]
 
 if CONFIG['ENABLE_TESTS']:
     DIRS += ['tests/gtest']
 
 FAIL_ON_WARNINGS = True
+
+# Include fallible for third party code using the xpcom glue
+USE_LIBS += [
+    'fallible',
+]
--- a/xpcom/glue/nomozalloc/moz.build
+++ b/xpcom/glue/nomozalloc/moz.build
@@ -37,8 +37,13 @@ LOCAL_INCLUDES += [
 # avoids "msvcrp" and assembly dependencies from creeping into the directives
 # for this library on Windows.
 USE_STATIC_LIBS = True
 
 # Don't use STL wrappers here (i.e. wrapped <new>); they require mozalloc
 DISABLE_STL_WRAPPING = True
 
 FAIL_ON_WARNINGS = True
+
+# Include fallible for third party code using the xpcom glue
+USE_LIBS += [
+    'fallible',
+]
--- a/xpcom/glue/nsBaseHashtable.h
+++ b/xpcom/glue/nsBaseHashtable.h
@@ -118,17 +118,17 @@ public:
   /**
    * put a new value for the associated key
    * @param aKey the key to put
    * @param aData the new data
    * @return always true, unless memory allocation failed
    */
   void Put(KeyType aKey, const UserDataType& aData)
   {
-    if (!Put(aKey, aData, fallible_t())) {
+    if (!Put(aKey, aData, mozilla::fallible)) {
       NS_ABORT_OOM(this->mTable.EntrySize() * this->mTable.EntryCount());
     }
   }
 
   NS_WARN_UNUSED_RESULT bool Put(KeyType aKey, const UserDataType& aData,
                                  const fallible_t&)
   {
     EntryType* ent = this->PutEntry(aKey);
--- a/xpcom/glue/nsDeque.h
+++ b/xpcom/glue/nsDeque.h
@@ -79,31 +79,31 @@ public:
 
   /**
    * Appends new member at the end of the deque.
    *
    * @param   item to store in deque
    */
   void Push(void* aItem)
   {
-    if (!Push(aItem, fallible_t())) {
+    if (!Push(aItem, mozilla::fallible)) {
       NS_ABORT_OOM(mSize * sizeof(void*));
     }
   }
 
   NS_WARN_UNUSED_RESULT bool Push(void* aItem, const fallible_t&);
 
   /**
    * Inserts new member at the front of the deque.
    *
    * @param   item to store in deque
    */
   void PushFront(void* aItem)
   {
-    if (!PushFront(aItem, fallible_t())) {
+    if (!PushFront(aItem, mozilla::fallible)) {
       NS_ABORT_OOM(mSize * sizeof(void*));
     }
   }
 
   NS_WARN_UNUSED_RESULT bool PushFront(void* aItem, const fallible_t&);
 
   /**
    * Remove and return the last item in the container.
--- a/xpcom/glue/nsRefPtrHashtable.h
+++ b/xpcom/glue/nsRefPtrHashtable.h
@@ -142,17 +142,17 @@ nsRefPtrHashtable<KeyClass, RefPtr>::Get
   return nullptr;
 }
 
 template<class KeyClass, class RefPtr>
 void
 nsRefPtrHashtable<KeyClass, RefPtr>::Put(KeyType aKey,
                                          already_AddRefed<RefPtr> aData)
 {
-  if (!Put(aKey, mozilla::Move(aData), mozilla::fallible_t())) {
+  if (!Put(aKey, mozilla::Move(aData), mozilla::fallible)) {
     NS_ABORT_OOM(this->mTable.EntrySize() * this->mTable.EntryCount());
   }
 }
 
 template<class KeyClass, class RefPtr>
 bool
 nsRefPtrHashtable<KeyClass, RefPtr>::Put(KeyType aKey,
                                          already_AddRefed<RefPtr> aData,
--- a/xpcom/glue/nsTHashtable.h
+++ b/xpcom/glue/nsTHashtable.h
@@ -144,17 +144,17 @@ public:
   /**
    * Get the entry associated with a key, or create a new entry,
    * @param     aKey the key to retrieve
    * @return    pointer to the entry class retreived; nullptr only if memory
                 can't be allocated
    */
   EntryType* PutEntry(KeyType aKey)
   {
-    EntryType* e = PutEntry(aKey, fallible_t());
+    EntryType* e = PutEntry(aKey, mozilla::fallible);
     if (!e) {
       NS_ABORT_OOM(mTable.EntrySize() * mTable.EntryCount());
     }
     return e;
   }
 
   EntryType* PutEntry(KeyType aKey, const fallible_t&) NS_WARN_UNUSED_RESULT {
     NS_ASSERTION(mTable.IsInitialized(),
--- a/xpcom/glue/pldhash.cpp
+++ b/xpcom/glue/pldhash.cpp
@@ -171,17 +171,17 @@ PLDHashTable*
 PL_NewDHashTable(const PLDHashTableOps* aOps, uint32_t aEntrySize,
                  uint32_t aLength)
 {
   PLDHashTable* table = (PLDHashTable*)malloc(sizeof(*table));
 
   if (!table) {
     return nullptr;
   }
-  if (!PL_DHashTableInit(table, aOps, aEntrySize, fallible_t(), aLength)) {
+  if (!PL_DHashTableInit(table, aOps, aEntrySize, fallible, aLength)) {
     free(table);
     return nullptr;
   }
   return table;
 }
 
 void
 PL_DHashTableDestroy(PLDHashTable* aTable)
@@ -271,17 +271,17 @@ PL_DHashTableInit(PLDHashTable* aTable, 
 {
   return aTable->Init(aOps, aEntrySize, aFallible, aLength);
 }
 
 void
 PL_DHashTableInit(PLDHashTable* aTable, const PLDHashTableOps* aOps,
                   uint32_t aEntrySize, uint32_t aLength)
 {
-  if (!PL_DHashTableInit(aTable, aOps, aEntrySize, fallible_t(), aLength)) {
+  if (!PL_DHashTableInit(aTable, aOps, aEntrySize, fallible, aLength)) {
     if (aLength > PL_DHASH_MAX_INITIAL_LENGTH) {
       MOZ_CRASH();          // the asked-for length was too big
     }
     uint32_t capacity = MinCapacity(aLength), nbytes;
     if (!SizeOfEntryStore(capacity, aEntrySize, &nbytes)) {
       MOZ_CRASH();          // the required mEntryStore size was too big
     }
     NS_ABORT_OOM(nbytes);   // allocation failed
--- a/xpcom/glue/standalone/moz.build
+++ b/xpcom/glue/standalone/moz.build
@@ -39,8 +39,13 @@ DEFINES['XPCOM_GLUE'] = True
 LOCAL_INCLUDES += [
     '../../build',
 ]
 
 # Don't use STL wrappers here (i.e. wrapped <new>); they require mozalloc
 DISABLE_STL_WRAPPING = True
 
 FAIL_ON_WARNINGS = True
+
+# Include fallible for third party code using the xpcom glue
+USE_LIBS += [
+    'fallible',
+]
--- a/xpcom/glue/standalone/staticruntime/moz.build
+++ b/xpcom/glue/standalone/staticruntime/moz.build
@@ -34,8 +34,13 @@ LOCAL_INCLUDES += [
 
 # Statically link to the CRT on Windows
 USE_STATIC_LIBS = True
 
 # Don't use STL wrappers here (i.e. wrapped <new>); they require mozalloc
 DISABLE_STL_WRAPPING = True
 
 FAIL_ON_WARNINGS = True
+
+# Include fallible for third party code using the xpcom glue
+USE_LIBS += [
+    'fallible',
+]
--- a/xpcom/glue/staticruntime/moz.build
+++ b/xpcom/glue/staticruntime/moz.build
@@ -32,8 +32,13 @@ LOCAL_INCLUDES += [
 
 # Statically link to the CRT on Windows
 USE_STATIC_LIBS = True
 
 # Don't use STL wrappers here (i.e. wrapped <new>); they require mozalloc
 DISABLE_STL_WRAPPING = True
 
 FAIL_ON_WARNINGS = True
+
+# Include fallible for third party code using the xpcom glue
+USE_LIBS += [
+    'fallible',
+]
--- a/xpcom/io/Base64.cpp
+++ b/xpcom/io/Base64.cpp
@@ -262,17 +262,17 @@ Base64Encode(const nsACString& aBinaryDa
     return NS_OK;
   }
 
   uint32_t stringLen = ((aBinaryData.Length() + 2) / 3) * 4;
 
   char* buffer;
 
   // Add one byte for null termination.
-  if (aString.SetCapacity(stringLen + 1, fallible_t()) &&
+  if (aString.SetCapacity(stringLen + 1, fallible) &&
       (buffer = aString.BeginWriting()) &&
       PL_Base64Encode(aBinaryData.BeginReading(), aBinaryData.Length(), buffer)) {
     // PL_Base64Encode doesn't null terminate the buffer for us when we pass
     // the buffer in. Do that manually.
     buffer[stringLen] = '\0';
 
     aString.SetLength(stringLen);
     return NS_OK;
@@ -312,17 +312,17 @@ Base64Decode(const nsACString& aString, 
     return NS_OK;
   }
 
   uint32_t binaryDataLen = ((aString.Length() * 3) / 4);
 
   char* buffer;
 
   // Add one byte for null termination.
-  if (aBinaryData.SetCapacity(binaryDataLen + 1, fallible_t()) &&
+  if (aBinaryData.SetCapacity(binaryDataLen + 1, fallible) &&
       (buffer = aBinaryData.BeginWriting()) &&
       PL_Base64Decode(aString.BeginReading(), aString.Length(), buffer)) {
     // PL_Base64Decode doesn't null terminate the buffer for us when we pass
     // the buffer in. Do that manually, taking into account the number of '='
     // characters we were passed.
     if (!aString.IsEmpty() && aString[aString.Length() - 1] == '=') {
       if (aString.Length() > 1 && aString[aString.Length() - 2] == '=') {
         binaryDataLen -= 2;
--- a/xpcom/io/SnappyCompressOutputStream.cpp
+++ b/xpcom/io/SnappyCompressOutputStream.cpp
@@ -102,17 +102,17 @@ SnappyCompressOutputStream::WriteSegment
 {
   *aBytesWrittenOut = 0;
 
   if (!mBaseStream) {
     return NS_BASE_STREAM_CLOSED;
   }
 
   if (!mBuffer) {
-    mBuffer.reset(new ((fallible_t())) char[mBlockSize]);
+    mBuffer.reset(new (fallible) char[mBlockSize]);
     if (NS_WARN_IF(!mBuffer)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
   while (aCount > 0) {
     // Determine how much space is left in our flat, uncompressed buffer.
     MOZ_ASSERT(mNextByte <= mBlockSize);
@@ -169,17 +169,17 @@ SnappyCompressOutputStream::FlushToBaseS
 {
   MOZ_ASSERT(mBaseStream);
 
   // Lazily create the compressed buffer on our first flush.  This
   // allows us to report OOM during stream operation.  This buffer
   // will then get re-used until the stream is closed.
   if (!mCompressedBuffer) {
     mCompressedBufferLength = MaxCompressedBufferLength(mBlockSize);
-    mCompressedBuffer.reset(new ((fallible_t())) char[mCompressedBufferLength]);
+    mCompressedBuffer.reset(new (fallible) char[mCompressedBufferLength]);
     if (NS_WARN_IF(!mCompressedBuffer)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
   // The first chunk must be a StreamIdentifier chunk.  Write it out
   // if we have not done so already.
   nsresult rv = MaybeFlushStreamIdentifier();
--- a/xpcom/io/SnappyUncompressInputStream.cpp
+++ b/xpcom/io/SnappyUncompressInputStream.cpp
@@ -183,24 +183,24 @@ SnappyUncompressInputStream::ParseNextCh
 
   nsresult rv;
   *aBytesReadOut = 0;
 
   // Lazily create our two buffers so we can report OOM during stream
   // operation.  These allocations only happens once.  The buffers are reused
   // until the stream is closed.
   if (!mUncompressedBuffer) {
-    mUncompressedBuffer.reset(new ((fallible_t())) char[snappy::kBlockSize]);
+    mUncompressedBuffer.reset(new (fallible) char[snappy::kBlockSize]);
     if (NS_WARN_IF(!mUncompressedBuffer)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
   if (!mCompressedBuffer) {
-    mCompressedBuffer.reset(new ((fallible_t())) char[kCompressedBufferLength]);
+    mCompressedBuffer.reset(new (fallible) char[kCompressedBufferLength]);
     if (NS_WARN_IF(!mCompressedBuffer)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
   // We have no decompressed data and we also have not seen the start of stream
   // yet. Read and validate the StreamIdentifier chunk.  Also read the next
   // header to determine the size of the first real data chunk.
--- a/xpcom/io/nsBinaryStream.cpp
+++ b/xpcom/io/nsBinaryStream.cpp
@@ -760,17 +760,17 @@ nsBinaryInputStream::ReadString(nsAStrin
   }
 
   if (length == 0) {
     aString.Truncate();
     return NS_OK;
   }
 
   // pre-allocate output buffer, and get direct access to buffer...
-  if (!aString.SetLength(length, mozilla::fallible_t())) {
+  if (!aString.SetLength(length, mozilla::fallible)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   nsAString::iterator start;
   aString.BeginWriting(start);
 
   WriteStringClosure closure;
   closure.mWriteCursor = start.get();
--- a/xpcom/io/nsLocalFileWin.cpp
+++ b/xpcom/io/nsLocalFileWin.cpp
@@ -3649,17 +3649,17 @@ nsDriveEnumerator::~nsDriveEnumerator()
 nsresult
 nsDriveEnumerator::Init()
 {
   /* If the length passed to GetLogicalDriveStrings is smaller
    * than the length of the string it would return, it returns
    * the length required for the string. */
   DWORD length = GetLogicalDriveStringsW(0, 0);
   /* The string is null terminated */
-  if (!mDrives.SetLength(length + 1, fallible_t())) {
+  if (!mDrives.SetLength(length + 1, fallible)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   if (!GetLogicalDriveStringsW(length, wwc(mDrives.BeginWriting()))) {
     return NS_ERROR_FAILURE;
   }
   mDrives.BeginReading(mStartOfCurrentDrive);
   mDrives.EndReading(mEndOfDrivesString);
   return NS_OK;
--- a/xpcom/io/nsNativeCharsetUtils.cpp
+++ b/xpcom/io/nsNativeCharsetUtils.cpp
@@ -809,17 +809,17 @@ NS_CopyNativeToUnicode(const nsACString&
 
   //
   // OPTIMIZATION: preallocate space for largest possible result; convert
   // directly into the result buffer to avoid intermediate buffer copy.
   //
   // this will generally result in a larger allocation, but that seems
   // better than an extra buffer copy.
   //
-  if (!aOutput.SetLength(inputLen, fallible_t())) {
+  if (!aOutput.SetLength(inputLen, fallible)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   nsAString::iterator out_iter;
   aOutput.BeginWriting(out_iter);
 
   char16_t* result = out_iter.get();
   uint32_t resultLeft = inputLen;
 
@@ -920,17 +920,17 @@ NS_CopyNativeToUnicode(const nsACString&
   // determine length of result
   uint32_t resultLen = 0;
   int n = ::MultiByteToWideChar(CP_ACP, 0, buf, inputLen, nullptr, 0);
   if (n > 0) {
     resultLen += n;
   }
 
   // allocate sufficient space
-  if (!aOutput.SetLength(resultLen, fallible_t())) {
+  if (!aOutput.SetLength(resultLen, fallible)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   if (resultLen > 0) {
     nsAString::iterator out_iter;
     aOutput.BeginWriting(out_iter);
 
     char16_t* result = out_iter.get();
 
@@ -954,17 +954,17 @@ NS_CopyUnicodeToNative(const nsAString& 
 
   int n = ::WideCharToMultiByte(CP_ACP, 0, buf, inputLen, nullptr, 0,
                                 nullptr, nullptr);
   if (n > 0) {
     resultLen += n;
   }
 
   // allocate sufficient space
-  if (!aOutput.SetLength(resultLen, fallible_t())) {
+  if (!aOutput.SetLength(resultLen, fallible)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   if (resultLen > 0) {
     nsACString::iterator out_iter;
     aOutput.BeginWriting(out_iter);
 
     // default "defaultChar" is '?', which is an illegal character on windows
     // file system.  That will cause file uncreatable. Change it to '_'
--- a/xpcom/string/nsAString.h
+++ b/xpcom/string/nsAString.h
@@ -9,18 +9,16 @@
 #define nsAString_h___
 
 #include "nsStringFwd.h"
 #include "nsStringIterator.h"
 
 #include <string.h>
 #include <stdarg.h>
 
-#include "mozilla/fallible.h"
-
 #define kNotFound -1
 
 // declare nsAString
 #include "string-template-def-unichar.h"
 #include "nsTSubstring.h"
 #include "string-template-undef.h"
 
 // declare nsACString
--- a/xpcom/string/nsReadableUtils.cpp
+++ b/xpcom/string/nsReadableUtils.cpp
@@ -41,29 +41,29 @@ CopyASCIItoUTF16(const char* aSource, ns
   if (aSource) {
     AppendASCIItoUTF16(nsDependentCString(aSource), aDest);
   }
 }
 
 void
 CopyUTF16toUTF8(const nsAString& aSource, nsACString& aDest)
 {
-  if (!CopyUTF16toUTF8(aSource, aDest, mozilla::fallible_t())) {
+  if (!CopyUTF16toUTF8(aSource, aDest, mozilla::fallible)) {
     // Note that this may wildly underestimate the allocation that failed, as
     // we report the length of aSource as UTF-16 instead of UTF-8.
     aDest.AllocFailed(aDest.Length() + aSource.Length());
   }
 }
 
 bool
 CopyUTF16toUTF8(const nsAString& aSource, nsACString& aDest,
-                const mozilla::fallible_t&)
+                const mozilla::fallible_t& aFallible)
 {
   aDest.Truncate();
-  if (!AppendUTF16toUTF8(aSource, aDest, mozilla::fallible_t())) {
+  if (!AppendUTF16toUTF8(aSource, aDest, aFallible)) {
     return false;
   }
   return true;
 }
 
 void
 CopyUTF8toUTF16(const nsACString& aSource, nsAString& aDest)
 {
@@ -103,28 +103,28 @@ LossyAppendUTF16toASCII(const nsAString&
 
   copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd),
               converter);
 }
 
 void
 AppendASCIItoUTF16(const nsACString& aSource, nsAString& aDest)
 {
-  if (!AppendASCIItoUTF16(aSource, aDest, mozilla::fallible_t())) {
+  if (!AppendASCIItoUTF16(aSource, aDest, mozilla::fallible)) {
     aDest.AllocFailed(aDest.Length() + aSource.Length());
   }
 }
 
 bool
 AppendASCIItoUTF16(const nsACString& aSource, nsAString& aDest,
-                   const mozilla::fallible_t&)
+                   const mozilla::fallible_t& aFallible)
 {
   uint32_t old_dest_length = aDest.Length();
   if (!aDest.SetLength(old_dest_length + aSource.Length(),
-                       mozilla::fallible_t())) {
+                       aFallible)) {
     return false;
   }
 
   nsACString::const_iterator fromBegin, fromEnd;
 
   nsAString::iterator dest;
   aDest.BeginWriting(dest);
 
@@ -152,39 +152,39 @@ AppendASCIItoUTF16(const char* aSource, 
   if (aSource) {
     AppendASCIItoUTF16(nsDependentCString(aSource), aDest);
   }
 }
 
 void
 AppendUTF16toUTF8(const nsAString& aSource, nsACString& aDest)
 {
-  if (!AppendUTF16toUTF8(aSource, aDest, mozilla::fallible_t())) {
+  if (!AppendUTF16toUTF8(aSource, aDest, mozilla::fallible)) {
     // Note that this may wildly underestimate the allocation that failed, as
     // we report the length of aSource as UTF-16 instead of UTF-8.
     aDest.AllocFailed(aDest.Length() + aSource.Length());
   }
 }
 
 bool
 AppendUTF16toUTF8(const nsAString& aSource, nsACString& aDest,
-                  const mozilla::fallible_t&)
+                  const mozilla::fallible_t& aFallible)
 {
   nsAString::const_iterator source_start, source_end;
   CalculateUTF8Size calculator;
   copy_string(aSource.BeginReading(source_start),
               aSource.EndReading(source_end), calculator);
 
   uint32_t count = calculator.Size();
 
   if (count) {
     uint32_t old_dest_length = aDest.Length();
 
     // Grow the buffer if we need to.
-    if (!aDest.SetLength(old_dest_length + count, mozilla::fallible_t())) {
+    if (!aDest.SetLength(old_dest_length + count, aFallible)) {
       return false;
     }
 
     // All ready? Time to convert
 
     ConvertUTF16toUTF8 converter(aDest.BeginWriting() + old_dest_length);
     copy_string(aSource.BeginReading(source_start),
                 aSource.EndReading(source_end), converter);
@@ -195,38 +195,38 @@ AppendUTF16toUTF8(const nsAString& aSour
   }
 
   return true;
 }
 
 void
 AppendUTF8toUTF16(const nsACString& aSource, nsAString& aDest)
 {
-  if (!AppendUTF8toUTF16(aSource, aDest, mozilla::fallible_t())) {
+  if (!AppendUTF8toUTF16(aSource, aDest, mozilla::fallible)) {
     aDest.AllocFailed(aDest.Length() + aSource.Length());
   }
 }
 
 bool
 AppendUTF8toUTF16(const nsACString& aSource, nsAString& aDest,
-                  const mozilla::fallible_t&)
+                  const mozilla::fallible_t& aFallible)
 {
   nsACString::const_iterator source_start, source_end;
   CalculateUTF8Length calculator;
   copy_string(aSource.BeginReading(source_start),
               aSource.EndReading(source_end), calculator);
 
   uint32_t count = calculator.Length();
 
   // Avoid making the string mutable if we're appending an empty string
   if (count) {
     uint32_t old_dest_length = aDest.Length();
 
     // Grow the buffer if we need to.
-    if (!aDest.SetLength(old_dest_length + count, mozilla::fallible_t())) {
+    if (!aDest.SetLength(old_dest_length + count, aFallible)) {
       return false;
     }
 
     // All ready? Time to convert
 
     ConvertUTF8toUTF16 converter(aDest.BeginWriting() + old_dest_length);
     copy_string(aSource.BeginReading(source_start),
                 aSource.EndReading(source_end), converter);
--- a/xpcom/string/nsTStringObsolete.cpp
+++ b/xpcom/string/nsTStringObsolete.cpp
@@ -459,28 +459,28 @@ nsTString_CharT::ReplaceSubstring(const 
 {
   ReplaceSubstring(nsTDependentString_CharT(aTarget),
                    nsTDependentString_CharT(aNewValue));
 }
 
 bool
 nsTString_CharT::ReplaceSubstring(const char_type* aTarget,
                                   const char_type* aNewValue,
-                                  const fallible_t& fallible)
+                                  const fallible_t& aFallible)
 {
   return ReplaceSubstring(nsTDependentString_CharT(aTarget),
                           nsTDependentString_CharT(aNewValue),
-                          fallible);
+                          aFallible);
 }
 
 void
 nsTString_CharT::ReplaceSubstring(const self_type& aTarget,
                                   const self_type& aNewValue)
 {
-  if (!ReplaceSubstring(aTarget, aNewValue, fallible_t())) {
+  if (!ReplaceSubstring(aTarget, aNewValue, mozilla::fallible)) {
     // Note that this may wildly underestimate the allocation that failed, as
     // we could have been replacing multiple copies of aTarget.
     AllocFailed(mLength + (aNewValue.Length() - aTarget.Length()));
   }
 }
 
 bool
 nsTString_CharT::ReplaceSubstring(const self_type& aTarget,
--- a/xpcom/string/nsTSubstring.cpp
+++ b/xpcom/string/nsTSubstring.cpp
@@ -248,17 +248,17 @@ nsTSubstring_CharT::EnsureMutable(size_t
     }
     if ((mFlags & F_SHARED) &&
         !nsStringBuffer::FromData(mData)->IsReadonly()) {
       return true;
     }
 
     aNewLen = mLength;
   }
-  return SetLength(aNewLen, fallible_t());
+  return SetLength(aNewLen, mozilla::fallible);
 }
 
 // ---------------------------------------------------------------------------
 
 // This version of Assign is optimized for single-character assignment.
 void
 nsTSubstring_CharT::Assign(char_type aChar)
 {
@@ -278,72 +278,72 @@ nsTSubstring_CharT::Assign(char_type aCh
 
   *mData = aChar;
   return true;
 }
 
 void
 nsTSubstring_CharT::Assign(const char_type* aData)
 {
-  if (!Assign(aData, size_type(-1), fallible_t())) {
+  if (!Assign(aData, size_type(-1), mozilla::fallible)) {
     AllocFailed(char_traits::length(aData));
   }
 }
 
 void
 nsTSubstring_CharT::Assign(const char_type* aData, size_type aLength)
 {
-  if (!Assign(aData, aLength, fallible_t())) {
+  if (!Assign(aData, aLength, mozilla::fallible)) {
     AllocFailed(aLength == size_type(-1) ? char_traits::length(aData)
                                          : aLength);
   }
 }
 
 bool
 nsTSubstring_CharT::Assign(const char_type* aData, size_type aLength,
-                           const fallible_t&)
+                           const fallible_t& aFallible)
 {
   if (!aData || aLength == 0) {
     Truncate();
     return true;
   }
 
   if (aLength == size_type(-1)) {
     aLength = char_traits::length(aData);
   }
 
   if (IsDependentOn(aData, aData + aLength)) {
-    return Assign(string_type(aData, aLength), fallible_t());
+    return Assign(string_type(aData, aLength), aFallible);
   }
 
   if (!ReplacePrep(0, mLength, aLength)) {
     return false;
   }
 
   char_traits::copy(mData, aData, aLength);
   return true;
 }
 
 void
 nsTSubstring_CharT::AssignASCII(const char* aData, size_type aLength)
 {
-  if (!AssignASCII(aData, aLength, fallible_t())) {
+  if (!AssignASCII(aData, aLength, mozilla::fallible)) {
     AllocFailed(aLength);
   }
 }
 
 bool
 nsTSubstring_CharT::AssignASCII(const char* aData, size_type aLength,
-                                const fallible_t&)
+                                const fallible_t& aFallible)
 {
   // A Unicode string can't depend on an ASCII string buffer,
   // so this dependence check only applies to CStrings.
 #ifdef CharT_is_char
   if (IsDependentOn(aData, aData + aLength)) {
-    return Assign(string_type(aData, aLength), fallible_t());
+    return Assign(string_type(aData, aLength), aFallible);
   }
 #endif
 
   if (!ReplacePrep(0, mLength, aLength)) {
     return false;
   }
 
   char_traits::copyASCII(mData, aData, aLength);
@@ -357,23 +357,23 @@ nsTSubstring_CharT::AssignLiteral(const 
   mData = const_cast<char_type*>(aData);
   mLength = aLength;
   SetDataFlags(F_TERMINATED | F_LITERAL);
 }
 
 void
 nsTSubstring_CharT::Assign(const self_type& aStr)
 {
-  if (!Assign(aStr, fallible_t())) {
+  if (!Assign(aStr, mozilla::fallible)) {
     AllocFailed(aStr.Length());
   }
 }
 
 bool
-nsTSubstring_CharT::Assign(const self_type& aStr, const fallible_t&)
+nsTSubstring_CharT::Assign(const self_type& aStr, const fallible_t& aFallible)
 {
   // |aStr| could be sharable. We need to check its flags to know how to
   // deal with it.
 
   if (&aStr == this) {
     return true;
   }
 
@@ -401,34 +401,34 @@ nsTSubstring_CharT::Assign(const self_ty
   } else if (aStr.mFlags & F_LITERAL) {
     NS_ABORT_IF_FALSE(aStr.mFlags & F_TERMINATED, "Unterminated literal");
 
     AssignLiteral(aStr.mData, aStr.mLength);
     return true;
   }
 
   // else, treat this like an ordinary assignment.
-  return Assign(aStr.Data(), aStr.Length(), fallible_t());
+  return Assign(aStr.Data(), aStr.Length(), aFallible);
 }
 
 void
 nsTSubstring_CharT::Assign(const substring_tuple_type& aTuple)
 {
-  if (!Assign(aTuple, fallible_t())) {
+  if (!Assign(aTuple, mozilla::fallible)) {
     AllocFailed(aTuple.Length());
   }
 }
 
 bool
 nsTSubstring_CharT::Assign(const substring_tuple_type& aTuple,
-                           const fallible_t&)
+                           const fallible_t& aFallible)
 {
   if (aTuple.IsDependentOn(mData, mData + mLength)) {
     // take advantage of sharing here...
-    return Assign(string_type(aTuple), fallible_t());
+    return Assign(string_type(aTuple), aFallible);
   }
 
   size_type length = aTuple.Length();
 
   // don't use ReplacePrep here because it changes the length
   char_type* oldData;
   uint32_t oldFlags;
   if (!MutatePrep(length, &oldData, &oldFlags)) {
@@ -481,17 +481,17 @@ nsTSubstring_CharT::Replace(index_type a
   if (ReplacePrep(aCutStart, aCutLength, 1)) {
     mData[aCutStart] = aChar;
   }
 }
 
 bool
 nsTSubstring_CharT::Replace(index_type aCutStart, size_type aCutLength,
                             char_type aChar,
-                            const mozilla::fallible_t&)
+                            const fallible_t&)
 {
   aCutStart = XPCOM_MIN(aCutStart, Length());
 
   if (!ReplacePrep(aCutStart, aCutLength, 1)) {
     return false;
   }
 
   mData[aCutStart] = aChar;
@@ -499,37 +499,37 @@ nsTSubstring_CharT::Replace(index_type a
   return true;
 }
 
 void
 nsTSubstring_CharT::Replace(index_type aCutStart, size_type aCutLength,
                             const char_type* aData, size_type aLength)
 {
   if (!Replace(aCutStart, aCutLength, aData, aLength,
-               mozilla::fallible_t())) {
+               mozilla::fallible)) {
     AllocFailed(Length() - aCutLength + 1);
   }
 }
 
 bool
 nsTSubstring_CharT::Replace(index_type aCutStart, size_type aCutLength,
                             const char_type* aData, size_type aLength,
-                            const mozilla::fallible_t&)
+                            const fallible_t& aFallible)
 {
   // unfortunately, some callers pass null :-(
   if (!aData) {
     aLength = 0;
   } else {
     if (aLength == size_type(-1)) {
       aLength = char_traits::length(aData);
     }
 
     if (IsDependentOn(aData, aData + aLength)) {
       nsTAutoString_CharT temp(aData, aLength);
-      return Replace(aCutStart, aCutLength, temp, mozilla::fallible_t());
+      return Replace(aCutStart, aCutLength, temp, aFallible);
     }
   }
 
   aCutStart = XPCOM_MIN(aCutStart, Length());
 
   bool ok = ReplacePrep(aCutStart, aCutLength, aLength);
   if (!ok) {
     return false;
@@ -597,17 +597,17 @@ nsTSubstring_CharT::ReplaceLiteral(index
   } else if (ReplacePrep(aCutStart, aCutLength, aLength) && aLength > 0) {
     char_traits::copy(mData + aCutStart, aData, aLength);
   }
 }
 
 void
 nsTSubstring_CharT::SetCapacity(size_type aCapacity)
 {
-  if (!SetCapacity(aCapacity, fallible_t())) {
+  if (!SetCapacity(aCapacity, mozilla::fallible)) {
     AllocFailed(aCapacity);
   }
 }
 
 bool
 nsTSubstring_CharT::SetCapacity(size_type aCapacity, const fallible_t&)
 {
   // capacity does not include room for the terminating null char
@@ -654,19 +654,19 @@ nsTSubstring_CharT::SetCapacity(size_typ
 void
 nsTSubstring_CharT::SetLength(size_type aLength)
 {
   SetCapacity(aLength);
   mLength = aLength;
 }
 
 bool
-nsTSubstring_CharT::SetLength(size_type aLength, const fallible_t&)
+nsTSubstring_CharT::SetLength(size_type aLength, const fallible_t& aFallible)
 {
-  if (!SetCapacity(aLength, fallible_t())) {
+  if (!SetCapacity(aLength, aFallible)) {
     return false;
   }
 
   mLength = aLength;
   return true;
 }
 
 void
--- a/xpcom/string/nsTSubstring.h
+++ b/xpcom/string/nsTSubstring.h
@@ -171,29 +171,29 @@ public:
     return EnsureMutable() ? (mData + mLength) : char_iterator(0);
   }
 
   char_iterator& BeginWriting(char_iterator& aIter)
   {
     return aIter = BeginWriting();
   }
 
-  char_iterator& BeginWriting(char_iterator& aIter, const fallible_t&)
+  char_iterator& BeginWriting(char_iterator& aIter, const fallible_t& aFallible)
   {
-    return aIter = BeginWriting(fallible_t());
+    return aIter = BeginWriting(aFallible);
   }
 
   char_iterator& EndWriting(char_iterator& aIter)
   {
     return aIter = EndWriting();
   }
 
-  char_iterator& EndWriting(char_iterator& aIter, const fallible_t&)
+  char_iterator& EndWriting(char_iterator& aIter, const fallible_t& aFallible)
   {
-    return aIter = EndWriting(fallible_t());
+    return aIter = EndWriting(aFallible);
   }
 
   /**
    * deprecated writing iterators
    */
 
   iterator& BeginWriting(iterator& aIter)
   {
@@ -375,48 +375,50 @@ public:
                                                 const fallible_t&);
 
 #if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER)
   void Assign(char16ptr_t aData)
   {
     Assign(static_cast<const char16_t*>(aData));
   }
 
-  NS_WARN_UNUSED_RESULT bool Assign(char16ptr_t aData, const fallible_t&)
+  NS_WARN_UNUSED_RESULT bool Assign(char16ptr_t aData,
+                                    const fallible_t& aFallible)
   {
-    return Assign(static_cast<const char16_t*>(aData), fallible_t());
+    return Assign(static_cast<const char16_t*>(aData), aFallible);
   }
 
   void Assign(char16ptr_t aData, size_type aLength)
   {
     Assign(static_cast<const char16_t*>(aData), aLength);
   }
 
   NS_WARN_UNUSED_RESULT bool Assign(char16ptr_t aData, size_type aLength,
-                                    const fallible_t&)
+                                    const fallible_t& aFallible)
   {
-    return Assign(static_cast<const char16_t*>(aData), aLength, fallible_t());
+    return Assign(static_cast<const char16_t*>(aData), aLength,
+                  aFallible);
   }
 #endif
 
   void NS_FASTCALL AssignASCII(const char* aData, size_type aLength);
   NS_WARN_UNUSED_RESULT bool NS_FASTCALL AssignASCII(const char* aData,
                                                      size_type aLength,
                                                      const fallible_t&);
 
   void NS_FASTCALL AssignASCII(const char* aData)
   {
     AssignASCII(aData, mozilla::AssertedCast<size_type, size_t>(strlen(aData)));
   }
   NS_WARN_UNUSED_RESULT bool NS_FASTCALL AssignASCII(const char* aData,
-                                                     const fallible_t&)
+                                                     const fallible_t& aFallible)
   {
     return AssignASCII(aData,
                        mozilla::AssertedCast<size_type, size_t>(strlen(aData)),
-                       fallible_t());
+                       aFallible);
   }
 
   // AssignLiteral must ONLY be applied to an actual literal string, or
   // a char array *constant* declared without an explicit size.
   // Do not attempt to use it with a regular char* pointer, or with a
   // non-constant char array variable. Use AssignASCII for those.
   // There are not fallible version of these methods because they only really
   // apply to small allocations that we wouldn't want to check anyway.
@@ -468,37 +470,37 @@ public:
    * buffer manipulation
    */
 
   void NS_FASTCALL Replace(index_type aCutStart, size_type aCutLength,
                            char_type aChar);
   NS_WARN_UNUSED_RESULT bool NS_FASTCALL Replace(index_type aCutStart,
                                                  size_type aCutLength,
                                                  char_type aChar,
-                                                 const mozilla::fallible_t&);
+                                                 const fallible_t&);
   void NS_FASTCALL Replace(index_type aCutStart, size_type aCutLength,
                            const char_type* aData,
                            size_type aLength = size_type(-1));
   NS_WARN_UNUSED_RESULT bool NS_FASTCALL Replace(index_type aCutStart,
                                                  size_type aCutLength,
                                                  const char_type* aData,
                                                  size_type aLength,
-                                                 const mozilla::fallible_t&);
+                                                 const fallible_t&);
   void Replace(index_type aCutStart, size_type aCutLength,
                const self_type& aStr)
   {
     Replace(aCutStart, aCutLength, aStr.Data(), aStr.Length());
   }
   NS_WARN_UNUSED_RESULT bool Replace(index_type aCutStart,
                                      size_type aCutLength,
                                      const self_type& aStr,
-                                     const mozilla::fallible_t&)
+                                     const fallible_t& aFallible)
   {
     return Replace(aCutStart, aCutLength, aStr.Data(), aStr.Length(),
-                   mozilla::fallible_t());
+                   aFallible);
   }
   void NS_FASTCALL Replace(index_type aCutStart, size_type aCutLength,
                            const substring_tuple_type& aTuple);
 
   void NS_FASTCALL ReplaceASCII(index_type aCutStart, size_type aCutLength,
                                 const char* aData,
                                 size_type aLength = size_type(-1));
 
@@ -512,28 +514,28 @@ public:
     ReplaceLiteral(aCutStart, aCutLength, aStr, N - 1);
   }
 
   void Append(char_type aChar)
   {
     Replace(mLength, 0, aChar);
   }
   NS_WARN_UNUSED_RESULT bool Append(char_type aChar,
-                                    const mozilla::fallible_t&)
+                                    const fallible_t& aFallible)
   {
-    return Replace(mLength, 0, aChar, mozilla::fallible_t());
+    return Replace(mLength, 0, aChar, aFallible);
   }
   void Append(const char_type* aData, size_type aLength = size_type(-1))
   {
     Replace(mLength, 0, aData, aLength);
   }
   NS_WARN_UNUSED_RESULT bool Append(const char_type* aData, size_type aLength,
-                                    const mozilla::fallible_t&)
+                                    const fallible_t& aFallible)
   {
-    return Replace(mLength, 0, aData, aLength, mozilla::fallible_t());
+    return Replace(mLength, 0, aData, aLength, aFallible);
   }
 
 #if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER)
   void Append(char16ptr_t aData, size_type aLength = size_type(-1))
   {
     Append(static_cast<const char16_t*>(aData), aLength);
   }
 #endif
@@ -761,20 +763,21 @@ public:
   }
 
 #if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER)
   size_type GetMutableData(wchar_t** aData, size_type aNewLen = size_type(-1))
   {
     return GetMutableData(reinterpret_cast<char16_t**>(aData), aNewLen);
   }
 
-  size_type GetMutableData(wchar_t** aData, size_type aNewLen, const fallible_t&)
+  size_type GetMutableData(wchar_t** aData, size_type aNewLen,
+                           const fallible_t& aFallible)
   {
     return GetMutableData(reinterpret_cast<char16_t**>(aData), aNewLen,
-                          fallible_t());
+                          aFallible);
   }
 #endif
 
 
   /**
    * string data is never null, but can be marked void.  if true, the
    * string will be truncated.  @see nsTSubstring::IsVoid
    */
--- a/xpcom/tests/TestPLDHash.cpp
+++ b/xpcom/tests/TestPLDHash.cpp
@@ -22,17 +22,17 @@ static bool test_pldhash_Init_capacity_o
   if (t.IsInitialized()) {
     return false;
   }
 
   // Try the largest allowed capacity.  With PL_DHASH_MAX_CAPACITY==1<<26, this
   // will allocate 0.5GB of entry store on 32-bit platforms and 1GB on 64-bit
   // platforms.
   if (!PL_DHashTableInit(&t, PL_DHashGetStubOps(), sizeof(PLDHashEntryStub),
-                         mozilla::fallible_t(), PL_DHASH_MAX_INITIAL_LENGTH)) {
+                         mozilla::fallible, PL_DHASH_MAX_INITIAL_LENGTH)) {
     return false;
   }
 
   // Check that Init() sets |ops|.
   if (!t.IsInitialized()) {
     return false;
   }
 
@@ -52,17 +52,17 @@ static bool test_pldhash_Init_capacity_t
   // Check that the constructor nulls |ops|.
   if (t.IsInitialized()) {
     return false;
   }
 
   // Try the smallest too-large capacity.
   if (PL_DHashTableInit(&t, PL_DHashGetStubOps(),
                         sizeof(PLDHashEntryStub),
-                        mozilla::fallible_t(),
+                        mozilla::fallible,
                         PL_DHASH_MAX_INITIAL_LENGTH + 1)) {
     return false;   // it succeeded!?
   }
   // Don't call PL_DHashTableFinish() here; it's not safe after Init() failure.
 
   // Check that |ops| is still null.
   if (t.IsInitialized()) {
     return false;
@@ -88,17 +88,17 @@ static bool test_pldhash_Init_overflow()
   // test wouldn't be reliable.
 
   struct OneKBEntry {
       PLDHashEntryHdr hdr;
       char buf[1024 - sizeof(PLDHashEntryHdr)];
   };
 
   if (PL_DHashTableInit(&t, PL_DHashGetStubOps(), sizeof(OneKBEntry),
-                        mozilla::fallible_t(), PL_DHASH_MAX_INITIAL_LENGTH)) {
+                        mozilla::fallible, PL_DHASH_MAX_INITIAL_LENGTH)) {
     return false;   // it succeeded!?
   }
   // Don't call PL_DHashTableFinish() here; it's not safe after Init() failure.
 
   // Check that |ops| is still null.
   if (t.IsInitialized()) {
     return false;
   }
--- a/xpcom/tests/gtest/TestStrings.cpp
+++ b/xpcom/tests/gtest/TestStrings.cpp
@@ -6,22 +6,21 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include "nsString.h"
 #include "nsStringBuffer.h"
 #include "nsReadableUtils.h"
 #include "nsCRTGlue.h"
 #include "nsRefPtr.h"
 #include "nsTArray.h"
-#include "mozilla/fallible.h"
 #include "gtest/gtest.h"
 
 namespace TestStrings {
 
-using mozilla::fallible_t;
+using mozilla::fallible;
 
 void test_assign_helper(const nsACString& in, nsACString &_retval)
 {
   _retval = in;
 }
 
 TEST(Strings, assign)
 {
@@ -846,85 +845,85 @@ TEST(String, strip_chars)
 TEST(Strings, huge_capacity)
 {
   nsString a, b, c, d, e, f, g, h, i, j, k, l, m, n;
   nsCString n1;
 
   // Ignore the result if the address space is less than 64-bit because
   // some of the allocations above will exhaust the address space.
   if (sizeof(void*) >= 8) {
-    EXPECT_TRUE(a.SetCapacity(1, fallible_t()));
-    EXPECT_FALSE(a.SetCapacity(nsString::size_type(-1)/2, fallible_t()));
-    EXPECT_TRUE(a.SetCapacity(0, fallible_t()));  // free the allocated memory
+    EXPECT_TRUE(a.SetCapacity(1, fallible));
+    EXPECT_FALSE(a.SetCapacity(nsString::size_type(-1)/2, fallible));
+    EXPECT_TRUE(a.SetCapacity(0, fallible));  // free the allocated memory
 
-    EXPECT_TRUE(b.SetCapacity(1, fallible_t()));
-    EXPECT_FALSE(b.SetCapacity(nsString::size_type(-1)/2 - 1, fallible_t()));
-    EXPECT_TRUE(b.SetCapacity(0, fallible_t()));
+    EXPECT_TRUE(b.SetCapacity(1, fallible));
+    EXPECT_FALSE(b.SetCapacity(nsString::size_type(-1)/2 - 1, fallible));
+    EXPECT_TRUE(b.SetCapacity(0, fallible));
 
-    EXPECT_TRUE(c.SetCapacity(1, fallible_t()));
-    EXPECT_FALSE(c.SetCapacity(nsString::size_type(-1)/2, fallible_t()));
-    EXPECT_TRUE(c.SetCapacity(0, fallible_t()));
+    EXPECT_TRUE(c.SetCapacity(1, fallible));
+    EXPECT_FALSE(c.SetCapacity(nsString::size_type(-1)/2, fallible));
+    EXPECT_TRUE(c.SetCapacity(0, fallible));
 
-    EXPECT_FALSE(d.SetCapacity(nsString::size_type(-1)/2 - 1, fallible_t()));
-    EXPECT_FALSE(d.SetCapacity(nsString::size_type(-1)/2, fallible_t()));
-    EXPECT_TRUE(d.SetCapacity(0, fallible_t()));
+    EXPECT_FALSE(d.SetCapacity(nsString::size_type(-1)/2 - 1, fallible));
+    EXPECT_FALSE(d.SetCapacity(nsString::size_type(-1)/2, fallible));
+    EXPECT_TRUE(d.SetCapacity(0, fallible));
 
-    EXPECT_FALSE(e.SetCapacity(nsString::size_type(-1)/4, fallible_t()));
-    EXPECT_FALSE(e.SetCapacity(nsString::size_type(-1)/4 + 1, fallible_t()));
-    EXPECT_TRUE(e.SetCapacity(0, fallible_t()));
+    EXPECT_FALSE(e.SetCapacity(nsString::size_type(-1)/4, fallible));
+    EXPECT_FALSE(e.SetCapacity(nsString::size_type(-1)/4 + 1, fallible));
+    EXPECT_TRUE(e.SetCapacity(0, fallible));
 
-    EXPECT_FALSE(f.SetCapacity(nsString::size_type(-1)/2, fallible_t()));
-    EXPECT_TRUE(f.SetCapacity(0, fallible_t()));
+    EXPECT_FALSE(f.SetCapacity(nsString::size_type(-1)/2, fallible));
+    EXPECT_TRUE(f.SetCapacity(0, fallible));
 
-    EXPECT_FALSE(g.SetCapacity(nsString::size_type(-1)/4 + 1000, fallible_t()));
-    EXPECT_FALSE(g.SetCapacity(nsString::size_type(-1)/4 + 1001, fallible_t()));
-    EXPECT_TRUE(g.SetCapacity(0, fallible_t()));
+    EXPECT_FALSE(g.SetCapacity(nsString::size_type(-1)/4 + 1000, fallible));
+    EXPECT_FALSE(g.SetCapacity(nsString::size_type(-1)/4 + 1001, fallible));
+    EXPECT_TRUE(g.SetCapacity(0, fallible));
 
-    EXPECT_FALSE(h.SetCapacity(nsString::size_type(-1)/4+1, fallible_t()));
-    EXPECT_FALSE(h.SetCapacity(nsString::size_type(-1)/2, fallible_t()));
-    EXPECT_TRUE(h.SetCapacity(0, fallible_t()));
+    EXPECT_FALSE(h.SetCapacity(nsString::size_type(-1)/4+1, fallible));
+    EXPECT_FALSE(h.SetCapacity(nsString::size_type(-1)/2, fallible));
+    EXPECT_TRUE(h.SetCapacity(0, fallible));
 
-    EXPECT_TRUE(i.SetCapacity(1, fallible_t()));
-    EXPECT_TRUE(i.SetCapacity(nsString::size_type(-1)/4 - 1000, fallible_t()));
-    EXPECT_FALSE(i.SetCapacity(nsString::size_type(-1)/4 + 1, fallible_t()));
-    EXPECT_TRUE(i.SetCapacity(0, fallible_t()));
+    EXPECT_TRUE(i.SetCapacity(1, fallible));
+    EXPECT_TRUE(i.SetCapacity(nsString::size_type(-1)/4 - 1000, fallible));
+    EXPECT_FALSE(i.SetCapacity(nsString::size_type(-1)/4 + 1, fallible));
+    EXPECT_TRUE(i.SetCapacity(0, fallible));
 
-    EXPECT_TRUE(j.SetCapacity(nsString::size_type(-1)/4 - 1000, fallible_t()));
-    EXPECT_FALSE(j.SetCapacity(nsString::size_type(-1)/4 + 1, fallible_t()));
-    EXPECT_TRUE(j.SetCapacity(0, fallible_t()));
+    EXPECT_TRUE(j.SetCapacity(nsString::size_type(-1)/4 - 1000, fallible));
+    EXPECT_FALSE(j.SetCapacity(nsString::size_type(-1)/4 + 1, fallible));
+    EXPECT_TRUE(j.SetCapacity(0, fallible));
 
-    EXPECT_TRUE(k.SetCapacity(nsString::size_type(-1)/8 - 1000, fallible_t()));
-    EXPECT_TRUE(k.SetCapacity(nsString::size_type(-1)/4 - 1001, fallible_t()));
-    EXPECT_TRUE(k.SetCapacity(nsString::size_type(-1)/4 - 998, fallible_t()));
-    EXPECT_FALSE(k.SetCapacity(nsString::size_type(-1)/4 + 1, fallible_t()));
-    EXPECT_TRUE(k.SetCapacity(0, fallible_t()));
+    EXPECT_TRUE(k.SetCapacity(nsString::size_type(-1)/8 - 1000, fallible));
+    EXPECT_TRUE(k.SetCapacity(nsString::size_type(-1)/4 - 1001, fallible));
+    EXPECT_TRUE(k.SetCapacity(nsString::size_type(-1)/4 - 998, fallible));
+    EXPECT_FALSE(k.SetCapacity(nsString::size_type(-1)/4 + 1, fallible));
+    EXPECT_TRUE(k.SetCapacity(0, fallible));
 
-    EXPECT_TRUE(l.SetCapacity(nsString::size_type(-1)/8, fallible_t()));
-    EXPECT_TRUE(l.SetCapacity(nsString::size_type(-1)/8 + 1, fallible_t()));
-    EXPECT_TRUE(l.SetCapacity(nsString::size_type(-1)/8 + 2, fallible_t()));
-    EXPECT_TRUE(l.SetCapacity(0, fallible_t()));
+    EXPECT_TRUE(l.SetCapacity(nsString::size_type(-1)/8, fallible));
+    EXPECT_TRUE(l.SetCapacity(nsString::size_type(-1)/8 + 1, fallible));
+    EXPECT_TRUE(l.SetCapacity(nsString::size_type(-1)/8 + 2, fallible));
+    EXPECT_TRUE(l.SetCapacity(0, fallible));
 
-    EXPECT_TRUE(m.SetCapacity(nsString::size_type(-1)/8 + 1000, fallible_t()));
-    EXPECT_TRUE(m.SetCapacity(nsString::size_type(-1)/8 + 1001, fallible_t()));
-    EXPECT_TRUE(m.SetCapacity(0, fallible_t()));
+    EXPECT_TRUE(m.SetCapacity(nsString::size_type(-1)/8 + 1000, fallible));
+    EXPECT_TRUE(m.SetCapacity(nsString::size_type(-1)/8 + 1001, fallible));
+    EXPECT_TRUE(m.SetCapacity(0, fallible));
 
-    EXPECT_TRUE(n.SetCapacity(nsString::size_type(-1)/8+1, fallible_t()));
-    EXPECT_FALSE(n.SetCapacity(nsString::size_type(-1)/4, fallible_t()));
-    EXPECT_TRUE(n.SetCapacity(0, fallible_t()));
+    EXPECT_TRUE(n.SetCapacity(nsString::size_type(-1)/8+1, fallible));
+    EXPECT_FALSE(n.SetCapacity(nsString::size_type(-1)/4, fallible));
+    EXPECT_TRUE(n.SetCapacity(0, fallible));
 
-    EXPECT_TRUE(n.SetCapacity(0, fallible_t()));
-    EXPECT_TRUE(n.SetCapacity((nsString::size_type(-1)/2 - sizeof(nsStringBuffer)) / 2 - 2, fallible_t()));
-    EXPECT_TRUE(n.SetCapacity(0, fallible_t()));
-    EXPECT_FALSE(n.SetCapacity((nsString::size_type(-1)/2 - sizeof(nsStringBuffer)) / 2 - 1, fallible_t()));
-    EXPECT_TRUE(n.SetCapacity(0, fallible_t()));
-    EXPECT_TRUE(n1.SetCapacity(0, fallible_t()));
-    EXPECT_TRUE(n1.SetCapacity((nsCString::size_type(-1)/2 - sizeof(nsStringBuffer)) / 1 - 2, fallible_t()));
-    EXPECT_TRUE(n1.SetCapacity(0, fallible_t()));
-    EXPECT_FALSE(n1.SetCapacity((nsCString::size_type(-1)/2 - sizeof(nsStringBuffer)) / 1 - 1, fallible_t()));
-    EXPECT_TRUE(n1.SetCapacity(0, fallible_t()));
+    EXPECT_TRUE(n.SetCapacity(0, fallible));
+    EXPECT_TRUE(n.SetCapacity((nsString::size_type(-1)/2 - sizeof(nsStringBuffer)) / 2 - 2, fallible));
+    EXPECT_TRUE(n.SetCapacity(0, fallible));
+    EXPECT_FALSE(n.SetCapacity((nsString::size_type(-1)/2 - sizeof(nsStringBuffer)) / 2 - 1, fallible));
+    EXPECT_TRUE(n.SetCapacity(0, fallible));
+    EXPECT_TRUE(n1.SetCapacity(0, fallible));
+    EXPECT_TRUE(n1.SetCapacity((nsCString::size_type(-1)/2 - sizeof(nsStringBuffer)) / 1 - 2, fallible));
+    EXPECT_TRUE(n1.SetCapacity(0, fallible));
+    EXPECT_FALSE(n1.SetCapacity((nsCString::size_type(-1)/2 - sizeof(nsStringBuffer)) / 1 - 1, fallible));
+    EXPECT_TRUE(n1.SetCapacity(0, fallible));
   }
 }
 
 static void test_tofloat_helper(const nsString& aStr, float aExpected, bool aSuccess)
 {
   nsresult result;
   EXPECT_EQ(aStr.ToFloat(&result), aExpected);
   if (aSuccess) {