Merge m-i to m-c
authorPhil Ringnalda <philringnalda@gmail.com>
Fri, 28 Jun 2013 18:26:53 -0700
changeset 136835 c5ce065936fa
parent 136798 39d5755fd780 (current diff)
parent 136834 8d95c0feed77 (diff)
child 136836 ba1617e2e67d
child 136867 4df4f2767a69
child 136895 a8d2b85d56db
push id24896
push userphilringnalda@gmail.com
push date2013-06-29 01:27 +0000
treeherdermozilla-central@c5ce065936fa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone25.0a1
first release with
nightly linux32
c5ce065936fa / 25.0a1 / 20130629031116 / files
nightly linux64
c5ce065936fa / 25.0a1 / 20130629031116 / files
nightly mac
c5ce065936fa / 25.0a1 / 20130629031116 / files
nightly win32
c5ce065936fa / 25.0a1 / 20130629031116 / files
nightly win64
c5ce065936fa / 25.0a1 / 20130629031116 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-i to m-c
--- a/accessible/src/windows/ia2/ia2AccessibleAction.cpp
+++ b/accessible/src/windows/ia2/ia2AccessibleAction.cpp
@@ -14,16 +14,19 @@
 
 using namespace mozilla::a11y;
 
 // IUnknown
 
 STDMETHODIMP
 ia2AccessibleAction::QueryInterface(REFIID iid, void** ppv)
 {
+  if (!ppv)
+    return E_INVALIDARG;
+
   *ppv = nullptr;
 
   if (IID_IAccessibleAction == iid) {
     *ppv = static_cast<IAccessibleAction*>(this);
     (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
     return S_OK;
   }
 
@@ -68,16 +71,19 @@ ia2AccessibleAction::doAction(long aActi
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleAction::get_description(long aActionIndex, BSTR *aDescription)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aDescription)
+    return E_INVALIDARG;
+
   *aDescription = nullptr;
 
   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
   if (acc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   nsAutoString description;
   uint8_t index = static_cast<uint8_t>(aActionIndex);
@@ -145,16 +151,19 @@ ia2AccessibleAction::get_keyBinding(long
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleAction::get_name(long aActionIndex, BSTR *aName)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aName)
+    return E_INVALIDARG;
+
   *aName = nullptr;
 
   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
   if (acc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   nsAutoString name;
   uint8_t index = static_cast<uint8_t>(aActionIndex);
@@ -171,13 +180,16 @@ ia2AccessibleAction::get_name(long aActi
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleAction::get_localizedName(long aActionIndex, BSTR *aLocalizedName)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aLocalizedName)
+    return E_INVALIDARG;
+
   *aLocalizedName = nullptr;
   return E_NOTIMPL;
 
   A11Y_TRYBLOCK_END
 }
--- a/accessible/src/windows/ia2/ia2AccessibleComponent.cpp
+++ b/accessible/src/windows/ia2/ia2AccessibleComponent.cpp
@@ -17,16 +17,19 @@
 
 using namespace mozilla::a11y;
 
 // IUnknown
 
 STDMETHODIMP
 ia2AccessibleComponent::QueryInterface(REFIID iid, void** ppv)
 {
+  if (!ppv)
+    return E_INVALIDARG;
+
   *ppv = nullptr;
 
   if (IID_IAccessibleComponent == iid) {
     *ppv = static_cast<IAccessibleComponent*>(this);
     (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
     return S_OK;
   }
 
@@ -35,16 +38,19 @@ ia2AccessibleComponent::QueryInterface(R
 
 // IAccessibleComponent
 
 STDMETHODIMP
 ia2AccessibleComponent::get_locationInParent(long* aX, long* aY)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aX || !aY)
+    return E_INVALIDARG;
+
   *aX = 0;
   *aY = 0;
 
   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
   if (acc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   // If the object is not on any screen the returned position is (0,0).
@@ -82,16 +88,21 @@ ia2AccessibleComponent::get_locationInPa
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleComponent::get_foreground(IA2Color* aForeground)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aForeground)
+    return E_INVALIDARG;
+
+  *aForeground = 0;
+
   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
   if (acc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   nsIFrame* frame = acc->GetFrame();
   if (frame)
     *aForeground = frame->StyleColor()->mColor;
 
@@ -100,16 +111,21 @@ ia2AccessibleComponent::get_foreground(I
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleComponent::get_background(IA2Color* aBackground)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aBackground)
+    return E_INVALIDARG;
+
+  *aBackground = 0;
+
   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
   if (acc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   nsIFrame* frame = acc->GetFrame();
   if (frame)
     *aBackground = frame->StyleBackground()->mBackgroundColor;
 
--- a/accessible/src/windows/ia2/ia2AccessibleHyperlink.cpp
+++ b/accessible/src/windows/ia2/ia2AccessibleHyperlink.cpp
@@ -14,16 +14,19 @@
 
 using namespace mozilla::a11y;
 
 // IUnknown
 
 STDMETHODIMP
 ia2AccessibleHyperlink::QueryInterface(REFIID iid, void** ppv)
 {
+  if (!ppv)
+    return E_INVALIDARG;
+
   *ppv = nullptr;
 
   if (IID_IAccessibleHyperlink == iid) {
     if (!static_cast<AccessibleWrap*>(this)->IsLink())
       return E_NOINTERFACE;
 
     *ppv = static_cast<IAccessibleHyperlink*>(this);
     (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
@@ -35,16 +38,19 @@ ia2AccessibleHyperlink::QueryInterface(R
 
 // IAccessibleHyperlink
 
 STDMETHODIMP
 ia2AccessibleHyperlink::get_anchor(long aIndex, VARIANT* aAnchor)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aAnchor)
+    return E_INVALIDARG;
+
   VariantInit(aAnchor);
 
   Accessible* thisObj = static_cast<AccessibleWrap*>(this);
   if (thisObj->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   if (aIndex < 0 || aIndex >= static_cast<long>(thisObj->AnchorCount()))
     return E_INVALIDARG;
@@ -70,16 +76,19 @@ ia2AccessibleHyperlink::get_anchor(long 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleHyperlink::get_anchorTarget(long aIndex, VARIANT* aAnchorTarget)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aAnchorTarget)
+    return E_INVALIDARG;
+
   VariantInit(aAnchorTarget);
 
   Accessible* thisObj = static_cast<AccessibleWrap*>(this);
   if (thisObj->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   if (aIndex < 0 || aIndex >= static_cast<long>(thisObj->AnchorCount()))
     return E_INVALIDARG;
@@ -113,16 +122,19 @@ ia2AccessibleHyperlink::get_anchorTarget
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleHyperlink::get_startIndex(long* aIndex)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aIndex)
+    return E_INVALIDARG;
+
   *aIndex = 0;
 
   Accessible* thisObj = static_cast<AccessibleWrap*>(this);
   if (thisObj->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   if (!thisObj->IsLink())
     return S_FALSE;
@@ -133,16 +145,19 @@ ia2AccessibleHyperlink::get_startIndex(l
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleHyperlink::get_endIndex(long* aIndex)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aIndex)
+    return E_INVALIDARG;
+
   *aIndex = 0;
 
   Accessible* thisObj = static_cast<AccessibleWrap*>(this);
   if (thisObj->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   if (!thisObj->IsLink())
     return S_FALSE;
@@ -153,16 +168,19 @@ ia2AccessibleHyperlink::get_endIndex(lon
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleHyperlink::get_valid(boolean* aValid)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aValid)
+    return E_INVALIDARG;
+
   *aValid = false;
 
   Accessible* thisObj = static_cast<AccessibleWrap*>(this);
   if (thisObj->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   if (!thisObj->IsLink())
     return S_FALSE;
--- a/accessible/src/windows/ia2/ia2AccessibleHypertext.cpp
+++ b/accessible/src/windows/ia2/ia2AccessibleHypertext.cpp
@@ -16,16 +16,19 @@ using namespace mozilla::a11y;
 
 // IAccessibleHypertext
 
 STDMETHODIMP
 ia2AccessibleHypertext::get_nHyperlinks(long* aHyperlinkCount)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aHyperlinkCount)
+    return E_INVALIDARG;
+
   *aHyperlinkCount = 0;
 
   HyperTextAccessibleWrap* hyperText = static_cast<HyperTextAccessibleWrap*>(this);
   if (hyperText->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   *aHyperlinkCount = hyperText->GetLinkCount();
   return S_OK;
@@ -34,16 +37,19 @@ ia2AccessibleHypertext::get_nHyperlinks(
 }
 
 STDMETHODIMP
 ia2AccessibleHypertext::get_hyperlink(long aLinkIndex,
                                       IAccessibleHyperlink** aHyperlink)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aHyperlink)
+    return E_INVALIDARG;
+
   *aHyperlink = nullptr;
 
   HyperTextAccessibleWrap* hyperText = static_cast<HyperTextAccessibleWrap*>(this);
   if (hyperText->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   Accessible* hyperLink = hyperText->GetLinkAt(aLinkIndex);
   if (!hyperLink)
@@ -57,16 +63,19 @@ ia2AccessibleHypertext::get_hyperlink(lo
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleHypertext::get_hyperlinkIndex(long aCharIndex, long* aHyperlinkIndex)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aHyperlinkIndex)
+    return E_INVALIDARG;
+
   *aHyperlinkIndex = 0;
 
   HyperTextAccessibleWrap* hyperAcc = static_cast<HyperTextAccessibleWrap*>(this);
   if (hyperAcc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   *aHyperlinkIndex = hyperAcc->GetLinkIndexAtOffset(aCharIndex);
   return S_OK;
--- a/accessible/src/windows/ia2/ia2AccessibleImage.cpp
+++ b/accessible/src/windows/ia2/ia2AccessibleImage.cpp
@@ -18,16 +18,19 @@
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 // IUnknown
 
 STDMETHODIMP
 ia2AccessibleImage::QueryInterface(REFIID iid, void** ppv)
 {
+  if (!ppv)
+    return E_INVALIDARG;
+
   *ppv = nullptr;
 
   if (IID_IAccessibleImage == iid) {
     *ppv = static_cast<IAccessibleImage*>(this);
     (static_cast<IUnknown*>(*ppv))->AddRef();
     return S_OK;
   }
 
@@ -36,16 +39,19 @@ ia2AccessibleImage::QueryInterface(REFII
 
 // IAccessibleImage
 
 STDMETHODIMP
 ia2AccessibleImage::get_description(BSTR* aDescription)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aDescription)
+    return E_INVALIDARG;
+
   *aDescription = nullptr;
 
   ImageAccessibleWrap* acc = static_cast<ImageAccessibleWrap*>(this);
   if (acc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   nsAutoString description;
   nsresult rv = acc->GetName(description);
@@ -63,16 +69,19 @@ ia2AccessibleImage::get_description(BSTR
 
 STDMETHODIMP
 ia2AccessibleImage::get_imagePosition(enum IA2CoordinateType aCoordType,
                                       long* aX,
                                       long* aY)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aX || !aY)
+    return E_INVALIDARG;
+
   *aX = 0;
   *aY = 0;
 
   ImageAccessibleWrap* imageAcc = static_cast<ImageAccessibleWrap*>(this);
   if (imageAcc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   uint32_t geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ?
@@ -91,16 +100,19 @@ ia2AccessibleImage::get_imagePosition(en
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleImage::get_imageSize(long* aHeight, long* aWidth)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aHeight || !aWidth)
+    return E_INVALIDARG;
+
   *aHeight = 0;
   *aWidth = 0;
 
   ImageAccessibleWrap* imageAcc = static_cast<ImageAccessibleWrap*>(this);
   if (imageAcc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   int32_t width = 0, height = 0;
--- a/accessible/src/windows/ia2/ia2AccessibleTable.cpp
+++ b/accessible/src/windows/ia2/ia2AccessibleTable.cpp
@@ -21,16 +21,19 @@
 
 using namespace mozilla::a11y;
 
 // IUnknown
 
 STDMETHODIMP
 ia2AccessibleTable::QueryInterface(REFIID iid, void** ppv)
 {
+  if (!ppv)
+    return E_INVALIDARG;
+
   *ppv = nullptr;
 
   if (IID_IAccessibleTable == iid) {
     statistics::IAccessibleTableUsed();
     *ppv = static_cast<IAccessibleTable*>(this);
     (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
     return S_OK;
   }
@@ -54,16 +57,19 @@ ia2AccessibleTable::get_accessibleAt(lon
   return get_cellAt(aRowIdx, aColIdx, aAccessible);
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_caption(IUnknown** aAccessible)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aAccessible)
+    return E_INVALIDARG;
+
   *aAccessible = nullptr;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
   AccessibleWrap* caption = static_cast<AccessibleWrap*>(mTable->Caption());
   if (!caption)
     return S_FALSE;
 
@@ -74,16 +80,19 @@ ia2AccessibleTable::get_caption(IUnknown
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_childIndex(long aRowIdx, long aColIdx,
                                    long* aChildIdx)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aChildIdx)
+    return E_INVALIDARG;
+
   *aChildIdx = 0;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
   if (aRowIdx < 0 || aColIdx < 0 ||
       static_cast<uint32_t>(aRowIdx) >= mTable->RowCount() ||
       static_cast<uint32_t>(aColIdx) >= mTable->ColCount())
     return E_INVALIDARG;
@@ -94,16 +103,19 @@ ia2AccessibleTable::get_childIndex(long 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_columnDescription(long aColIdx, BSTR* aDescription)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aDescription)
+    return E_INVALIDARG;
+
   *aDescription = nullptr;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
   if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= mTable->ColCount())
     return E_INVALIDARG;
 
   nsAutoString descr;
@@ -118,16 +130,19 @@ ia2AccessibleTable::get_columnDescriptio
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_columnExtentAt(long aRowIdx, long aColIdx,
                                       long* aSpan)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aSpan)
+    return E_INVALIDARG;
+
   *aSpan = 0;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
   if (aRowIdx < 0 || aColIdx < 0 ||
       static_cast<uint32_t>(aRowIdx) >= mTable->RowCount() ||
       static_cast<uint32_t>(aColIdx) >= mTable->ColCount())
     return E_INVALIDARG;
@@ -139,28 +154,34 @@ ia2AccessibleTable::get_columnExtentAt(l
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_columnHeader(IAccessibleTable** aAccessibleTable,
                                     long* aStartingRowIndex)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aAccessibleTable || !aStartingRowIndex)
+    return E_INVALIDARG;
+
   *aAccessibleTable = nullptr;
   *aStartingRowIndex = -1;
   return E_NOTIMPL;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_columnIndex(long aCellIdx, long* aColIdx)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aColIdx)
+    return E_INVALIDARG;
+
   *aColIdx = 0;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
   if (aCellIdx < 0 ||
       static_cast<uint32_t>(aCellIdx) >= mTable->ColCount() * mTable->RowCount())
     return E_INVALIDARG;
 
@@ -170,31 +191,37 @@ ia2AccessibleTable::get_columnIndex(long
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_nColumns(long* aColCount)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aColCount)
+    return E_INVALIDARG;
+
   *aColCount = 0;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
   *aColCount = mTable->ColCount();
   return S_OK;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_nRows(long* aRowCount)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aRowCount)
+    return E_INVALIDARG;
+
   *aRowCount = 0;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
   *aRowCount = mTable->RowCount();
   return S_OK;
 
   A11Y_TRYBLOCK_END
@@ -206,47 +233,56 @@ ia2AccessibleTable::get_nSelectedChildre
   return get_nSelectedCells(aChildCount);
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_nSelectedColumns(long* aColCount)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aColCount)
+    return E_INVALIDARG;
+
   *aColCount = 0;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
   *aColCount = mTable->SelectedColCount();
   return S_OK;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_nSelectedRows(long* aRowCount)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aRowCount)
+    return E_INVALIDARG;
+
   *aRowCount = 0;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
   *aRowCount = mTable->SelectedRowCount();
 
   return S_OK;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_rowDescription(long aRowIdx, BSTR* aDescription)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aDescription)
+    return E_INVALIDARG;
+
   *aDescription = nullptr;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
   if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= mTable->RowCount())
     return E_INVALIDARG;
 
   nsAutoString descr;
@@ -260,16 +296,19 @@ ia2AccessibleTable::get_rowDescription(l
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_rowExtentAt(long aRowIdx, long aColIdx, long* aSpan)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aSpan)
+    return E_INVALIDARG;
+
   *aSpan = 0;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
   if (aRowIdx < 0 || aColIdx < 0 ||
       static_cast<uint32_t>(aRowIdx) >= mTable->RowCount() ||
       static_cast<uint32_t>(aColIdx) >= mTable->ColCount())
     return E_INVALIDARG;
@@ -281,28 +320,34 @@ ia2AccessibleTable::get_rowExtentAt(long
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_rowHeader(IAccessibleTable** aAccessibleTable,
                                   long* aStartingColumnIndex)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aAccessibleTable || !aStartingColumnIndex)
+    return E_INVALIDARG;
+
   *aAccessibleTable = nullptr;
   *aStartingColumnIndex = -1;
   return E_NOTIMPL;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_rowIndex(long aCellIdx, long* aRowIdx)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aRowIdx)
+    return E_INVALIDARG;
+
   *aRowIdx = 0;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
   if (aCellIdx < 0 ||
       static_cast<uint32_t>(aCellIdx) >= mTable->ColCount() * mTable->RowCount())
     return E_INVALIDARG;
 
@@ -313,16 +358,19 @@ ia2AccessibleTable::get_rowIndex(long aC
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_selectedChildren(long aMaxChildren, long** aChildren,
                                          long* aNChildren)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aChildren || !aNChildren)
+    return E_INVALIDARG;
+
   *aChildren = nullptr;
   *aNChildren = 0;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
   nsAutoTArray<uint32_t, 30> cellIndices;
   mTable->SelectedCellIndices(&cellIndices);
 
@@ -361,32 +409,38 @@ ia2AccessibleTable::get_selectedRows(lon
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_summary(IUnknown** aAccessible)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aAccessible)
+    return E_INVALIDARG;
+
   // Neither html:table nor xul:tree nor ARIA grid/tree have an ability to
   // link an accessible object to specify a summary. There is closes method
   // in nsIAccessibleTable::summary to get a summary as a string which is not
   // mapped directly to IAccessible2.
 
   *aAccessible = nullptr;
   return S_FALSE;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_isColumnSelected(long aColIdx, boolean* aIsSelected)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aIsSelected)
+    return E_INVALIDARG;
+
   *aIsSelected = false;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
   if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= mTable->ColCount())
     return E_INVALIDARG;
 
   *aIsSelected = mTable->IsColSelected(aColIdx);
@@ -395,16 +449,19 @@ ia2AccessibleTable::get_isColumnSelected
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_isRowSelected(long aRowIdx, boolean* aIsSelected)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aIsSelected)
+    return E_INVALIDARG;
+
   *aIsSelected = false;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
   if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= mTable->RowCount())
     return E_INVALIDARG;
 
   *aIsSelected = mTable->IsRowSelected(aRowIdx);
@@ -414,16 +471,19 @@ ia2AccessibleTable::get_isRowSelected(lo
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_isSelected(long aRowIdx, long aColIdx,
                                    boolean* aIsSelected)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aIsSelected)
+    return E_INVALIDARG;
+
   *aIsSelected = false;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
   if (aRowIdx < 0 || aColIdx < 0 ||
       static_cast<uint32_t>(aColIdx) >= mTable->ColCount() ||
       static_cast<uint32_t>(aRowIdx) >= mTable->RowCount())
     return E_INVALIDARG;
@@ -506,16 +566,19 @@ STDMETHODIMP
 ia2AccessibleTable::get_rowColumnExtentsAtIndex(long aCellIdx, long* aRowIdx,
                                                 long* aColIdx,
                                                 long* aRowExtents,
                                                 long* aColExtents,
                                                 boolean* aIsSelected)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aRowIdx || !aColIdx || !aRowExtents || !aColExtents || !aIsSelected)
+    return E_INVALIDARG;
+
   *aRowIdx = 0;
   *aColIdx = 0;
   *aRowExtents = 0;
   *aColExtents = 0;
   *aIsSelected = false;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
@@ -545,16 +608,19 @@ ia2AccessibleTable::get_modelChange(IA2T
 ////////////////////////////////////////////////////////////////////////////////
 // IAccessibleTable2
 
 STDMETHODIMP
 ia2AccessibleTable::get_cellAt(long aRowIdx, long aColIdx, IUnknown** aCell)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aCell)
+    return E_INVALIDARG;
+
   *aCell = nullptr;
 
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
   AccessibleWrap* cell =
     static_cast<AccessibleWrap*>(mTable->CellAt(aRowIdx, aColIdx));
   if (!cell)
@@ -566,31 +632,37 @@ ia2AccessibleTable::get_cellAt(long aRow
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_nSelectedCells(long* aCellCount)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aCellCount)
+    return E_INVALIDARG;
+
   *aCellCount = 0;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
   *aCellCount = mTable->SelectedCellCount();
   return S_OK;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_selectedCells(IUnknown*** aCells, long* aNSelectedCells)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aCells || !aNSelectedCells)
+    return E_INVALIDARG;
+
   *aCells = nullptr;
   *aNSelectedCells = 0;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
   nsAutoTArray<Accessible*, 30> cells;
   mTable->SelectedCells(&cells);
   if (cells.IsEmpty())
@@ -614,16 +686,19 @@ ia2AccessibleTable::get_selectedCells(IU
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_selectedColumns(long** aColumns, long* aNColumns)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aColumns || !aNColumns)
+    return E_INVALIDARG;
+
   *aColumns = nullptr;
   *aNColumns = 0;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
   nsAutoTArray<uint32_t, 30> colIndices;
   mTable->SelectedColIndices(&colIndices);
 
@@ -641,16 +716,19 @@ ia2AccessibleTable::get_selectedColumns(
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_selectedRows(long** aRows, long* aNRows)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aRows || !aNRows)
+    return E_INVALIDARG;
+
   *aRows = nullptr;
   *aNRows = 0;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
   nsAutoTArray<uint32_t, 30> rowIndices;
   mTable->SelectedRowIndices(&rowIndices);
 
--- a/accessible/src/windows/ia2/ia2AccessibleTableCell.cpp
+++ b/accessible/src/windows/ia2/ia2AccessibleTableCell.cpp
@@ -21,16 +21,19 @@
 
 using namespace mozilla::a11y;
 
 // IUnknown
 
 STDMETHODIMP
 ia2AccessibleTableCell::QueryInterface(REFIID iid, void** ppv)
 {
+  if (!ppv)
+    return E_INVALIDARG;
+
   *ppv = nullptr;
 
   if (IID_IAccessibleTableCell == iid) {
     *ppv = static_cast<IAccessibleTableCell*>(this);
     (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
     return S_OK;
   }
 
@@ -40,16 +43,19 @@ ia2AccessibleTableCell::QueryInterface(R
 ////////////////////////////////////////////////////////////////////////////////
 // IAccessibleTableCell
 
 STDMETHODIMP
 ia2AccessibleTableCell::get_table(IUnknown** aTable)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aTable)
+    return E_INVALIDARG;
+
   *aTable = nullptr;
   if (!mTableCell)
     return CO_E_OBJNOTCONNECTED;
 
   TableAccessible* table = mTableCell->Table();
   if (!table)
     return E_FAIL;
 
@@ -61,16 +67,19 @@ ia2AccessibleTableCell::get_table(IUnkno
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleTableCell::get_columnExtent(long* aSpan)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aSpan)
+    return E_INVALIDARG;
+
   *aSpan = 0;
   if (!mTableCell)
     return CO_E_OBJNOTCONNECTED;
 
   *aSpan = mTableCell->ColExtent();
 
   return S_OK;
 
@@ -78,16 +87,19 @@ ia2AccessibleTableCell::get_columnExtent
 }
 
 STDMETHODIMP
 ia2AccessibleTableCell::get_columnHeaderCells(IUnknown*** aCellAccessibles,
                                               long* aNColumnHeaderCells)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aCellAccessibles || !aNColumnHeaderCells)
+    return E_INVALIDARG;
+
   *aCellAccessibles = nullptr;
   *aNColumnHeaderCells = 0;
   if (!mTableCell)
     return CO_E_OBJNOTCONNECTED;
 
   nsAutoTArray<Accessible*, 10> cells;
   mTableCell->ColHeaderCells(&cells);
 
@@ -110,47 +122,56 @@ ia2AccessibleTableCell::get_columnHeader
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleTableCell::get_columnIndex(long* aColIdx)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aColIdx)
+    return E_INVALIDARG;
+
   *aColIdx = -1;
   if (!mTableCell)
     return CO_E_OBJNOTCONNECTED;
 
   *aColIdx = mTableCell->ColIdx();
   return S_OK;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleTableCell::get_rowExtent(long* aSpan)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aSpan)
+    return E_INVALIDARG;
+
   *aSpan = 0;
   if (!mTableCell)
     return CO_E_OBJNOTCONNECTED;
 
   *aSpan = mTableCell->RowExtent();
   return S_OK;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleTableCell::get_rowHeaderCells(IUnknown*** aCellAccessibles,
                                            long* aNRowHeaderCells)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aCellAccessibles || !aNRowHeaderCells)
+    return E_INVALIDARG;
+
   *aCellAccessibles = nullptr;
   *aNRowHeaderCells = 0;
   if (!mTableCell)
     return CO_E_OBJNOTCONNECTED;
 
   nsAutoTArray<Accessible*, 10> cells;
   mTableCell->RowHeaderCells(&cells);
 
@@ -172,16 +193,19 @@ ia2AccessibleTableCell::get_rowHeaderCel
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleTableCell::get_rowIndex(long* aRowIdx)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aRowIdx)
+    return E_INVALIDARG;
+
   *aRowIdx = -1;
   if (!mTableCell)
     return CO_E_OBJNOTCONNECTED;
 
   *aRowIdx = mTableCell->RowIdx();
   return S_OK;
 
   A11Y_TRYBLOCK_END
@@ -190,16 +214,19 @@ ia2AccessibleTableCell::get_rowIndex(lon
 STDMETHODIMP
 ia2AccessibleTableCell::get_rowColumnExtents(long* aRowIdx, long* aColIdx,
                                              long* aRowExtents,
                                              long* aColExtents,
                                              boolean* aIsSelected)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aRowIdx || !aColIdx || !aRowExtents || !aColExtents || !aIsSelected)
+    return E_INVALIDARG;
+
   *aRowIdx = *aColIdx = *aRowExtents = *aColExtents = 0;
   *aIsSelected = false;
   if (!mTableCell)
     return CO_E_OBJNOTCONNECTED;
 
   *aRowIdx = mTableCell->RowIdx();
   *aColIdx = mTableCell->ColIdx();
   *aRowExtents = mTableCell->RowExtent();
@@ -211,16 +238,19 @@ ia2AccessibleTableCell::get_rowColumnExt
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleTableCell::get_isSelected(boolean* aIsSelected)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aIsSelected)
+    return E_INVALIDARG;
+
   *aIsSelected = false;
   if (!mTableCell)
     return CO_E_OBJNOTCONNECTED;
 
   *aIsSelected = mTableCell->Selected();
   return S_OK;
 
   A11Y_TRYBLOCK_END
--- a/accessible/src/windows/ia2/ia2AccessibleText.cpp
+++ b/accessible/src/windows/ia2/ia2AccessibleText.cpp
@@ -71,16 +71,19 @@ ia2AccessibleText::get_attributes(long a
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleText::get_caretOffset(long *aOffset)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aOffset)
+    return E_INVALIDARG;
+
   *aOffset = -1;
 
   HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
   if (textAcc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   int32_t offset = 0;
   nsresult rv = textAcc->GetCaretOffset(&offset);
@@ -96,16 +99,19 @@ ia2AccessibleText::get_caretOffset(long 
 STDMETHODIMP
 ia2AccessibleText::get_characterExtents(long aOffset,
                                         enum IA2CoordinateType aCoordType,
                                         long *aX, long *aY,
                                         long *aWidth, long *aHeight)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aX || !aY || !aWidth || !aHeight)
+    return E_INVALIDARG;
+
   *aX = 0;
   *aY = 0;
   *aWidth = 0;
   *aHeight = 0;
 
   HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
   if (textAcc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
@@ -129,16 +135,19 @@ ia2AccessibleText::get_characterExtents(
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleText::get_nSelections(long *aNSelections)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aNSelections)
+    return E_INVALIDARG;
+
   *aNSelections = 0;
 
   HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
   if (textAcc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   int32_t selCount = 0;
   nsresult rv = textAcc->GetSelectionCount(&selCount);
@@ -153,16 +162,19 @@ ia2AccessibleText::get_nSelections(long 
 
 STDMETHODIMP
 ia2AccessibleText::get_offsetAtPoint(long aX, long aY,
                                      enum IA2CoordinateType aCoordType,
                                      long *aOffset)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aOffset)
+    return E_INVALIDARG;
+
   *aOffset = 0;
 
   HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
   if (textAcc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   uint32_t geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ?
     nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE :
@@ -180,16 +192,19 @@ ia2AccessibleText::get_offsetAtPoint(lon
 }
 
 STDMETHODIMP
 ia2AccessibleText::get_selection(long aSelectionIndex, long *aStartOffset,
                                  long *aEndOffset)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aStartOffset || !aEndOffset)
+    return E_INVALIDARG;
+
   *aStartOffset = 0;
   *aEndOffset = 0;
 
   HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
   if (textAcc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   int32_t startOffset = 0, endOffset = 0;
@@ -205,16 +220,19 @@ ia2AccessibleText::get_selection(long aS
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleText::get_text(long aStartOffset, long aEndOffset, BSTR *aText)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aText)
+    return E_INVALIDARG;
+
   *aText = nullptr;
 
   HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
   if (textAcc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   nsAutoString text;
   nsresult rv = textAcc->GetText(aStartOffset, aEndOffset, text);
@@ -233,16 +251,19 @@ ia2AccessibleText::get_text(long aStartO
 STDMETHODIMP
 ia2AccessibleText::get_textBeforeOffset(long aOffset,
                                         enum IA2TextBoundaryType aBoundaryType,
                                         long *aStartOffset, long *aEndOffset,
                                         BSTR *aText)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aStartOffset || !aEndOffset || !aText)
+    return E_INVALIDARG;
+
   *aStartOffset = 0;
   *aEndOffset = 0;
   *aText = nullptr;
 
   HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
   if (textAcc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
@@ -280,16 +301,19 @@ ia2AccessibleText::get_textBeforeOffset(
 STDMETHODIMP
 ia2AccessibleText::get_textAfterOffset(long aOffset,
                                        enum IA2TextBoundaryType aBoundaryType,
                                        long *aStartOffset, long *aEndOffset,
                                        BSTR *aText)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aStartOffset || !aEndOffset || !aText)
+    return E_INVALIDARG;
+
   *aStartOffset = 0;
   *aEndOffset = 0;
   *aText = nullptr;
 
   HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
   if (textAcc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
@@ -327,16 +351,19 @@ ia2AccessibleText::get_textAfterOffset(l
 STDMETHODIMP
 ia2AccessibleText::get_textAtOffset(long aOffset,
                                     enum IA2TextBoundaryType aBoundaryType,
                                     long *aStartOffset, long *aEndOffset,
                                     BSTR *aText)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aStartOffset || !aEndOffset || !aText)
+    return E_INVALIDARG;
+
   *aStartOffset = 0;
   *aEndOffset = 0;
   *aText = nullptr;
 
   HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
   if (textAcc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
@@ -418,16 +445,19 @@ ia2AccessibleText::setSelection(long aSe
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleText::get_nCharacters(long *aNCharacters)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aNCharacters)
+    return E_INVALIDARG;
+
   *aNCharacters = 0;
 
   HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
   if (textAcc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   *aNCharacters  = textAcc->CharacterCount();
   return S_OK;
@@ -494,16 +524,19 @@ ia2AccessibleText::get_oldText(IA2TextSe
 }
 
 // ia2AccessibleText
 
 HRESULT
 ia2AccessibleText::GetModifiedText(bool aGetInsertedText,
                                    IA2TextSegment *aText)
 {
+  if (!aText)
+    return E_INVALIDARG;
+
   uint32_t startOffset = 0, endOffset = 0;
   nsAutoString text;
 
   nsresult rv = GetModifiedText(aGetInsertedText, text,
                                 &startOffset, &endOffset);
   if (NS_FAILED(rv))
     return GetHRESULT(rv);
 
--- a/accessible/src/windows/ia2/ia2AccessibleValue.cpp
+++ b/accessible/src/windows/ia2/ia2AccessibleValue.cpp
@@ -15,16 +15,19 @@
 
 using namespace mozilla::a11y;
 
 // IUnknown
 
 STDMETHODIMP
 ia2AccessibleValue::QueryInterface(REFIID iid, void** ppv)
 {
+  if (!ppv)
+    return E_INVALIDARG;
+
   *ppv = nullptr;
 
   if (IID_IAccessibleValue == iid) {
     AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this);
     if (valueAcc->HasNumericValue()) {
       *ppv = static_cast<IAccessibleValue*>(this);
       valueAcc->AddRef();
       return S_OK;
@@ -38,16 +41,19 @@ ia2AccessibleValue::QueryInterface(REFII
 
 // IAccessibleValue
 
 STDMETHODIMP
 ia2AccessibleValue::get_currentValue(VARIANT* aCurrentValue)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aCurrentValue)
+    return E_INVALIDARG;
+
   VariantInit(aCurrentValue);
 
   AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this);
   if (valueAcc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   double currentValue = 0;
   nsresult rv = valueAcc->GetCurrentValue(&currentValue);
@@ -79,16 +85,19 @@ ia2AccessibleValue::setCurrentValue(VARI
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleValue::get_maximumValue(VARIANT* aMaximumValue)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aMaximumValue)
+    return E_INVALIDARG;
+
   VariantInit(aMaximumValue);
 
   AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this);
   if (valueAcc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   double maximumValue = 0;
   nsresult rv = valueAcc->GetMaximumValue(&maximumValue);
@@ -102,16 +111,19 @@ ia2AccessibleValue::get_maximumValue(VAR
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleValue::get_minimumValue(VARIANT* aMinimumValue)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aMinimumValue)
+    return E_INVALIDARG;
+
   VariantInit(aMinimumValue);
 
   AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this);
   if (valueAcc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   double minimumValue = 0;
   nsresult rv = valueAcc->GetMinimumValue(&minimumValue);
--- a/accessible/src/windows/msaa/AccessibleWrap.cpp
+++ b/accessible/src/windows/msaa/AccessibleWrap.cpp
@@ -73,16 +73,19 @@ NS_IMPL_ISUPPORTS_INHERITED0(AccessibleW
 //-----------------------------------------------------
 
 // Microsoft COM QueryInterface
 STDMETHODIMP
 AccessibleWrap::QueryInterface(REFIID iid, void** ppv)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!ppv)
+    return E_INVALIDARG;
+
   *ppv = nullptr;
 
   if (IID_IUnknown == iid || IID_IDispatch == iid || IID_IAccessible == iid)
     *ppv = static_cast<IAccessible*>(this);
   else if (IID_IEnumVARIANT == iid) {
     // Don't support this interface for leaf elements.
     if (!HasChildren() || nsAccUtils::MustPrune(this))
       return E_NOINTERFACE;
@@ -130,16 +133,19 @@ AccessibleWrap::QueryInterface(REFIID ii
 // IAccessible methods
 //-----------------------------------------------------
 
 STDMETHODIMP
 AccessibleWrap::get_accParent( IDispatch __RPC_FAR *__RPC_FAR *ppdispParent)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!ppdispParent)
+    return E_INVALIDARG;
+
   *ppdispParent = nullptr;
 
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   DocAccessible* doc = AsDoc();
   if (doc) {
     // Return window system accessible object for root document and tab document
@@ -190,16 +196,19 @@ AccessibleWrap::get_accChildCount( long 
 
 STDMETHODIMP
 AccessibleWrap::get_accChild(
       /* [in] */ VARIANT varChild,
       /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispChild)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!ppdispChild)
+    return E_INVALIDARG;
+
   *ppdispChild = nullptr;
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   // IAccessible::accChild is used to return this accessible or child accessible
   // at the given index or to get an accessible by child ID in the case of
   // document accessible (it's handled by overriden GetXPAccessibleFor method
   // on the document accessible). The getting an accessible by child ID is used
@@ -219,16 +228,19 @@ AccessibleWrap::get_accChild(
 
 STDMETHODIMP
 AccessibleWrap::get_accName(
       /* [optional][in] */ VARIANT varChild,
       /* [retval][out] */ BSTR __RPC_FAR *pszName)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!pszName)
+    return E_INVALIDARG;
+
   *pszName = nullptr;
 
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   Accessible* xpAccessible = GetXPAccessibleFor(varChild);
   if (!xpAccessible)
     return E_INVALIDARG;
@@ -256,16 +268,19 @@ AccessibleWrap::get_accName(
 
 STDMETHODIMP
 AccessibleWrap::get_accValue(
       /* [optional][in] */ VARIANT varChild,
       /* [retval][out] */ BSTR __RPC_FAR *pszValue)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!pszValue)
+    return E_INVALIDARG;
+
   *pszValue = nullptr;
 
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   Accessible* xpAccessible = GetXPAccessibleFor(varChild);
   if (!xpAccessible)
     return E_INVALIDARG;
@@ -294,16 +309,19 @@ AccessibleWrap::get_accValue(
 }
 
 STDMETHODIMP
 AccessibleWrap::get_accDescription(VARIANT varChild,
                                    BSTR __RPC_FAR *pszDescription)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!pszDescription)
+    return E_INVALIDARG;
+
   *pszDescription = nullptr;
 
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   Accessible* xpAccessible = GetXPAccessibleFor(varChild);
   if (!xpAccessible)
     return E_INVALIDARG;
@@ -323,16 +341,19 @@ AccessibleWrap::get_accDescription(VARIA
 
 STDMETHODIMP
 AccessibleWrap::get_accRole(
       /* [optional][in] */ VARIANT varChild,
       /* [retval][out] */ VARIANT __RPC_FAR *pvarRole)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!pvarRole)
+    return E_INVALIDARG;
+
   VariantInit(pvarRole);
 
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   Accessible* xpAccessible = GetXPAccessibleFor(varChild);
   if (!xpAccessible)
     return E_INVALIDARG;
@@ -418,16 +439,19 @@ AccessibleWrap::get_accRole(
 
 STDMETHODIMP
 AccessibleWrap::get_accState(
       /* [optional][in] */ VARIANT varChild,
       /* [retval][out] */ VARIANT __RPC_FAR *pvarState)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!pvarState)
+    return E_INVALIDARG;
+
   VariantInit(pvarState);
   pvarState->vt = VT_I4;
   pvarState->lVal = 0;
 
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   Accessible* xpAccessible = GetXPAccessibleFor(varChild);
@@ -456,30 +480,36 @@ AccessibleWrap::get_accState(
 
 STDMETHODIMP
 AccessibleWrap::get_accHelp(
       /* [optional][in] */ VARIANT varChild,
       /* [retval][out] */ BSTR __RPC_FAR *pszHelp)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!pszHelp)
+    return E_INVALIDARG;
+
   *pszHelp = nullptr;
   return S_FALSE;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 AccessibleWrap::get_accHelpTopic(
       /* [out] */ BSTR __RPC_FAR *pszHelpFile,
       /* [optional][in] */ VARIANT varChild,
       /* [retval][out] */ long __RPC_FAR *pidTopic)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!pszHelpFile || !pidTopic)
+    return E_INVALIDARG;
+
   *pszHelpFile = nullptr;
   *pidTopic = 0;
   return S_FALSE;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
@@ -518,27 +548,30 @@ AccessibleWrap::get_accKeyboardShortcut(
 }
 
 STDMETHODIMP
 AccessibleWrap::get_accFocus(
       /* [retval][out] */ VARIANT __RPC_FAR *pvarChild)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!pvarChild)
+    return E_INVALIDARG;
+
+  VariantInit(pvarChild);
+
   // VT_EMPTY:    None. This object does not have the keyboard focus itself
   //              and does not contain a child that has the keyboard focus.
   // VT_I4:       lVal is CHILDID_SELF. The object itself has the keyboard focus.
   // VT_I4:       lVal contains the child ID of the child element with the keyboard focus.
   // VT_DISPATCH: pdispVal member is the address of the IDispatch interface
   //              for the child object with the keyboard focus.
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
-  VariantInit(pvarChild);
-
   // Return the current IAccessible child that has focus
   Accessible* focusedAccessible = FocusedChild();
   if (focusedAccessible == this) {
     pvarChild->vt = VT_I4;
     pvarChild->lVal = CHILDID_SELF;
   }
   else if (focusedAccessible) {
     pvarChild->vt = VT_DISPATCH;
@@ -687,16 +720,19 @@ AccessibleEnumerator::Skip(unsigned long
   *  - there are no selected children for this object
   *  - the object is not the type that can have children selected
   */
 STDMETHODIMP
 AccessibleWrap::get_accSelection(VARIANT __RPC_FAR *pvarChildren)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!pvarChildren)
+    return E_INVALIDARG;
+
   VariantInit(pvarChildren);
   pvarChildren->vt = VT_EMPTY;
 
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   if (IsSelect()) {
     nsCOMPtr<nsIArray> selectedItems = SelectedItems();
@@ -719,16 +755,19 @@ AccessibleWrap::get_accSelection(VARIANT
 
 STDMETHODIMP
 AccessibleWrap::get_accDefaultAction(
       /* [optional][in] */ VARIANT varChild,
       /* [retval][out] */ BSTR __RPC_FAR *pszDefaultAction)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!pszDefaultAction)
+    return E_INVALIDARG;
+
   *pszDefaultAction = nullptr;
 
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   Accessible* xpAccessible = GetXPAccessibleFor(varChild);
   if (!xpAccessible)
     return E_INVALIDARG;
@@ -795,16 +834,24 @@ AccessibleWrap::accLocation(
       /* [out] */ long __RPC_FAR *pxLeft,
       /* [out] */ long __RPC_FAR *pyTop,
       /* [out] */ long __RPC_FAR *pcxWidth,
       /* [out] */ long __RPC_FAR *pcyHeight,
       /* [optional][in] */ VARIANT varChild)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!pxLeft || !pyTop || !pcxWidth || !pcyHeight)
+    return E_INVALIDARG;
+
+  *pxLeft = 0;
+  *pyTop = 0;
+  *pcxWidth = 0;
+  *pcyHeight = 0;
+
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   Accessible* xpAccessible = GetXPAccessibleFor(varChild);
   if (!xpAccessible)
     return E_INVALIDARG;
 
   if (xpAccessible->IsDefunct())
@@ -829,28 +876,28 @@ AccessibleWrap::accNavigate(
       /* [optional][in] */ VARIANT varStart,
       /* [retval][out] */ VARIANT __RPC_FAR *pvarEndUpAt)
 {
   A11Y_TRYBLOCK_BEGIN
 
   if (!pvarEndUpAt)
     return E_INVALIDARG;
 
+  VariantInit(pvarEndUpAt);
+
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   Accessible* accessible = GetXPAccessibleFor(varStart);
   if (!accessible)
     return E_INVALIDARG;
 
   if (accessible->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
-  VariantInit(pvarEndUpAt);
-
   Accessible* navAccessible = nullptr;
   int32_t xpRelation = -1;
 
   switch(navDir) {
     case NAVDIR_FIRSTCHILD:
       if (!nsAccUtils::MustPrune(accessible))
         navAccessible = accessible->FirstChild();
       break;
@@ -947,16 +994,19 @@ AccessibleWrap::accNavigate(
 STDMETHODIMP
 AccessibleWrap::accHitTest(
       /* [in] */ long xLeft,
       /* [in] */ long yTop,
       /* [retval][out] */ VARIANT __RPC_FAR *pvarChild)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!pvarChild)
+    return E_INVALIDARG;
+
   VariantInit(pvarChild);
 
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   Accessible* accessible = ChildAtPoint(xLeft, yTop, eDirectChild);
 
   // if we got a child
@@ -1108,16 +1158,19 @@ AccessibleWrap::get_relations(long aMaxR
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 AccessibleWrap::role(long *aRole)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aRole)
+    return E_INVALIDARG;
+
   *aRole = 0;
 
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
 #define ROLE(_geckoRole, stringRole, atkRole, macRole, \
              msaaRole, ia2Role, nameRule) \
   case roles::_geckoRole: \
@@ -1181,16 +1234,23 @@ AccessibleWrap::scrollToPoint(enum IA2Co
 
 STDMETHODIMP
 AccessibleWrap::get_groupPosition(long *aGroupLevel,
                                   long *aSimilarItemsInGroup,
                                   long *aPositionInGroup)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aGroupLevel || !aSimilarItemsInGroup || !aPositionInGroup)
+    return E_INVALIDARG;
+
+  *aGroupLevel = 0;
+  *aSimilarItemsInGroup = 0;
+  *aPositionInGroup = 0;
+
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   GroupPos groupPos = GroupPosition();
 
   // Group information for accessibles having level only (like html headings
   // elements) isn't exposed by this method. AT should look for 'level' object
   // attribute.
@@ -1206,16 +1266,19 @@ AccessibleWrap::get_groupPosition(long *
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 AccessibleWrap::get_states(AccessibleStates *aStates)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aStates)
+    return E_INVALIDARG;
+
   *aStates = 0;
 
   // XXX: bug 344674 should come with better approach that we have here.
 
   uint64_t state = State();
 
   if (state & states::INVALID)
     *aStates |= IA2_STATE_INVALID_ENTRY;
@@ -1264,88 +1327,109 @@ AccessibleWrap::get_states(AccessibleSta
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 AccessibleWrap::get_extendedRole(BSTR *aExtendedRole)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aExtendedRole)
+    return E_INVALIDARG;
+
   *aExtendedRole = nullptr;
   return E_NOTIMPL;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 AccessibleWrap::get_localizedExtendedRole(BSTR *aLocalizedExtendedRole)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aLocalizedExtendedRole)
+    return E_INVALIDARG;
+
   *aLocalizedExtendedRole = nullptr;
   return E_NOTIMPL;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 AccessibleWrap::get_nExtendedStates(long *aNExtendedStates)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aNExtendedStates)
+    return E_INVALIDARG;
+
   *aNExtendedStates = 0;
   return E_NOTIMPL;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 AccessibleWrap::get_extendedStates(long aMaxExtendedStates,
                                    BSTR **aExtendedStates,
                                    long *aNExtendedStates)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aExtendedStates || !aNExtendedStates)
+    return E_INVALIDARG;
+
   *aExtendedStates = nullptr;
   *aNExtendedStates = 0;
   return E_NOTIMPL;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 AccessibleWrap::get_localizedExtendedStates(long aMaxLocalizedExtendedStates,
                                             BSTR** aLocalizedExtendedStates,
                                             long* aNLocalizedExtendedStates)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aLocalizedExtendedStates || !aNLocalizedExtendedStates)
+    return E_INVALIDARG;
+
   *aLocalizedExtendedStates = nullptr;
   *aNLocalizedExtendedStates = 0;
   return E_NOTIMPL;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 AccessibleWrap::get_uniqueID(long *uniqueID)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!uniqueID)
+    return E_INVALIDARG;
+
   *uniqueID = - reinterpret_cast<intptr_t>(UniqueID());
   return S_OK;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 AccessibleWrap::get_windowHandle(HWND *aWindowHandle)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aWindowHandle)
+    return E_INVALIDARG;
+
   *aWindowHandle = 0;
 
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   *aWindowHandle = GetHWNDFor(this);
   return S_OK;
 
@@ -1373,16 +1457,19 @@ AccessibleWrap::get_indexInParent(long *
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 AccessibleWrap::get_locale(IA2Locale *aLocale)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aLocale)
+    return E_INVALIDARG;
+
   // Language codes consist of a primary code and a possibly empty series of
   // subcodes: language-code = primary-code ( "-" subcode )*
   // Two-letter primary codes are reserved for [ISO639] language abbreviations.
   // Any two-letter subcode is understood to be a [ISO3166] country code.
 
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
@@ -1420,16 +1507,19 @@ AccessibleWrap::get_locale(IA2Locale *aL
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 AccessibleWrap::get_attributes(BSTR *aAttributes)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aAttributes)
+    return E_INVALIDARG;
+
   // The format is name:value;name:value; with \ for escaping these
   // characters ":;=,\".
   *aAttributes = nullptr;
 
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   nsCOMPtr<nsIPersistentProperties> attributes = Attributes();
@@ -1439,23 +1529,29 @@ AccessibleWrap::get_attributes(BSTR *aAt
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // IDispatch
 
 STDMETHODIMP
 AccessibleWrap::GetTypeInfoCount(UINT *pctinfo)
 {
+  if (!pctinfo)
+    return E_INVALIDARG;
+
   *pctinfo = 1;
   return S_OK;
 }
 
 STDMETHODIMP
 AccessibleWrap::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
 {
+  if (!ppTInfo)
+    return E_INVALIDARG;
+
   *ppTInfo = nullptr;
 
   if (iTInfo != 0)
     return DISP_E_BADINDEX;
 
   ITypeInfo * typeInfo = GetTI(lcid);
   if (!typeInfo)
     return E_FAIL;
--- a/accessible/src/windows/msaa/ApplicationAccessibleWrap.cpp
+++ b/accessible/src/windows/msaa/ApplicationAccessibleWrap.cpp
@@ -43,16 +43,19 @@ ApplicationAccessibleWrap::NativeAttribu
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // IUnknown
 
 STDMETHODIMP
 ApplicationAccessibleWrap::QueryInterface(REFIID iid, void** ppv)
 {
+  if (!ppv)
+    return E_INVALIDARG;
+
   *ppv = nullptr;
 
   if (IID_IAccessibleApplication == iid) {
     *ppv = static_cast<IAccessibleApplication*>(this);
     (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
     return S_OK;
   }
 
@@ -62,16 +65,19 @@ ApplicationAccessibleWrap::QueryInterfac
 ////////////////////////////////////////////////////////////////////////////////
 // IAccessibleApplication
 
 STDMETHODIMP
 ApplicationAccessibleWrap::get_appName(BSTR* aName)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aName)
+    return E_INVALIDARG;
+
   *aName = nullptr;
 
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   nsAutoString name;
   nsresult rv = GetAppName(name);
   if (NS_FAILED(rv))
@@ -86,16 +92,19 @@ ApplicationAccessibleWrap::get_appName(B
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ApplicationAccessibleWrap::get_appVersion(BSTR* aVersion)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aVersion)
+    return E_INVALIDARG;
+
   *aVersion = nullptr;
 
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   nsAutoString version;
   nsresult rv = GetAppVersion(version);
   if (NS_FAILED(rv))
@@ -110,16 +119,19 @@ ApplicationAccessibleWrap::get_appVersio
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ApplicationAccessibleWrap::get_toolkitName(BSTR* aName)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aName)
+    return E_INVALIDARG;
+
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   nsAutoString name;
   nsresult rv = GetPlatformName(name);
   if (NS_FAILED(rv))
     return GetHRESULT(rv);
 
@@ -132,16 +144,19 @@ ApplicationAccessibleWrap::get_toolkitNa
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ApplicationAccessibleWrap::get_toolkitVersion(BSTR* aVersion)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aVersion)
+    return E_INVALIDARG;
+
   *aVersion = nullptr;
 
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   nsAutoString version;
   nsresult rv = GetPlatformVersion(version);
   if (NS_FAILED(rv))
--- a/accessible/src/windows/msaa/DocAccessibleWrap.cpp
+++ b/accessible/src/windows/msaa/DocAccessibleWrap.cpp
@@ -59,32 +59,38 @@ STDMETHODIMP_(ULONG) DocAccessibleWrap::
 {
   return nsAccessNode::Release();
 }
 
 // Microsoft COM QueryInterface
 STDMETHODIMP
 DocAccessibleWrap::QueryInterface(REFIID iid, void** ppv)
 {
+  if (!ppv)
+    return E_INVALIDARG;
+
   *ppv = nullptr;
 
   if (IID_ISimpleDOMDocument != iid)
     return HyperTextAccessibleWrap::QueryInterface(iid, ppv);
 
   statistics::ISimpleDOMUsed();
   *ppv = static_cast<ISimpleDOMDocument*>(this);
   (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
   return S_OK;
 }
 
 STDMETHODIMP
 DocAccessibleWrap::get_URL(/* [out] */ BSTR __RPC_FAR *aURL)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aURL)
+    return E_INVALIDARG;
+
   *aURL = nullptr;
 
   nsAutoString URL;
   nsresult rv = GetURL(URL);
   if (NS_FAILED(rv))
     return E_FAIL;
 
   if (URL.IsEmpty())
@@ -96,16 +102,19 @@ DocAccessibleWrap::get_URL(/* [out] */ B
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 DocAccessibleWrap::get_title( /* [out] */ BSTR __RPC_FAR *aTitle)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aTitle)
+    return E_INVALIDARG;
+
   *aTitle = nullptr;
 
   nsAutoString title;
   nsresult rv = GetTitle(title);
   if (NS_FAILED(rv))
     return E_FAIL;
 
   *aTitle = ::SysAllocStringLen(title.get(), title.Length());
@@ -114,16 +123,19 @@ DocAccessibleWrap::get_title( /* [out] *
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 DocAccessibleWrap::get_mimeType(/* [out] */ BSTR __RPC_FAR *aMimeType)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aMimeType)
+    return E_INVALIDARG;
+
   *aMimeType = nullptr;
 
   nsAutoString mimeType;
   nsresult rv = GetMimeType(mimeType);
   if (NS_FAILED(rv))
     return E_FAIL;
 
   if (mimeType.IsEmpty())
@@ -135,16 +147,19 @@ DocAccessibleWrap::get_mimeType(/* [out]
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 DocAccessibleWrap::get_docType(/* [out] */ BSTR __RPC_FAR *aDocType)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aDocType)
+    return E_INVALIDARG;
+
   *aDocType = nullptr;
 
   nsAutoString docType;
   nsresult rv = GetDocType(docType);
   if (NS_FAILED(rv))
     return E_FAIL;
 
   if (docType.IsEmpty())
@@ -157,16 +172,19 @@ DocAccessibleWrap::get_docType(/* [out] 
 }
 
 STDMETHODIMP
 DocAccessibleWrap::get_nameSpaceURIForID(/* [in] */  short aNameSpaceID,
   /* [out] */ BSTR __RPC_FAR *aNameSpaceURI)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aNameSpaceURI)
+    return E_INVALIDARG;
+
   *aNameSpaceURI = nullptr;
 
   if (aNameSpaceID < 0)
     return E_INVALIDARG;  // -1 is kNameSpaceID_Unknown
 
   nsAutoString nameSpaceURI;
   nsresult rv = GetNameSpaceURIForID(aNameSpaceID, nameSpaceURI);
   if (NS_FAILED(rv))
@@ -183,27 +201,33 @@ DocAccessibleWrap::get_nameSpaceURIForID
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 DocAccessibleWrap::put_alternateViewMediaTypes( /* [in] */ BSTR __RPC_FAR *aCommaSeparatedMediaTypes)
 {
   A11Y_TRYBLOCK_BEGIN
 
+  if (!aCommaSeparatedMediaTypes)
+    return E_INVALIDARG;
+
   *aCommaSeparatedMediaTypes = nullptr;
   return E_NOTIMPL;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 DocAccessibleWrap::get_accValue(
       /* [optional][in] */ VARIANT varChild,
       /* [retval][out] */ BSTR __RPC_FAR *pszValue)
 {
+  if (!pszValue)
+    return E_INVALIDARG;
+
   // For backwards-compat, we still support old MSAA hack to provide URL in accValue
   *pszValue = nullptr;
   // Check for real value first
   HRESULT hr = AccessibleWrap::get_accValue(varChild, pszValue);
   if (FAILED(hr) || *pszValue || varChild.lVal != CHILDID_SELF)
     return hr;
   // If document is being used to create a widget, don't use the URL hack
   roles::Role role = Role();
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -282,16 +282,61 @@
                               gContextMenu.hiding();
                               gContextMenu = null;
                               updateEditUIVisibility();">
 #include browser-context.inc
     </menupopup>
 
     <menupopup id="placesContext"/>
 
+    <!-- Popup for site identity information -->
+    <panel id="identity-popup"
+           type="arrow"
+           hidden="true"
+           noautofocus="true"
+           consumeoutsideclicks="true"
+           onpopupshown="gIdentityHandler.onPopupShown(event);"
+           level="top">
+      <hbox id="identity-popup-container" align="top">
+        <image id="identity-popup-icon"/>
+        <vbox id="identity-popup-content-box">
+          <label id="identity-popup-connectedToLabel"
+                 class="identity-popup-label"
+                 value="&identity.connectedTo;"/>
+          <label id="identity-popup-connectedToLabel2"
+                 class="identity-popup-label"
+                 value="&identity.unverifiedsite2;"/>
+          <description id="identity-popup-content-host"
+                       class="identity-popup-description"/>
+          <label id="identity-popup-runByLabel"
+                 class="identity-popup-label"
+                 value="&identity.runBy;"/>
+          <description id="identity-popup-content-owner"
+                       class="identity-popup-description"/>
+          <description id="identity-popup-content-supplemental"
+                       class="identity-popup-description"/>
+          <description id="identity-popup-content-verifier"
+                       class="identity-popup-description"/>
+          <hbox id="identity-popup-encryption" flex="1">
+            <vbox>
+              <image id="identity-popup-encryption-icon"/>
+            </vbox>
+            <description id="identity-popup-encryption-label" flex="1"
+                         class="identity-popup-description"/>
+          </hbox>
+          <!-- Footer button to open security page info -->
+          <hbox id="identity-popup-button-container" pack="end">
+            <button id="identity-popup-more-info-button"
+                    label="&identity.moreInfoLinkText;"
+                    onblur="gIdentityHandler.hideIdentityPopup();"
+                    oncommand="gIdentityHandler.handleMoreInfoClick(event);"/>
+          </hbox>
+        </vbox>
+      </hbox>
+    </panel>
 
     <panel id="ctrlTab-panel" class="KUI-panel" hidden="true" norestorefocus="true" level="top">
       <hbox>
         <button class="ctrlTab-preview" flex="1"/>
         <button class="ctrlTab-preview" flex="1"/>
         <button class="ctrlTab-preview" flex="1"/>
         <button class="ctrlTab-preview" flex="1"/>
         <button class="ctrlTab-preview" flex="1"/>
--- a/browser/base/content/popup-notifications.inc
+++ b/browser/base/content/popup-notifications.inc
@@ -3,63 +3,16 @@
     <panel id="notification-popup"
            type="arrow"
            footertype="promobox"
            position="after_start"
            hidden="true"
            orient="vertical"
            role="alert"/>
 
-    <!-- Popup for site identity information -->
-    <panel id="identity-popup"
-           type="arrow"
-           hidden="true"
-           noautofocus="true"
-           consumeoutsideclicks="true"
-           onpopupshown="gIdentityHandler.onPopupShown(event);"
-           level="top">
-      <hbox id="identity-popup-container" align="top">
-        <image id="identity-popup-icon"/>
-        <vbox id="identity-popup-content-box">
-          <label id="identity-popup-connectedToLabel"
-                 class="identity-popup-label"
-                 value="&identity.connectedTo;"/>
-          <label id="identity-popup-connectedToLabel2"
-                 class="identity-popup-label"
-                 value="&identity.unverifiedsite2;"/>
-          <description id="identity-popup-content-host"
-                       class="identity-popup-description"/>
-          <label id="identity-popup-runByLabel"
-                 class="identity-popup-label"
-                 value="&identity.runBy;"/>
-          <description id="identity-popup-content-owner"
-                       class="identity-popup-description"/>
-          <description id="identity-popup-content-supplemental"
-                       class="identity-popup-description"/>
-          <description id="identity-popup-content-verifier"
-                       class="identity-popup-description"/>
-          <hbox id="identity-popup-encryption" flex="1">
-            <vbox>
-              <image id="identity-popup-encryption-icon"/>
-            </vbox>
-            <description id="identity-popup-encryption-label" flex="1"
-                         class="identity-popup-description"/>
-          </hbox>
-          <!-- Footer button to open security page info -->
-          <hbox id="identity-popup-button-container" pack="end">
-            <button id="identity-popup-more-info-button"
-                    label="&identity.moreInfoLinkText;"
-                    onblur="gIdentityHandler.hideIdentityPopup();"
-                    oncommand="gIdentityHandler.handleMoreInfoClick(event);"/>
-          </hbox>
-        </vbox>
-      </hbox>
-    </panel>
-
-
     <popupnotification id="webRTC-shareDevices-notification" hidden="true">
       <popupnotificationcontent id="webRTC-selectCamera" orient="vertical">
         <separator class="thin"/>
         <label value="&getUserMedia.selectCamera.label;"
                accesskey="&getUserMedia.selectCamera.accesskey;"
                control="webRTC-selectCamera-menulist"/>
         <menulist id="webRTC-selectCamera-menulist">
           <menupopup id="webRTC-selectCamera-menupopup"/>
--- a/browser/base/content/test/browser_homeDrop.js
+++ b/browser/base/content/test/browser_homeDrop.js
@@ -1,14 +1,23 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test() {
   waitForExplicitFinish();
 
+  let str = Cc["@mozilla.org/supports-string;1"]
+              .createInstance(Ci.nsISupportsString);
+  str.data = "about:mozilla";
+  Services.prefs.setComplexValue("browser.startup.homepage",
+                                 Ci.nsISupportsString, str);
+  registerCleanupFunction(() => {
+    Services.prefs.clearUserPref("browser.startup.homepage");
+  });
+
   // Open a new tab, since starting a drag from the home button activates it and
   // we don't want to interfere with future tests by loading the home page.
   let newTab = gBrowser.selectedTab = gBrowser.addTab();
   registerCleanupFunction(function () {
     gBrowser.removeTab(newTab);
   });
 
   let scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
--- a/browser/components/sessionstore/test/Makefile.in
+++ b/browser/components/sessionstore/test/Makefile.in
@@ -10,17 +10,16 @@ relativesrcdir  = @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 # browser_506482.js is disabled because of frequent failures (bug 538672)
 # browser_526613.js is disabled because of frequent failures (bug 534489)
 # browser_589246.js is disabled for leaking browser windows (bug 752467)
 # browser_580512.js is disabled for leaking browser windows (bug 752467)
 # browser_capabilities.js is disabled for using resources outside of the build network (bug 882575)
-# browser_707862.js & browser_705597.js are disabled whilst waiting for review (bug 861700 & bug 883592)
 
 MOCHITEST_BROWSER_FILES = \
 	head.js \
 	browser_attributes.js \
 	browser_dying_cache.js \
 	browser_form_restore_events.js \
 	browser_form_restore_events_sample.html \
 	browser_formdata_format.js \
@@ -129,16 +128,18 @@ MOCHITEST_BROWSER_FILES = \
 	browser_662743_sample.html \
 	browser_662812.js \
 	browser_665702-state_session.js \
 	browser_682507.js \
 	browser_687710.js \
 	browser_687710_2.js \
 	browser_694378.js \
 	browser_701377.js \
+	browser_705597.js \
+	browser_707862.js \
 	browser_739531.js \
 	browser_739531_sample.html \
 	browser_739805.js \
 	browser_819510_perwindowpb.js \
 	browser_833286_atomic_backup.js \
 	$(filter disabled-for-intermittent-failures--bug-766044, browser_459906_empty.html) \
 	$(filter disabled-for-intermittent-failures--bug-766044, browser_459906_sample.html) \
 	$(filter disabled-for-intermittent-failures--bug-765389, browser_461743_sample.html) \
--- a/browser/components/sessionstore/test/browser_625257.js
+++ b/browser/components/sessionstore/test/browser_625257.js
@@ -10,17 +10,17 @@
 let tab;
 
 // This test steps through the following parts:
 //  1. Tab has been created is loading URI_TO_LOAD.
 //  2. Before URI_TO_LOAD finishes loading, browser.currentURI has changed and
 //     tab is scheduled to be removed.
 //  3. After the tab has been closed, undoCloseTab() has been called and the tab
 //     should fully load.
-const URI_TO_LOAD = "about:home";
+const URI_TO_LOAD = "about:mozilla";
 
 function test() {
   waitForExplicitFinish();
 
   gBrowser.addTabsProgressListener(tabsListener);
 
   tab = gBrowser.addTab();
 
--- a/browser/components/sessionstore/test/browser_705597.js
+++ b/browser/components/sessionstore/test/browser_705597.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 let tabState = {
-  entries: [{url: "about:home", children: [{url: "about:mozilla"}]}]
+  entries: [{url: "about:robots", children: [{url: "about:mozilla"}]}]
 };
 
 function test() {
   waitForExplicitFinish();
   requestLongerTimeout(2);
 
   Services.prefs.setIntPref("browser.sessionstore.interval", 4000);
   registerCleanupFunction(function () {
--- a/browser/components/sessionstore/test/browser_707862.js
+++ b/browser/components/sessionstore/test/browser_707862.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 let tabState = {
-  entries: [{url: "about:home", children: [{url: "about:mozilla"}]}]
+  entries: [{url: "about:robots", children: [{url: "about:mozilla"}]}]
 };
 
 function test() {
   waitForExplicitFinish();
   requestLongerTimeout(2);
 
   Services.prefs.setIntPref("browser.sessionstore.interval", 4000);
   registerCleanupFunction(function () {
--- a/browser/components/sessionstore/test/browser_capabilities.js
+++ b/browser/components/sessionstore/test/browser_capabilities.js
@@ -33,17 +33,17 @@ function runTests() {
   // Check that we correctly save disallowed features.
   let disallowedState = JSON.parse(ss.getTabState(tab));
   let disallow = new Set(disallowedState.disallow.split(","));
   ok(disallow.has("Images"), "images not allowed");
   ok(disallow.has("MetaRedirects"), "meta redirects not allowed");
   is(disallow.size, 2, "two capabilities disallowed");
 
   // Reuse the tab to restore a new, clean state into it.
-  ss.setTabState(tab, JSON.stringify({ entries: [{url: "about:home"}] }));
+  ss.setTabState(tab, JSON.stringify({ entries: [{url: "about:robots"}] }));
   yield waitForLoad(browser);
 
   // After restoring disallowed features must be available again.
   state = JSON.parse(ss.getTabState(tab));
   ok(!("disallow" in state), "everything allowed again");
   ok(flags.every(f => docShell[f]), "all flags set to true");
 
   // Restore the state with disallowed features.
--- a/browser/components/tabview/test/browser_tabview_bug631662.js
+++ b/browser/components/tabview/test/browser_tabview_bug631662.js
@@ -12,17 +12,17 @@ function test() {
 
   let checkTimestamp = function () {
     is(timestamp, cw.TabItems._lastUpdateTime, prefix +
        ": tabs were not updated");
   }
 
   let actionAddTab = function () {
     storeTimestamp();
-    gBrowser.addTab("about:home");
+    gBrowser.addTab("about:mozilla");
 
     afterAllTabsLoaded(function () {
       checkTimestamp();
       next();
     });
   }
 
   let actionMoveTab = function () {
--- a/browser/components/tabview/test/browser_tabview_bug643392.js
+++ b/browser/components/tabview/test/browser_tabview_bug643392.js
@@ -1,21 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 let state = {
   windows: [{
     tabs: [{
-      entries: [{ url: "about:home" }],
+      entries: [{ url: "about:mozilla" }],
       hidden: true,
-      extData: {"tabview-tab": '{"url":"about:home","groupID":1,"bounds":{"left":20,"top":20,"width":20,"height":20}}'}
+      extData: {"tabview-tab": '{"url":"about:mozilla","groupID":1,"bounds":{"left":20,"top":20,"width":20,"height":20}}'}
     },{
-      entries: [{ url: "about:home" }],
+      entries: [{ url: "about:mozilla" }],
       hidden: false,
-      extData: {"tabview-tab": '{"url":"about:home","groupID":2,"bounds":{"left":20,"top":20,"width":20,"height":20}}'},
+      extData: {"tabview-tab": '{"url":"about:mozilla","groupID":2,"bounds":{"left":20,"top":20,"width":20,"height":20}}'},
     }],
     selected: 2,
     extData: {
       "tabview-groups": '{"nextID":3,"activeGroupId":2}',
       "tabview-group":
         '{"1":{"bounds":{"left":15,"top":5,"width":280,"height":232},"id":1},' +
         '"2":{"bounds":{"left":309,"top":5,"width":267,"height":226},"id":2}}'
     }
--- a/browser/components/tabview/test/browser_tabview_bug654721.js
+++ b/browser/components/tabview/test/browser_tabview_bug654721.js
@@ -1,23 +1,23 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 let state = {
   windows: [{
     tabs: [{
-      entries: [{ url: "about:home" }],
+      entries: [{ url: "about:mozilla" }],
       hidden: true,
-      extData: {"tabview-tab": '{"url":"about:home","groupID":1,"bounds":{"left":20,"top":20,"width":20,"height":20}}'}
+      extData: {"tabview-tab": '{"url":"about:mozilla","groupID":1,"bounds":{"left":20,"top":20,"width":20,"height":20}}'}
     },{
-      entries: [{ url: "about:home" }],
+      entries: [{ url: "about:mozilla" }],
       hidden: false,
       // this is an existing orphan tab from a previous Fx version and we want
       // to make sure this gets transformed into a group
-      extData: {"tabview-tab": '{"url":"about:home","groupID":0,"bounds":{"left":300,"top":300,"width":200,"height":200}}'},
+      extData: {"tabview-tab": '{"url":"about:mozilla","groupID":0,"bounds":{"left":300,"top":300,"width":200,"height":200}}'},
     }],
     selected: 2,
     extData: {
       "tabview-groups": '{"nextID":3,"activeGroupId":1}',
       "tabview-group":
         '{"1":{"bounds":{"left":20,"top":20,"width":200,"height":200},"id":1}}'
     }
   }]
--- a/browser/devtools/debugger/test/browser_dbg_chrome-debugging.js
+++ b/browser/devtools/debugger/test/browser_dbg_chrome-debugging.js
@@ -3,17 +3,17 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // Tests that chrome debugging works.
 
 var gClient = null;
 var gTab = null;
-var gHomeTab = null;
+var gMozillaTab = null;
 var gThreadClient = null;
 var gNewGlobal = false;
 var gAttached = false;
 var gChromeSource = false;
 
 const DEBUGGER_TAB_URL = EXAMPLE_URL + "browser_dbg_debuggerstatement.html";
 
 function test()
@@ -30,17 +30,17 @@ function test()
         gClient.addListener("newSource", onNewSource);
 
         gClient.attachThread(dbg, function(aResponse, aThreadClient) {
           gThreadClient = aThreadClient;
           ok(!aResponse.error, "Attached to the chrome debugger.");
           gAttached = true;
 
           // Ensure that a new global will be created.
-          gHomeTab = gBrowser.addTab("about:home");
+          gMozillaTab = gBrowser.addTab("about:mozilla");
 
           finish_test();
         });
       });
     });
   });
 }
 
@@ -52,17 +52,17 @@ function onNewSource(aEvent, aPacket)
 
 function finish_test()
 {
   if (!gAttached || !gChromeSource) {
     return;
   }
   gClient.removeListener("newSource", onNewSource);
   gThreadClient.resume(function(aResponse) {
-    removeTab(gHomeTab);
+    removeTab(gMozillaTab);
     removeTab(gTab);
     gClient.close(function() {
       ok(gNewGlobal, "Received newGlobal event.");
       ok(gChromeSource, "Received newSource event for a chrome: script.");
       finish();
     });
   });
 }
--- a/browser/devtools/debugger/test/browser_dbg_sources-cache.js
+++ b/browser/devtools/debugger/test/browser_dbg_sources-cache.js
@@ -87,19 +87,16 @@ function testSourcesCache()
   fetchSources(function() {
     performReload(function() {
       closeDebuggerAndFinish();
     });
   });
 }
 
 function fetchSources(callback) {
-  let fetches = 0;
-  let timeouts = 0;
-
   gControllerSources.getTextForSources(gSources.values).then((aSources) => {
     testCacheIntegrity(aSources);
     callback();
   });
 }
 
 function performReload(callback) {
   gDebugger.DebuggerController._target.once("will-navigate", testStateBeforeReload);
@@ -136,26 +133,28 @@ function testStateAfterReload() {
     "There should be " + TOTAL_SOURCES + " labels cached after reload.");
   is(gDebugger.SourceUtils._groupsCache.size, TOTAL_SOURCES,
     "There should be " + TOTAL_SOURCES + " groups cached after reload.");
 }
 
 function testCacheIntegrity(aCache) {
   for (let source of aCache) {
     let [url, contents] = source;
-    let index = aCache.indexOf(source);
 
-    ok(url.contains("test-function-search-0" + (index + 1)),
+    // Sources of a debugee don't always finish fetching consecutively. D'uh.
+    let index = url.match(/test-function-search-0(\d)/).pop();
+
+    ok(index >= 1 && index <= TOTAL_SOURCES,
       "Found a source url cached correctly (" + index + ")");
     ok(contents.contains(
-      ["First source!", "Second source!", "Third source!"][index]),
+      ["First source!", "Second source!", "Third source!"][index - 1]),
       "Found a source's text contents cached correctly (" + index + ")");
 
-    info("Cached source url at " + index + ": " + source[0]);
-    info("Cached source text at " + index + ": " + source[1]);
+    info("Cached source url at " + index + ": " + url);
+    info("Cached source text at " + index + ": " + contents);
   }
 }
 
 registerCleanupFunction(function() {
   removeTab(gTab);
   gPane = null;
   gTab = null;
   gDebuggee = null;
--- a/build/mobile/remoteautomation.py
+++ b/build/mobile/remoteautomation.py
@@ -261,48 +261,51 @@ class RemoteAutomation(Automation):
 
         @property
         def stdout(self):
             """ Fetch the full remote log file using devicemanager and return just
                 the new log entries since the last call (as a multi-line string).
             """
             if self.dm.fileExists(self.proc):
                 try:
-                    t = self.dm.pullFile(self.proc)
+                    newLogContent = self.dm.pullFile(self.proc, self.stdoutlen)
                 except DMError:
                     # we currently don't retry properly in the pullFile
                     # function in dmSUT, so an error here is not necessarily
                     # the end of the world
                     return ''
-                newLogContent = t[self.stdoutlen:]
-                self.stdoutlen = len(t)
+                self.stdoutlen += len(newLogContent)
                 # Match the test filepath from the last TEST-START line found in the new
                 # log content. These lines are in the form:
                 # 1234 INFO TEST-START | /filepath/we/wish/to/capture.html\n
                 testStartFilenames = re.findall(r"TEST-START \| ([^\s]*)", newLogContent)
                 if testStartFilenames:
                     self.lastTestSeen = testStartFilenames[-1]
                 return newLogContent.strip('\n').strip()
             else:
                 return ''
 
         @property
         def getLastTestSeen(self):
             return self.lastTestSeen
 
         def wait(self, timeout = None):
             timer = 0
-            interval = 5
+            interval = 20 
 
             if timeout == None:
                 timeout = self.timeout
 
             while (self.dm.getTopActivity() == self.procName):
-                t = self.stdout
-                if t != '': print t
+                # retrieve log updates every 60 seconds
+                if timer % 60 == 0: 
+                    t = self.stdout
+                    if t != '':
+                        print t
+
                 time.sleep(interval)
                 timer += interval
                 if (timer > timeout):
                     break
 
             # Flush anything added to stdout during the sleep
             print self.stdout
 
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -723,21 +723,26 @@ nsScriptLoader::ProcessRequest(nsScriptL
   uint32_t parserCreated = aRequest->mElement->GetParserCreated();
   if (parserCreated) {
     oldParserInsertedScript = mCurrentParserInsertedScript;
     mCurrentParserInsertedScript = aRequest->mElement;
   }
 
   FireScriptAvailable(NS_OK, aRequest);
 
-  bool runScript = true;
-  nsContentUtils::DispatchTrustedEvent(scriptElem->OwnerDoc(),
-                                       scriptElem,
-                                       NS_LITERAL_STRING("beforescriptexecute"),
-                                       true, true, &runScript);
+  // The window may have gone away by this point, in which case there's no point
+  // in trying to run the script.
+  nsPIDOMWindow *pwin = mDocument->GetInnerWindow();
+  bool runScript = !!pwin;
+  if (runScript) {
+    nsContentUtils::DispatchTrustedEvent(scriptElem->OwnerDoc(),
+                                         scriptElem,
+                                         NS_LITERAL_STRING("beforescriptexecute"),
+                                         true, true, &runScript);
+  }
 
   nsresult rv = NS_OK;
   if (runScript) {
     if (doc) {
       doc->BeginEvaluatingExternalScript();
     }
     aRequest->mElement->BeginEvaluating();
     rv = EvaluateScript(aRequest, *script);
@@ -802,19 +807,18 @@ nsScriptLoader::EvaluateScript(nsScriptL
   nsCOMPtr<nsIContent> scriptContent(do_QueryInterface(aRequest->mElement));
   nsIDocument* ownerDoc = scriptContent->OwnerDoc();
   if (ownerDoc != mDocument) {
     // Willful violation of HTML5 as of 2010-12-01
     return NS_ERROR_FAILURE;
   }
 
   nsPIDOMWindow *pwin = mDocument->GetInnerWindow();
-  if (!pwin) {
-    return NS_ERROR_FAILURE;
-  }
+  NS_ASSERTION(pwin, "shouldn't be called with a null inner window");
+
   nsCOMPtr<nsIScriptGlobalObject> globalObject = do_QueryInterface(pwin);
   NS_ASSERTION(globalObject, "windows must be global objects");
 
   // Get the script-type to be used by this element.
   NS_ASSERTION(scriptContent, "no content - what is default script-type?");
 
   // and make sure we are setup for this type of script.
   rv = globalObject->EnsureScriptEnvironment();
--- a/content/events/src/nsEventDispatcher.cpp
+++ b/content/events/src/nsEventDispatcher.cpp
@@ -19,16 +19,36 @@
 #include "nsDOMTouchEvent.h"
 #include "GeckoProfiler.h"
 #include "GeneratedEvents.h"
 #include "mozilla/dom/EventTarget.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
+class ELMCreationDetector
+{
+public:
+  ELMCreationDetector() :
+    // We can do this optimization only in the main thread.
+    mDefault(!NS_IsMainThread()),
+    mInitialCount(mDefault ? 0 : nsEventListenerManager::sMainThreadCreatedCount)
+  {
+  }
+
+  bool MayHaveNewListenerManager()
+  {
+    return mDefault ||
+           mInitialCount != nsEventListenerManager::sMainThreadCreatedCount;
+  }
+private:
+  bool mDefault;
+  uint32_t mInitialCount;
+};
+
 #define NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH  (1 << 0)
 #define NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT (1 << 1)
 #define NS_TARGET_CHAIN_MAY_HAVE_MANAGER        (1 << 2)
 
 // nsEventTargetChainItem represents a single item in the event target chain.
 class nsEventTargetChainItem
 {
 private:
@@ -158,41 +178,41 @@ public:
   /**
    * Dispatches event through the event target chain.
    * Handles capture, target and bubble phases both in default
    * and system event group and calls also PostHandleEvent for each
    * item in the chain.
    */
   nsresult HandleEventTargetChain(nsEventChainPostVisitor& aVisitor,
                                   nsDispatchingCallback* aCallback,
-                                  bool aMayHaveNewListenerManagers,
+                                  ELMCreationDetector& aCd,
                                   nsCxPusher* aPusher);
 
   /**
    * Resets aVisitor object and calls PreHandleEvent.
    * Copies mItemFlags and mItemData to the current nsEventTargetChainItem.
    */
   nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
 
   /**
    * If the current item in the event target chain has an event listener
    * manager, this method calls nsEventListenerManager::HandleEvent().
    */
   nsresult HandleEvent(nsEventChainPostVisitor& aVisitor,
-                       bool aMayHaveNewListenerManagers,
+                       ELMCreationDetector& aCd,
                        nsCxPusher* aPusher)
   {
     if (WantsWillHandleEvent()) {
       mTarget->WillHandleEvent(aVisitor);
     }
     if (aVisitor.mEvent->mFlags.mPropagationStopped) {
       return NS_OK;
     }
     if (!mManager) {
-      if (!MayHaveListenerManager() && !aMayHaveNewListenerManagers) {
+      if (!MayHaveListenerManager() && !aCd.MayHaveNewListenerManager()) {
         return NS_OK;
       }
       mManager =
         static_cast<nsEventListenerManager*>(mTarget->GetListenerManager(false));
     }
     if (mManager) {
       NS_ASSERTION(aVisitor.mEvent->currentTarget == nullptr,
                    "CurrentTarget should be null!");
@@ -276,35 +296,31 @@ nsEventTargetChainItem::PostHandleEvent(
   mTarget->PostHandleEvent(aVisitor);
   return NS_OK;
 }
 
 nsresult
 nsEventTargetChainItem::HandleEventTargetChain(
                           nsEventChainPostVisitor& aVisitor,
                           nsDispatchingCallback* aCallback,
-                          bool aMayHaveNewListenerManagers,
+                          ELMCreationDetector& aCd,
                           nsCxPusher* aPusher)
 {
-  uint32_t createdELMs = nsEventListenerManager::sCreatedCount;
   // Save the target so that it can be restored later.
   nsCOMPtr<EventTarget> firstTarget = aVisitor.mEvent->target;
 
   // Capture
   nsEventTargetChainItem* item = this;
   aVisitor.mEvent->mFlags.mInCapturePhase = true;
   aVisitor.mEvent->mFlags.mInBubblingPhase = false;
   while (item->mChild) {
     if ((!aVisitor.mEvent->mFlags.mNoContentDispatch ||
          item->ForceContentDispatch()) &&
         !aVisitor.mEvent->mFlags.mPropagationStopped) {
-      item->HandleEvent(aVisitor,
-                        aMayHaveNewListenerManagers ||
-                        createdELMs != nsEventListenerManager::sCreatedCount,
-                        aPusher);
+      item->HandleEvent(aVisitor, aCd, aPusher);
     }
 
     if (item->GetNewTarget()) {
       // item is at anonymous boundary. Need to retarget for the child items.
       nsEventTargetChainItem* nextTarget = item->mChild;
       while (nextTarget) {
         EventTarget* newTarget = nextTarget->GetNewTarget();
         if (newTarget) {
@@ -318,20 +334,17 @@ nsEventTargetChainItem::HandleEventTarge
     item = item->mChild;
   }
 
   // Target
   aVisitor.mEvent->mFlags.mInBubblingPhase = true;
   if (!aVisitor.mEvent->mFlags.mPropagationStopped &&
       (!aVisitor.mEvent->mFlags.mNoContentDispatch ||
        item->ForceContentDispatch())) {
-    item->HandleEvent(aVisitor,
-                      aMayHaveNewListenerManagers ||
-                      createdELMs != nsEventListenerManager::sCreatedCount,
-                      aPusher);
+    item->HandleEvent(aVisitor, aCd, aPusher);
   }
   if (aVisitor.mEvent->mFlags.mInSystemGroup) {
     item->PostHandleEvent(aVisitor, aPusher);
   }
 
   // Bubble
   aVisitor.mEvent->mFlags.mInCapturePhase = false;
   item = item->mParent;
@@ -342,19 +355,17 @@ nsEventTargetChainItem::HandleEventTarge
       // and for parent items.
       aVisitor.mEvent->target = newTarget;
     }
 
     if (aVisitor.mEvent->mFlags.mBubbles || newTarget) {
       if ((!aVisitor.mEvent->mFlags.mNoContentDispatch ||
            item->ForceContentDispatch()) &&
           !aVisitor.mEvent->mFlags.mPropagationStopped) {
-        item->HandleEvent(aVisitor,
-                          createdELMs != nsEventListenerManager::sCreatedCount,
-                          aPusher);
+        item->HandleEvent(aVisitor, aCd, aPusher);
       }
       if (aVisitor.mEvent->mFlags.mInSystemGroup) {
         item->PostHandleEvent(aVisitor, aPusher);
       }
     }
     item = item->mParent;
   }
   aVisitor.mEvent->mFlags.mInBubblingPhase = false;
@@ -376,17 +387,17 @@ nsEventTargetChainItem::HandleEventTarge
     }
 
     // Retarget for system event group (which does the default handling too).
     // Setting back the target which was used also for default event group.
     aVisitor.mEvent->target = firstTarget;
     aVisitor.mEvent->mFlags.mInSystemGroup = true;
     HandleEventTargetChain(aVisitor,
                            aCallback,
-                           createdELMs != nsEventListenerManager::sCreatedCount,
+                           aCd,
                            aPusher);
     aVisitor.mEvent->mFlags.mInSystemGroup = false;
 
     // After dispatch, clear all the propagation flags so that
     // system group listeners don't affect to the event.
     aVisitor.mEvent->mFlags.mPropagationStopped = false;
     aVisitor.mEvent->mFlags.mImmediatePropagationStopped = false;
   }
@@ -624,19 +635,20 @@ nsEventDispatcher::Dispatch(nsISupports*
         while(item) {
           aTargets->AppendObject(item->CurrentTarget()->GetTargetForDOMEvent());
           item = item->mParent;
         }
       } else {
         // Event target chain is created. Handle the chain.
         nsEventChainPostVisitor postVisitor(preVisitor);
         nsCxPusher pusher;
+        ELMCreationDetector cd;
         rv = topEtci->HandleEventTargetChain(postVisitor,
                                              aCallback,
-                                             false,
+                                             cd,
                                              &pusher);
 
         preVisitor.mEventStatus = postVisitor.mEventStatus;
         // If the DOM event was created during event flow.
         if (!preVisitor.mDOMEvent && postVisitor.mDOMEvent) {
           preVisitor.mDOMEvent = postVisitor.mDOMEvent;
         }
       }
--- a/content/events/src/nsEventListenerManager.cpp
+++ b/content/events/src/nsEventListenerManager.cpp
@@ -95,33 +95,35 @@ MutationBitForEventType(uint32_t aEventT
     case NS_MUTATION_CHARACTERDATAMODIFIED:
       return NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED;
     default:
       break;
   }
   return 0;
 }
 
-uint32_t nsEventListenerManager::sCreatedCount = 0;
+uint32_t nsEventListenerManager::sMainThreadCreatedCount = 0;
 
 nsEventListenerManager::nsEventListenerManager(EventTarget* aTarget) :
   mMayHavePaintEventListener(false),
   mMayHaveMutationListeners(false),
   mMayHaveCapturingListeners(false),
   mMayHaveSystemGroupListeners(false),
   mMayHaveAudioAvailableEventListener(false),
   mMayHaveTouchEventListener(false),
   mMayHaveMouseEnterLeaveEventListener(false),
   mClearingListeners(false),
   mNoListenerForEvent(0),
   mTarget(aTarget)
 {
   NS_ASSERTION(aTarget, "unexpected null pointer");
 
-  ++sCreatedCount;
+  if (NS_IsMainThread()) {
+    ++sMainThreadCreatedCount;
+  }
 }
 
 nsEventListenerManager::~nsEventListenerManager() 
 {
   // If your code fails this assertion, a possible reason is that
   // a class did not call our Disconnect() manually. Note that
   // this class can have Disconnect called in one of two ways:
   // if it is part of a cycle, then in Unlink() (such a cycle
--- a/content/events/src/nsEventListenerManager.h
+++ b/content/events/src/nsEventListenerManager.h
@@ -532,21 +532,18 @@ protected:
   uint32_t mMayHaveMouseEnterLeaveEventListener : 1;
   uint32_t mClearingListeners : 1;
   uint32_t mNoListenerForEvent : 24;
 
   nsAutoTObserverArray<nsListenerStruct, 2> mListeners;
   mozilla::dom::EventTarget*                mTarget;  //WEAK
   nsCOMPtr<nsIAtom>                         mNoListenerForEventAtom;
 
-  static uint32_t                           mInstanceCount;
-  static jsid                               sAddListenerID;
-
-  friend class nsEventTargetChainItem;
-  static uint32_t                           sCreatedCount;
+  friend class ELMCreationDetector;
+  static uint32_t                           sMainThreadCreatedCount;
 };
 
 /**
  * NS_AddSystemEventListener() is a helper function for implementing
  * EventTarget::AddSystemEventListener().
  */
 inline nsresult
 NS_AddSystemEventListener(mozilla::dom::EventTarget* aTarget,
--- a/content/media/MediaDecoderStateMachine.cpp
+++ b/content/media/MediaDecoderStateMachine.cpp
@@ -2461,21 +2461,23 @@ void MediaDecoderStateMachine::AdvanceFr
 #ifdef PR_LOGGING
   int32_t droppedFrames = 0;
 #endif
   if (mReader->VideoQueue().GetSize() > 0) {
     VideoData* frame = mReader->VideoQueue().PeekFront();
     while (mRealTime || clock_time >= frame->mTime) {
       mVideoFrameEndTime = frame->mEndTime;
       currentFrame = frame;
-      LOG(PR_LOG_DEBUG, ("%p Decoder discarding video frame %lld", mDecoder.get(), frame->mTime));
 #ifdef PR_LOGGING
-      if (droppedFrames++) {
-        LOG(PR_LOG_DEBUG, ("%p Decoder discarding video frame %lld (%d so far)",
-              mDecoder.get(), frame->mTime, droppedFrames - 1));
+      if (!PR_GetEnv("MOZ_QUIET")) {
+        LOG(PR_LOG_DEBUG, ("%p Decoder discarding video frame %lld", mDecoder.get(), frame->mTime));
+        if (droppedFrames++) {
+          LOG(PR_LOG_DEBUG, ("%p Decoder discarding video frame %lld (%d so far)",
+            mDecoder.get(), frame->mTime, droppedFrames - 1));
+        }
       }
 #endif
       mReader->VideoQueue().PopFront();
       // Notify the decode thread that the video queue's buffers may have
       // free'd up space for more frames.
       mDecoder->GetReentrantMonitor().NotifyAll();
       mDecoder->UpdatePlaybackOffset(frame->mOffset);
       if (mReader->VideoQueue().GetSize() == 0)
--- a/content/media/webaudio/AudioBuffer.cpp
+++ b/content/media/webaudio/AudioBuffer.cpp
@@ -133,40 +133,16 @@ AudioBuffer::GetChannelData(JSContext* a
   if (!RestoreJSChannelData(aJSContext)) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return nullptr;
   }
 
   return mJSChannels[aChannel];
 }
 
-bool
-AudioBuffer::SetChannelDataFromArrayBufferContents(JSContext* aJSContext,
-                                                   uint32_t aChannel,
-                                                   void* aContents)
-{
-  if (!RestoreJSChannelData(aJSContext)) {
-    return false;
-  }
-
-  MOZ_ASSERT(aChannel < NumberOfChannels());
-  JS::RootedObject arrayBuffer(aJSContext, JS_NewArrayBufferWithContents(aJSContext, aContents));
-  if (!arrayBuffer) {
-    return false;
-  }
-  mJSChannels[aChannel] = JS_NewFloat32ArrayWithBuffer(aJSContext, arrayBuffer,
-                                                       0, -1);
-  if (!mJSChannels[aChannel]) {
-    return false;
-  }
-  MOZ_ASSERT(mLength == JS_GetTypedArrayLength(mJSChannels[aChannel]));
-
-  return true;
-}
-
 static already_AddRefed<ThreadSharedFloatArrayBufferList>
 StealJSArrayDataIntoThreadSharedFloatArrayBufferList(JSContext* aJSContext,
                                                      const nsTArray<JSObject*>& aJSArrays)
 {
   nsRefPtr<ThreadSharedFloatArrayBufferList> result =
     new ThreadSharedFloatArrayBufferList(aJSArrays.Length());
   for (uint32_t i = 0; i < aJSArrays.Length(); ++i) {
     JS::RootedObject arrayBuffer(aJSContext, JS_GetArrayBufferViewBuffer(aJSArrays[i]));
--- a/content/media/webaudio/AudioBuffer.h
+++ b/content/media/webaudio/AudioBuffer.h
@@ -89,22 +89,16 @@ public:
     return mJSChannels[aChannel];
   }
 
   /**
    * Returns a ThreadSharedFloatArrayBufferList containing the sample data.
    */
   ThreadSharedFloatArrayBufferList* GetThreadSharedChannelsForRate(JSContext* aContext);
 
-  // aContents should either come from JS_AllocateArrayBufferContents or
-  // JS_StealArrayBufferContents.
-  bool SetChannelDataFromArrayBufferContents(JSContext* aJSContext,
-                                             uint32_t aChannel,
-                                             void* aContents);
-
   // This replaces the contents of the JS array for the given channel.
   // This function needs to be called on an AudioBuffer which has not been
   // handed off to the content yet, and right after the object has been
   // initialized.
   void SetRawChannelContents(JSContext* aJSContext,
                              uint32_t aChannel,
                              float* aContents);
 
--- a/content/media/wmf/WMFByteStream.cpp
+++ b/content/media/wmf/WMFByteStream.cpp
@@ -111,29 +111,30 @@ WMFByteStream::WMFByteStream(MediaResour
   NS_ASSERTION(mResource, "Must have a valid media resource");
   NS_ASSERTION(mSourceReaderCallback, "Must have a source reader callback.");
 
 #ifdef PR_LOGGING
   if (!gWMFByteStreamLog) {
     gWMFByteStreamLog = PR_NewLogModule("WMFByteStream");
   }
 #endif
-
+  LOG("[%p] WMFByteStream CTOR", this);
   MOZ_COUNT_CTOR(WMFByteStream);
 }
 
 WMFByteStream::~WMFByteStream()
 {
   MOZ_COUNT_DTOR(WMFByteStream);
   // The WMFByteStream can be deleted from a thread pool thread, so we
   // dispatch an event to the main thread to deref the thread pool and
   // deref the MediaResource.
   nsCOMPtr<nsIRunnable> event =
     new ReleaseWMFByteStreamResourcesEvent(mResource.forget());
   NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
+  LOG("[%p] WMFByteStream DTOR", this);
 }
 
 nsresult
 WMFByteStream::Init()
 {
   NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
 
   if (!sThreadPool) {
@@ -174,17 +175,17 @@ WMFByteStream::Init()
   if (!contentTypeUTF16.IsEmpty()) {
     HRESULT hr = wmf::MFCreateAttributes(byRef(mAttributes), 1);
     NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
 
     hr = mAttributes->SetString(MF_BYTESTREAM_CONTENT_TYPE,
                                 contentTypeUTF16.get());
     NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
 
-    LOG("WMFByteStream has Content-Type=%s", mResource->GetContentType().get());
+    LOG("[%p] WMFByteStream has Content-Type=%s", this, mResource->GetContentType().get());
   }
   return NS_OK;
 }
 
 nsresult
 WMFByteStream::Shutdown()
 {
   {
@@ -194,17 +195,17 @@ WMFByteStream::Shutdown()
   mSourceReaderCallback->Cancel();
   return NS_OK;
 }
 
 // IUnknown Methods
 STDMETHODIMP
 WMFByteStream::QueryInterface(REFIID aIId, void **aInterface)
 {
-  LOG("WMFByteStream::QueryInterface %s", GetGUIDName(aIId).get());
+  LOG("[%p] WMFByteStream::QueryInterface %s", this, GetGUIDName(aIId).get());
 
   if (aIId == IID_IMFByteStream) {
     return DoGetInterface(static_cast<IMFByteStream*>(this), aInterface);
   }
   if (aIId == IID_IUnknown) {
     return DoGetInterface(static_cast<IMFByteStream*>(this), aInterface);
   }
   if (aIId == IID_IMFAttributes) {
@@ -286,18 +287,18 @@ WMFByteStream::BeginRead(BYTE *aBuffer,
                          ULONG aLength,
                          IMFAsyncCallback *aCallback,
                          IUnknown *aCallerState)
 {
   NS_ENSURE_TRUE(aBuffer, E_POINTER);
   NS_ENSURE_TRUE(aCallback, E_POINTER);
 
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
-  LOG("WMFByteStream::BeginRead() mOffset=%lld tell=%lld length=%lu mIsShutdown=%d",
-      mOffset, mResource->Tell(), aLength, mIsShutdown);
+  LOG("[%p] WMFByteStream::BeginRead() mOffset=%lld tell=%lld length=%lu mIsShutdown=%d",
+      this, mOffset, mResource->Tell(), aLength, mIsShutdown);
 
   if (mIsShutdown || mOffset < 0) {
     return E_INVALIDARG;
   }
 
   // Create an object to store our state.
   RefPtr<ReadRequest> requestState = new ReadRequest(mOffset, aBuffer, aLength);
 
@@ -363,49 +364,49 @@ WMFByteStream::Read(ReadRequest* aReques
 void
 WMFByteStream::ProcessReadRequest(IMFAsyncResult* aResult,
                                   ReadRequest* aRequestState)
 {
   if (mResource->GetLength() > -1 &&
       aRequestState->mOffset > mResource->GetLength()) {
     aResult->SetStatus(S_OK);
     wmf::MFInvokeCallback(aResult);
-    LOG("WMFByteStream::Invoke() read offset greater than length, soft-failing read");
+    LOG("[%p] WMFByteStream::ProcessReadRequest() read offset greater than length, soft-failing read", this);
     return;
   }
 
   nsresult rv = Read(aRequestState);
   if (NS_FAILED(rv)) {
     Shutdown();
     aResult->SetStatus(E_ABORT);
   } else {
     aResult->SetStatus(S_OK);
   }
 
-  LOG("WMFByteStream::Invoke() read %d at %lld finished rv=%x",
-       aRequestState->mBytesRead, aRequestState->mOffset, rv);
+  LOG("[%p] WMFByteStream::ProcessReadRequest() read %d at %lld finished rv=%x",
+       this, aRequestState->mBytesRead, aRequestState->mOffset, rv);
 
   // Let caller know read is complete.
   DebugOnly<HRESULT> hr = wmf::MFInvokeCallback(aResult);
   NS_ASSERTION(SUCCEEDED(hr), "Failed to invoke callback!");
 }
 
 STDMETHODIMP
 WMFByteStream::BeginWrite(const BYTE *, ULONG ,
                           IMFAsyncCallback *,
                           IUnknown *)
 {
-  LOG("WMFByteStream::BeginWrite()");
+  LOG("[%p] WMFByteStream::BeginWrite()", this);
   return E_NOTIMPL;
 }
 
 STDMETHODIMP
 WMFByteStream::Close()
 {
-  LOG("WMFByteStream::Close()");
+  LOG("[%p] WMFByteStream::Close()", this);
   return S_OK;
 }
 
 uint32_t
 WMFByteStream::GetAndResetBytesConsumedCount()
 {
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   uint32_t bytesConsumed = mBytesConsumed;
@@ -428,44 +429,44 @@ WMFByteStream::EndRead(IMFAsyncResult* a
     return E_INVALIDARG;
   }
   ReadRequest* requestState =
     static_cast<ReadRequest*>(unknown.get());
 
   // Report result.
   *aBytesRead = requestState->mBytesRead;
 
-  LOG("WMFByteStream::EndRead() offset=%lld *aBytesRead=%u mOffset=%lld status=0x%x hr=0x%x eof=%d",
-      requestState->mOffset, *aBytesRead, mOffset, aResult->GetStatus(), hr, IsEOS());
+  LOG("[%p] WMFByteStream::EndRead() offset=%lld *aBytesRead=%u mOffset=%lld status=0x%x hr=0x%x eof=%d",
+      this, requestState->mOffset, *aBytesRead, mOffset, aResult->GetStatus(), hr, IsEOS());
 
   if (SUCCEEDED(aResult->GetStatus())) {
     mBytesConsumed += requestState->mBytesRead;
   }
 
   return aResult->GetStatus();
 }
 
 STDMETHODIMP
 WMFByteStream::EndWrite(IMFAsyncResult *, ULONG *)
 {
-  LOG("WMFByteStream::EndWrite()");
+  LOG("[%p] WMFByteStream::EndWrite()", this);
   return E_NOTIMPL;
 }
 
 STDMETHODIMP
 WMFByteStream::Flush()
 {
-  LOG("WMFByteStream::Flush()");
+  LOG("[%p] WMFByteStream::Flush()", this);
   return S_OK;
 }
 
 STDMETHODIMP
 WMFByteStream::GetCapabilities(DWORD *aCapabilities)
 {
-  LOG("WMFByteStream::GetCapabilities()");
+  LOG("[%p] WMFByteStream::GetCapabilities()", this);
   NS_ENSURE_TRUE(aCapabilities, E_POINTER);
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   bool seekable = mResource->IsTransportSeekable();
   bool cached = mResource->IsDataCachedToEndOfResource(0);
   *aCapabilities = MFBYTESTREAM_IS_READABLE |
                    MFBYTESTREAM_IS_SEEKABLE |
                    (!cached ? MFBYTESTREAM_IS_PARTIALLY_DOWNLOADED : 0) |
                    (!seekable ? MFBYTESTREAM_HAS_SLOW_SEEK : 0);
@@ -480,27 +481,27 @@ WMFByteStream::GetCurrentPosition(QWORD 
   // Note: Returning the length of stream as position when read
   // cursor is < 0 seems to be the behaviour expected by WMF, but
   // also note it doesn't seem to expect that the position is an
   // unsigned value since if you seek to > length and read WMF
   // expects the read to succeed after reading 0 bytes, but if you
   // seek to < 0 and read, the read is expected to fails... So
   // go figure...
   *aPosition = mOffset < 0 ? mResource->GetLength() : mOffset;
-  LOG("WMFByteStream::GetCurrentPosition() %lld", mOffset);
+  LOG("[%p] WMFByteStream::GetCurrentPosition() %lld", this, mOffset);
   return S_OK;
 }
 
 STDMETHODIMP
 WMFByteStream::GetLength(QWORD *aLength)
 {
   NS_ENSURE_TRUE(aLength, E_POINTER);
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   *aLength = mResource->GetLength();
-  LOG("WMFByteStream::GetLength() %lld", *aLength);
+  LOG("[%p] WMFByteStream::GetLength() %lld", this, *aLength);
   return S_OK;
 }
 
 bool
 WMFByteStream::IsEOS()
 {
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   return mResource->GetLength() > -1 &&
@@ -508,45 +509,45 @@ WMFByteStream::IsEOS()
           mOffset >= mResource->GetLength());
 }
 
 STDMETHODIMP
 WMFByteStream::IsEndOfStream(BOOL *aEndOfStream)
 {
   NS_ENSURE_TRUE(aEndOfStream, E_POINTER);
   *aEndOfStream = IsEOS();
-  LOG("WMFByteStream::IsEndOfStream() %d", *aEndOfStream);
+  LOG("[%p] WMFByteStream::IsEndOfStream() %d", this, *aEndOfStream);
   return S_OK;
 }
 
 STDMETHODIMP
 WMFByteStream::Read(BYTE* aBuffer, ULONG aBufferLength, ULONG* aOutBytesRead)
 {
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   ReadRequest request(mOffset, aBuffer, aBufferLength);
   if (NS_FAILED(Read(&request))) {
-    LOG("WMFByteStream::Read() offset=%lld failed!", mOffset);
+    LOG("[%p] WMFByteStream::Read() offset=%lld failed!", this, mOffset);
     return E_FAIL;
   }
   if (aOutBytesRead) {
     *aOutBytesRead = request.mBytesRead;
   }
-  LOG("WMFByteStream::Read() offset=%lld length=%u bytesRead=%u",
-      mOffset, aBufferLength, request.mBytesRead);
+  LOG("[%p] WMFByteStream::Read() offset=%lld length=%u bytesRead=%u",
+      this, mOffset, aBufferLength, request.mBytesRead);
   mOffset += request.mBytesRead;
   return S_OK;
 }
 
 STDMETHODIMP
 WMFByteStream::Seek(MFBYTESTREAM_SEEK_ORIGIN aSeekOrigin,
                     LONGLONG aSeekOffset,
                     DWORD aSeekFlags,
                     QWORD *aCurrentPosition)
 {
-  LOG("WMFByteStream::Seek(%d, %lld)", aSeekOrigin, aSeekOffset);
+  LOG("[%p] WMFByteStream::Seek(%d, %lld)", this, aSeekOrigin, aSeekOffset);
 
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
 
   int64_t offset = mOffset;
   if (aSeekOrigin == msoBegin) {
     offset = aSeekOffset;
   } else {
     offset += aSeekOffset;
@@ -563,40 +564,40 @@ WMFByteStream::Seek(MFBYTESTREAM_SEEK_OR
 
   return S_OK;
 }
 
 STDMETHODIMP
 WMFByteStream::SetCurrentPosition(QWORD aPosition)
 {
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
-  LOG("WMFByteStream::SetCurrentPosition(%lld)",
-      aPosition);
+  LOG("[%p] WMFByteStream::SetCurrentPosition(%lld)",
+      this, aPosition);
 
   int64_t length = mResource->GetLength();
   if (length > -1) {
     mOffset = std::min<int64_t>(aPosition, length);
   } else {
     mOffset = aPosition;
   }
 
   return S_OK;
 }
 
 STDMETHODIMP
 WMFByteStream::SetLength(QWORD)
 {
-  LOG("WMFByteStream::SetLength()");
+  LOG("[%p] WMFByteStream::SetLength()", this);
   return E_NOTIMPL;
 }
 
 STDMETHODIMP
 WMFByteStream::Write(const BYTE *, ULONG, ULONG *)
 {
-  LOG("WMFByteStream::Write()");
+  LOG("[%p] WMFByteStream::Write()", this);
   return E_NOTIMPL;
 }
 
 // IMFAttributes methods
 STDMETHODIMP
 WMFByteStream::GetItem(REFGUID guidKey, PROPVARIANT* pValue)
 {
     MOZ_ASSERT(mAttributes);
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -153,20 +153,58 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsIMozNavigatorAudioChannelManager)
 #endif
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Navigator)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Navigator)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Navigator)
 
-// We seem to manually break cycles through most of our members in Invalidate.
-// That said, if those members get set _after_ the window calls Invalidate on
-// us, then what?
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(Navigator, mWindow)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Navigator)
+  // mMimeTypes isn't cycle collected
+  tmp->Invalidate();
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
+  // mMimeTypes isn't cycle collected
+  // mPlugins isn't cycle collected
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGeolocation)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotification)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager)
+  // mPowerManager isn't cycle collected
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSmsManager)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileMessageManager)
+#ifdef MOZ_B2G_RIL
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTelephony)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVoicemail)
+#endif
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
+#ifdef MOZ_B2G_RIL
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileConnection)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCellBroadcast)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIccManager)
+#endif
+#ifdef MOZ_B2G_BT
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBluetooth)
+#endif
+#ifdef MOZ_AUDIO_CHANNEL_MANAGER
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioChannelManager)
+#endif
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCameraManager)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessagesManager)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDeviceStorageStores)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTimeManager)
+
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(Navigator)
 
 void
 Navigator::Invalidate()
 {
   // Don't clear mWindow here so we know we've got a non-null mWindow
   // until we're unlinked.
 
   if (mPlugins) {
new file mode 100644
--- /dev/null
+++ b/dom/base/crashtests/886213.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<script>
+
+function boom()
+{
+    // This shouldn't leak
+    var frame = document.getElementById("f");
+    var frameWin = frame.contentWindow;
+    document.body.removeChild(frame);
+    frameWin.navigator;
+}
+
+</script>
+</head>
+
+<body onload="boom();">
+<iframe id="f" src="data:text/html;charset=utf-8,1"></iframe>
+</body>
+</html>
--- a/dom/base/crashtests/crashtests.list
+++ b/dom/base/crashtests/crashtests.list
@@ -35,8 +35,9 @@ load 693811-1.html
 load 693811-2.html
 load 693811-3.html
 load 695867.html
 load 697643.html
 load 706283-1.html
 load 708405-1.html
 load 745495.html
 load 844559.html
+load 886213.html
\ No newline at end of file
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1639,16 +1639,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
     return NS_SUCCESS_INTERRUPTED_TRAVERSE;
   }
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArguments)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDialogArguments)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance)
 
 #ifdef MOZ_WEBSPEECH
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSpeechSynthesis)
 #endif
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInnerWindowHolder)
@@ -1693,16 +1694,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
   nsGlobalWindow::CleanupCachedXBLHandlers(tmp);
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mArguments)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDialogArguments)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance)
 
 #ifdef MOZ_WEBSPEECH
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSpeechSynthesis)
 #endif
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mInnerWindowHolder)
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -10,16 +10,17 @@
 #include "mozilla/Util.h"
 
 #include "ion/PerfSpewer.h"
 #include "ion/CodeGenerator.h"
 #include "ion/IonLinker.h"
 #include "ion/IonSpewer.h"
 #include "ion/MIRGenerator.h"
 #include "ion/shared/CodeGenerator-shared-inl.h"
+#include "ion/MoveEmitter.h"
 #include "jsnum.h"
 #include "jsmath.h"
 #include "ion/ParallelFunctions.h"
 #include "ion/ExecutionModeInlines.h"
 #include "builtin/Eval.h"
 #include "gc/Nursery.h"
 #include "vm/ForkJoin.h"
 #include "ion/ParallelSafetyAnalysis.h"
@@ -943,16 +944,53 @@ CodeGenerator::visitStackArgV(LStackArgV
     uint32_t argslot = lir->argslot();
     int32_t stack_offset = StackOffsetOfPassedArg(argslot);
 
     masm.storeValue(val, Address(StackPointer, stack_offset));
     return pushedArgumentSlots_.append(StackOffsetToSlot(stack_offset));
 }
 
 bool
+CodeGenerator::visitMoveGroup(LMoveGroup *group)
+{
+    if (!group->numMoves())
+        return true;
+
+    MoveResolver &resolver = masm.moveResolver();
+
+    for (size_t i = 0; i < group->numMoves(); i++) {
+        const LMove &move = group->getMove(i);
+
+        const LAllocation *from = move.from();
+        const LAllocation *to = move.to();
+
+        // No bogus moves.
+        JS_ASSERT(*from != *to);
+        JS_ASSERT(!from->isConstant());
+        JS_ASSERT(from->isDouble() == to->isDouble());
+
+        MoveResolver::Move::Kind kind = from->isDouble()
+                                        ? MoveResolver::Move::DOUBLE
+                                        : MoveResolver::Move::GENERAL;
+
+        if (!resolver.addMove(toMoveOperand(from), toMoveOperand(to), kind))
+            return false;
+    }
+
+    if (!resolver.resolve())
+        return false;
+
+    MoveEmitter emitter(masm);
+    emitter.emit(resolver);
+    emitter.finish();
+
+    return true;
+}
+
+bool
 CodeGenerator::visitInteger(LInteger *lir)
 {
     masm.move32(Imm32(lir->getValue()), ToRegister(lir->output()));
     return true;
 }
 
 bool
 CodeGenerator::visitPointer(LPointer *lir)
--- a/js/src/ion/CodeGenerator.h
+++ b/js/src/ion/CodeGenerator.h
@@ -60,16 +60,17 @@ class CodeGenerator : public CodeGenerat
     bool visitStart(LStart *lir);
     bool visitReturn(LReturn *ret);
     bool visitDefVar(LDefVar *lir);
     bool visitDefFun(LDefFun *lir);
     bool visitOsrEntry(LOsrEntry *lir);
     bool visitOsrScopeChain(LOsrScopeChain *lir);
     bool visitStackArgT(LStackArgT *lir);
     bool visitStackArgV(LStackArgV *lir);
+    bool visitMoveGroup(LMoveGroup *group);
     bool visitValueToInt32(LValueToInt32 *lir);
     bool visitValueToDouble(LValueToDouble *lir);
     bool visitInt32ToDouble(LInt32ToDouble *lir);
     void emitOOLTestObject(Register objreg, Label *ifTruthy, Label *ifFalsy, Register scratch);
     bool visitTestOAndBranch(LTestOAndBranch *lir);
     bool visitTestVAndBranch(LTestVAndBranch *lir);
     bool visitFunctionDispatch(LFunctionDispatch *lir);
     bool visitTypeObjectDispatch(LTypeObjectDispatch *lir);
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -3717,30 +3717,30 @@ IonBuilder::getInlineableGetPropertyCach
 
     MDefinition *funcDef = callInfo.fun();
     if (funcDef->type() != MIRType_Object)
         return NULL;
 
     // MGetPropertyCache with no uses may be optimized away.
     if (funcDef->isGetPropertyCache()) {
         MGetPropertyCache *cache = funcDef->toGetPropertyCache();
-        if (cache->useCount() > 0)
+        if (cache->hasUses())
             return NULL;
         if (!CanInlineGetPropertyCache(cache, thisDef))
             return NULL;
         return cache;
     }
 
     // Optimize away the following common pattern:
     // MUnbox[MIRType_Object, Infallible] <- MTypeBarrier <- MGetPropertyCache
     if (funcDef->isUnbox()) {
         MUnbox *unbox = funcDef->toUnbox();
         if (unbox->mode() != MUnbox::Infallible)
             return NULL;
-        if (unbox->useCount() > 0)
+        if (unbox->hasUses())
             return NULL;
         if (!unbox->input()->isTypeBarrier())
             return NULL;
 
         MTypeBarrier *barrier = unbox->input()->toTypeBarrier();
         if (barrier->useCount() != 1)
             return NULL;
         if (!barrier->input()->isGetPropertyCache())
@@ -3973,17 +3973,17 @@ IonBuilder::inlineTypeObjectFallback(Cal
     //    followed by an MTypeBarrier, followed by an MUnbox.
     JS_ASSERT(callInfo.fun()->isGetPropertyCache() || callInfo.fun()->isUnbox());
 
     // 2. The MGetPropertyCache has inlineable cases by guarding on the TypeObject.
     JS_ASSERT(dispatch->numCases() > 0);
 
     // 3. The MGetPropertyCache (and, if applicable, MTypeBarrier and MUnbox) only
     //    have at most a single use.
-    JS_ASSERT_IF(callInfo.fun()->isGetPropertyCache(), cache->useCount() == 0);
+    JS_ASSERT_IF(callInfo.fun()->isGetPropertyCache(), !cache->hasUses());
     JS_ASSERT_IF(callInfo.fun()->isUnbox(), cache->useCount() == 1);
 
     // This means that no resume points yet capture the MGetPropertyCache,
     // so everything from the MGetPropertyCache up until the call is movable.
     // We now move the MGetPropertyCache and friends into a fallback path.
 
     // Create a new CallInfo to track modified state within the fallback path.
     CallInfo fallbackInfo(cx, callInfo.constructing());
--- a/js/src/ion/MIR.h
+++ b/js/src/ion/MIR.h
@@ -4887,16 +4887,17 @@ class MArrayConcat
 {
     CompilerRootObject templateObj_;
 
     MArrayConcat(MDefinition *lhs, MDefinition *rhs, HandleObject templateObj)
       : MBinaryInstruction(lhs, rhs),
         templateObj_(templateObj)
     {
         setResultType(MIRType_Object);
+        setResultTypeSet(MakeSingletonTypeSet(templateObj));
     }
 
   public:
     INSTRUCTION_HEADER(ArrayConcat)
 
     static MArrayConcat *New(MDefinition *lhs, MDefinition *rhs, HandleObject templateObj) {
         return new MArrayConcat(lhs, rhs, templateObj);
     }
--- a/js/src/ion/MIRGraph.cpp
+++ b/js/src/ion/MIRGraph.cpp
@@ -594,17 +594,17 @@ MBasicBlock::moveBefore(MInstruction *at
 }
 
 static inline void
 AssertSafelyDiscardable(MDefinition *def)
 {
 #ifdef DEBUG
     // Instructions captured by resume points cannot be safely discarded, since
     // they are necessary for interpreter frame reconstruction in case of bailout.
-    JS_ASSERT(def->useCount() == 0);
+    JS_ASSERT(!def->hasUses());
 #endif
 }
 
 void
 MBasicBlock::discard(MInstruction *ins)
 {
     AssertSafelyDiscardable(ins);
     for (size_t i = 0; i < ins->numOperands(); i++)
--- a/js/src/ion/PerfSpewer.cpp
+++ b/js/src/ion/PerfSpewer.cpp
@@ -37,17 +37,17 @@ js::ion::CheckPerf() {
             PerfMode = PERF_MODE_NONE;
         } else if (!strcmp(env, "none")) {
             PerfMode = PERF_MODE_NONE;
         } else if (!strcmp(env, "block")) {
             PerfMode = PERF_MODE_BLOCK;
         } else if (!strcmp(env, "func")) {
             PerfMode = PERF_MODE_FUNC;
         } else {
-            fprintf(stderr, "Use IONPERF=func to record at basic block granularity\n");
+            fprintf(stderr, "Use IONPERF=func to record at function granularity\n");
             fprintf(stderr, "Use IONPERF=block to record at basic block granularity\n");
             fprintf(stderr, "\n");
             fprintf(stderr, "Be advised that using IONPERF will cause all scripts\n");
             fprintf(stderr, "to be leaked.\n");
             exit(0);
         }
         PerfChecked = true;
     }
--- a/js/src/ion/PerfSpewer.h
+++ b/js/src/ion/PerfSpewer.h
@@ -58,18 +58,16 @@ class PerfSpewer
 
     FILE *fp_;
     Vector<Record, 1, SystemAllocPolicy> basicBlocks_;
 
   public:
     PerfSpewer();
     ~PerfSpewer();
 
-    bool init(const char *path);
-
     bool startBasicBlock(MBasicBlock *blk, MacroAssembler &masm);
     bool endBasicBlock(MacroAssembler &masm);
     void writeProfile(JSScript *script,
                       IonCode *code,
                       MacroAssembler &masm);
 };
 
 } // namespace ion
--- a/js/src/ion/RangeAnalysis.cpp
+++ b/js/src/ion/RangeAnalysis.cpp
@@ -344,22 +344,31 @@ Range::intersect(const Range *lhs, const
     }
 
     return r;
 }
 
 void
 Range::unionWith(const Range *other)
 {
-   lower_infinite_ |= other->lower_infinite_;
-   upper_infinite_ |= other->upper_infinite_;
-   decimal_ |= other->decimal_;
-   max_exponent_ = Max(max_exponent_, other->max_exponent_);
-   setLower(Min(lower_, other->lower_));
-   setUpper(Max(upper_, other->upper_));
+   bool decimal = decimal_ | other->decimal_;
+   uint16_t max_exponent = Max(max_exponent_, other->max_exponent_);
+
+   if (lower_infinite_ || other->lower_infinite_)
+       makeLowerInfinite();
+   else
+       setLower(Min(lower_, other->lower_));
+
+   if (upper_infinite_ || other->upper_infinite_)
+       makeUpperInfinite();
+   else
+       setUpper(Max(upper_, other->upper_));
+
+   decimal_ = decimal;
+   max_exponent_ = max_exponent;
 }
 
 static const Range emptyRange;
 
 Range::Range(const MDefinition *def)
   : symbolicLower_(NULL),
     symbolicUpper_(NULL)
 {
--- a/js/src/ion/ValueNumbering.cpp
+++ b/js/src/ion/ValueNumbering.cpp
@@ -84,17 +84,17 @@ ValueNumberer::simplifyControlInstructio
     // Ensure this instruction has a value number.
     if (!repl->valueNumberData())
         repl->setValueNumberData(new ValueNumberData);
 
     MBasicBlock *block = def->block();
 
     // MControlInstructions should not have consumers.
     JS_ASSERT(repl->isControlInstruction());
-    JS_ASSERT(def->useCount() == 0);
+    JS_ASSERT(!def->hasUses());
 
     if (def->isInWorklist())
         repl->setInWorklist();
 
     block->discardLastIns();
     block->end((MControlInstruction *)repl);
     return (MControlInstruction *)repl;
 }
--- a/js/src/ion/arm/Architecture-arm.cpp
+++ b/js/src/ion/arm/Architecture-arm.cpp
@@ -119,11 +119,16 @@ bool has32DP()
 {
     return !(js::ion::getFlags() & HWCAP_VFPv3D16 && !(js::ion::getFlags() & HWCAP_NEON));
 }
 bool useConvReg()
 {
     return has32DP();
 }
 
+bool hasIDIV()
+{
+    return js::ion::getFlags() & HWCAP_IDIVA;
+}
+
 } // namespace ion
 } // namespace js
 
--- a/js/src/ion/arm/Architecture-arm.h
+++ b/js/src/ion/arm/Architecture-arm.h
@@ -206,13 +206,14 @@ class FloatRegisters
 
     static const uint32_t AllocatableMask = AllMask & ~NonAllocatableMask;
 };
 
 bool hasMOVWT();
 bool hasVFPv3();
 bool hasVFP();
 bool has16DP();
+bool hasIDIV();
 
 } // namespace ion
 } // namespace js
 
 #endif /* ion_arm_Architecture_arm_h */
--- a/js/src/ion/arm/Assembler-arm.cpp
+++ b/js/src/ion/arm/Assembler-arm.cpp
@@ -1540,16 +1540,28 @@ Assembler::as_smull(Register destHI, Reg
 
 BufferOffset
 Assembler::as_smlal(Register destHI, Register destLO, Register src1, Register src2,
                     SetCond_ sc, Condition c)
 {
     return as_genmul(destHI, destLO, src1, src2, opm_smlal, sc, c);
 }
 
+BufferOffset
+Assembler::as_sdiv(Register rd, Register rn, Register rm, Condition c)
+{
+    return writeInst(0x0710f010 | c | RN(rd) | RM(rm) | rn.code());
+}
+
+BufferOffset
+Assembler::as_udiv(Register rd, Register rn, Register rm, Condition c)
+{
+    return writeInst(0x0730f010 | c | RN(rd) | RM(rm) | rn.code());
+}
+
 // Data transfer instructions: ldr, str, ldrb, strb.
 // Using an int to differentiate between 8 bits and 32 bits is
 // overkill, but meh
 BufferOffset
 Assembler::as_dtr(LoadStore ls, int size, Index mode,
                   Register rt, DTRAddr addr, Condition c, uint32_t *dest)
 {
     JS_ASSERT (mode == Offset ||  (rt != addr.getBase() && pc != addr.getBase()));
--- a/js/src/ion/arm/Assembler-arm.h
+++ b/js/src/ion/arm/Assembler-arm.h
@@ -1457,16 +1457,20 @@ class Assembler
     BufferOffset as_umull(Register dest1, Register dest2, Register src1, Register src2,
                 SetCond_ sc = NoSetCond, Condition c = Always);
     BufferOffset as_umlal(Register dest1, Register dest2, Register src1, Register src2,
                 SetCond_ sc = NoSetCond, Condition c = Always);
     BufferOffset as_smull(Register dest1, Register dest2, Register src1, Register src2,
                 SetCond_ sc = NoSetCond, Condition c = Always);
     BufferOffset as_smlal(Register dest1, Register dest2, Register src1, Register src2,
                 SetCond_ sc = NoSetCond, Condition c = Always);
+
+    BufferOffset as_sdiv(Register dest, Register num, Register div, Condition c = Always);
+    BufferOffset as_udiv(Register dest, Register num, Register div, Condition c = Always);
+
     // Data transfer instructions: ldr, str, ldrb, strb.
     // Using an int to differentiate between 8 bits and 32 bits is
     // overkill, but meh
     BufferOffset as_dtr(LoadStore ls, int size, Index mode,
                 Register rt, DTRAddr addr, Condition c = Always, uint32_t *dest = NULL);
     // Handles all of the other integral data transferring functions:
     // ldrsb, ldrsh, ldrd, etc.
     // size is given in bits.
--- a/js/src/ion/arm/CodeGenerator-arm.cpp
+++ b/js/src/ion/arm/CodeGenerator-arm.cpp
@@ -11,17 +11,16 @@
 
 #include "ion/arm/CodeGenerator-arm.h"
 #include "ion/PerfSpewer.h"
 #include "ion/CodeGenerator.h"
 #include "ion/IonCompartment.h"
 #include "ion/IonFrames.h"
 #include "ion/MIR.h"
 #include "ion/MIRGraph.h"
-#include "ion/MoveEmitter.h"
 #include "ion/shared/CodeGenerator-shared-inl.h"
 #include "vm/Shape.h"
 
 #include "jsscriptinlines.h"
 
 #include "vm/Shape-inl.h"
 
 using namespace js;
@@ -486,46 +485,35 @@ CodeGeneratorARM::visitMulI(LMulI *ins)
 
             masm.bind(&done);
         }
     }
 
     return true;
 }
 
-extern "C" {
-    extern int __aeabi_idivmod(int,int);
-    extern int __aeabi_uidivmod(int,int);
-}
-
 bool
-CodeGeneratorARM::visitDivI(LDivI *ins)
+CodeGeneratorARM::divICommon(MDiv *mir, Register lhs, Register rhs, Register output,
+                             LSnapshot *snapshot, Label &done)
 {
-    // Extract the registers from this instruction
-    Register lhs = ToRegister(ins->lhs());
-    Register rhs = ToRegister(ins->rhs());
-    MDiv *mir = ins->mir();
-
-    Label done;
-
     if (mir->canBeNegativeOverflow()) {
         // Handle INT32_MIN / -1;
         // The integer division will give INT32_MIN, but we want -(double)INT32_MIN.
         masm.ma_cmp(lhs, Imm32(INT32_MIN)); // sets EQ if lhs == INT32_MIN
         masm.ma_cmp(rhs, Imm32(-1), Assembler::Equal); // if EQ (LHS == INT32_MIN), sets EQ if rhs == -1
         if (mir->isTruncated()) {
             // (-INT32_MIN)|0 = INT32_MIN
             Label skip;
             masm.ma_b(&skip, Assembler::NotEqual);
-            masm.ma_mov(Imm32(INT32_MIN), r0);
+            masm.ma_mov(Imm32(INT32_MIN), output);
             masm.ma_b(&done);
             masm.bind(&skip);
         } else {
             JS_ASSERT(mir->fallible());
-            if (!bailoutIf(Assembler::Equal, ins->snapshot()))
+            if (!bailoutIf(Assembler::Equal, snapshot))
                 return false;
         }
     }
 
     // 0/X (with X < 0) is bad because both of these values *should* be doubles, and
     // the result should be -0.0, which cannot be represented in integers.
     // X/0 is bad because it will give garbage (or abort), when it should give
     // either \infty, -\infty or NAN.
@@ -540,25 +528,77 @@ CodeGeneratorARM::visitDivI(LDivI *ins)
     // if (Y > 0), we don't set EQ, and we don't trigger LT, so we don't take the bailout.
     if (mir->canBeDivideByZero() || mir->canBeNegativeZero()) {
         masm.ma_cmp(rhs, Imm32(0));
         masm.ma_cmp(lhs, Imm32(0), Assembler::LessThan);
         if (mir->isTruncated()) {
             // Infinity|0 == 0 and -0|0 == 0
             Label skip;
             masm.ma_b(&skip, Assembler::NotEqual);
-            masm.ma_mov(Imm32(0), r0);
+            masm.ma_mov(Imm32(0), output);
             masm.ma_b(&done);
             masm.bind(&skip);
         } else {
             JS_ASSERT(mir->fallible());
-            if (!bailoutIf(Assembler::Equal, ins->snapshot()))
+            if (!bailoutIf(Assembler::Equal, snapshot))
                 return false;
         }
     }
+
+    return true;
+}
+
+bool
+CodeGeneratorARM::visitDivI(LDivI *ins)
+{
+    // Extract the registers from this instruction
+    Register lhs = ToRegister(ins->lhs());
+    Register rhs = ToRegister(ins->rhs());
+    Register temp = ToRegister(ins->getTemp(0));
+    Register output = ToRegister(ins->output());
+    MDiv *mir = ins->mir();
+
+    Label done;
+    if (!divICommon(mir, lhs, rhs, output, ins->snapshot(), done))
+        return false;
+
+    if (mir->isTruncated()) {
+        masm.ma_sdiv(lhs, rhs, output);
+    } else {
+        masm.ma_sdiv(lhs, rhs, ScratchRegister);
+        masm.ma_mul(ScratchRegister, rhs, temp);
+        masm.ma_cmp(lhs, temp);
+        if (!bailoutIf(Assembler::NotEqual, ins->snapshot()))
+            return false;
+        masm.ma_mov(ScratchRegister, output);
+    }
+
+    masm.bind(&done);
+
+    return true;
+}
+
+extern "C" {
+    extern int __aeabi_idivmod(int,int);
+    extern int __aeabi_uidivmod(int,int);
+}
+
+bool
+CodeGeneratorARM::visitSoftDivI(LSoftDivI *ins)
+{
+    // Extract the registers from this instruction
+    Register lhs = ToRegister(ins->lhs());
+    Register rhs = ToRegister(ins->rhs());
+    Register output = ToRegister(ins->output());
+    MDiv *mir = ins->mir();
+
+    Label done;
+    if (!divICommon(mir, lhs, rhs, output, ins->snapshot(), done))
+        return false;
+
     masm.setupAlignedABICall(2);
     masm.passABIArg(lhs);
     masm.passABIArg(rhs);
     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, __aeabi_idivmod));
     // idivmod returns the quotient in r0, and the remainder in r1.
     if (!mir->isTruncated()) {
         JS_ASSERT(mir->fallible());
         masm.ma_cmp(r1, Imm32(0));
@@ -899,53 +939,16 @@ CodeGeneratorARM::toMoveOperand(const LA
     // The way the stack slots work, we assume that everything from depth == 0 downwards is writable
     // however, since our frame is included in this, ensure that the frame gets skipped
     if (gen->compilingAsmJS())
         offset -= AlignmentMidPrologue;
 
     return MoveOperand(StackPointer, offset);
 }
 
-bool
-CodeGeneratorARM::visitMoveGroup(LMoveGroup *group)
-{
-    if (!group->numMoves())
-        return true;
-
-    MoveResolver &resolver = masm.moveResolver();
-
-    for (size_t i = 0; i < group->numMoves(); i++) {
-        const LMove &move = group->getMove(i);
-
-        const LAllocation *from = move.from();
-        const LAllocation *to = move.to();
-
-        // No bogus moves.
-        JS_ASSERT(*from != *to);
-        JS_ASSERT(!from->isConstant());
-        JS_ASSERT(from->isDouble() == to->isDouble());
-
-        MoveResolver::Move::Kind kind = from->isDouble()
-                                        ? MoveResolver::Move::DOUBLE
-                                        : MoveResolver::Move::GENERAL;
-
-        if (!resolver.addMove(toMoveOperand(from), toMoveOperand(to), kind))
-            return false;
-    }
-
-    if (!resolver.resolve())
-        return false;
-
-    MoveEmitter emitter(masm);
-    emitter.emit(resolver);
-    emitter.finish();
-
-    return true;
-}
-
 class js::ion::OutOfLineTableSwitch : public OutOfLineCodeBase<CodeGeneratorARM>
 {
     MTableSwitch *mir_;
     Vector<CodeLabel, 8, IonAllocPolicy> codeLabels_;
 
     bool accept(CodeGeneratorARM *codegen) {
         return codegen->visitOutOfLineTableSwitch(this);
     }
--- a/js/src/ion/arm/CodeGenerator-arm.h
+++ b/js/src/ion/arm/CodeGenerator-arm.h
@@ -70,22 +70,22 @@ class CodeGeneratorARM : public CodeGene
     virtual bool visitAddI(LAddI *ins);
     virtual bool visitSubI(LSubI *ins);
     virtual bool visitBitNotI(LBitNotI *ins);
     virtual bool visitBitOpI(LBitOpI *ins);
 
     virtual bool visitMulI(LMulI *ins);
 
     virtual bool visitDivI(LDivI *ins);
+    virtual bool visitSoftDivI(LSoftDivI *ins);
     virtual bool visitDivPowTwoI(LDivPowTwoI *ins);
     virtual bool visitModI(LModI *ins);
     virtual bool visitModPowTwoI(LModPowTwoI *ins);
     virtual bool visitModMaskI(LModMaskI *ins);
     virtual bool visitPowHalfD(LPowHalfD *ins);
-    virtual bool visitMoveGroup(LMoveGroup *group);
     virtual bool visitShiftI(LShiftI *ins);
     virtual bool visitUrshD(LUrshD *ins);
 
     virtual bool visitTestIAndBranch(LTestIAndBranch *test);
     virtual bool visitCompare(LCompare *comp);
     virtual bool visitCompareAndBranch(LCompareAndBranch *comp);
     virtual bool visitTestDAndBranch(LTestDAndBranch *test);
     virtual bool visitCompareD(LCompareD *comp);
@@ -113,16 +113,19 @@ class CodeGeneratorARM : public CodeGene
     ValueOperand ToTempValue(LInstruction *ins, size_t pos);
 
     // Functions for LTestVAndBranch.
     Register splitTagForTest(const ValueOperand &value);
 
     void storeElementTyped(const LAllocation *value, MIRType valueType, MIRType elementType,
                            const Register &elements, const LAllocation *index);
 
+    bool divICommon(MDiv *mir, Register lhs, Register rhs, Register output, LSnapshot *snapshot,
+                    Label &done);
+
   public:
     CodeGeneratorARM(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm);
 
   public:
     bool visitBox(LBox *box);
     bool visitBoxDouble(LBoxDouble *box);
     bool visitUnbox(LUnbox *unbox);
     bool visitValue(LValue *value);
--- a/js/src/ion/arm/LIR-arm.h
+++ b/js/src/ion/arm/LIR-arm.h
@@ -73,32 +73,51 @@ class LUInt32ToDouble : public LInstruct
   public:
     LIR_HEADER(UInt32ToDouble)
 
     LUInt32ToDouble(const LAllocation &input) {
         setOperand(0, input);
     }
 };
 
-// LDivI is presently implemented as a proper C function,
-// so it trashes r0, r1, r2 and r3.  The call also trashes lr, and has the
-// ability to trash ip. The function also takes two arguments (dividend in r0,
-// divisor in r1). The LInstruction gets encoded such that the divisor and
-// dividend are passed in their apropriate registers, and are marked as copy
-// so we can modify them (and the function will).
-// The other thre registers that can be trashed are marked as such. For the time
-// being, the link register is not marked as trashed because we never allocate
-// to the link register.
-class LDivI : public LBinaryMath<2>
+class LDivI : public LBinaryMath<1>
 {
   public:
     LIR_HEADER(DivI);
 
     LDivI(const LAllocation &lhs, const LAllocation &rhs,
-          const LDefinition &temp1, const LDefinition &temp2) {
+          const LDefinition &temp) {
+        setOperand(0, lhs);
+        setOperand(1, rhs);
+        setTemp(0, temp);
+    }
+
+    MDiv *mir() const {
+        return mir_->toDiv();
+    }
+};
+
+// LSoftDivI is a software divide for ARM cores that don't support a hardware
+// divide instruction.
+//
+// It is implemented as a proper C function so it trashes r0, r1, r2 and r3.  The
+// call also trashes lr, and has the ability to trash ip. The function also
+// takes two arguments (dividend in r0, divisor in r1). The LInstruction gets
+// encoded such that the divisor and dividend are passed in their apropriate
+// registers, and are marked as copy so we can modify them (and the function
+// will).  The other thre registers that can be trashed are marked as such. For
+// the time being, the link register is not marked as trashed because we never
+// allocate to the link register.
+class LSoftDivI : public LBinaryMath<2>
+{
+  public:
+    LIR_HEADER(SoftDivI);
+
+    LSoftDivI(const LAllocation &lhs, const LAllocation &rhs,
+              const LDefinition &temp1, const LDefinition &temp2) {
         setOperand(0, lhs);
         setOperand(1, rhs);
         setTemp(0, temp1);
         setTemp(1, temp2);
     }
 
     MDiv *mir() const {
         return mir_->toDiv();
--- a/js/src/ion/arm/LOpcodes-arm.h
+++ b/js/src/ion/arm/LOpcodes-arm.h
@@ -8,16 +8,17 @@
 #define ion_arm_LOpcodes_arm_h
 
 #define LIR_CPU_OPCODE_LIST(_)  \
     _(Unbox)                    \
     _(UnboxDouble)              \
     _(Box)                      \
     _(BoxDouble)                \
     _(DivI)                     \
+    _(SoftDivI)                 \
     _(DivPowTwoI)               \
     _(ModI)                     \
     _(ModPowTwoI)               \
     _(ModMaskI)                 \
     _(PowHalfD)                 \
     _(UInt32ToDouble)           \
     _(AsmJSDivOrMod)            \
     _(AsmJSLoadFuncPtr)
--- a/js/src/ion/arm/Lowering-arm.cpp
+++ b/js/src/ion/arm/Lowering-arm.cpp
@@ -242,21 +242,28 @@ LIRGeneratorARM::lowerDivI(MDiv *div)
         if (rhs > 0 && 1 << shift == rhs) {
             LDivPowTwoI *lir = new LDivPowTwoI(useRegisterAtStart(div->lhs()), shift);
             if (div->fallible() && !assignSnapshot(lir))
                 return false;
             return define(lir, div);
         }
     }
 
-    LDivI *lir = new LDivI(useFixed(div->lhs(), r0), use(div->rhs(), r1),
-                           tempFixed(r2), tempFixed(r3));
-    if (div->fallible() && !assignSnapshot(lir))
-        return false;
-    return defineFixed(lir, div, LAllocation(AnyRegister(r0)));
+    if (hasIDIV()) {
+        LDivI *lir = new LDivI(useRegister(div->lhs()), useRegister(div->rhs()), temp());
+        if (div->fallible() && !assignSnapshot(lir))
+            return false;
+        return define(lir, div);
+    } else {
+        LSoftDivI *lir = new LSoftDivI(useFixed(div->lhs(), r0), use(div->rhs(), r1),
+                                       tempFixed(r2), tempFixed(r3));
+        if (div->fallible() && !assignSnapshot(lir))
+            return false;
+        return defineFixed(lir, div, LAllocation(AnyRegister(r0)));
+    }
 }
 
 bool
 LIRGeneratorARM::lowerMulI(MMul *mul, MDefinition *lhs, MDefinition *rhs)
 {
     LMulI *lir = new LMulI;
     if (mul->fallible() && !assignSnapshot(lir))
         return false;
--- a/js/src/ion/arm/MacroAssembler-arm.cpp
+++ b/js/src/ion/arm/MacroAssembler-arm.cpp
@@ -881,16 +881,23 @@ MacroAssemblerARM::ma_mod_mask(Register 
     // If the hold was non-zero, negate the result to be in line with what JS wants
     // this will set the condition codes if we try to negate
     ma_rsb(Imm32(0), dest, SetCond, Signed);
     // Since the Zero flag is not set by the compare, we can *only* set the Zero flag
     // in the rsb, so Zero is set iff we negated zero (e.g. the result of the computation was -0.0).
 
 }
 
+// division
+void
+MacroAssemblerARM::ma_sdiv(Register num, Register div, Register dest, Condition cond)
+{
+    as_sdiv(dest, num, div, cond);
+}
+
 // Memory.
 // Shortcut for when we know we're transferring 32 bits of data.
 void
 MacroAssemblerARM::ma_dtr(LoadStore ls, Register rn, Imm32 offset, Register rt,
                           Index mode, Assembler::Condition cc)
 {
     ma_dataTransferN(ls, 32, true, rn, offset, rt, mode, cc);
 }
--- a/js/src/ion/arm/MacroAssembler-arm.h
+++ b/js/src/ion/arm/MacroAssembler-arm.h
@@ -233,16 +233,19 @@ class MacroAssemblerARM : public Assembl
     void ma_mul(Register src1, Imm32 imm, Register dest);
     Condition ma_check_mul(Register src1, Register src2, Register dest, Condition cond);
     Condition ma_check_mul(Register src1, Imm32 imm, Register dest, Condition cond);
 
     // fast mod, uses scratch registers, and thus needs to be in the assembler
     // implicitly assumes that we can overwrite dest at the beginning of the sequence
     void ma_mod_mask(Register src, Register dest, Register hold, int32_t shift);
 
+    // division
+    void ma_sdiv(Register num, Register div, Register dest, Condition cond = Always);
+
     // memory
     // shortcut for when we know we're transferring 32 bits of data
     void ma_dtr(LoadStore ls, Register rn, Imm32 offset, Register rt,
                 Index mode = Offset, Condition cc = Always);
 
     void ma_dtr(LoadStore ls, Register rn, Register rm, Register rt,
                 Index mode = Offset, Condition cc = Always);
 
--- a/js/src/ion/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/ion/shared/CodeGenerator-x86-shared.cpp
@@ -7,17 +7,16 @@
 #include "mozilla/DebugOnly.h"
 
 #include "jscntxt.h"
 #include "jscompartment.h"
 #include "jsmath.h"
 #include "ion/shared/CodeGenerator-x86-shared.h"
 #include "ion/shared/CodeGenerator-shared-inl.h"
 #include "ion/IonFrames.h"
-#include "ion/MoveEmitter.h"
 #include "ion/IonCompartment.h"
 #include "ion/ParallelFunctions.h"
 
 using namespace js;
 using namespace js::ion;
 
 namespace js {
 namespace ion {
@@ -1030,53 +1029,16 @@ CodeGeneratorX86Shared::toMoveOperand(co
 {
     if (a->isGeneralReg())
         return MoveOperand(ToRegister(a));
     if (a->isFloatReg())
         return MoveOperand(ToFloatRegister(a));
     return MoveOperand(StackPointer, ToStackOffset(a));
 }
 
-bool
-CodeGeneratorX86Shared::visitMoveGroup(LMoveGroup *group)
-{
-    if (!group->numMoves())
-        return true;
-
-    MoveResolver &resolver = masm.moveResolver();
-
-    for (size_t i = 0; i < group->numMoves(); i++) {
-        const LMove &move = group->getMove(i);
-
-        const LAllocation *from = move.from();
-        const LAllocation *to = move.to();
-
-        // No bogus moves.
-        JS_ASSERT(*from != *to);
-        JS_ASSERT(!from->isConstant());
-        JS_ASSERT(from->isDouble() == to->isDouble());
-
-        MoveResolver::Move::Kind kind = from->isDouble()
-                                        ? MoveResolver::Move::DOUBLE
-                                        : MoveResolver::Move::GENERAL;
-
-        if (!resolver.addMove(toMoveOperand(from), toMoveOperand(to), kind))
-            return false;
-    }
-
-    if (!resolver.resolve())
-        return false;
-
-    MoveEmitter emitter(masm);
-    emitter.emit(resolver);
-    emitter.finish();
-
-    return true;
-}
-
 class OutOfLineTableSwitch : public OutOfLineCodeBase<CodeGeneratorX86Shared>
 {
     MTableSwitch *mir_;
     CodeLabel jumpLabel_;
 
     bool accept(CodeGeneratorX86Shared *codegen) {
         return codegen->visitOutOfLineTableSwitch(this);
     }
--- a/js/src/ion/shared/CodeGenerator-x86-shared.h
+++ b/js/src/ion/shared/CodeGenerator-x86-shared.h
@@ -86,17 +86,16 @@ class CodeGeneratorX86Shared : public Co
     virtual bool visitDivI(LDivI *ins);
     virtual bool visitDivPowTwoI(LDivPowTwoI *ins);
     virtual bool visitModI(LModI *ins);
     virtual bool visitModPowTwoI(LModPowTwoI *ins);
     virtual bool visitBitNotI(LBitNotI *ins);
     virtual bool visitBitOpI(LBitOpI *ins);
     virtual bool visitShiftI(LShiftI *ins);
     virtual bool visitUrshD(LUrshD *ins);
-    virtual bool visitMoveGroup(LMoveGroup *group);
     virtual bool visitTestIAndBranch(LTestIAndBranch *test);
     virtual bool visitTestDAndBranch(LTestDAndBranch *test);
     virtual bool visitCompare(LCompare *comp);
     virtual bool visitCompareAndBranch(LCompareAndBranch *comp);
     virtual bool visitCompareD(LCompareD *comp);
     virtual bool visitCompareDAndBranch(LCompareDAndBranch *comp);
     virtual bool visitNotI(LNotI *comp);
     virtual bool visitNotD(LNotD *comp);
--- a/js/src/ion/x64/Trampoline-x64.cpp
+++ b/js/src/ion/x64/Trampoline-x64.cpp
@@ -15,16 +15,22 @@
 #include "ion/x64/BaselineHelpers-x64.h"
 #include "ion/ExecutionModeInlines.h"
 
 #include "jsscriptinlines.h"
 
 using namespace js;
 using namespace js::ion;
 
+// All registers to save and restore. This includes the stack pointer, since we
+// use the ability to reference register values on the stack by index.
+static const RegisterSet AllRegs =
+  RegisterSet(GeneralRegisterSet(Registers::AllMask),
+              FloatRegisterSet(FloatRegisters::AllMask));
+
 /* This method generates a trampoline on x64 for a c++ function with
  * the following signature:
  *   JSBool blah(void *code, int argc, Value *argv, JSObject *scopeChain,
  *               Value *vp)
  *   ...using standard x64 fastcall calling convention
  */
 IonCode *
 IonRuntime::generateEnterJIT(JSContext *cx, EnterJitType type)
@@ -277,25 +283,17 @@ IonRuntime::generateInvalidator(JSContex
     AutoIonContextAlloc aica(cx);
     MacroAssembler masm(cx);
 
     // See explanatory comment in x86's IonRuntime::generateInvalidator.
 
     masm.addq(Imm32(sizeof(uintptr_t)), rsp);
 
     // Push registers such that we can access them from [base + code].
-    for (uint32_t i = Registers::Total; i > 0; ) {
-        i--;
-        masm.Push(Register::FromCode(i));
-    }
-
-    // Push xmm registers, such that we can access them from [base + code].
-    masm.reserveStack(FloatRegisters::Total * sizeof(double));
-    for (uint32_t i = 0; i < FloatRegisters::Total; i++)
-        masm.movsd(FloatRegister::FromCode(i), Operand(rsp, i * sizeof(double)));
+    masm.PushRegsInMask(AllRegs);
 
     masm.movq(rsp, rax); // Argument to ion::InvalidationBailout.
 
     // Make space for InvalidationBailout's frameSize outparam.
     masm.reserveStack(sizeof(size_t));
     masm.movq(rsp, rbx);
 
     // Make space for InvalidationBailout's bailoutInfo outparam.
@@ -411,25 +409,17 @@ IonRuntime::generateArgumentsRectifier(J
         *returnAddrOut = (void *) (code->raw() + returnLabel.offset());
     return code;
 }
 
 static void
 GenerateBailoutThunk(JSContext *cx, MacroAssembler &masm, uint32_t frameClass)
 {
     // Push registers such that we can access them from [base + code].
-    for (uint32_t i = Registers::Total; i > 0; ) {
-        i--;
-        masm.Push(Register::FromCode(i));
-    }
-
-    // Push xmm registers, such that we can access them from [base + code].
-    masm.reserveStack(FloatRegisters::Total * sizeof(double));
-    for (uint32_t i = 0; i < FloatRegisters::Total; i++)
-        masm.movsd(FloatRegister::FromCode(i), Operand(rsp, i * sizeof(double)));
+    masm.PushRegsInMask(AllRegs);
 
     // Get the stack pointer into a register, pre-alignment.
     masm.movq(rsp, r8);
 
     // Make space for Bailout's bailoutInfo outparam.
     masm.reserveStack(sizeof(void *));
     masm.movq(rsp, r9);
 
--- a/js/src/ion/x86/Trampoline-x86.cpp
+++ b/js/src/ion/x86/Trampoline-x86.cpp
@@ -16,16 +16,22 @@
 #include "ion/x86/BaselineHelpers-x86.h"
 #include "ion/ExecutionModeInlines.h"
 
 #include "jsscriptinlines.h"
 
 using namespace js;
 using namespace js::ion;
 
+// All registers to save and restore. This includes the stack pointer, since we
+// use the ability to reference register values on the stack by index.
+static const RegisterSet AllRegs =
+  RegisterSet(GeneralRegisterSet(Registers::AllMask),
+              FloatRegisterSet(FloatRegisters::AllMask));
+
 enum EnterJitEbpArgumentOffset {
     ARG_JITCODE         = 2 * sizeof(void *),
     ARG_ARGC            = 3 * sizeof(void *),
     ARG_ARGV            = 4 * sizeof(void *),
     ARG_STACKFRAME      = 5 * sizeof(void *),
     ARG_CALLEETOKEN     = 6 * sizeof(void *),
     ARG_SCOPECHAIN      = 7 * sizeof(void *),
     ARG_STACKVALUES     = 8 * sizeof(void *),
@@ -260,23 +266,18 @@ IonRuntime::generateInvalidator(JSContex
     // - Push the machine state onto the stack.
     // - Call the InvalidationBailout routine with the stack pointer.
     // - Now that the frame has been bailed out, convert the invalidated
     //   frame into an exit frame.
     // - Do the normal check-return-code-and-thunk-to-the-interpreter dance.
 
     masm.addl(Imm32(sizeof(uintptr_t)), esp);
 
-    masm.reserveStack(Registers::Total * sizeof(void *));
-    for (uint32_t i = 0; i < Registers::Total; i++)
-        masm.movl(Register::FromCode(i), Operand(esp, i * sizeof(void *)));
-
-    masm.reserveStack(FloatRegisters::Total * sizeof(double));
-    for (uint32_t i = 0; i < FloatRegisters::Total; i++)
-        masm.movsd(FloatRegister::FromCode(i), Operand(esp, i * sizeof(double)));
+    // Push registers such that we can access them from [base + code].
+    masm.PushRegsInMask(AllRegs);
 
     masm.movl(esp, eax); // Argument to ion::InvalidationBailout.
 
     // Make space for InvalidationBailout's frameSize outparam.
     masm.reserveStack(sizeof(size_t));
     masm.movl(esp, ebx);
 
     // Make space for InvalidationBailout's bailoutInfo outparam.
@@ -406,24 +407,17 @@ IonRuntime::generateArgumentsRectifier(J
         *returnAddrOut = (void *) (code->raw() + returnLabel.offset());
     return code;
 }
 
 static void
 GenerateBailoutThunk(JSContext *cx, MacroAssembler &masm, uint32_t frameClass)
 {
     // Push registers such that we can access them from [base + code].
-    masm.reserveStack(Registers::Total * sizeof(void *));
-    for (uint32_t i = 0; i < Registers::Total; i++)
-        masm.movl(Register::FromCode(i), Operand(esp, i * sizeof(void *)));
-
-    // Push xmm registers, such that we can access them from [base + code].
-    masm.reserveStack(FloatRegisters::Total * sizeof(double));
-    for (uint32_t i = 0; i < FloatRegisters::Total; i++)
-        masm.movsd(FloatRegister::FromCode(i), Operand(esp, i * sizeof(double)));
+    masm.PushRegsInMask(AllRegs);
 
     // Push the bailout table number.
     masm.push(Imm32(frameClass));
 
     // The current stack pointer is the first argument to ion::Bailout.
     masm.movl(esp, eax);
 
     // Make space for Bailout's baioutInfo outparam.
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug886246.js
@@ -0,0 +1,11 @@
+function f(x)
+{
+    x = x|0;
+    return ~~((x ? 1.0e60 : 1.0e60) + 1.0);
+}
+
+var r = -1;
+for(var i = 0; i < 20000; i++) {
+    r = f();
+}
+assertEq(r, 0);
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -207,19 +207,17 @@ js::OnUnknownMethod(JSContext *cx, Handl
     RootedValue idval(cx, idval_);
 
     RootedValue value(cx);
     if (!JSObject::getProperty(cx, obj, obj, cx->names().noSuchMethod, &value))
         return false;
 
     TypeScript::MonitorUnknown(cx);
 
-    if (value.get().isPrimitive()) {
-        vp.set(value);
-    } else {
+    if (value.isObject()) {
         JSObject *obj = NewObjectWithClassProto(cx, &js_NoSuchMethodClass, NULL, NULL);
         if (!obj)
             return false;
 
         obj->setSlot(JSSLOT_FOUND_FUNCTION, value);
         obj->setSlot(JSSLOT_SAVED_ID, idval);
         vp.setObject(*obj);
     }
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -6126,34 +6126,41 @@ DisplayLine(nsDisplayListBuilder* aBuild
   // we approximate it by checking it on aFrame; if it's true for any
   // frame in the line, it's also true for aFrame.
   bool lineInline = aLine->IsInline();
   bool lineMayHaveTextOverflow = aTextOverflow && lineInline;
   if (!intersect && !aBuilder->ShouldDescendIntoFrame(aFrame) &&
       !lineMayHaveTextOverflow)
     return;
 
+  // Collect our line's display items in a temporary nsDisplayListCollection,
+  // so that we can apply any "text-overflow" clipping to the entire collection
+  // without affecting previous lines.
+  nsDisplayListCollection collection;
+
   // Block-level child backgrounds go on the blockBorderBackgrounds list ...
   // Inline-level child backgrounds go on the regular child content list.
-  nsDisplayListSet childLists(aLists,
-    lineInline ? aLists.Content() : aLists.BlockBorderBackgrounds());
+  nsDisplayListSet childLists(collection,
+    lineInline ? collection.Content() : collection.BlockBorderBackgrounds());
 
   uint32_t flags = lineInline ? nsIFrame::DISPLAY_CHILD_INLINE : 0;
 
   nsIFrame* kid = aLine->mFirstChild;
   int32_t n = aLine->GetChildCount();
   while (--n >= 0) {
     aFrame->BuildDisplayListForChild(aBuilder, kid, aDirtyRect,
                                      childLists, flags);
     kid = kid->GetNextSibling();
   }
   
   if (lineMayHaveTextOverflow) {
-    aTextOverflow->ProcessLine(aLists, aLine.get());
-  }
+    aTextOverflow->ProcessLine(collection, aLine.get());
+  }
+
+  collection.MoveTo(aLists);
 }
 
 void
 nsBlockFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                const nsRect&           aDirtyRect,
                                const nsDisplayListSet& aLists)
 {
   int32_t drawnLines; // Will only be used if set (gLamePaintMetrics).
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/883987-1-ref.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<style>
+body { background: green }
+</style>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/883987-1a.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<style>
+body { background: green }
+@supports (color: red) or (content: "foo
+) {
+  body { background: red }
+}
+</style>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/883987-1b.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<style>
+body { background: green }
+@supports (color: red) or (content: url("foo" "bar")) {
+  body { background: red }
+}
+</style>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/883987-1c.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<style>
+body { background: green }
+@supports (color: red) or (url("foo" "bar")) {
+  body { background: red }
+}
+</style>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/883987-1d.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<style>
+body { background: green }
+@supports (color: red) or ("foo
+) {
+  body { background: red }
+}
+</style>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/883987-1e.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<style>
+body { background: green }
+@supports (color: red) or (content: url("foo
+)) {
+  body { background: red }
+}
+</style>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/883987-1f.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<style>
+body { background: green }
+@supports (not "foo
+{}
+body { background: red }
+</style>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1756,8 +1756,14 @@ fails-if(Android&&AndroidVersion<15) == 
 == 847850-1.html 847850-1-ref.html
 == 848421-1.html 848421-1-ref.html
 test-pref(layout.css.flexbox.enabled,true) == 849407-1.html 849407-1-ref.html
 == 849996-1.html 849996-1-ref.html
 == 858803-1.html 858803-1-ref.html
 != 860370.html 860370-notref.html
 == 871338-1.html 871338-1-ref.html
 random-if(Android&&AndroidVersion>=15) == 875060-1.html 875060-1-ref.html #Bug 885303
+== 883987-1a.html 883987-1-ref.html
+== 883987-1b.html 883987-1-ref.html
+== 883987-1c.html 883987-1-ref.html
+== 883987-1d.html 883987-1-ref.html
+== 883987-1e.html 883987-1-ref.html
+== 883987-1f.html 883987-1-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/line-clipping-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+-->
+<html>
+<head>
+<title>Reference for bug 886313</title>
+<style type="text/css">
+@font-face {
+  font-family: DejaVuSansMono;
+  src: url(../fonts/DejaVuSansMono.woff),url(DejaVuSansMono.woff);
+}
+.test {
+  font: 16px DejaVuSansMono;
+  overflow: hidden;
+  width:55px;
+  border: 1px solid black;
+  margin-bottom: 2px;
+}
+</style>
+</head>
+<body>
+  <div class="test">well, hello world</div>
+  <div class="test">well, hello worl&#x2026;</div>
+  <div class="test">well, hell&#x2026; world</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/line-clipping.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+
+    Test: When we have multiple lines of text with "text-overflow: ellipsis",
+    an ellipsis on one line shouldn't affect the other lines.
+-->
+<html>
+<head>
+<title>Testcase for bug 886313</title>
+<style type="text/css">
+@font-face {
+  font-family: DejaVuSansMono;
+  src: url(../fonts/DejaVuSansMono.woff),url(DejaVuSansMono.woff);
+}
+.test {
+  font: 16px DejaVuSansMono;
+  text-overflow:ellipsis;
+  overflow: hidden;
+  width:55px;
+  border: 1px solid black;
+  margin-bottom: 2px;
+}
+</style>
+</head>
+<body>
+  <div class="test">well, hello world</div>
+  <div class="test">well, hello world!</div>
+  <div class="test">well, helloo world</div>
+</body>
+</html>
--- a/layout/reftests/text-overflow/reftest.list
+++ b/layout/reftests/text-overflow/reftest.list
@@ -1,9 +1,10 @@
 skip-if(B2G) == ellipsis-font-fallback.html ellipsis-font-fallback-ref.html
+== line-clipping.html line-clipping-ref.html
 skip-if(B2G) HTTP(..) == marker-basic.html marker-basic-ref.html
 skip-if(B2G) HTTP(..) == marker-string.html marker-string-ref.html
 skip-if(Android||B2G) HTTP(..) == bidi-simple.html bidi-simple-ref.html # Fails on Android due to anti-aliasing
 skip-if(!gtk2Widget) HTTP(..) == bidi-simple-scrolled.html bidi-simple-scrolled-ref.html # Fails on Windows and OSX due to anti-aliasing
 skip-if(B2G) fuzzy-if(Android&&AndroidVersion<15,9,2545) fuzzy-if(Android&&AndroidVersion>=15,24,4000) HTTP(..) == scroll-rounding.html scroll-rounding-ref.html # bug 760264
 fuzzy-if(OSX==10.8,1,1) HTTP(..) == anonymous-block.html anonymous-block-ref.html
 skip-if(B2G) HTTP(..) == false-marker-overlap.html false-marker-overlap-ref.html
 HTTP(..) == visibility-hidden.html visibility-hidden-ref.html
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -2777,27 +2777,31 @@ CSSParserImpl::ParseSupportsCondition(bo
 {
   if (!GetToken(true)) {
     REPORT_UNEXPECTED_EOF(PESupportsConditionStartEOF2);
     return false;
   }
 
   UngetToken();
 
+  mScanner->ClearSeenBadToken();
+
   if (mToken.IsSymbol('(') ||
       mToken.mType == eCSSToken_Function ||
       mToken.mType == eCSSToken_URL ||
       mToken.mType == eCSSToken_Bad_URL) {
     return ParseSupportsConditionInParens(aConditionMet) &&
-           ParseSupportsConditionTerms(aConditionMet);
+           ParseSupportsConditionTerms(aConditionMet) &&
+           !mScanner->SeenBadToken();
   }
 
   if (mToken.mType == eCSSToken_Ident &&
       mToken.mIdent.LowerCaseEqualsLiteral("not")) {
-    return ParseSupportsConditionNegation(aConditionMet);
+    return ParseSupportsConditionNegation(aConditionMet) &&
+           !mScanner->SeenBadToken();
   }
 
   REPORT_UNEXPECTED_TOKEN(PESupportsConditionExpectedStart);
   return false;
 }
 
 // supports_condition_negation
 //   : 'not' S+ supports_condition_in_parens
--- a/layout/style/nsCSSScanner.cpp
+++ b/layout/style/nsCSSScanner.cpp
@@ -347,16 +347,17 @@ nsCSSScanner::nsCSSScanner(const nsAStri
   , mLineOffset(0)
   , mTokenLineNumber(aLineNumber)
   , mTokenLineOffset(0)
   , mTokenOffset(0)
   , mRecordStartOffset(0)
   , mReporter(nullptr)
   , mSVGMode(false)
   , mRecording(false)
+  , mSeenBadToken(false)
 {
   MOZ_COUNT_CTOR(nsCSSScanner);
 }
 
 nsCSSScanner::~nsCSSScanner()
 {
   MOZ_COUNT_DTOR(nsCSSScanner);
 }
@@ -917,16 +918,17 @@ nsCSSScanner::ScanString(nsCSSToken& aTo
     }
     // Both " and ' are excluded from IS_STRING.
     if (ch == '"' || ch == '\'') {
       aToken.mIdent.Append(ch);
       Advance();
       continue;
     }
 
+    mSeenBadToken = true;
     aToken.mType = eCSSToken_Bad_String;
     mReporter->ReportUnexpected("SEUnterminatedString", aToken);
     break;
   }
   return true;
 }
 
 /**
@@ -1051,16 +1053,17 @@ nsCSSScanner::NextURL(nsCSSToken& aToken
 
   // Consume trailing whitespace and then look for a close parenthesis.
   SkipWhitespace();
   ch = Peek();
   if (MOZ_LIKELY(ch < 0 || ch == ')')) {
     Advance();
     aToken.mType = eCSSToken_URL;
   } else {
+    mSeenBadToken = true;
     aToken.mType = eCSSToken_Bad_URL;
   }
   return true;
 }
 
 /**
  * Primary scanner entry point.  Consume one token and fill in
  * |aToken| accordingly.  Will skip over any number of comments first,
--- a/layout/style/nsCSSScanner.h
+++ b/layout/style/nsCSSScanner.h
@@ -136,16 +136,25 @@ class nsCSSScanner {
   // Set whether or not we are processing SVG
   void SetSVGMode(bool aSVGMode) {
     mSVGMode = aSVGMode;
   }
   bool IsSVGMode() const {
     return mSVGMode;
   }
 
+  // Reset or check whether a BAD_URL or BAD_STRING token has been seen.
+  void ClearSeenBadToken() {
+    mSeenBadToken = false;
+  }
+
+  bool SeenBadToken() const {
+    return mSeenBadToken;
+  }
+
   // Get the 1-based line number of the last character of
   // the most recently processed token.
   uint32_t GetLineNumber() const { return mTokenLineNumber; }
 
   // Get the 0-based column number of the first character of
   // the most recently processed token.
   uint32_t GetColumnNumber() const
   { return mTokenOffset - mTokenLineOffset; }
@@ -216,11 +225,12 @@ protected:
 
   uint32_t mRecordStartOffset;
 
   mozilla::css::ErrorReporter *mReporter;
 
   // True if we are in SVG mode; false in "normal" CSS
   bool mSVGMode;
   bool mRecording;
+  bool mSeenBadToken;
 };
 
 #endif /* nsCSSScanner_h___ */
--- a/media/webrtc/signaling/src/sipcc/core/common/resource_manager.h
+++ b/media/webrtc/signaling/src/sipcc/core/common/resource_manager.h
@@ -1,14 +1,14 @@
 /* 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 _RM_MGR_H__
-#define _RM_MGR_H_
+#define _RM_MGR_H__
 
 typedef struct resource_manager {
     int16_t  max_element;
     int16_t  max_index;
     uint32_t *table;
 } resource_manager_t;
 
 void               rm_clear_all_elements(resource_manager_t *rm);
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -630,29 +630,30 @@ abstract public class GeckoApp
                 startActivity(intent);
             } else if (event.equals("WebApps:Install")) {
                 String name = message.getString("name");
                 String manifestURL = message.getString("manifestURL");
                 String iconURL = message.getString("iconURL");
                 String origin = message.getString("origin");
                 // preInstallWebapp will return a File object pointing to the profile directory of the webapp
                 mCurrentResponse = GeckoAppShell.preInstallWebApp(name, manifestURL, origin).toString();
-                GeckoAppShell.postInstallWebApp(name, manifestURL, origin, iconURL);
+                GeckoAppShell.postInstallWebApp(name, manifestURL, origin, iconURL, origin);
             } else if (event.equals("WebApps:PreInstall")) {
                 String name = message.getString("name");
                 String manifestURL = message.getString("manifestURL");
                 String origin = message.getString("origin");
                 // preInstallWebapp will return a File object pointing to the profile directory of the webapp
                 mCurrentResponse = GeckoAppShell.preInstallWebApp(name, manifestURL, origin).toString();
             } else if (event.equals("WebApps:PostInstall")) {
                 String name = message.getString("name");
                 String manifestURL = message.getString("manifestURL");
                 String iconURL = message.getString("iconURL");
+                String originalOrigin = message.getString("originalOrigin");
                 String origin = message.getString("origin");
-                GeckoAppShell.postInstallWebApp(name, manifestURL, origin, iconURL);
+                GeckoAppShell.postInstallWebApp(name, manifestURL, origin, iconURL, originalOrigin);
             } else if (event.equals("WebApps:Uninstall")) {
                 String origin = message.getString("origin");
                 GeckoAppShell.uninstallWebApp(origin);
             } else if (event.equals("Share:Text")) {
                 String text = message.getString("text");
                 GeckoAppShell.openUriExternal(text, "text/plain", "", "", Intent.ACTION_SEND, "");
             } else if (event.equals("Share:Image")) {
                 String src = message.getString("url");
@@ -2409,32 +2410,34 @@ abstract public class GeckoApp
             DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'");
             locInfo.put("time", df.format(new Date(location.getTime())));
             locInfo.put("cell", cellInfo);
 
             MessageDigest digest = MessageDigest.getInstance("SHA-1");
 
             JSONArray wifiInfo = new JSONArray();
             List<ScanResult> aps = wm.getScanResults();
-            for (ScanResult ap : aps) {
-                if (!shouldLog(ap))
-                    continue;
-                StringBuilder sb = new StringBuilder();
-                try {
-                    byte[] result = digest.digest((ap.BSSID + ap.SSID).getBytes("UTF-8"));
-                    for (byte b : result) sb.append(String.format("%02X", b));
+            if (aps != null) {
+                for (ScanResult ap : aps) {
+                    if (!shouldLog(ap))
+                        continue;
+                    StringBuilder sb = new StringBuilder();
+                    try {
+                        byte[] result = digest.digest((ap.BSSID + ap.SSID).getBytes("UTF-8"));
+                        for (byte b : result) sb.append(String.format("%02X", b));
 
-                    JSONObject obj = new JSONObject();
+                        JSONObject obj = new JSONObject();
 
-                    obj.put("key", sb.toString());
-                    obj.put("frequency", ap.frequency);
-                    obj.put("signal", ap.level);
-                    wifiInfo.put(obj);
-                } catch (UnsupportedEncodingException uee) {
-                    Log.w(LOGTAG, "can't encode the key", uee);
+                        obj.put("key", sb.toString());
+                        obj.put("frequency", ap.frequency);
+                        obj.put("signal", ap.level);
+                        wifiInfo.put(obj);
+                    } catch (UnsupportedEncodingException uee) {
+                        Log.w(LOGTAG, "can't encode the key", uee);
+                    }
                 }
             }
             locInfo.put("wifi", wifiInfo);
         } catch (JSONException jsonex) {
             Log.w(LOGTAG, "json exception", jsonex);
         } catch (NoSuchAlgorithmException nsae) {
             Log.w(LOGTAG, "can't creat a SHA1", nsae);
         }
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -627,36 +627,36 @@ public class GeckoAppShell
         Log.d(LOGTAG, "Killing via System.exit()");
         System.exit(0);
     }
 
     static void scheduleRestart() {
         gRestartScheduled = true;
     }
 
-    public static File preInstallWebApp(String aTitle, String aURI, String aUniqueURI) {
-        int index = WebAppAllocator.getInstance(getContext()).findAndAllocateIndex(aUniqueURI, aTitle, (String) null);
+    public static File preInstallWebApp(String aTitle, String aURI, String aOrigin) {
+        int index = WebAppAllocator.getInstance(getContext()).findAndAllocateIndex(aOrigin, aTitle, (String) null);
         GeckoProfile profile = GeckoProfile.get(getContext(), "webapp" + index);
         return profile.getDir();
     }
 
-    public static void postInstallWebApp(String aTitle, String aURI, String aUniqueURI, String aIconURL) {
+    public static void postInstallWebApp(String aTitle, String aURI, String aOrigin, String aIconURL, String aOriginalOrigin) {
     	WebAppAllocator allocator = WebAppAllocator.getInstance(getContext());
-		int index = allocator.getIndexForApp(aUniqueURI);
+		int index = allocator.getIndexForApp(aOriginalOrigin);
     	assert index != -1 && aIconURL != null;
-    	allocator.updateAppAllocation(aUniqueURI, index, BitmapUtils.getBitmapFromDataURI(aIconURL));
-    	createShortcut(aTitle, aURI, aUniqueURI, aIconURL, "webapp");
+    	allocator.updateAppAllocation(aOrigin, index, BitmapUtils.getBitmapFromDataURI(aIconURL));
+    	createShortcut(aTitle, aURI, aOrigin, aIconURL, "webapp");
     }
 
-    public static Intent getWebAppIntent(String aURI, String aUniqueURI, String aTitle, Bitmap aIcon) {
+    public static Intent getWebAppIntent(String aURI, String aOrigin, String aTitle, Bitmap aIcon) {
         int index;
         if (aIcon != null && !TextUtils.isEmpty(aTitle))
-            index = WebAppAllocator.getInstance(getContext()).findAndAllocateIndex(aUniqueURI, aTitle, aIcon);
+            index = WebAppAllocator.getInstance(getContext()).findAndAllocateIndex(aOrigin, aTitle, aIcon);
         else
-            index = WebAppAllocator.getInstance(getContext()).getIndexForApp(aUniqueURI);
+            index = WebAppAllocator.getInstance(getContext()).getIndexForApp(aOrigin);
 
         if (index == -1)
             return null;
 
         return getWebAppIntent(index, aURI);
     }
 
     public static Intent getWebAppIntent(int aIndex, String aURI) {
--- a/mobile/android/base/GeckoScreenOrientationListener.java
+++ b/mobile/android/base/GeckoScreenOrientationListener.java
@@ -55,16 +55,21 @@ public class GeckoScreenOrientationListe
     private GeckoScreenOrientationListener() {
         mListener = new OrientationEventListenerImpl(GeckoAppShell.getContext());
 
         PrefsHelper.getPref(DEFAULT_ORIENTATION_PREF, new PrefsHelper.PrefHandlerBase() {
             @Override public void prefValue(String pref, String value) {
                 mDefaultOrientation = orientationFromStringArray(value);
                 unlockScreenOrientation();
             }
+
+            @Override
+            public boolean isObserver() {
+                return true;
+            }
         });
 
         mDefaultOrientation = DEFAULT_ORIENTATION;
     }
 
     public static GeckoScreenOrientationListener getInstance() {
         if (sInstance == null) {
             sInstance = new GeckoScreenOrientationListener();
--- a/mobile/android/base/WebAppImpl.java
+++ b/mobile/android/base/WebAppImpl.java
@@ -66,16 +66,21 @@ public class WebAppImpl extends GeckoApp
             return;
         }
 
         // Try to use the origin stored in the WebAppAllocator first
         String origin = WebAppAllocator.getInstance(this).getAppForIndex(getIndex());
         try {
             mOrigin = new URL(origin);
         } catch (java.net.MalformedURLException ex) {
+            // If we can't parse the this is an app protocol, just settle for not having an origin
+            if (!origin.startsWith("app://")) {
+                return;
+            }
+
             // If that failed fall back to the origin stored in the shortcut
             Log.i(LOGTAG, "Webapp is not registered with allocator");
             try {
                 mOrigin = new URL(getIntent().getData().toString());
             } catch (java.net.MalformedURLException ex2) {
                 Log.e(LOGTAG, "Unable to parse intent url: ", ex);
             }
         }
--- a/mobile/android/chrome/content/aboutHealthReport.xhtml
+++ b/mobile/android/chrome/content/aboutHealthReport.xhtml
@@ -11,16 +11,17 @@
 ]>
 
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <html xmlns="http://www.w3.org/1999/xhtml">
   <head>
+   <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>&abouthealth.pagetitle;</title>
    <link rel="icon" type="image/png" sizes="64x64"
      href="chrome://branding/content/favicon64.png" />
    <link rel="stylesheet"
      href="chrome://browser/skin/aboutHealthReport.css"
      type="text/css" />
    <script type="text/javascript;version=1.8"
      src="chrome://browser/content/aboutHealthReport.js" />
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -3512,18 +3512,22 @@ Tab.prototype = {
 
       // Reset showProgress after state change
       this.showProgress = true;
     }
   },
 
   onLocationChange: function(aWebProgress, aRequest, aLocationURI, aFlags) {
     let contentWin = aWebProgress.DOMWindow;
-    if (contentWin != contentWin.top)
-        return;
+
+    // Browser webapps may load content inside iframes that can not reach across the app/frame boundary
+    // i.e. even though the page is loaded in an iframe window.top != webapp
+    // Make cure this window is a top level tab before moving on.
+    if (BrowserApp.getBrowserForWindow(contentWin) == null)
+      return;
 
     this._hostChanged = true;
 
     let fixedURI = aLocationURI;
     try {
       fixedURI = URIFixup.createExposableURI(aLocationURI);
     } catch (ex) { }
 
@@ -6553,38 +6557,27 @@ var WebappsUI = {
   doInstall: function doInstall(aData) {
     let jsonManifest = aData.isPackage ? aData.app.updateManifest : aData.app.manifest;
     let manifest = new ManifestHelper(jsonManifest, aData.app.origin);
     let name = manifest.name ? manifest.name : manifest.fullLaunchPath();
     let showPrompt = true;
 
     if (!showPrompt || Services.prompt.confirm(null, Strings.browser.GetStringFromName("webapps.installTitle"), name + "\n" + aData.app.origin)) {
       // Get a profile for the app to be installed in. We'll download everything before creating the icons.
+      let origin = aData.app.origin;
       let profilePath = sendMessageToJava({
         type: "WebApps:PreInstall",
         name: manifest.name,
         manifestURL: aData.app.manifestURL,
-        origin: aData.app.origin
+        origin: origin
       });
-      let file = null;
       if (profilePath) {
-        file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
+        let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
         file.initWithPath(profilePath);
-
-        // build any app specific default prefs
-        let prefs = [];
-        if (manifest.orientation) {
-          prefs.push({name:"app.orientation.default", value: manifest.orientation});
-        }
-
-        // write them into the app profile
-        let defaultPrefsFile = file.clone();
-        defaultPrefsFile.append(this.DEFAULT_PREFS_FILENAME);
-        this.writeDefaultPrefs(defaultPrefsFile, prefs);
-
+  
         let self = this;
         DOMApplicationRegistry.confirmInstall(aData, false, file, null,
           function (manifest) {
             // the manifest argument is the manifest from within the zip file,
             // TODO so now would be a good time to ask about permissions.
             self.makeBase64Icon(self.getBiggestIcon(manifest.icons, Services.io.newURI(aData.app.origin, null, null)),
               function(scaledIcon, fullsizeIcon) {
                 // if java returned a profile path to us, try to use it to pre-populate the app cache
@@ -6594,47 +6587,63 @@ var WebappsUI = {
                   iconFile.append("logo.png");
                   let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Ci.nsIWebBrowserPersist);
                   persist.persistFlags = Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES;
                   persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
 
                   let source = Services.io.newURI(fullsizeIcon, "UTF8", null);
                   persist.saveURI(source, null, null, null, null, iconFile, null);
 
+                  // aData.app.origin may now point to the app: url that hosts this app
                   sendMessageToJava({
                     type: "WebApps:PostInstall",
                     name: manifest.name,
                     manifestURL: aData.app.manifestURL,
+                    originalOrigin: origin,
                     origin: aData.app.origin,
                     iconURL: fullsizeIcon
                   });
                   if (!!aData.isPackage) {
                     // For packaged apps, put a notification in the notification bar.
                     let message = Strings.browser.GetStringFromName("webapps.alertSuccess");
                     let alerts = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
                     alerts.showAlertNotification("drawable://alert_app", manifest.name, message, true, "", {
                       observe: function () {
                         self.openURL(aData.app.manifestURL, aData.app.origin);
                       }
                     }, "webapp");
                   }
                 } catch(ex) {
                   console.log(ex);
                 }
+                self.writeDefaultPrefs(file, manifest);
               }
             );
           }
         );
       }
     } else {
       DOMApplicationRegistry.denyInstall(aData);
     }
   },
 
-  writeDefaultPrefs: function webapps_writeDefaultPrefs(aFile, aPrefs) {
+  writeDefaultPrefs: function webapps_writeDefaultPrefs(aProfile, aManifest) {
+      // build any app specific default prefs
+      let prefs = [];
+      if (aManifest.orientation) {
+        prefs.push({name:"app.orientation.default", value: aManifest.orientation.join(",") });
+      }
+
+      // write them into the app profile
+      let defaultPrefsFile = aProfile.clone();
+      defaultPrefsFile.append(this.DEFAULT_PREFS_FILENAME);
+      this._writeData(defaultPrefsFile, prefs);
+  },
+
+  _writeData: function(aFile, aPrefs) {
     if (aPrefs.length > 0) {
       let data = JSON.stringify(aPrefs);
 
       let ostream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
       ostream.init(aFile, -1, -1, 0);
 
       let istream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
       istream.setData(data, data.length);
--- a/mobile/android/installer/package-manifest.in
+++ b/mobile/android/installer/package-manifest.in
@@ -25,36 +25,62 @@
 @BINPATH@/defaults/profile/chrome/*
 #ifdef MOZ_UPDATER
 @BINPATH@/update.locale
 @BINPATH@/updater.ini
 #endif
 @BINPATH@/dictionaries/*
 @BINPATH@/hyphenation/*
 
-[xpcom]
-@BINPATH@/dependentlibs.list
+[assets destdir="assets"]
 #ifndef MOZ_STATIC_JS
 @BINPATH@/@DLL_PREFIX@mozjs@DLL_SUFFIX@
 #endif
 #ifndef MOZ_FOLD_LIBS
 @BINPATH@/@DLL_PREFIX@plc4@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@plds4@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@nspr4@DLL_SUFFIX@
 #endif
 @BINPATH@/@DLL_PREFIX@mozalloc@DLL_SUFFIX@
-@BINPATH@/@DLL_PREFIX@mozglue@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@omxplugin@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@omxplugingb@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@omxplugingb235@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@omxpluginhc@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@omxpluginjb-htc@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@omxpluginsony@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@omxpluginfroyo@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@xul@DLL_SUFFIX@
+
+@BINPATH@/@DLL_PREFIX@nssckbi@DLL_SUFFIX@
+@BINPATH@/@DLL_PREFIX@nss3@DLL_SUFFIX@
+#ifndef MOZ_FOLD_LIBS
+@BINPATH@/@DLL_PREFIX@nssutil3@DLL_SUFFIX@
+@BINPATH@/@DLL_PREFIX@smime3@DLL_SUFFIX@
+@BINPATH@/@DLL_PREFIX@ssl3@DLL_SUFFIX@
+#endif
+@BINPATH@/@DLL_PREFIX@softokn3@DLL_SUFFIX@
+@BINPATH@/@DLL_PREFIX@freebl3@DLL_SUFFIX@
+#ifndef CROSS_COMPILE
+@BINPATH@/@DLL_PREFIX@freebl3.chk
+@BINPATH@/@DLL_PREFIX@softokn3.chk
+#endif
+#ifndef NSS_DISABLE_DBM
+@BINPATH@/@DLL_PREFIX@nssdbm3@DLL_SUFFIX@
+#ifndef CROSS_COMPILE
+@BINPATH@/@DLL_PREFIX@nssdbm3.chk
+#endif
+#endif
+
+#ifndef MOZ_FOLD_LIBS
+@BINPATH@/@DLL_PREFIX@mozsqlite3@DLL_SUFFIX@
+#endif
+
+[xpcom]
+@BINPATH@/dependentlibs.list
+@BINPATH@/@DLL_PREFIX@mozglue@DLL_SUFFIX@
 @BINPATH@/@MOZ_CHILD_PROCESS_NAME@
 
 @BINPATH@/AndroidManifest.xml
 @BINPATH@/resources.arsc
 @BINPATH@/package-name.txt
 @BINPATH@/classes.dex
 @BINPATH@/res/drawable
 @BINPATH@/res/drawable-hdpi
@@ -67,19 +93,16 @@
 #ifndef XP_UNIX
 @BINPATH@/@MOZ_APP_NAME@.exe
 #else
 @BINPATH@/@MOZ_APP_NAME@-bin
 @BINPATH@/@MOZ_APP_NAME@
 #endif
 @BINPATH@/application.ini
 @BINPATH@/platform.ini
-#ifndef MOZ_FOLD_LIBS
-@BINPATH@/@DLL_PREFIX@mozsqlite3@DLL_SUFFIX@
-#endif
 @BINPATH@/blocklist.xml
 #ifdef XP_UNIX
 @BINPATH@/run-mozilla.sh
 @BINPATH@/mozilla-xremote-client
 #endif
 
 ; [Components]
 @BINPATH@/components/components.manifest
@@ -473,38 +496,19 @@
 
 ; svg
 @BINPATH@/res/svg.css
 @BINPATH@/components/dom_svg.xpt
 @BINPATH@/components/dom_smil.xpt
 
 ; [Personal Security Manager]
 ;
-@BINPATH@/@DLL_PREFIX@nssckbi@DLL_SUFFIX@
 @BINPATH@/components/pipboot.xpt
 @BINPATH@/components/pipnss.xpt
 @BINPATH@/components/pippki.xpt
-@BINPATH@/@DLL_PREFIX@nss3@DLL_SUFFIX@
-#ifndef MOZ_FOLD_LIBS
-@BINPATH@/@DLL_PREFIX@nssutil3@DLL_SUFFIX@
-@BINPATH@/@DLL_PREFIX@smime3@DLL_SUFFIX@
-@BINPATH@/@DLL_PREFIX@ssl3@DLL_SUFFIX@
-#endif
-@BINPATH@/@DLL_PREFIX@softokn3@DLL_SUFFIX@
-@BINPATH@/@DLL_PREFIX@freebl3@DLL_SUFFIX@
-#ifndef CROSS_COMPILE
-@BINPATH@/@DLL_PREFIX@freebl3.chk
-@BINPATH@/@DLL_PREFIX@softokn3.chk
-#endif
-#ifndef NSS_DISABLE_DBM
-@BINPATH@/@DLL_PREFIX@nssdbm3@DLL_SUFFIX@
-#ifndef CROSS_COMPILE
-@BINPATH@/@DLL_PREFIX@nssdbm3.chk
-#endif
-#endif
 @BINPATH@/chrome/pippki@JAREXT@
 @BINPATH@/chrome/pippki.manifest
 
 ; for Solaris SPARC
 #ifdef SOLARIS
 bin/libfreebl_32fpu_3.chk
 bin/libfreebl_32fpu_3.so
 bin/libfreebl_32int_3.chk
--- a/python/mozbuild/mozpack/packager/__init__.py
+++ b/python/mozbuild/mozpack/packager/__init__.py
@@ -12,52 +12,153 @@ from mozpack.chrome.manifest import (
     ManifestInterfaces,
     is_manifest,
     parse_manifest,
 )
 import mozpack.path
 from collections import deque
 
 
+class Component(object):
+    '''
+    Class that represents a component in a package manifest.
+    '''
+    def __init__(self, name, destdir=''):
+        if name.find(' ') > 0:
+            errors.fatal('Malformed manifest: space in component name "%s"'
+                         % component)
+        self._name = name
+        self._destdir = destdir
+
+    def __repr__(self):
+        s = self.name
+        if self.destdir:
+            s += ' destdir="%s"' % self.destdir
+        return s
+
+    @property
+    def name(self):
+        return self._name
+
+    @property
+    def destdir(self):
+        return self._destdir
+
+    @staticmethod
+    def _triples(lst):
+        '''
+        Split [1, 2, 3, 4, 5, 6, 7] into [(1, 2, 3), (4, 5, 6)].
+        '''
+        return zip(*[iter(lst)] * 3)
+
+    KEY_VALUE_RE = re.compile(r'''
+        \s*                 # optional whitespace.
+        ([a-zA-Z0-9_]+)     # key.
+        \s*=\s*             # optional space around =.
+        "([^"]*)"           # value without surrounding quotes.
+        (?:\s+|$)
+        ''', re.VERBOSE)
+
+    @staticmethod
+    def _split_options(string):
+        '''
+        Split 'key1="value1" key2="value2"' into
+        {'key1':'value1', 'key2':'value2'}.
+
+        Returned keys and values are all strings.
+
+        Throws ValueError if the input is malformed.
+        '''
+        options = {}
+        splits = Component.KEY_VALUE_RE.split(string)
+        if len(splits) % 3 != 1:
+            # This should never happen -- we expect to always split
+            # into ['', ('key', 'val', '')*].
+            raise ValueError("Bad input")
+        if splits[0]:
+            raise ValueError('Unrecognized input ' + splits[0])
+        for key, val, no_match in Component._triples(splits[1:]):
+            if no_match:
+                raise ValueError('Unrecognized input ' + no_match)
+            options[key] = val
+        return options
+
+    @staticmethod
+    def _split_component_and_options(string):
+        '''
+        Split 'name key1="value1" key2="value2"' into
+        ('name', {'key1':'value1', 'key2':'value2'}).
+
+        Returned name, keys and values are all strings.
+
+        Raises ValueError if the input is malformed.
+        '''
+        splits = string.strip().split(None, 1)
+        if not splits:
+            raise ValueError('No component found')
+        component = splits[0].strip()
+        if not component:
+            raise ValueError('No component found')
+        if not re.match('[a-zA-Z0-9_\-]+$', component):
+            raise ValueError('Bad component name ' + component)
+        options = Component._split_options(splits[1]) if len(splits) > 1 else {}
+        return component, options
+
+    @staticmethod
+    def from_string(string):
+        '''
+        Create a component from a string.
+        '''
+        try:
+            name, options = Component._split_component_and_options(string)
+        except ValueError as e:
+            errors.fatal('Malformed manifest: %s' % e)
+            return
+        destdir = options.pop('destdir', '')
+        if options:
+            errors.fatal('Malformed manifest: options %s not recognized'
+                         % options.keys())
+        return Component(name, destdir=destdir)
+
+
 class PackageManifestParser(object):
     '''
     Class for parsing of a package manifest, after preprocessing.
 
     A package manifest is a list of file paths, with some syntaxic sugar:
         [] designates a toplevel component. Example: [xpcom]
         - in front of a file specifies it to be removed
         * wildcard support
         ** expands to all files and zero or more directories
         ; file comment
 
     The parser takes input from the preprocessor line by line, and pushes
-    parsed information to a sink object. The add and remove methods of the
-    sink object are called with the current component and a path.
+    parsed information to a sink object.
+
+    The add and remove methods of the sink object are called with the
+    current Component instance and a path.
     '''
     def __init__(self, sink):
         '''
         Initialize the package manifest parser with the given sink.
         '''
-        self._component = ''
+        self._component = Component('')
         self._sink = sink
 
     def handle_line(self, str):
         '''
         Handle a line of input and push the parsed information to the sink
         object.
         '''
         # Remove comments.
         str = str.strip()
         if not str or str.startswith(';'):
             return
         if str.startswith('[') and str.endswith(']'):
-            if str == '[]' or re.search(r'[\[\]\s]', str[1:-1]):
-                errors.fatal('Malformed manifest')
-            else:
-                self._component = str[1:-1]
+            self._component = Component.from_string(str[1:-1])
         elif str.startswith('-'):
             str = str[1:]
             self._sink.remove(self._component, str)
         elif ',' in str:
             errors.fatal('Incompatible syntax')
         else:
             self._sink.add(self._component, str)
 
@@ -222,31 +323,35 @@ class SimpleManifestSink(object):
     def normalize_path(path):
         '''
         Remove any bin/ prefix.
         '''
         if mozpack.path.basedir(path, ['bin']) == 'bin':
             return mozpack.path.relpath(path, 'bin')
         return path
 
-    def add(self, section, pattern):
+    def add(self, component, pattern):
         '''
-        Add files with the given pattern.
+        Add files with the given pattern in the given component.
         '''
         assert not self._closed
         added = False
         for p, f in self._finder.find(pattern):
             added = True
             if is_manifest(p):
                 self._manifests.add(p)
-            self.packager.add(SimpleManifestSink.normalize_path(p), f)
+            dest = mozpack.path.join(component.destdir, SimpleManifestSink.normalize_path(p))
+            self.packager.add(dest, f)
         if not added:
             errors.error('Missing file(s): %s' % pattern)
 
-    def remove(self, section, pattern):
+    def remove(self, component, pattern):
+        '''
+        Remove files with the given pattern in the given component.
+        '''
         assert not self._closed
         errors.fatal('Removal is unsupported')
 
     def close(self, auto_root_manifest=True):
         '''
         Add possibly missing bits and push all instructions to the formatter.
         '''
         if auto_root_manifest:
--- a/python/mozbuild/mozpack/test/test_packager.py
+++ b/python/mozbuild/mozpack/test/test_packager.py
@@ -2,19 +2,20 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import unittest
 import mozunit
 import os
 from mozpack.packager import (
     preprocess_manifest,
+    CallDeque,
+    Component,
     SimplePackager,
     SimpleManifestSink,
-    CallDeque,
 )
 from mozpack.files import GeneratedFile
 from mozpack.chrome.manifest import (
     ManifestResource,
     ManifestContent,
 )
 from mozunit import MockedOpen
 from Preprocessor import Preprocessor
@@ -25,44 +26,47 @@ from mozpack.errors import (
 import mozpack.path
 
 MANIFEST = '''
 bar/*
 [foo]
 foo/*
 -foo/bar
 chrome.manifest
+[zot destdir="destdir"]
+foo/zot
 ; comment
 #ifdef baz
 [baz]
 baz@SUFFIX@
 #endif
 '''
 
 
 class TestPreprocessManifest(unittest.TestCase):
     MANIFEST_PATH = os.path.join(os.path.abspath(os.curdir), 'manifest')
 
     EXPECTED_LOG = [
         ((MANIFEST_PATH, 2), 'add', '', 'bar/*'),
         ((MANIFEST_PATH, 4), 'add', 'foo', 'foo/*'),
         ((MANIFEST_PATH, 5), 'remove', 'foo', 'foo/bar'),
-        ((MANIFEST_PATH, 6), 'add', 'foo', 'chrome.manifest')
+        ((MANIFEST_PATH, 6), 'add', 'foo', 'chrome.manifest'),
+        ((MANIFEST_PATH, 8), 'add', 'zot destdir="destdir"', 'foo/zot'),
     ]
 
     def setUp(self):
         class MockSink(object):
             def __init__(self):
                 self.log = []
 
-            def add(self, section, path):
-                self._log(errors.get_context(), 'add', section, path)
+            def add(self, component, path):
+                self._log(errors.get_context(), 'add', repr(component), path)
 
-            def remove(self, section, path):
-                self._log(errors.get_context(), 'remove', section, path)
+            def remove(self, component, path):
+                self._log(errors.get_context(), 'remove', repr(component), path)
 
             def _log(self, *args):
                 self.log.append(args)
 
         self.sink = MockSink()
 
     def test_preprocess_manifest(self):
         with MockedOpen({'manifest': MANIFEST}):
@@ -79,17 +83,17 @@ class TestPreprocessManifest(unittest.Te
                 {'baz': 1}
             )
 
     def test_preprocess_manifest_defines(self):
         with MockedOpen({'manifest': MANIFEST}):
             preprocess_manifest(self.sink, 'manifest',
                                 {'baz': 1, 'SUFFIX': '.exe'})
         self.assertEqual(self.sink.log, self.EXPECTED_LOG +
-                         [((self.MANIFEST_PATH, 10), 'add', 'baz', 'baz.exe')])
+                         [((self.MANIFEST_PATH, 12), 'add', 'baz', 'baz.exe')])
 
 
 class MockFinder(object):
     def __init__(self, files):
         self.files = files
         self.log = []
 
     def find(self, path):
@@ -194,44 +198,52 @@ class TestSimplePackager(unittest.TestCa
 
 
 class TestSimpleManifestSink(unittest.TestCase):
     def test_simple_manifest_parser(self):
         formatter = MockFormatter()
         foobar = GeneratedFile('foobar')
         foobaz = GeneratedFile('foobaz')
         fooqux = GeneratedFile('fooqux')
+        foozot = GeneratedFile('foozot')
         finder = MockFinder({
             'bin/foo/bar': foobar,
             'bin/foo/baz': foobaz,
             'bin/foo/qux': fooqux,
+            'bin/foo/zot': foozot,
             'bin/foo/chrome.manifest': GeneratedFile('resource foo foo/'),
             'bin/chrome.manifest':
             GeneratedFile('manifest foo/chrome.manifest'),
         })
         parser = SimpleManifestSink(finder, formatter)
-        parser.add('section0', 'bin/foo/b*')
-        parser.add('section1', 'bin/foo/qux')
-        parser.add('section1', 'bin/foo/chrome.manifest')
-        self.assertRaises(ErrorMessage, parser.add, 'section1', 'bin/bar')
+        component0 = Component('component0')
+        component1 = Component('component1')
+        component2 = Component('component2', destdir='destdir')
+        parser.add(component0, 'bin/foo/b*')
+        parser.add(component1, 'bin/foo/qux')
+        parser.add(component1, 'bin/foo/chrome.manifest')
+        parser.add(component2, 'bin/foo/zot')
+        self.assertRaises(ErrorMessage, parser.add, 'component1', 'bin/bar')
 
         self.assertEqual(formatter.log, [])
         parser.close()
         self.assertEqual(formatter.log, [
             (('foo/chrome.manifest', 1),
              'add_manifest', ManifestResource('foo', 'foo', 'foo/')),
             (None, 'add', 'foo/bar', foobar),
             (None, 'add', 'foo/baz', foobaz),
             (None, 'add', 'foo/qux', fooqux),
+            (None, 'add', 'destdir/foo/zot', foozot),
         ])
 
         self.assertEqual(finder.log, [
             'bin/foo/b*',
             'bin/foo/qux',
             'bin/foo/chrome.manifest',
+            'bin/foo/zot',
             'bin/bar',
             'bin/chrome.manifest'
         ])
 
 
 class TestCallDeque(unittest.TestCase):
     def test_call_deque(self):
         class Logger(object):
@@ -253,10 +265,64 @@ class TestCallDeque(unittest.TestCase):
         d.append(logger.log, 'foo')
         d.append(logger.log, 'bar')
         d.append(logger.staticlog, logger, 'baz')
         d.append(do_log, logger, 'qux')
         self.assertEqual(logger._log, [])
         d.execute()
         self.assertEqual(logger._log, ['foo', 'bar', 'baz', 'qux'])
 
+
+class TestComponent(unittest.TestCase):
+    def do_split(self, string, name, options):
+        n, o = Component._split_component_and_options(string)
+        self.assertEqual(name, n)
+        self.assertEqual(options, o)
+
+    def test_component_split_component_and_options(self):
+        self.do_split('component', 'component', {})
+        self.do_split('trailingspace ', 'trailingspace', {})
+        self.do_split(' leadingspace', 'leadingspace', {})
+        self.do_split(' trim ', 'trim', {})
+        self.do_split(' trim key="value"', 'trim', {'key':'value'})
+        self.do_split(' trim empty=""', 'trim', {'empty':''})
+        self.do_split(' trim space=" "', 'trim', {'space':' '})
+        self.do_split('component key="value"  key2="second" ',
+                      'component', {'key':'value', 'key2':'second'})
+        self.do_split( 'trim key="  value with spaces   "  key2="spaces again"',
+                       'trim', {'key':'  value with spaces   ', 'key2': 'spaces again'})
+
+    def do_split_error(self, string):
+        self.assertRaises(ValueError, Component._split_component_and_options, string)
+
+    def test_component_split_component_and_options_errors(self):
+        self.do_split_error('"component')
+        self.do_split_error('comp"onent')
+        self.do_split_error('component"')
+        self.do_split_error('"component"')
+        self.do_split_error('=component')
+        self.do_split_error('comp=onent')
+        self.do_split_error('component=')
+        self.do_split_error('key="val"')
+        self.do_split_error('component key=')
+        self.do_split_error('component key="val')
+        self.do_split_error('component key=val"')
+        self.do_split_error('component key="val" x')
+        self.do_split_error('component x key="val"')
+        self.do_split_error('component key1="val" x key2="val"')
+
+    def do_from_string(self, string, name, destdir=''):
+        component = Component.from_string(string)
+        self.assertEqual(name, component.name)
+        self.assertEqual(destdir, component.destdir)
+
+    def test_component_from_string(self):
+        self.do_from_string('component', 'component')
+        self.do_from_string('component-with-hyphen', 'component-with-hyphen')
+        self.do_from_string('component destdir="foo/bar"', 'component', 'foo/bar')
+        self.do_from_string('component destdir="bar spc"', 'component', 'bar spc')
+        self.assertRaises(ErrorMessage, Component.from_string, '')
+        self.assertRaises(ErrorMessage, Component.from_string, 'component novalue=')
+        self.assertRaises(ErrorMessage, Component.from_string, 'component badoption=badvalue')
+
+
 if __name__ == '__main__':
     mozunit.main()
--- a/toolkit/components/places/History.cpp
+++ b/toolkit/components/places/History.cpp
@@ -2708,17 +2708,17 @@ History::GetPlacesInfo(const JS::Value& 
 
       VisitData& placeInfo = *placesInfo.AppendElement(VisitData());
       placeInfo.guid = guid;
     }
     else {
       nsCOMPtr<nsIURI> uri = GetJSValueAsURI(aCtx, placeIdentifier);
       if (!uri)
         return NS_ERROR_INVALID_ARG; // neither a guid, nor a uri.
-      *placesInfo.AppendElement(VisitData(uri));
+      placesInfo.AppendElement(VisitData(uri));
     }
   }
 
   mozIStorageConnection* dbConn = GetDBConn();
   NS_ENSURE_STATE(dbConn);
 
   for (nsTArray<VisitData>::size_type i = 0; i < placesInfo.Length(); i++) {
     nsresult rv = GetPlaceInfo::Start(dbConn, placesInfo.ElementAt(i), aCallback);
--- a/toolkit/mozapps/installer/packager.mk
+++ b/toolkit/mozapps/installer/packager.mk
@@ -340,39 +340,36 @@ endif
 else
 INNER_ROBOCOP_PACKAGE=echo 'Testing is disabled - No Robocop for you'
 endif
 
 ifdef MOZ_OMX_PLUGIN
 DIST_FILES += libomxplugin.so libomxplugingb.so libomxplugingb235.so libomxpluginhc.so libomxpluginsony.so libomxpluginfroyo.so libomxpluginjb-htc.so
 endif
 
-SO_LIBRARIES := $(filter-out $(MOZ_CHILD_PROCESS_NAME),$(filter %.so,$(DIST_FILES)))
-# These libraries are moved into the assets/ directory of the APK.
-ASSET_SO_LIBRARIES := $(addprefix assets/,$(SO_LIBRARIES))
+SO_LIBRARIES := $(filter %.so,$(DIST_FILES))
+# These libraries are placed in the assets/ directory by packager.py.
+ASSET_SO_LIBRARIES := $(addprefix assets/,$(filter-out libmozglue.so $(MOZ_CHILD_PROCESS_NAME),$(SO_LIBRARIES)))
 
 DIST_FILES := $(filter-out $(SO_LIBRARIES),$(DIST_FILES))
-NON_DIST_FILES += $(SO_LIBARIES)
+NON_DIST_FILES += libmozglue.so $(MOZ_CHILD_PROCESS_NAME) $(ASSET_SO_LIBRARIES)
 
 ifdef MOZ_ENABLE_SZIP
-# These libraries are szipped (before being moved into the assets/
-# directory of the APK).
-SZIP_LIBRARIES := $(SO_LIBRARIES)
+# These libraries are szipped in-place in the assets/ directory.
+SZIP_LIBRARIES := $(ASSET_SO_LIBRARIES)
 endif
 
 PKG_SUFFIX      = .apk
 INNER_MAKE_PACKAGE	= \
   $(if $(ALREADY_SZIPPED),,$(foreach lib,$(SZIP_LIBRARIES),host/bin/szip $(MOZ_SZIP_FLAGS) $(STAGEPATH)$(MOZ_PKG_DIR)$(_BINPATH)/$(lib) && )) \
   make -C $(GECKO_APP_AP_PATH) gecko.ap_ && \
   cp $(GECKO_APP_AP_PATH)/gecko.ap_ $(_ABS_DIST) && \
   ( cd $(STAGEPATH)$(MOZ_PKG_DIR)$(_BINPATH) && \
-    mkdir -p assets && \
     mkdir -p lib/$(ABI_DIR) && \
     mv libmozglue.so $(MOZ_CHILD_PROCESS_NAME) lib/$(ABI_DIR) && \
-    mv $(SO_LIBRARIES) assets && \
     unzip -o $(_ABS_DIST)/gecko.ap_ && \
     rm $(_ABS_DIST)/gecko.ap_ && \
     $(ZIP) -0 $(_ABS_DIST)/gecko.ap_ $(ASSET_SO_LIBRARIES) && \
     $(ZIP) -r9D $(_ABS_DIST)/gecko.ap_ $(DIST_FILES) -x $(NON_DIST_FILES) $(SZIP_LIBRARIES) && \
     $(ZIP) -0 $(_ABS_DIST)/gecko.ap_ $(OMNIJAR_NAME)) && \
   rm -f $(_ABS_DIST)/gecko.apk && \
   cp $(_ABS_DIST)/gecko.ap_ $(_ABS_DIST)/gecko.apk && \
   $(ZIP) -j0 $(_ABS_DIST)/gecko.apk $(STAGEPATH)$(MOZ_PKG_DIR)$(_BINPATH)/classes.dex && \
@@ -382,17 +379,16 @@ INNER_MAKE_PACKAGE	= \
   $(INNER_ROBOCOP_PACKAGE)
 
 INNER_UNMAKE_PACKAGE	= \
   mkdir $(MOZ_PKG_DIR) && \
   ( cd $(MOZ_PKG_DIR) && \
     $(UNZIP) $(UNPACKAGE) && \
     mv lib/$(ABI_DIR)/libmozglue.so . && \
     mv lib/$(ABI_DIR)/*plugin-container* $(MOZ_CHILD_PROCESS_NAME) && \
-    mv $(ASSET_SO_LIBRARIES) . && \
     rm -rf lib/$(ABI_DIR) )
 endif
 
 ifeq ($(MOZ_PKG_FORMAT),DMG)
 PKG_SUFFIX	= .dmg
 PKG_DMG_FLAGS	=
 ifneq (,$(MOZ_PKG_MAC_DSSTORE))
 PKG_DMG_FLAGS += --copy "$(MOZ_PKG_MAC_DSSTORE):/.DS_Store"
--- a/widget/windows/nsNativeThemeWin.cpp
+++ b/widget/windows/nsNativeThemeWin.cpp
@@ -98,32 +98,16 @@ static int32_t
 GetClassicWindowFrameButtonState(nsEventStates eventState)
 {
   if (eventState.HasState(NS_EVENT_STATE_ACTIVE) &&
       eventState.HasState(NS_EVENT_STATE_HOVER))
     return DFCS_BUTTONPUSH|DFCS_PUSHED;
   return DFCS_BUTTONPUSH;
 }
 
-static void
-QueryForButtonData(nsIFrame *aFrame)
-{
-  if (nsUXThemeData::sTitlebarInfoPopulatedThemed && nsUXThemeData::sTitlebarInfoPopulatedAero)
-    return;
-  nsIWidget* widget = aFrame->GetNearestWidget();
-  nsWindow * window = static_cast<nsWindow*>(widget);
-  if (!window)
-    return;
-  if (!window->IsTopLevelWidget() &&
-      !(window = window->GetParentWindow(false)))
-    return;
-
-  nsUXThemeData::UpdateTitlebarInfo(window->GetWindowHandle());
-}
-
 static bool
 IsTopLevelMenu(nsIFrame *aFrame)
 {
   bool isTopLevel(false);
   nsMenuFrame *menuFrame = do_QueryFrame(aFrame);
   if (menuFrame) {
     isTopLevel = menuFrame->IsOnMenuBar();
   }
@@ -2349,42 +2333,39 @@ nsNativeThemeWin::GetMinimumWidgetSize(n
       }
       break;
 
     case NS_THEME_WINDOW_BUTTON_MAXIMIZE:
     case NS_THEME_WINDOW_BUTTON_RESTORE:
       // The only way to get accurate titlebar button info is to query a
       // window w/buttons when it's visible. nsWindow takes care of this and
       // stores that info in nsUXThemeData.
-      QueryForButtonData(aFrame);
       aResult->width = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_RESTORE].cx;
       aResult->height = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_RESTORE].cy;
       // For XP, subtract 4 from system metrics dimensions.
       if (WinUtils::GetWindowsVersion() == WinUtils::WINXP_VERSION) {
         aResult->width -= 4;
         aResult->height -= 4;
       }
       AddPaddingRect(aResult, CAPTIONBUTTON_RESTORE);
       *aIsOverridable = false;
       return NS_OK;
 
     case NS_THEME_WINDOW_BUTTON_MINIMIZE:
-      QueryForButtonData(aFrame);
       aResult->width = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_MINIMIZE].cx;
       aResult->height = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_MINIMIZE].cy;
       if (WinUtils::GetWindowsVersion() == WinUtils::WINXP_VERSION) {
         aResult->width -= 4;
         aResult->height -= 4;
       }
       AddPaddingRect(aResult, CAPTIONBUTTON_MINIMIZE);
       *aIsOverridable = false;
       return NS_OK;
 
     case NS_THEME_WINDOW_BUTTON_CLOSE:
-      QueryForButtonData(aFrame);
       aResult->width = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_CLOSE].cx;
       aResult->height = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_CLOSE].cy;
       if (WinUtils::GetWindowsVersion() == WinUtils::WINXP_VERSION) {
         aResult->width -= 4;
         aResult->height -= 4;
       }
       AddPaddingRect(aResult, CAPTIONBUTTON_CLOSE);
       *aIsOverridable = false;
@@ -2396,17 +2377,16 @@ nsNativeThemeWin::GetMinimumWidgetSize(n
       aResult->height += GetSystemMetrics(SM_CYFRAME);
       aResult->height += GetSystemMetrics(SM_CXPADDEDBORDER);
       *aIsOverridable = false;
       return NS_OK;
 
     case NS_THEME_WINDOW_BUTTON_BOX:
     case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED:
       if (nsUXThemeData::CheckForCompositor()) {
-        QueryForButtonData(aFrame);
         aResult->width = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_BUTTONBOX].cx;
         aResult->height = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_BUTTONBOX].cy
                           - GetSystemMetrics(SM_CYFRAME)
                           - GetSystemMetrics(SM_CXPADDEDBORDER);
         if (aWidgetType == NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED) {
           aResult->width += 1;
           aResult->height -= 2;
         }
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -592,16 +592,22 @@ nsWindow::Create(nsIWidget *aParent,
     // bugs over the years, disable it (sTrimOnMinimize=1) on Vista and up.
     sTrimOnMinimize =
       Preferences::GetBool("config.trim_on_minimize",
         (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION)) ? 1 : 0;
     sSwitchKeyboardLayout =
       Preferences::GetBool("intl.keyboard.per_window_layout", false);
   }
 
+  // Query for command button metric data for rendering the titlebar. We
+  // only do this once on the first window.
+  if (!nsUXThemeData::sTitlebarInfoPopulatedThemed ||
+      !nsUXThemeData::sTitlebarInfoPopulatedAero) {
+    nsUXThemeData::UpdateTitlebarInfo(mWnd);
+  }
   return NS_OK;
 }
 
 // Close this nsWindow
 NS_METHOD nsWindow::Destroy()
 {
   // WM_DESTROY has already fired, avoid calling it twice
   if (mOnDestroyCalled)