merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 08 Oct 2014 15:45:22 +0200
changeset 209284 3a0d57d665bb7bab3ecd89ca32b0b2e8be79ad02
parent 209226 dd7637cc42d552747144724baac3e745db256fa4 (current diff)
parent 209283 60c38a8155cedfdd4b74fb38c478d9b9f8d05eee (diff)
child 209308 5eb604320844640653c24e17d7a86d9d4421dab6
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersmerge
milestone35.0a1
merge mozilla-inbound to mozilla-central a=merge
browser/base/content/test/general/privateBrowsingMode.js
js/src/jit-test/tests/basic/testErrorReportIn_getPrototypeOf.js
js/src/vm/ObjectImpl-inl.h
js/src/vm/ObjectImpl.cpp
js/src/vm/ObjectImpl.h
testing/xpcshell/xpcshell_android.ini
testing/xpcshell/xpcshell_b2g.ini
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1069071: IPDL changes require CLOBBER
+Bug 1069071: IPDL changes require CLOBBER (second time around)
--- a/accessible/base/ARIAMap.cpp
+++ b/accessible/base/ARIAMap.cpp
@@ -734,17 +734,17 @@ static const AttrCharacteristics gWAIUni
   {&nsGkAtoms::aria_valuetext,         ATTR_BYPASSOBJ                               }
 };
 
 namespace {
 
 struct RoleComparator
 {
   const nsDependentSubstring& mRole;
-  RoleComparator(const nsDependentSubstring& aRole) : mRole(aRole) {}
+  explicit RoleComparator(const nsDependentSubstring& aRole) : mRole(aRole) {}
   int operator()(const nsRoleMapEntry& aEntry) const {
     return Compare(mRole, aEntry.ARIARoleString());
   }
 };
 
 }
 
 nsRoleMapEntry*
--- a/accessible/generic/Accessible-inl.h
+++ b/accessible/generic/Accessible-inl.h
@@ -62,12 +62,20 @@ Accessible::HasNumericValue() const
 
 inline void
 Accessible::ScrollTo(uint32_t aHow) const
 {
   if (mContent)
     nsCoreUtils::ScrollTo(mDoc->PresShell(), mContent, aHow);
 }
 
+inline bool
+Accessible::UpdateChildren()
+{
+  AutoTreeMutation mut(this);
+  InvalidateChildren();
+  return EnsureChildren();
+}
+
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -1931,30 +1931,34 @@ Accessible::BindToParent(Accessible* aPa
       NS_ERROR("Binding to the same parent!");
       return;
     }
   }
 
   mParent = aParent;
   mIndexInParent = aIndexInParent;
 
-  mParent->InvalidateChildrenGroupInfo();
+#ifdef DEBUG
+  AssertInMutatingSubtree();
+#endif
 
   // Note: this is currently only used for richlistitems and their children.
   if (mParent->HasNameDependentParent() || mParent->IsXULListItem())
     mContextFlags |= eHasNameDependentParent;
   else
     mContextFlags &= ~eHasNameDependentParent;
 }
 
 // Accessible protected
 void
 Accessible::UnbindFromParent()
 {
-  mParent->InvalidateChildrenGroupInfo();
+#ifdef DEBUG
+  AssertInMutatingSubtree();
+#endif
   mParent = nullptr;
   mIndexInParent = -1;
   mIndexOfEmbeddedChild = -1;
   mGroupInfo = nullptr;
   mContextFlags &= ~eHasNameDependentParent;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -2653,16 +2657,31 @@ Accessible::StaticAsserts() const
   static_assert(eLastAccType <= (1 << kTypeBits) - 1,
                 "Accessible::mType was oversized by eLastAccType!");
   static_assert(eLastContextFlag <= (1 << kContextFlagsBits) - 1,
                 "Accessible::mContextFlags was oversized by eLastContextFlag!");
   static_assert(eLastAccGenericType <= (1 << kGenericTypesBits) - 1,
                 "Accessible::mGenericType was oversized by eLastAccGenericType!");
 }
 
+void
+Accessible::AssertInMutatingSubtree() const
+{
+  if (IsDoc() || IsApplication())
+    return;
+
+  const Accessible *acc = this;
+  while (!acc->IsDoc() && !(acc->mStateFlags & eSubtreeMutating)) {
+    acc = acc->Parent();
+    if (!acc)
+      return;
+  }
+
+  MOZ_ASSERT(acc->mStateFlags & eSubtreeMutating);
+}
 
 ////////////////////////////////////////////////////////////////////////////////
 // KeyBinding class
 
 // static
 uint32_t
 KeyBinding::AccelModifier()
 {
--- a/accessible/generic/Accessible.h
+++ b/accessible/generic/Accessible.h
@@ -368,21 +368,17 @@ public:
    * Set the ARIA role map entry for a new accessible.
    */
   void SetRoleMapEntry(nsRoleMapEntry* aRoleMapEntry)
     { mRoleMapEntry = aRoleMapEntry; }
 
   /**
    * Update the children cache.
    */
-  inline bool UpdateChildren()
-  {
-    InvalidateChildren();
-    return EnsureChildren();
-  }
+  bool UpdateChildren();
 
   /**
    * Cache children if necessary. Return true if the accessible is defunct.
    */
   bool EnsureChildren();
 
   /**
    * Set the child count to -1 (unknown) and null out cached child pointers.
@@ -943,17 +939,18 @@ protected:
    */
   enum StateFlags {
     eIsDefunct = 1 << 0, // accessible is defunct
     eIsNotInDocument = 1 << 1, // accessible is not in document
     eSharedNode = 1 << 2, // accessible shares DOM node from another accessible
     eNotNodeMapEntry = 1 << 3, // accessible shouldn't be in document node map
     eHasNumericValue = 1 << 4, // accessible has a numeric value
     eGroupInfoDirty = 1 << 5, // accessible needs to update group info
-    eIgnoreDOMUIEvent = 1 << 6, // don't process DOM UI events for a11y events
+    eSubtreeMutating = 1 << 6, // subtree is being mutated
+    eIgnoreDOMUIEvent = 1 << 7, // don't process DOM UI events for a11y events
 
     eLastStateFlag = eIgnoreDOMUIEvent
   };
 
   /**
    * Flags used for contextual information about the accessible.
    */
   enum ContextFlags {
@@ -1059,34 +1056,36 @@ protected:
   nsCOMPtr<nsIContent> mContent;
   DocAccessible* mDoc;
 
   nsRefPtr<Accessible> mParent;
   nsTArray<nsRefPtr<Accessible> > mChildren;
   int32_t mIndexInParent;
 
   static const uint8_t kChildrenFlagsBits = 2;
-  static const uint8_t kStateFlagsBits = 7;
+  static const uint8_t kStateFlagsBits = 8;
   static const uint8_t kContextFlagsBits = 1;
   static const uint8_t kTypeBits = 6;
   static const uint8_t kGenericTypesBits = 13;
 
   /**
    * Keep in sync with ChildrenFlags, StateFlags, ContextFlags, and AccTypes.
    */
   uint32_t mChildrenFlags : kChildrenFlagsBits;
   uint32_t mStateFlags : kStateFlagsBits;
   uint32_t mContextFlags : kContextFlagsBits;
   uint32_t mType : kTypeBits;
   uint32_t mGenericTypes : kGenericTypesBits;
 
   void StaticAsserts() const;
+  void AssertInMutatingSubtree() const;
 
   friend class DocAccessible;
   friend class xpcAccessible;
+  friend class AutoTreeMutation;
 
   nsAutoPtr<mozilla::a11y::EmbeddedObjCollector> mEmbeddedObjCollector;
   int32_t mIndexOfEmbeddedChild;
   friend class EmbeddedObjCollector;
 
   nsAutoPtr<AccGroupInfo> mGroupInfo;
   friend class AccGroupInfo;
 
@@ -1160,12 +1159,41 @@ public:
 private:
   void ToPlatformFormat(nsAString& aValue) const;
   void ToAtkFormat(nsAString& aValue) const;
 
   uint32_t mKey;
   uint32_t mModifierMask;
 };
 
+/**
+ * This class makes sure required tasks are done before and after tree
+ * mutations. Currently this only includes group info invalidation. You must
+ * have an object of this class on the stack when calling methods that mutate
+ * the accessible tree.
+ */
+class AutoTreeMutation
+{
+public:
+  AutoTreeMutation(Accessible* aRoot, bool aInvalidationRequired = true) :
+    mInvalidationRequired(aInvalidationRequired), mRoot(aRoot)
+  {
+    MOZ_ASSERT(!(mRoot->mStateFlags & Accessible::eSubtreeMutating));
+    mRoot->mStateFlags |= Accessible::eSubtreeMutating;
+  }
+  ~AutoTreeMutation()
+  {
+    if (mInvalidationRequired)
+      mRoot->InvalidateChildrenGroupInfo();
+
+    MOZ_ASSERT(mRoot->mStateFlags & Accessible::eSubtreeMutating);
+    mRoot->mStateFlags &= ~Accessible::eSubtreeMutating;
+  }
+
+  bool mInvalidationRequired;
+private:
+  Accessible* mRoot;
+};
+
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -478,17 +478,23 @@ DocAccessible::Shutdown()
     mVirtualCursor = nullptr;
   }
 
   mPresShell->SetDocAccessible(nullptr);
   mPresShell = nullptr;  // Avoid reentrancy
 
   mDependentIDsHash.Clear();
   mNodeToAccessibleMap.Clear();
-  ClearCache(mAccessibleCache);
+
+  {
+    // We're about to get rid of all of our children so there won't be anything
+    // to invalidate.
+    AutoTreeMutation mut(this, false);
+    ClearCache(mAccessibleCache);
+  }
 
   HyperTextAccessibleWrap::Shutdown();
 
   GetAccService()->NotifyOfDocumentShutdown(kungFuDeathGripDoc);
 }
 
 nsIFrame*
 DocAccessible::GetFrame() const
@@ -1313,18 +1319,20 @@ DocAccessible::ProcessInvalidationList()
       Accessible* container = GetContainerAccessible(content);
       if (container) {
         container->UpdateChildren();
         accessible = GetAccessible(content);
       }
     }
 
     // Make sure the subtree is created.
-    if (accessible)
+    if (accessible) {
+      AutoTreeMutation mut(accessible);
       CacheChildrenInSubtree(accessible);
+    }
   }
 
   mInvalidationList.Clear();
 }
 
 Accessible*
 DocAccessible::GetAccessibleEvenIfNotInMap(nsINode* aNode) const
 {
@@ -1420,17 +1428,19 @@ DocAccessible::DoInitialUpdate()
   // miss the notification (since content tree change notifications are ignored
   // prior to initial update). Make sure the content element is valid.
   nsIContent* contentElm = nsCoreUtils::GetRoleContent(mDocumentNode);
   if (mContent != contentElm) {
     mContent = contentElm;
     SetRoleMapEntry(aria::GetRoleMap(mContent));
   }
 
-  // Build initial tree.
+  // Build initial tree.  Since its the initial tree there's no group info to
+  // invalidate.
+  AutoTreeMutation mut(this, false);
   CacheChildrenInSubtree(this);
 
   // Fire reorder event after the document tree is constructed. Note, since
   // this reorder event is processed by parent document then events targeted to
   // this document may be fired prior to this reorder event. If this is
   // a problem then consider to keep event processing per tab document.
   if (!IsRoot()) {
     nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(Parent());
@@ -1654,16 +1664,19 @@ DocAccessible::ProcessContentInserted(Ac
         // there is no HTML body element.
       }
 
       // XXX: Invalidate parent-child relations for container accessible and its
       // children because there's no good way to find insertion point of new child
       // accessibles into accessible tree. We need to invalidate children even
       // there's no inserted accessibles in the end because accessible children
       // are created while parent recaches child accessibles.
+      // XXX Group invalidation here may be redundant with invalidation in
+      // UpdateTree.
+      AutoTreeMutation mut(aContainer);
       aContainer->InvalidateChildren();
       CacheChildrenInSubtree(aContainer);
     }
 
     UpdateTree(aContainer, aInsertedContent->ElementAt(idx), true);
   }
 }
 
@@ -1686,16 +1699,17 @@ DocAccessible::UpdateTree(Accessible* aC
     else
       logging::MsgEntry("child accessible: null");
 
     logging::MsgEnd();
   }
 #endif
 
   nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(aContainer);
+  AutoTreeMutation mut(aContainer);
 
   if (child) {
     updateFlags |= UpdateTreeInternal(child, aIsInsert, reorderEvent);
   } else {
     if (aIsInsert) {
       TreeWalker walker(aContainer, aChildNode, TreeWalker::eWalkCache);
 
       while ((child = walker.NextChild()))
--- a/accessible/html/HTMLImageMapAccessible.cpp
+++ b/accessible/html/HTMLImageMapAccessible.cpp
@@ -80,33 +80,34 @@ HTMLImageMapAccessible::UpdateChildAreas
 {
   nsImageFrame* imageFrame = do_QueryFrame(mContent->GetPrimaryFrame());
 
   // If image map is not initialized yet then we trigger one time more later.
   nsImageMap* imageMapObj = imageFrame->GetExistingImageMap();
   if (!imageMapObj)
     return;
 
-  bool doReorderEvent = false;
+  bool treeChanged = false;
+  AutoTreeMutation mut(this);
   nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(this);
 
   // Remove areas that are not a valid part of the image map anymore.
   for (int32_t childIdx = mChildren.Length() - 1; childIdx >= 0; childIdx--) {
     Accessible* area = mChildren.ElementAt(childIdx);
     if (area->GetContent()->GetPrimaryFrame())
       continue;
 
     if (aDoFireEvents) {
       nsRefPtr<AccHideEvent> event = new AccHideEvent(area, area->GetContent());
       mDoc->FireDelayedEvent(event);
       reorderEvent->AddSubMutationEvent(event);
-      doReorderEvent = true;
     }
 
     RemoveChild(area);
+    treeChanged = true;
   }
 
   // Insert new areas into the tree.
   uint32_t areaElmCount = imageMapObj->AreaCount();
   for (uint32_t idx = 0; idx < areaElmCount; idx++) {
     nsIContent* areaContent = imageMapObj->GetAreaAt(idx);
 
     Accessible* area = mChildren.SafeElementAt(idx);
@@ -118,24 +119,28 @@ HTMLImageMapAccessible::UpdateChildAreas
         mDoc->UnbindFromDocument(area);
         break;
       }
 
       if (aDoFireEvents) {
         nsRefPtr<AccShowEvent> event = new AccShowEvent(area, areaContent);
         mDoc->FireDelayedEvent(event);
         reorderEvent->AddSubMutationEvent(event);
-        doReorderEvent = true;
       }
+
+      treeChanged = true;
     }
   }
 
   // Fire reorder event if needed.
-  if (doReorderEvent)
+  if (treeChanged && aDoFireEvents)
     mDoc->FireDelayedEvent(reorderEvent);
+
+  if (!treeChanged)
+    mut.mInvalidationRequired = false;
 }
 
 Accessible*
 HTMLImageMapAccessible::GetChildAccessibleFor(const nsINode* aNode) const
 {
   uint32_t length = mChildren.Length();
   for (uint32_t i = 0; i < length; i++) {
     Accessible* area = mChildren[i];
--- a/accessible/jsat/OutputGenerator.jsm
+++ b/accessible/jsat/OutputGenerator.jsm
@@ -380,16 +380,24 @@ let OutputGenerator = {
         }, {
           string: this._getOutputName('tblRowInfo'),
           count: table.rowCount
         });
         this._addName(output, aAccessible, aFlags);
         this._addLandmark(output, aAccessible);
         return output;
       }
+    },
+
+    gridcell: function gridcell(aAccessible, aRoleStr, aState, aFlags) {
+      let output = [];
+      this._addState(output, aState);
+      this._addName(output, aAccessible, aFlags);
+      this._addLandmark(output, aAccessible);
+      return output;
     }
   }
 };
 
 /**
  * Generates speech utterances from objects, actions and state changes.
  * An utterance is an array of speech data.
  *
--- a/accessible/tests/mochitest/jsat/test_output.html
+++ b/accessible/tests/mochitest/jsat/test_output.html
@@ -435,16 +435,22 @@ https://bugzilla.mozilla.org/show_bug.cg
           oldAccOrElmOrID: "grid",
           expectedUtterance: [["3"], ["3"]],
           expectedBraille: [["3"], ["3"]]
         }, {
           accOrElmOrID: "gridcell2",
           oldAccOrElmOrID: "grid",
           expectedUtterance: [["4", "7"], ["4", "7"]],
           expectedBraille: [["4", "7"], ["4", "7"]]
+        }, {
+          accOrElmOrID: "gridcell3",
+          oldAccOrElmOrID: "grid",
+          expectedUtterance: [[{"string": "stateSelected"}, "5"],
+                              ["5", {"string": "stateSelected"}]],
+          expectedBraille: [["5"], ["5"]],
         }];
 
         // Test all possible utterance order preference values.
         tests.forEach(function run(test) {
           var utteranceOrderValues = [0, 1];
           utteranceOrderValues.forEach(
             function testUtteranceOrder(utteranceOrder) {
               SpecialPowers.setIntPref(PREF_UTTERANCE_ORDER, utteranceOrder);
@@ -576,15 +582,15 @@ https://bugzilla.mozilla.org/show_bug.cg
         </ol>
         <ol role="row">
           <li id="rowheader" role="rowheader" aria-label="Week 1">1</li>
           <li id="gridcell1" role="gridcell"><span>3</span><div></div></li>
           <li id="gridcell2" role="gridcell"><span>4</span><div>7</div></li>
         </ol>
         <ol role="row">
           <li role="rowheader">2</li>
-          <li role="gridcell">5</li>
+          <li id="gridcell3" aria-selected="true" role="gridcell">5</li>
           <li role="gridcell">6</li>
         </ol>
       </section>
     </div>
   </body>
 </html>
--- a/b2g/installer/Makefile.in
+++ b/b2g/installer/Makefile.in
@@ -52,18 +52,20 @@ endif
 endif
 
 include $(topsrcdir)/toolkit/mozapps/installer/packager.mk
 
 # Note that JS_BINARY can be defined in packager.mk, so this test must come after
 # including that file. MOZ_PACKAGER_MINIFY_JS is used in packager.mk, but since
 # recipe evaluation is deferred, we can set it here after the inclusion.
 ifneq (,$(JS_BINARY))
+ifndef MOZ_DEBUG
 MOZ_PACKAGER_MINIFY_JS=1
 endif
+endif
 
 ifeq (bundle, $(MOZ_FS_LAYOUT))
 BINPATH = $(_BINPATH)
 DEFINES += -DAPPNAME=$(_APPNAME)
 else
 # Every other platform just winds up in dist/bin
 BINPATH = bin
 endif
--- a/browser/base/content/test/general/mochitest.ini
+++ b/browser/base/content/test/general/mochitest.ini
@@ -18,17 +18,16 @@ support-files =
   offlineChild.cacheManifest^headers^
   offlineChild.html
   offlineChild2.cacheManifest
   offlineChild2.cacheManifest^headers^
   offlineChild2.html
   offlineEvent.cacheManifest
   offlineEvent.cacheManifest^headers^
   offlineEvent.html
-  privateBrowsingMode.js
   subtst_contextmenu.html
   video.ogg
 
 [test_bug364677.html]
 [test_bug395533.html]
 [test_contextmenu.html]
 skip-if = toolkit == "gtk2" || toolkit == "gtk3" # disabled on Linux due to bug 513558
 [test_contextmenu_input.html]
deleted file mode 100644
--- a/browser/base/content/test/general/privateBrowsingMode.js
+++ /dev/null
@@ -1,3 +0,0 @@
-// This file is only present in per-window private browsing buikds.
-var perWindowPrivateBrowsing = true;
-
--- a/browser/base/content/test/general/test_contextmenu.html
+++ b/browser/base/content/test/general/test_contextmenu.html
@@ -10,18 +10,16 @@
 <body>
 Browser context menu tests.
 <p id="display"></p>
 
 <div id="content">
 </div>
 
 <pre id="test">
-<script> var perWindowPrivateBrowsing = false; </script>
-<script type="text/javascript" src="privateBrowsingMode.js"></script>
 <script type="text/javascript" src="contextmenu_common.js"></script>
 <script class="testbody" type="text/javascript">
 
 SpecialPowers.Cu.import("resource://gre/modules/InlineSpellChecker.jsm", window);
 
 const Ci = SpecialPowers.Ci;
 
 function executeCopyCommand(command, expectedValue)
@@ -106,36 +104,25 @@ function runTest(testNum) {
                          ].concat(inspectItems);
         checkContextMenu(plainTextItems);
         closeContextMenu();
         openContextMenuFor(link); // Invoke context menu for next test.
     },
 
     function () {
         // Context menu for text link
-        if (perWindowPrivateBrowsing) {
-          checkContextMenu(["context-openlinkintab", true,
-                            "context-openlink",      true,
-                            "context-openlinkprivate", true,
-                            "---",                   null,
-                            "context-bookmarklink",  true,
-                            "context-savelink",      true,
-                            "context-copylink",      true,
-                            "context-searchselect",  true
-                           ].concat(inspectItems));
-        } else {
-          checkContextMenu(["context-openlinkintab", true,
-                            "context-openlink",      true,
-                            "---",                   null,
-                            "context-bookmarklink",  true,
-                            "context-savelink",      true,
-                            "context-copylink",      true,
-                            "context-searchselect",  true
-                           ].concat(inspectItems));
-        }
+        checkContextMenu(["context-openlinkintab", true,
+                          "context-openlink",      true,
+                          "context-openlinkprivate", true,
+                          "---",                   null,
+                          "context-bookmarklink",  true,
+                          "context-savelink",      true,
+                          "context-copylink",      true,
+                          "context-searchselect",  true
+                         ].concat(inspectItems));
         closeContextMenu();
         openContextMenuFor(mailto); // Invoke context menu for next test.
     },
 
     function () {
         // Context menu for text mailto-link
         checkContextMenu(["context-copyemail", true,
                           "context-searchselect", true
@@ -582,90 +569,56 @@ function runTest(testNum) {
         selectText(selecttextlink); // Select text prior to opening context menu.
         openContextMenuFor(selecttextlink); // Invoke context menu for next test.
     },
 
     function () {
         // Context menu for selected text which matches valid URL pattern
         if (SpecialPowers.Services.appinfo.OS == "Darwin") {
           // This test is only enabled on Mac due to bug 736399.
-          if (perWindowPrivateBrowsing) {
-            checkContextMenu(["context-openlinkincurrent",           true,
-                              "context-openlinkintab",               true,
-                              "context-openlink",                    true,
-                              "context-openlinkprivate",             true,
-                              "---",                                 null,
-                              "context-bookmarklink",                true,
-                              "context-savelink",                    true,
-                              "context-copy",                        true,
-                              "context-selectall",                   true,
-                              "---",                                 null,
-                              "context-searchselect",                true,
-                              "context-viewpartialsource-selection", true
-                             ].concat(inspectItems));
-          } else {
-            checkContextMenu(["context-openlinkincurrent",           true,
-                              "context-openlinkintab",               true,
-                              "context-openlink",                    true,
-                              "---",                                 null,
-                              "context-bookmarklink",                true,
-                              "context-savelink",                    true,
-                              "context-copy",                        true,
-                              "context-selectall",                   true,
-                              "---",                                 null,
-                              "context-searchselect",                true,
-                              "context-viewpartialsource-selection", true
-                             ].concat(inspectItems));
-          }
+          checkContextMenu(["context-openlinkincurrent",           true,
+                            "context-openlinkintab",               true,
+                            "context-openlink",                    true,
+                            "context-openlinkprivate",             true,
+                            "---",                                 null,
+                            "context-bookmarklink",                true,
+                            "context-savelink",                    true,
+                            "context-copy",                        true,
+                            "context-selectall",                   true,
+                            "---",                                 null,
+                            "context-searchselect",                true,
+                            "context-viewpartialsource-selection", true
+                           ].concat(inspectItems));
         }
         closeContextMenu();
         // clear the selection because following tests don't expect any selection
         subwindow.getSelection().removeAllRanges();
 
         openContextMenuFor(imagelink)
     },
 
     function () {
         // Context menu for image link
-        if (perWindowPrivateBrowsing) {
-          checkContextMenu(["context-openlinkintab", true,
-                            "context-openlink",      true,
-                            "context-openlinkprivate", true,
-                            "---",                   null,
-                            "context-bookmarklink",  true,
-                            "context-savelink",      true,
-                            "context-copylink",      true,
-                            "---",                   null,
-                            "context-viewimage",            true,
-                            "context-copyimage-contents",   true,
-                            "context-copyimage",            true,
-                            "---",                          null,
-                            "context-saveimage",            true,
-                            "context-sendimage",            true,
-                            "context-setDesktopBackground", true,
-                            "context-viewimageinfo",        true
-                           ].concat(inspectItems));
-        } else {
-          checkContextMenu(["context-openlinkintab", true,
-                            "context-openlink",      true,
-                            "---",                   null,
-                            "context-bookmarklink",  true,
-                            "context-savelink",      true,
-                            "context-copylink",      true,
-                            "---",                   null,
-                            "context-viewimage",            true,
-                            "context-copyimage-contents",   true,
-                            "context-copyimage",            true,
-                            "---",                          null,
-                            "context-saveimage",            true,
-                            "context-sendimage",            true,
-                            "context-setDesktopBackground", true,
-                            "context-viewimageinfo",        true
-                           ].concat(inspectItems));
-        }
+        checkContextMenu(["context-openlinkintab", true,
+                          "context-openlink",      true,
+                          "context-openlinkprivate", true,
+                          "---",                   null,
+                          "context-bookmarklink",  true,
+                          "context-savelink",      true,
+                          "context-copylink",      true,
+                          "---",                   null,
+                          "context-viewimage",            true,
+                          "context-copyimage-contents",   true,
+                          "context-copyimage",            true,
+                          "---",                          null,
+                          "context-saveimage",            true,
+                          "context-sendimage",            true,
+                          "context-setDesktopBackground", true,
+                          "context-viewimageinfo",        true
+                         ].concat(inspectItems));
         closeContextMenu();
         selectInputText(select_inputtext); // Select text prior to opening context menu.
         openContextMenuFor(select_inputtext); // Invoke context menu for next test.
     },
 
     function () {
         // Context menu for selected text in input
         checkContextMenu(["context-undo",        false,
--- a/browser/components/dirprovider/tests/unit/xpcshell.ini
+++ b/browser/components/dirprovider/tests/unit/xpcshell.ini
@@ -1,7 +1,8 @@
 [DEFAULT]
 head = head_dirprovider.js
 tail = 
 firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 
 [test_bookmark_pref.js]
 [test_keys.js]
--- a/browser/components/downloads/test/unit/xpcshell.ini
+++ b/browser/components/downloads/test/unit/xpcshell.ini
@@ -1,6 +1,7 @@
 [DEFAULT]
 head = head.js
 tail =
 firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 
 [test_DownloadsCommon.js]
--- a/browser/components/feeds/test/unit/xpcshell.ini
+++ b/browser/components/feeds/test/unit/xpcshell.ini
@@ -1,7 +1,8 @@
 [DEFAULT]
 head = head_feeds.js
 tail = 
 firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 
 [test_355473.js]
 [test_758990.js]
--- a/browser/components/loop/test/xpcshell/xpcshell.ini
+++ b/browser/components/loop/test/xpcshell/xpcshell.ini
@@ -1,12 +1,13 @@
 [DEFAULT]
 head = head.js
 tail =
 firefox-appdir = browser
+skip-if = toolkit == 'gonk'
 
 [test_loopapi_hawk_request.js]
 [test_looppush_initialize.js]
 [test_loopservice_directcall.js]
 [test_loopservice_dnd.js]
 [test_loopservice_expiry.js]
 [test_loopservice_hawk_errors.js]
 [test_loopservice_loop_prefs.js]
--- a/browser/components/migration/tests/unit/xpcshell.ini
+++ b/browser/components/migration/tests/unit/xpcshell.ini
@@ -1,7 +1,8 @@
 [DEFAULT]
 head = head_migration.js
 tail =
 firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 
 [test_IE_bookmarks.js]
 skip-if = os != "win"
--- a/browser/components/places/tests/unit/xpcshell.ini
+++ b/browser/components/places/tests/unit/xpcshell.ini
@@ -1,12 +1,13 @@
 [DEFAULT]
 head = head_bookmarks.js
 tail =
 firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 support-files =
   bookmarks.glue.html
   bookmarks.glue.json
   corruptDB.sqlite
   distribution.ini
 
 [test_421483.js]
 [test_browserGlue_bookmarkshtml.js]
--- a/browser/components/sessionstore/test/unit/xpcshell.ini
+++ b/browser/components/sessionstore/test/unit/xpcshell.ini
@@ -1,12 +1,13 @@
 [DEFAULT]
 head = head.js
 tail =
 firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 support-files =
   data/sessionCheckpoints_all.json
   data/sessionstore_invalid.js
   data/sessionstore_valid.js
 
 [test_backup_once.js]
 [test_startup_nosession_async.js]
 [test_startup_session_async.js]
--- a/browser/components/shell/test/unit/xpcshell.ini
+++ b/browser/components/shell/test/unit/xpcshell.ini
@@ -1,6 +1,7 @@
 [DEFAULT]
 head = 
 tail = 
 firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 
 [test_421977.js]
--- a/browser/components/translation/test/unit/xpcshell.ini
+++ b/browser/components/translation/test/unit/xpcshell.ini
@@ -1,7 +1,8 @@
 [DEFAULT]
 head = 
 tail = 
 firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 
 [test_cld2.js]
 [test_healthreport.js]
--- a/browser/devtools/shared/test/unit/xpcshell.ini
+++ b/browser/devtools/shared/test/unit/xpcshell.ini
@@ -1,8 +1,9 @@
 [DEFAULT]
 head =
 tail =
 firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 
 [test_bezierCanvas.js]
 [test_cubicBezier.js]
 [test_undoStack.js]
--- a/browser/devtools/styleinspector/test/unit/xpcshell.ini
+++ b/browser/devtools/styleinspector/test/unit/xpcshell.ini
@@ -1,7 +1,8 @@
 [DEFAULT]
 head =
 tail =
 firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 
 [test_parseDeclarations.js]
 [test_parseSingleValue.js]
--- a/browser/experiments/test/xpcshell/xpcshell.ini
+++ b/browser/experiments/test/xpcshell/xpcshell.ini
@@ -1,12 +1,13 @@
 [DEFAULT]
 head = head.js
 tail =
 firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 support-files =
   experiments_1.manifest
   experiment-1.xpi
   experiment-1a.xpi
   experiment-2.xpi
   experiment-racybranch.xpi
 generated-files =
   experiment-1.xpi
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -439,16 +439,19 @@
 @BINPATH@/components/nsUpdateService.js
 @BINPATH@/components/nsUpdateServiceStub.js
 #endif
 @BINPATH@/components/nsUpdateTimerManager.manifest
 @BINPATH@/components/nsUpdateTimerManager.js
 @BINPATH@/components/addoncompat.manifest
 @BINPATH@/components/multiprocessShims.js
 @BINPATH@/components/pluginGlue.manifest
+@BINPATH@/components/ProcessSingleton.manifest
+@BINPATH@/components/MainProcessSingleton.js
+@BINPATH@/components/ContentProcessSingleton.js
 @BINPATH@/browser/components/nsSessionStore.manifest
 @BINPATH@/browser/components/nsSessionStartup.js
 @BINPATH@/browser/components/nsSessionStore.js
 @BINPATH@/components/nsURLFormatter.manifest
 @BINPATH@/components/nsURLFormatter.js
 @BINPATH@/browser/components/@DLL_PREFIX@browsercomps@DLL_SUFFIX@
 @BINPATH@/components/txEXSLTRegExFunctions.manifest
 @BINPATH@/components/txEXSLTRegExFunctions.js
--- a/browser/locales/Makefile.in
+++ b/browser/locales/Makefile.in
@@ -69,17 +69,20 @@ STUB_HOOK = $(NSINSTALL) -D '$(_ABS_DIST
 endif
 
 ifeq ($(MOZ_WIDGET_TOOLKIT) $(DIST_SUBDIR),windows metro)
 SEARCHPLUGINS_NAMES = $(shell cat $(call MERGE_FILE,/searchplugins/metrolist.txt))
 else
 SEARCHPLUGINS_NAMES = $(shell cat $(call MERGE_FILE,/searchplugins/list.txt))
 endif
 SEARCHPLUGINS_PATH := $(FINAL_TARGET)/searchplugins
-SEARCHPLUGINS := $(addsuffix .xml,$(SEARCHPLUGINS_NAMES))
+# metro build call a searchplugins target for search engine plugins
+.PHONY: searchplugins
+SEARCHPLUGINS_TARGET := libs searchplugins
+SEARCHPLUGINS := $(foreach plugin,$(addsuffix .xml,$(SEARCHPLUGINS_NAMES)),$(or $(wildcard $(call MERGE_FILE,searchplugins/$(plugin))),$(info Missing searchplugin: $(plugin))))
 PP_TARGETS += SEARCHPLUGINS
 
 # Required for l10n.mk - defines a list of app sub dirs that should
 # be included in langpack xpis.
 ifdef MOZ_METRO
 # metro build, include both app folders
 DIST_SUBDIRS = browser metro
 else
@@ -114,20 +117,16 @@ NO_JA_JP_MAC_AB_CD := $(if $(filter ja-J
 libs:: $(FINAL_TARGET)/defaults/profile/bookmarks.html ;
 
 libs:: $(addprefix generic/profile/,$(PROFILE_FILES))
 	$(SYSINSTALL) $(IFLAGS1) $^ $(FINAL_TARGET)/defaults/profile
 
 libs:: $(call MERGE_FILES,$(addprefix profile/chrome/,$(PROFILE_CHROME)))
 	$(SYSINSTALL) $(IFLAGS1) $^ $(FINAL_TARGET)/defaults/profile/chrome
 
-# metro build calls back here for search engine plugins
-searchplugins: $(addprefix $(FINAL_TARGET)/searchplugins/,$(SEARCHPLUGINS))
-.PHONY: searchplugins
-
 libs-%:
 	$(NSINSTALL) -D $(DIST)/install
 	@$(MAKE) -C ../../toolkit/locales libs-$*
 	@$(MAKE) -C ../../services/sync/locales AB_CD=$* XPI_NAME=locale-$*
 ifdef MOZ_WEBAPP_RUNTIME
 	@$(MAKE) -C ../../webapprt/locales AB_CD=$* XPI_NAME=locale-$*
 endif
 	@$(MAKE) -C ../../extensions/spellcheck/locales AB_CD=$* XPI_NAME=locale-$*
--- a/browser/modules/test/unit/social/xpcshell.ini
+++ b/browser/modules/test/unit/social/xpcshell.ini
@@ -1,8 +1,9 @@
 [DEFAULT]
 head = head.js
 tail =
 firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 support-files = blocklist.xml
 
 [test_social.js]
 [test_socialDisabledStartup.js]
--- a/browser/modules/test/xpcshell/xpcshell.ini
+++ b/browser/modules/test/xpcshell/xpcshell.ini
@@ -1,6 +1,7 @@
 [DEFAULT]
 head =
 tail =
 firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 
 [test_DirectoryLinksProvider.js]
--- a/build/autoconf/compiler-opts.m4
+++ b/build/autoconf/compiler-opts.m4
@@ -321,16 +321,44 @@ if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -
              rm -rf conftest*])
          if test "$GC_SECTIONS_BREAKS_DEBUG_RANGES" = no; then
              DSO_LDOPTS="$DSO_LDOPTS -Wl,--gc-sections"
          fi
     else
         DSO_LDOPTS="$DSO_LDOPTS -Wl,--gc-sections"
     fi
 fi
+
+# bionic in Android < 4.1 doesn't support PIE
+# On OSX, the linker defaults to building PIE programs when targetting OSX 10.7+,
+# but not when targetting OSX < 10.7. OSX < 10.7 doesn't support running PIE
+# programs, so as long as support for OSX 10.6 is kept, we can't build PIE.
+# Even after dropping 10.6 support, MOZ_PIE would not be useful since it's the
+# default (and clang says the -pie option is not used).
+# On other Unix systems, some file managers (Nautilus) can't start PIE programs
+MOZ_PIE=
+
+MOZ_ARG_ENABLE_BOOL(pie,
+[  --enable-pie           Enable Position Independent Executables],
+    MOZ_PIE=1,
+    MOZ_PIE= )
+
+if test "$GNU_CC" -a -n "$MOZ_PIE"; then
+    AC_MSG_CHECKING([for PIE support])
+    _SAVE_LDFLAGS=$LDFLAGS
+    LDFLAGS="$LDFLAGS -pie"
+    AC_TRY_LINK(,,AC_MSG_RESULT([yes])
+                  [MOZ_PROGRAM_LDFLAGS="$MOZ_PROGRAM_LDFLAGS -pie"],
+                  AC_MSG_RESULT([no])
+                  AC_MSG_ERROR([--enable-pie requires PIE support from the linker.]))
+    LDFLAGS=$_SAVE_LDFLAGS
+fi
+
+AC_SUBST(MOZ_PROGRAM_LDFLAGS)
+
 ])
 
 dnl GCC and clang will fail if given an unknown warning option like -Wfoobar. 
 dnl But later versions won't fail if given an unknown negated warning option
 dnl like -Wno-foobar.  So when we are check for support of negated warning 
 dnl options, we actually test the positive form, but add the negated form to 
 dnl the flags variable.
 
--- a/chrome/test/unit/xpcshell.ini
+++ b/chrome/test/unit/xpcshell.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 head = head_crtestutils.js
 tail =
+skip-if = toolkit == 'gonk'
 support-files = data/**
 
 [test_abi.js]
 [test_bug292789.js]
 [test_bug380398.js]
 [test_bug397073.js]
 [test_bug399707.js]
 [test_bug401153.js]
--- a/chrome/test/unit_ipc/xpcshell.ini
+++ b/chrome/test/unit_ipc/xpcshell.ini
@@ -1,5 +1,6 @@
 [DEFAULT]
 head = 
 tail = 
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 
 [test_resolve_uris_ipc.js]
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -636,16 +636,18 @@ ifdef GNU_CC
 # Force rebuilding libraries and programs in both passes because each
 # pass uses different object files.
 $(PROGRAM) $(SHARED_LIBRARY) $(LIBRARY): FORCE
 endif
 endif
 
 endif # NO_PROFILE_GUIDED_OPTIMIZE
 
+MOZ_PROGRAM_LDFLAGS += $(MOZ_GLUE_PROGRAM_LDFLAGS)
+
 ##############################################
 
 checkout:
 	$(MAKE) -C $(topsrcdir) -f client.mk checkout
 
 clean clobber realclean clobber_all::
 	-$(RM) $(ALL_TRASH)
 	-$(RM) -r $(ALL_TRASH_DIRS)
@@ -668,17 +670,17 @@ alltags:
 #
 # PROGRAM = Foo
 # creates OBJS, links with LIBS to create Foo
 #
 $(PROGRAM): $(PROGOBJS) $(STATIC_LIBS_DEPS) $(EXTRA_DEPS) $(EXE_DEF_FILE) $(RESFILE) $(GLOBAL_DEPS)
 	$(REPORT_BUILD)
 	@$(RM) $@.manifest
 ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
-	$(EXPAND_LD) -NOLOGO -OUT:$@ -PDB:$(LINK_PDBFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(PROGOBJS) $(RESFILE) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS)
+	$(EXPAND_LD) -NOLOGO -OUT:$@ -PDB:$(LINK_PDBFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_PROGRAM_LDFLAGS) $(PROGOBJS) $(RESFILE) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS)
 ifdef MSMANIFEST_TOOL
 	@if test -f $@.manifest; then \
 		if test -f '$(srcdir)/$@.manifest'; then \
 			echo 'Embedding manifest from $(srcdir)/$@.manifest and $@.manifest'; \
 			mt.exe -NOLOGO -MANIFEST '$(win_srcdir)/$@.manifest' $@.manifest -OUTPUTRESOURCE:$@\;1; \
 		else \
 			echo 'Embedding manifest from $@.manifest'; \
 			mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \
@@ -689,17 +691,17 @@ ifdef MSMANIFEST_TOOL
 	fi
 endif	# MSVC with manifest tool
 ifdef MOZ_PROFILE_GENERATE
 # touch it a few seconds into the future to work around FAT's
 # 2-second granularity
 	touch -t `date +%Y%m%d%H%M.%S -d 'now+5seconds'` pgo.relink
 endif
 else # !WINNT || GNU_CC
-	$(EXPAND_CCC) -o $@ $(CXXFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(EXE_DEF_FILE) $(STLPORT_LIBS)
+	$(EXPAND_CCC) -o $@ $(CXXFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(EXE_DEF_FILE) $(STLPORT_LIBS)
 	$(call CHECK_BINARY,$@)
 endif # WINNT && !GNU_CC
 
 ifdef ENABLE_STRIP
 	$(STRIP) $(STRIP_FLAGS) $@
 endif
 ifdef MOZ_POST_PROGRAM_COMMAND
 	$(MOZ_POST_PROGRAM_COMMAND) $@
@@ -737,25 +739,25 @@ endif
 # Foo.o (from either Foo.c or Foo.cpp).
 #
 # SIMPLE_PROGRAMS = Foo Bar
 # creates Foo.o Bar.o, links with LIBS to create Foo, Bar.
 #
 $(SIMPLE_PROGRAMS): %$(BIN_SUFFIX): %.$(OBJ_SUFFIX) $(STATIC_LIBS_DEPS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
 	$(REPORT_BUILD)
 ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
-	$(EXPAND_LD) -nologo -out:$@ -pdb:$(LINK_PDBFILE) $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS)
+	$(EXPAND_LD) -nologo -out:$@ -pdb:$(LINK_PDBFILE) $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_PROGRAM_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS)
 ifdef MSMANIFEST_TOOL
 	@if test -f $@.manifest; then \
 		mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \
 		rm -f $@.manifest; \
 	fi
 endif	# MSVC with manifest tool
 else
-	$(EXPAND_CCC) $(CXXFLAGS) -o $@ $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(STLPORT_LIBS)
+	$(EXPAND_CCC) $(CXXFLAGS) -o $@ $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(STLPORT_LIBS)
 	$(call CHECK_BINARY,$@)
 endif # WINNT && !GNU_CC
 
 ifdef ENABLE_STRIP
 	$(STRIP) $(STRIP_FLAGS) $@
 endif
 ifdef MOZ_POST_PROGRAM_COMMAND
 	$(MOZ_POST_PROGRAM_COMMAND) $@
--- a/configure.in
+++ b/configure.in
@@ -1407,32 +1407,64 @@ if test "$GNU_CC"; then
                 else
                     DSO_LDOPTS="$DSO_LDOPTS -Wl,--warn-unresolved-symbols"
                 fi
                 ;;
             esac
         fi
     fi
 
-    # Turn on GNU-specific warnings:
+    # Turn on gcc/clang warnings:
+    # https://gcc.gnu.org/onlinedocs/gcc-4.4.0/gcc/Warning-Options.html
+    #
     # -Wall - turn on a lot of warnings
-    # -Wpointer-arith - good to have
+    # -Wchar-subscripts - catches array index using signed char
+    # -Wcomment - catches nested comments
     # -Wdeclaration-after-statement - MSVC doesn't like these
-    # -Werror=return-type - catches missing returns, zero false positives
-    # -Werror=int-to-pointer-cast - catches cast to pointer from integer of different size
-    # -Wtype-limits - catches overflow bugs, few false positives
     # -Wempty-body - catches bugs, e.g. "if (c); foo();", few false positives
+    # -Wendif-labels - catches `#else FOO` and `#endif FOO` not in comment
+    # -Wenum-compare - catches comparison of different enum types
+    # -Wignored-qualifiers - catches returns types with qualifiers like const
+    # -Wimplicit-int - catches C variable declaration without a type
+    # -Wint-to-pointer-cast - catches cast to pointer from integer of different size
+    # -Wmultichar - catches multicharacter integer constants like 'THIS'
+    # -Wnonnull - catches NULL used with functions arguments marked as non-null
+    # -Wpointer-arith - catches pointer arithmetic using NULL or sizeof(void)
+    # -Wpointer-sign - catches mixing pointers to signed and unsigned types
+    # -Wpointer-to-int-cast - catches casts from pointer to different sized int
+    # -Wreturn-type - catches missing returns, zero false positives
+    # -Wsequence-point - catches undefined order behavior like `a = a++`
     # -Wsign-compare - catches comparison of signed and unsigned types
+    # -Wtrigraphs - catches unlikely use of trigraphs
+    # -Wtype-limits - catches overflow bugs, few false positives
+    # -Wunknown-pragmas - catches unexpected #pragma directives
     #
-    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wall -Wpointer-arith -Wdeclaration-after-statement"
-    MOZ_C_SUPPORTS_WARNING(-W, error=return-type, ac_c_has_werror_return_type)
-    MOZ_C_SUPPORTS_WARNING(-W, error=int-to-pointer-cast, ac_c_has_werror_int_to_pointer_cast)
-    MOZ_C_SUPPORTS_WARNING(-W, type-limits, ac_c_has_wtype_limits)
-    MOZ_C_SUPPORTS_WARNING(-W, empty-body, ac_c_has_wempty_body)
-    MOZ_C_SUPPORTS_WARNING(-W, sign-compare, ac_c_has_sign_compare)
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wall"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wdeclaration-after-statement"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wempty-body"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wpointer-to-int-cast"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wsign-compare"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wtype-limits"
+
+    # Treat some warnings as errors:
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=char-subscripts"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=comment"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=endif-labels"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=enum-compare"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=ignored-qualifiers"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=implicit-int"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=int-to-pointer-cast"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=multichar"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=nonnull"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=pointer-arith"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=pointer-sign"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=return-type"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=sequence-point"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=trigraphs"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=unknown-pragmas"
 
     # Turn off the following warnings that -Wall turns on:
     # -Wno-unused - lots of violations in third-party code
     #
     _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wno-unused"
 
     if test -z "$INTEL_CC" -a -z "$CLANG_CC"; then
        # Don't use -Wcast-align with ICC or clang
@@ -1473,40 +1505,61 @@ else
     DSO_PIC_CFLAGS='-KPIC'
     _DEFINES_CFLAGS='$(ACDEFINES) -D_MOZILLA_CONFIG_H_ -DMOZILLA_CLIENT'
 fi
 
 if test "$GNU_CXX"; then
     # FIXME: Let us build with strict aliasing. bug 414641.
     CXXFLAGS="$CXXFLAGS -fno-exceptions -fno-strict-aliasing"
 
-    # Turn on GNU-specific warnings:
+    # Turn on gcc/clang warnings:
+    # https://gcc.gnu.org/onlinedocs/gcc-4.4.0/gcc/Warning-Options.html
+    #
     # -Wall - turn on a lot of warnings
-    # -Wpointer-arith - good to have
-    # -Woverloaded-virtual - ???
-    # -Werror=return-type - catches missing returns, zero false positives
-    # -Werror=int-to-pointer-cast - catches cast to pointer from integer of different size
-    # -Werror=type-limits - catches overflow bugs, few false positives
     # -Wempty-body - catches bugs, e.g. "if (c); foo();", few false positives
+    # -Wendif-labels - catches `#else FOO` and `#endif FOO` not in comment
+    # -Wint-to-pointer-cast - catches cast to pointer from integer of different size
+    # -Wmissing-braces - catches aggregate initializers missing nested braces
+    # -Woverloaded-virtual - function declaration hides virtual function from base class
+    # -Wparentheses - catches `if (a=b)` and operator precedence bugs
+    # -Wpointer-arith - catches pointer arithmetic using NULL or sizeof(void)
+    # -Wreturn-type - catches missing returns, zero false positives
+    # -Wsequence-point - catches undefined order behavior like `a = a++`
     # -Wsign-compare - catches comparison of signed and unsigned types
+    # -Wtrigraphs - catches unlikely use of trigraphs
+    # -Wtype-limits - catches overflow bugs, few false positives
+    # -Wunused-label - catches unused goto labels
+    # -Wwrite-strings - catches non-const char* pointers to string literals
     #
-    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall -Wpointer-arith -Woverloaded-virtual"
-    MOZ_CXX_SUPPORTS_WARNING(-W, error=return-type, ac_cxx_has_werror_return_type)
-    MOZ_CXX_SUPPORTS_WARNING(-W, error=int-to-pointer-cast, ac_cxx_has_werror_int_to_pointer_cast)
-    MOZ_CXX_SUPPORTS_WARNING(-W, error=type-limits, ac_cxx_has_werror_type_limits)
-    MOZ_CXX_SUPPORTS_WARNING(-W, empty-body, ac_cxx_has_wempty_body)
-    MOZ_CXX_SUPPORTS_WARNING(-W, sign-compare, ac_cxx_has_sign_compare)
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall"
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wempty-body"
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Woverloaded-virtual"
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wpointer-arith"
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wsign-compare"
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wwrite-strings"
+
+    # Treat some warnings as errors:
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=endif-labels"
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=int-to-pointer-cast"
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=missing-braces"
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=parentheses"
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=return-type"
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=sequence-point"
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=unused-label"
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=trigraphs"
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=type-limits"
 
     # Turn off the following warnings that -Wall turns on:
     # -Wno-invalid-offsetof - we use offsetof on non-POD types frequently
     # -Wno-inline-new-delete - we inline 'new' and 'delete' in mozalloc
     #   for performance reasons, and because GCC and clang accept it (though
     #   clang warns about it).
     #
-    MOZ_CXX_SUPPORTS_WARNING(-Wno-, invalid-offsetof, ac_cxx_has_wno_invalid_offsetof)
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-invalid-offsetof"
+
     MOZ_CXX_SUPPORTS_WARNING(-Wno-, inline-new-delete, ac_cxx_has_wno_inline_new_delete)
 
     if test -z "$INTEL_CXX" -a -z "$CLANG_CXX"; then
        # Don't use -Wcast-align with ICC or clang
        case "$CPU_ARCH" in
            # And don't use it on hppa, ia64, sparc, arm, since it's noisy there
            hppa | ia64 | sparc | arm)
            ;;
--- a/content/base/src/ImportManager.h
+++ b/content/base/src/ImportManager.h
@@ -65,17 +65,17 @@ class ImportLoader MOZ_FINAL : public ns
                              , public nsIDOMEventListener
 {
 
   // A helper inner class to decouple the logic of updating the import graph
   // after a new import link has been found by one of the parsers.
   class Updater {
 
   public:
-    Updater(ImportLoader* aLoader) : mLoader(aLoader)
+    explicit Updater(ImportLoader* aLoader) : mLoader(aLoader)
     {}
 
     // After a new link is added that refers to this import, we
     // have to update the spanning tree, since given this new link the
     // priority of this import might be higher in the scripts
     // execution order than before. It updates mMainReferrer, mImportParent,
     // the corresponding pending ScriptRunners, etc.
     // It also handles updating additional dependant loaders via the
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -550,17 +550,17 @@ nsIdentifierMapEntry::FireChangeCallback
   mChangeCallbacks->EnumerateEntries(FireChangeEnumerator, &args);
 }
 
 namespace {
 
 struct PositionComparator
 {
   Element* const mElement;
-  PositionComparator(Element* const aElement) : mElement(aElement) {}
+  explicit PositionComparator(Element* const aElement) : mElement(aElement) {}
 
   int operator()(void* aElement) const {
     Element* curElement = static_cast<Element*>(aElement);
     if (mElement == curElement) {
       return 0;
     }
     if (nsContentUtils::PositionIsBefore(mElement, curElement)) {
       return -1;
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -1730,17 +1730,17 @@ public:
     InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
     if (aCpows && !cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
       return false;
     }
     if (aIsSync) {
       return cc->SendSyncMessage(PromiseFlatString(aMessage), data, cpows,
                                  IPC::Principal(aPrincipal), aJSONRetVal);
     }
-    return cc->CallRpcMessage(PromiseFlatString(aMessage), data, cpows,
+    return cc->SendRpcMessage(PromiseFlatString(aMessage), data, cpows,
                               IPC::Principal(aPrincipal), aJSONRetVal);
   }
 
   virtual bool DoSendAsyncMessage(JSContext* aCx,
                                   const nsAString& aMessage,
                                   const mozilla::dom::StructuredCloneData& aData,
                                   JS::Handle<JSObject *> aCpows,
                                   nsIPrincipal* aPrincipal) MOZ_OVERRIDE
--- a/content/base/src/nsPlainTextSerializer.cpp
+++ b/content/base/src/nsPlainTextSerializer.cpp
@@ -1868,17 +1868,17 @@ struct interval
 {
   uint16_t first;
   uint16_t last;
 };
 
 struct CombiningComparator
 {
   const char16_t mUcs;
-  CombiningComparator(char16_t ucs) : mUcs(ucs) {}
+  explicit CombiningComparator(char16_t aUcs) : mUcs(aUcs) {}
   int operator()(const interval& combining) const {
     if (mUcs > combining.last)
       return 1;
     if (mUcs < combining.first)
       return -1;
 
     MOZ_ASSERT(combining.first <= mUcs);
     MOZ_ASSERT(mUcs <= combining.last);
--- a/content/base/test/unit/xpcshell.ini
+++ b/content/base/test/unit/xpcshell.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 head = head_utilities.js
 tail =
+skip-if = toolkit == 'gonk'
 support-files =
   1_original.xml
   1_result.xml
   2_original.xml
   2_result_1.xml
   2_result_2.xml
   2_result_3.xml
   2_result_4.xml
--- a/content/base/test/unit_ipc/xpcshell.ini
+++ b/content/base/test/unit_ipc/xpcshell.ini
@@ -1,6 +1,7 @@
 [DEFAULT]
 head =
 tail =
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 
 [test_bug553888_wrap.js]
 [test_xhr_document_ipc.js]
--- a/content/html/content/src/HTMLFormElement.cpp
+++ b/content/html/content/src/HTMLFormElement.cpp
@@ -2239,33 +2239,33 @@ HTMLFormElement::Clear()
   mPastNameLookupTable.Clear();
 }
 
 namespace {
 
 struct PositionComparator
 {
   nsIContent* const mElement;
-  PositionComparator(nsIContent* const element) : mElement(element) {}
+  explicit PositionComparator(nsIContent* const aElement) : mElement(aElement) {}
 
   int operator()(nsIContent* aElement) const {
     if (mElement == aElement) {
       return 0;
     }
     if (nsContentUtils::PositionIsBefore(mElement, aElement)) {
       return -1;
     }
     return 1;
   }
 };
 
 struct NodeListAdaptor
 {
   nsINodeList* const mList;
-  NodeListAdaptor(nsINodeList* aList) : mList(aList) {}
+  explicit NodeListAdaptor(nsINodeList* aList) : mList(aList) {}
   nsIContent* operator[](size_t aIdx) const {
     return mList->Item(aIdx);
   }
 };
 
 } // namespace
 
 nsresult
--- a/content/media/MediaDecoderStateMachine.cpp
+++ b/content/media/MediaDecoderStateMachine.cpp
@@ -2473,18 +2473,18 @@ nsresult MediaDecoderStateMachine::RunSt
         return NS_OK;
       }
 
       StopAudioThread();
       // When we're decoding to a stream, the stream's main-thread finish signal
       // will take care of calling MediaDecoder::PlaybackEnded.
       if (mDecoder->GetState() == MediaDecoder::PLAY_STATE_PLAYING &&
           !mDecoder->GetDecodedStream()) {
-        int64_t videoTime = HasVideo() ? mVideoFrameEndTime : 0;
-        int64_t clockTime = std::max(mEndTime, videoTime);
+        int64_t clockTime = std::max(mAudioEndTime, mVideoFrameEndTime);
+        clockTime = std::max(int64_t(0), std::max(clockTime, mEndTime));
         UpdatePlaybackPosition(clockTime);
 
         {
           // Wait for the state change is completed in the main thread,
           // otherwise we might see |mDecoder->GetState() == MediaDecoder::PLAY_STATE_PLAYING|
           // in next loop and send |MediaDecoder::PlaybackEnded| again to trigger 'ended'
           // event twice in the media element.
           ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
@@ -3138,17 +3138,23 @@ void MediaDecoderStateMachine::OnAudioSi
   AssertCurrentThreadInMonitor();
   // AudioSink not used with captured streams, so ignore errors in this case.
   if (mAudioCaptured) {
     return;
   }
 
   mAudioCompleted = true;
 
-  // Notify media decoder/element about this error.
+  // Make the best effort to continue playback when there is video.
+  if (HasVideo()) {
+    return;
+  }
+
+  // Otherwise notify media decoder/element about this error for it makes
+  // no sense to play an audio-only file without sound output.
   RefPtr<nsIRunnable> task(
     NS_NewRunnableMethod(this, &MediaDecoderStateMachine::OnDecodeError));
   nsresult rv = mDecodeTaskQueue->Dispatch(task);
   if (NS_FAILED(rv)) {
     DECODER_WARN("Failed to dispatch OnDecodeError");
   }
 }
 
--- a/content/media/webaudio/AudioBuffer.cpp
+++ b/content/media/webaudio/AudioBuffer.cpp
@@ -221,17 +221,17 @@ StealJSArrayDataIntoThreadSharedFloatArr
   for (uint32_t i = 0; i < aJSArrays.Length(); ++i) {
     JS::Rooted<JSObject*> arrayBufferView(aJSContext, aJSArrays[i]);
     JS::Rooted<JSObject*> arrayBuffer(aJSContext,
                                       JS_GetArrayBufferViewBuffer(aJSContext, arrayBufferView));
     uint8_t* stolenData = arrayBuffer
                           ? (uint8_t*) JS_StealArrayBufferContents(aJSContext, arrayBuffer)
                           : nullptr;
     if (stolenData) {
-      result->SetData(i, stolenData, reinterpret_cast<float*>(stolenData));
+      result->SetData(i, stolenData, js_free, reinterpret_cast<float*>(stolenData));
     } else {
       return nullptr;
     }
   }
   return result.forget();
 }
 
 ThreadSharedFloatArrayBufferList*
--- a/content/media/webaudio/AudioNodeEngine.h
+++ b/content/media/webaudio/AudioNodeEngine.h
@@ -33,50 +33,61 @@ public:
    * Construct with null data.
    */
   explicit ThreadSharedFloatArrayBufferList(uint32_t aCount)
   {
     mContents.SetLength(aCount);
   }
 
   struct Storage {
-    Storage()
-    {
-      mDataToFree = nullptr;
-      mSampleData = nullptr;
+    Storage() :
+      mDataToFree(nullptr),
+      mFree(nullptr),
+      mSampleData(nullptr)
+    {}
+    ~Storage() {
+      if (mFree) {
+        mFree(mDataToFree);
+      } else { MOZ_ASSERT(!mDataToFree); }
     }
-    ~Storage() { free(mDataToFree); }
     size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
     {
       // NB: mSampleData might not be owned, if it is it just points to
       //     mDataToFree.
       return aMallocSizeOf(mDataToFree);
     }
     void* mDataToFree;
+    void (*mFree)(void*);
     const float* mSampleData;
   };
 
   /**
    * This can be called on any thread.
    */
   uint32_t GetChannels() const { return mContents.Length(); }
   /**
    * This can be called on any thread.
    */
   const float* GetData(uint32_t aIndex) const { return mContents[aIndex].mSampleData; }
 
   /**
    * Call this only during initialization, before the object is handed to
    * any other thread.
    */
-  void SetData(uint32_t aIndex, void* aDataToFree, const float* aData)
+  void SetData(uint32_t aIndex, void* aDataToFree, void (*aFreeFunc)(void*), const float* aData)
   {
     Storage* s = &mContents[aIndex];
-    free(s->mDataToFree);
+    if (s->mFree) {
+      s->mFree(s->mDataToFree);
+    } else {
+      MOZ_ASSERT(!s->mDataToFree);
+    }
+
     s->mDataToFree = aDataToFree;
+    s->mFree = aFreeFunc;
     s->mSampleData = aData;
   }
 
   /**
    * Put this object into an error state where there are no channels.
    */
   void Clear() { mContents.Clear(); }
 
--- a/content/media/webaudio/ConvolverNode.cpp
+++ b/content/media/webaudio/ConvolverNode.cpp
@@ -253,17 +253,17 @@ ConvolverNode::SetBuffer(JSContext* aCx,
       // has enough data to compute FFTs from.
       length = WEBAUDIO_BLOCK_SIZE;
       nsRefPtr<ThreadSharedFloatArrayBufferList> paddedBuffer =
         new ThreadSharedFloatArrayBufferList(data->GetChannels());
       float* channelData = (float*) malloc(sizeof(float) * length * data->GetChannels());
       for (uint32_t i = 0; i < data->GetChannels(); ++i) {
         PodCopy(channelData + length * i, data->GetData(i), mBuffer->Length());
         PodZero(channelData + length * i + mBuffer->Length(), WEBAUDIO_BLOCK_SIZE - mBuffer->Length());
-        paddedBuffer->SetData(i, (i == 0) ? channelData : nullptr, channelData);
+        paddedBuffer->SetData(i, (i == 0) ? channelData : nullptr, free, channelData);
       }
       data = paddedBuffer;
     }
     SendInt32ParameterToStream(ConvolverNodeEngine::BUFFER_LENGTH, length);
     SendDoubleParameterToStream(ConvolverNodeEngine::SAMPLE_RATE,
                                 mBuffer->SampleRate());
     ns->SetBuffer(data.forget());
   } else {
--- a/content/media/webaudio/PeriodicWave.cpp
+++ b/content/media/webaudio/PeriodicWave.cpp
@@ -33,19 +33,19 @@ PeriodicWave::PeriodicWave(AudioContext*
   // Copy coefficient data. The two arrays share an allocation.
   mCoefficients = new ThreadSharedFloatArrayBufferList(2);
   float* buffer = static_cast<float*>(malloc(aLength*sizeof(float)*2));
   if (buffer == nullptr) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
   PodCopy(buffer, aRealData, aLength);
-  mCoefficients->SetData(0, buffer, buffer);
+  mCoefficients->SetData(0, buffer, free, buffer);
   PodCopy(buffer+aLength, aImagData, aLength);
-  mCoefficients->SetData(1, nullptr, buffer+aLength);
+  mCoefficients->SetData(1, nullptr, free, buffer+aLength);
 }
 
 size_t
 PeriodicWave::SizeOfExcludingThisIfNotShared(MallocSizeOf aMallocSizeOf) const
 {
   // Not owned:
   // - mContext
   size_t amount = 0;
--- a/content/media/webspeech/synth/ipc/PSpeechSynthesis.ipdl
+++ b/content/media/webspeech/synth/ipc/PSpeechSynthesis.ipdl
@@ -12,17 +12,17 @@ namespace dom {
 
 struct RemoteVoice {
   nsString voiceURI;
   nsString name;
   nsString lang;
   bool localService;
 };
 
-intr protocol PSpeechSynthesis
+sync protocol PSpeechSynthesis
 {
   manager PContent;
   manages PSpeechSynthesisRequest;
 
 child:
 
     VoiceAdded(RemoteVoice aVoice);
 
--- a/content/media/webspeech/synth/ipc/PSpeechSynthesisRequest.ipdl
+++ b/content/media/webspeech/synth/ipc/PSpeechSynthesisRequest.ipdl
@@ -4,17 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PSpeechSynthesis;
 
 namespace mozilla {
 namespace dom {
 
-intr protocol PSpeechSynthesisRequest
+async protocol PSpeechSynthesisRequest
 {
   manager PSpeechSynthesis;
 
  parent:
 
   Pause();
 
   Resume();
--- a/content/test/unit/xpcshell.ini
+++ b/content/test/unit/xpcshell.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 head = head_content.js
 tail =
+skip-if = toolkit == 'gonk'
 support-files =
   empty_document.xml
   isequalnode_data.xml
   nodelist_data_1.xml
   nodelist_data_2.xul
   test_delete_range.xml
 
 [test_isequalnode.js]
--- a/docshell/test/unit/xpcshell.ini
+++ b/docshell/test/unit/xpcshell.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 head = head_docshell.js
 tail = 
+skip-if = toolkit == 'gonk'
 
 [test_bug414201_jfif.js]
 [test_bug442584.js]
 [test_nsDefaultURIFixup.js]
 [test_nsDefaultURIFixup_search.js]
 skip-if = os == 'android'
 [test_nsDefaultURIFixup_info.js]
 skip-if = os == 'android'
--- a/docshell/test/unit_ipc/xpcshell.ini
+++ b/docshell/test/unit_ipc/xpcshell.ini
@@ -1,7 +1,8 @@
 [DEFAULT]
 head =
 tail =
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 
 [test_pb_notification_ipc.js]
 # Bug 751575: Perma-fails with: command timed out: 1200 seconds without output
 skip-if = true
--- a/dom/activities/tests/unit/xpcshell.ini
+++ b/dom/activities/tests/unit/xpcshell.ini
@@ -1,5 +1,6 @@
 [DEFAULT]
 head =
 tail =
+skip-if = toolkit == 'gonk'
 
 [test_activityFilters.js]
--- a/dom/base/URLSearchParams.cpp
+++ b/dom/base/URLSearchParams.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "URLSearchParams.h"
 #include "mozilla/dom/URLSearchParamsBinding.h"
 #include "mozilla/dom/EncodingUtils.h"
+#include "nsDOMString.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(URLSearchParams, mObservers)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(URLSearchParams)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(URLSearchParams)
 
@@ -225,17 +226,17 @@ void
 URLSearchParams::RemoveObservers()
 {
   mObservers.Clear();
 }
 
 void
 URLSearchParams::Get(const nsAString& aName, nsString& aRetval)
 {
-  aRetval.Truncate();
+  SetDOMStringToNull(aRetval);
 
   for (uint32_t i = 0, len = mSearchParams.Length(); i < len; ++i) {
     if (mSearchParams[i].mKey.Equals(aName)) {
       aRetval.Assign(mSearchParams[i].mValue);
       break;
     }
   }
 }
--- a/dom/base/test/test_urlSearchParams.html
+++ b/dom/base/test/test_urlSearchParams.html
@@ -1,17 +1,17 @@
 
 <!DOCTYPE HTML>
 <html>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=887836
 -->
 <head>
   <meta charset="utf-8">
-  <title>Test for Bug 887836</title>
+  <title>Test for URLSearchParams</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=887836">Mozilla Bug 887836</a>
 <p id="display"></p>
 <div id="content" style="display: none">
   <iframe name="x" id="x"></iframe>
@@ -25,17 +25,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 
   /** Test for Bug 887836 **/
   ok("URLSearchParams" in window, "window.URLSearchParams exists");
 
   function testSimpleURLSearchParams() {
     var u = new URLSearchParams();
     ok(u, "URLSearchParams created");
     is(u.has('foo'), false, 'URLSearchParams.has(foo)');
-    is(u.get('foo'), '', 'URLSearchParams.get(foo)');
+    is(u.get('foo'), null, 'URLSearchParams.get(foo)');
     is(u.getAll('foo').length, 0, 'URLSearchParams.getAll(foo)');
 
     u.append('foo', 'bar');
     is(u.has('foo'), true, 'URLSearchParams.has(foo)');
     is(u.get('foo'), 'bar', 'URLSearchParams.get(foo)');
     is(u.getAll('foo').length, 1, 'URLSearchParams.getAll(foo)');
 
     u.set('foo', 'bar2');
@@ -270,27 +270,41 @@ https://bugzilla.mozilla.org/show_bug.cg
 
     a.delete('a');
     is(a.getAll('a').length, 0, "Correct length of getAll()");
     is(a.toString(), "b=3&c=4&c=5", "Order is correct");
 
     runTest();
   }
 
+  function testGetNULL() {
+      
+    var u = new URLSearchParams();
+    is(typeof u.get(''), "object", "typeof URL.searchParams.get('')");
+    is(u.get(''), null, "URL.searchParams.get('') should be null");
+
+    var url = new URL('http://www.example.net?a=b');
+    is(url.searchParams.get('b'), null, "URL.searchParams.get('b') should be null");
+    is(url.searchParams.get('a'), 'b', "URL.searchParams.get('a')");
+
+    runTest();
+  }
+
   var tests = [
     testSimpleURLSearchParams,
     testCopyURLSearchParams,
     testParserURLSearchParams,
     testURL,
     function() { testElement(document.getElementById('anchor')) },
     function() { testElement(document.getElementById('area')) },
     testEncoding,
     testMultiURL,
     testOrdering,
-    testDelete
+    testDelete,
+    testGetNULL
   ];
 
   function runTest() {
     if (!tests.length) {
       SimpleTest.finish();
       return;
     }
 
--- a/dom/canvas/WebGL2ContextTextures.cpp
+++ b/dom/canvas/WebGL2ContextTextures.cpp
@@ -148,26 +148,19 @@ WebGL2Context::TexStorage2D(GLenum targe
     WebGLTexture* tex = activeBoundTextureForTarget(target);
     tex->SetImmutable();
 
     const size_t facesCount = (target == LOCAL_GL_TEXTURE_2D) ? 1 : 6;
     GLsizei w = width;
     GLsizei h = height;
     for (size_t l = 0; l < size_t(levels); l++) {
         for (size_t f = 0; f < facesCount; f++) {
-            TexImageTarget imageTarget = TexImageTargetForTargetAndFace(target, f);
-            // FIXME: SetImageInfo wants a type, to go with the internalformat that it stores.
-            // 'type' is deprecated by sized internalformats, which are how TexStorage works.
-            // We must fix WebGLTexture::ImageInfo to store an "effective internalformat",
-            // which in the present case is just the sized internalformat, and drop 'types'
-            // altogether. For now, we just pass LOCAL_GL_UNSIGNED_BYTE, which works For
-            // the most commonly used formats.
-            const GLenum type = LOCAL_GL_UNSIGNED_BYTE;
-            tex->SetImageInfo(imageTarget, l, w, h,
-                              internalformat, type,
+            tex->SetImageInfo(TexImageTargetForTargetAndFace(target, f),
+                              l, w, h,
+                              internalformat,
                               WebGLImageDataStatus::UninitializedImageData);
         }
         w = std::max(1, w/2);
         h = std::max(1, h/2);
     }
 
     gl->fTexStorage2D(target, levels, internalformat, width, height);
 }
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -1755,16 +1755,23 @@ WebGLContext::DidRefresh()
         gl->FlushIfHeavyGLCallsSinceLastFlush();
     }
 }
 
 bool WebGLContext::TexImageFromVideoElement(const TexImageTarget texImageTarget, GLint level,
                               GLenum internalformat, GLenum format, GLenum type,
                               mozilla::dom::Element& elt)
 {
+    if (type == LOCAL_GL_HALF_FLOAT_OES) {
+        type = LOCAL_GL_HALF_FLOAT;
+    }
+
+    if (!ValidateTexImageFormatAndType(format, type, WebGLTexImageFunc::TexImage))
+        return false;
+
     HTMLVideoElement* video = HTMLVideoElement::FromContentOrNull(&elt);
     if (!video) {
         return false;
     }
 
     uint16_t readyState;
     if (NS_SUCCEEDED(video->GetReadyState(&readyState)) &&
         readyState < nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA)
@@ -1802,18 +1809,21 @@ bool WebGLContext::TexImageFromVideoElem
     bool dimensionsMatch = info.Width() == srcImage->GetSize().width &&
                            info.Height() == srcImage->GetSize().height;
     if (!dimensionsMatch) {
         // we need to allocation
         gl->fTexImage2D(texImageTarget.get(), level, internalformat, srcImage->GetSize().width, srcImage->GetSize().height, 0, format, type, nullptr);
     }
     bool ok = gl->BlitHelper()->BlitImageToTexture(srcImage.get(), srcImage->GetSize(), tex->GLName(), texImageTarget.get(), mPixelStoreFlipY);
     if (ok) {
-        tex->SetImageInfo(texImageTarget, level, srcImage->GetSize().width, srcImage->GetSize().height, internalformat, type,
-                          WebGLImageDataStatus::InitializedImageData);
+        TexInternalFormat effectiveinternalformat =
+            EffectiveInternalFormatFromInternalFormatAndType(internalformat, type);
+        MOZ_ASSERT(effectiveinternalformat != LOCAL_GL_NONE);
+        tex->SetImageInfo(texImageTarget, level, srcImage->GetSize().width, srcImage->GetSize().height,
+                          effectiveinternalformat, WebGLImageDataStatus::InitializedImageData);
         tex->Bind(TexImageTargetToTexTarget(texImageTarget));
     }
     srcImage = nullptr;
     container->UnlockCurrentImage();
     return ok;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -89,17 +89,17 @@ class Element;
 struct WebGLContextAttributes;
 template<typename> struct Nullable;
 }
 
 namespace gfx {
 class SourceSurface;
 }
 
-WebGLTexelFormat GetWebGLTexelFormat(TexInternalFormat format, TexType type);
+WebGLTexelFormat GetWebGLTexelFormat(TexInternalFormat format);
 
 void AssertUintParamCorrect(gl::GLContext* gl, GLenum pname, GLuint shadow);
 
 struct WebGLContextOptions {
     // these are defaults
     WebGLContextOptions();
 
     bool operator==(const WebGLContextOptions& other) const {
@@ -485,19 +485,16 @@ public:
 
         auto dims = 2;
 
         if (!ValidateTexImageTarget(dims, rawTexImgTarget, WebGLTexImageFunc::TexImage))
             return ErrorInvalidEnumInfo("texSubImage2D: target", rawTexImgTarget);
 
         const TexImageTarget texImageTarget(rawTexImgTarget);
 
-        if (!ValidateTexImageFormatAndType(format, type, WebGLTexImageFunc::TexImage))
-            return;
-
         if (level < 0)
             return ErrorInvalidValue("texImage2D: level is negative");
 
         const int32_t maxLevel = MaxTextureLevelForTexImageTarget(texImageTarget);
         if (level > maxLevel)
             return ErrorInvalidValue("texImage2D: level %d is too large, max is %d", level, maxLevel);
 
         WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget);
@@ -555,32 +552,29 @@ public:
         if (IsContextLost())
             return;
 
         if (!ValidateTexImageTarget(2, rawTexImageTarget, WebGLTexImageFunc::TexSubImage))
             return ErrorInvalidEnumInfo("texSubImage2D: target", rawTexImageTarget);
 
         const TexImageTarget texImageTarget(rawTexImageTarget);
 
-        if (!ValidateTexImageFormatAndType(format, type, WebGLTexImageFunc::TexImage))
-            return;
-
         if (level < 0)
             return ErrorInvalidValue("texSubImage2D: level is negative");
 
         const int32_t maxLevel = MaxTextureLevelForTexImageTarget(texImageTarget);
         if (level > maxLevel)
             return ErrorInvalidValue("texSubImage2D: level %d is too large, max is %d", level, maxLevel);
 
         WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget);
         if (!tex) {
             return ErrorInvalidOperation("texSubImage2D: no texture bound on active texture unit");
         }
         const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(texImageTarget, level);
-        const TexInternalFormat internalformat = imageInfo.InternalFormat();
+        const TexInternalFormat internalformat = imageInfo.EffectiveInternalFormat();
 
         // Trying to handle the video by GPU directly first
         if (TexImageFromVideoElement(texImageTarget, level,
                                      internalformat.get(), format, type, elt))
         {
             return;
         }
 
@@ -1140,18 +1134,16 @@ protected:
                                   GLsizei width, GLsizei height,
                                   GLsizei levelWidth, GLsizei levelHeight,
                                   WebGLTexImageFunc func);
     bool ValidateCompTexImageDataSize(GLint level,
                                       GLenum internalformat,
                                       GLsizei width, GLsizei height,
                                       uint32_t byteLength, WebGLTexImageFunc func);
 
-    static uint32_t GetBitsPerTexel(TexInternalFormat format, TexType type);
-
     void Invalidate();
     void DestroyResourcesAndContext();
 
     void MakeContextCurrent() const;
 
     // helpers
     void TexImage2D_base(TexImageTarget target,
                          GLint level,
@@ -1198,17 +1190,17 @@ protected:
     }
 
     nsresult SurfaceFromElementResultToImageSurface(nsLayoutUtils::SurfaceFromElementResult& res,
                                                     RefPtr<gfx::DataSourceSurface>& imageOut,
                                                     WebGLTexelFormat *format);
 
     void CopyTexSubImage2D_base(TexImageTarget texImageTarget,
                                 GLint level,
-                                GLenum internalformat,
+                                TexInternalFormat internalformat,
                                 GLint xoffset,
                                 GLint yoffset,
                                 GLint x,
                                 GLint y,
                                 GLsizei width,
                                 GLsizei height,
                                 bool sub);
 
@@ -1358,17 +1350,17 @@ protected:
         WebGLContext& mWebGL;
         const bool mNeedsChange;
 
         static bool NeedsChange(WebGLContext& webgl) {
             return webgl.mNeedsFakeNoAlpha &&
                    webgl.mColorWriteMask[3] != false;
         }
 
-        ScopedMaskWorkaround(WebGLContext& webgl);
+        explicit ScopedMaskWorkaround(WebGLContext& aWebgl);
 
         ~ScopedMaskWorkaround();
     };
 
     void LoseOldestWebGLContextIfLimitExceeded();
     void UpdateLastUseIndex();
 
     template <typename WebGLObjectType>
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -671,17 +671,17 @@ WebGLContext::BindFakeBlackTexturesHelpe
         WebGLTextureFakeBlackStatus s = boundTexturesArray[i]->ResolvedFakeBlackStatus();
         MOZ_ASSERT(s != WebGLTextureFakeBlackStatus::Unknown);
 
         if (MOZ_LIKELY(s == WebGLTextureFakeBlackStatus::NotNeeded)) {
             continue;
         }
 
         bool alpha = s == WebGLTextureFakeBlackStatus::UninitializedImageData &&
-                     FormatHasAlpha(boundTexturesArray[i]->ImageInfoBase().InternalFormat());
+                     FormatHasAlpha(boundTexturesArray[i]->ImageInfoBase().EffectiveInternalFormat());
         UniquePtr<FakeBlackTexture>&
             blackTexturePtr = alpha
                               ? transparentTextureScopedPtr
                               : opaqueTextureScopedPtr;
 
         if (!blackTexturePtr) {
             GLenum format = alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
             blackTexturePtr = MakeUnique<FakeBlackTexture>(gl, target, format);
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -349,17 +349,17 @@ WebGLContext::CheckFramebufferStatus(GLe
         return LOCAL_GL_FRAMEBUFFER_COMPLETE;
 
     return mBoundFramebuffer->CheckFramebufferStatus().get();
 }
 
 void
 WebGLContext::CopyTexSubImage2D_base(TexImageTarget texImageTarget,
                                      GLint level,
-                                     GLenum internalformat,
+                                     TexInternalFormat internalformat,
                                      GLint xoffset,
                                      GLint yoffset,
                                      GLint x,
                                      GLint y,
                                      GLsizei width,
                                      GLsizei height,
                                      bool sub)
 {
@@ -367,27 +367,27 @@ WebGLContext::CopyTexSubImage2D_base(Tex
     GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0;
     GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;
 
     const char* info = sub ? "copyTexSubImage2D" : "copyTexImage2D";
     WebGLTexImageFunc func = sub ? WebGLTexImageFunc::CopyTexSubImage : WebGLTexImageFunc::CopyTexImage;
 
     // TODO: This changes with color_buffer_float. Reassess when the
     // patch lands.
-    if (!ValidateTexImage(2, texImageTarget, level, internalformat,
+    if (!ValidateTexImage(2, texImageTarget, level, internalformat.get(),
                           xoffset, yoffset, 0,
                           width, height, 0,
                           0,
                           LOCAL_GL_NONE, LOCAL_GL_NONE,
                           func))
     {
         return;
     }
 
-    if (!ValidateCopyTexImage(internalformat, func))
+    if (!ValidateCopyTexImage(internalformat.get(), func))
         return;
 
     if (!mBoundFramebuffer)
         ClearBackbufferIfNeeded();
 
     MakeContextCurrent();
 
     WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget);
@@ -396,60 +396,60 @@ WebGLContext::CopyTexSubImage2D_base(Tex
         return ErrorInvalidOperation("%s: no texture is bound to this target");
 
     if (tex->IsImmutable()) {
         if (!sub) {
             return ErrorInvalidOperation("copyTexImage2D: disallowed because the texture bound to this target has already been made immutable by texStorage2D");
         }
     }
 
+    TexType framebuffertype = LOCAL_GL_NONE;
+    if (mBoundFramebuffer) {
+        TexInternalFormat framebuffereffectiveformat = mBoundFramebuffer->ColorAttachment(0).EffectiveInternalFormat();
+        framebuffertype = TypeFromInternalFormat(framebuffereffectiveformat);
+    } else {
+        // FIXME - here we're assuming that the default framebuffer is backed by UNSIGNED_BYTE
+        // that might not always be true, say if we had a 16bpp default framebuffer.
+        framebuffertype = LOCAL_GL_UNSIGNED_BYTE;
+    }
+
+    TexInternalFormat effectiveinternalformat =
+        EffectiveInternalFormatFromUnsizedInternalFormatAndType(internalformat, framebuffertype);
+
+    // this should never fail, validation happened earlier.
+    MOZ_ASSERT(effectiveinternalformat != LOCAL_GL_NONE);
+
+    // check if the memory size of this texture may change with this call
+    bool sizeMayChange = !sub;
+    if (!sub && tex->HasImageInfoAt(texImageTarget, level)) {
+        const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
+        sizeMayChange = width != imageInfo.Width() ||
+                        height != imageInfo.Height() ||
+                        effectiveinternalformat != imageInfo.EffectiveInternalFormat();
+    }
+
+    if (sizeMayChange)
+        GetAndFlushUnderlyingGLErrors();
+
     if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, framebufferWidth, framebufferHeight)) {
         if (sub)
             gl->fCopyTexSubImage2D(texImageTarget.get(), level, xoffset, yoffset, x, y, width, height);
         else
-            gl->fCopyTexImage2D(texImageTarget.get(), level, internalformat, x, y, width, height, 0);
+            gl->fCopyTexImage2D(texImageTarget.get(), level, internalformat.get(), x, y, width, height, 0);
     } else {
 
         // the rect doesn't fit in the framebuffer
 
-        /*** first, we initialize the texture as black ***/
-
-        // first, compute the size of the buffer we should allocate to initialize the texture as black
-
-        if (!ValidateTexInputData(LOCAL_GL_UNSIGNED_BYTE, -1, func))
-            return;
-
-        uint32_t texelSize = GetBitsPerTexel(internalformat, LOCAL_GL_UNSIGNED_BYTE) / 8;
-
-        CheckedUint32 checked_neededByteLength =
-            GetImageSize(height, width, texelSize, mPixelStoreUnpackAlignment);
-
-        if (!checked_neededByteLength.isValid())
-            return ErrorInvalidOperation("%s: integer overflow computing the needed buffer size", info);
-
-        uint32_t bytesNeeded = checked_neededByteLength.value();
-
-        // now that the size is known, create the buffer
-
-        // We need some zero pages, because GL doesn't guarantee the
-        // contents of a texture allocated with nullptr data.
-        // Hopefully calloc will just mmap zero pages here.
-        void* tempZeroData = calloc(1, bytesNeeded);
-        if (!tempZeroData)
-            return ErrorOutOfMemory("%s: could not allocate %d bytes (for zero fill)", info, bytesNeeded);
-
-        // now initialize the texture as black
-
-        if (sub)
-            gl->fTexSubImage2D(texImageTarget.get(), level, 0, 0, width, height,
-                               internalformat, LOCAL_GL_UNSIGNED_BYTE, tempZeroData);
-        else
-            gl->fTexImage2D(texImageTarget.get(), level, internalformat, width, height,
-                            0, internalformat, LOCAL_GL_UNSIGNED_BYTE, tempZeroData);
-        free(tempZeroData);
+        // first, we initialize the texture as black
+        if (!sub) {
+            tex->SetImageInfo(texImageTarget, level, width, height,
+                      effectiveinternalformat,
+                      WebGLImageDataStatus::UninitializedImageData);
+            tex->DoDeferredImageInitialization(texImageTarget, level);
+        }
 
         // if we are completely outside of the framebuffer, we can exit now with our black texture
         if (   x >= framebufferWidth
             || x+width <= 0
             || y >= framebufferHeight
             || y+height <= 0)
         {
             // we are completely outside of range, can exit now with buffer filled with zeros
@@ -463,16 +463,30 @@ WebGLContext::CopyTexSubImage2D_base(Tex
 
         GLint   actual_y             = clamped(y, 0, framebufferHeight);
         GLint   actual_y_plus_height = clamped(y + height, 0, framebufferHeight);
         GLsizei actual_height  = actual_y_plus_height - actual_y;
         GLint   actual_yoffset = yoffset + actual_y - y;
 
         gl->fCopyTexSubImage2D(texImageTarget.get(), level, actual_xoffset, actual_yoffset, actual_x, actual_y, actual_width, actual_height);
     }
+
+    if (sizeMayChange) {
+        GLenum error = GetAndFlushUnderlyingGLErrors();
+        if (error) {
+            GenerateWarning("copyTexImage2D generated error %s", ErrorName(error));
+            return;
+        }
+    }
+
+    if (!sub) {
+        tex->SetImageInfo(texImageTarget, level, width, height,
+                          effectiveinternalformat,
+                          WebGLImageDataStatus::InitializedImageData);
+    }
 }
 
 void
 WebGLContext::CopyTexImage2D(GLenum rawTexImgTarget,
                              GLint level,
                              GLenum internalformat,
                              GLint x,
                              GLint y,
@@ -499,47 +513,17 @@ WebGLContext::CopyTexImage2D(GLenum rawT
     }
 
     if (!ValidateCopyTexImage(internalformat, func))
         return;
 
     if (!mBoundFramebuffer)
         ClearBackbufferIfNeeded();
 
-    const TexImageTarget texImageTarget(rawTexImgTarget);
-
-    // check if the memory size of this texture may change with this call
-    bool sizeMayChange = true;
-    WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget);
-    if (tex->HasImageInfoAt(texImageTarget, level)) {
-        const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
-
-        sizeMayChange = width != imageInfo.Width() ||
-                        height != imageInfo.Height() ||
-                        internalformat != imageInfo.InternalFormat();
-    }
-
-    if (sizeMayChange)
-        GetAndFlushUnderlyingGLErrors();
-
-    CopyTexSubImage2D_base(texImageTarget, level, internalformat, 0, 0, x, y, width, height, false);
-
-    if (sizeMayChange) {
-        GLenum error = GetAndFlushUnderlyingGLErrors();
-        if (error) {
-            GenerateWarning("copyTexImage2D generated error %s", ErrorName(error));
-            return;
-        }
-    }
-
-    tex->SetImageInfo(texImageTarget, level, width, height,
-                      internalformat,
-                      LOCAL_GL_UNSIGNED_BYTE, /* dummy, artifact of us storing
-                                               the wrong data in ImageInfo */
-                      WebGLImageDataStatus::InitializedImageData);
+    CopyTexSubImage2D_base(rawTexImgTarget, level, internalformat, 0, 0, x, y, width, height, false);
 }
 
 void
 WebGLContext::CopyTexSubImage2D(GLenum rawTexImgTarget,
                                 GLint level,
                                 GLint xoffset,
                                 GLint yoffset,
                                 GLint x,
@@ -597,17 +581,21 @@ WebGLContext::CopyTexSubImage2D(GLenum r
 
     if (!mBoundFramebuffer)
         ClearBackbufferIfNeeded();
 
     if (imageInfo.HasUninitializedImageData()) {
         tex->DoDeferredImageInitialization(texImageTarget, level);
     }
 
-    return CopyTexSubImage2D_base(texImageTarget, level, imageInfo.InternalFormat().get(), xoffset, yoffset, x, y, width, height, true);
+    TexInternalFormat internalformat;
+    TexType type;
+    UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(imageInfo.EffectiveInternalFormat(),
+                                             &internalformat, &type);
+    return CopyTexSubImage2D_base(texImageTarget, level, internalformat, xoffset, yoffset, x, y, width, height, true);
 }
 
 
 already_AddRefed<WebGLProgram>
 WebGLContext::CreateProgram()
 {
     if (IsContextLost())
         return nullptr;
@@ -917,17 +905,17 @@ WebGLContext::GenerateMipmap(GLenum rawT
     if (!tex->HasImageInfoAt(imageTarget, 0))
     {
         return ErrorInvalidOperation("generateMipmap: Level zero of texture is not defined.");
     }
 
     if (!tex->IsFirstImagePowerOfTwo())
         return ErrorInvalidOperation("generateMipmap: Level zero of texture does not have power-of-two width and height.");
 
-    TexInternalFormat internalformat = tex->ImageInfoAt(imageTarget, 0).InternalFormat();
+    TexInternalFormat internalformat = tex->ImageInfoAt(imageTarget, 0).EffectiveInternalFormat();
     if (IsTextureFormatCompressed(internalformat))
         return ErrorInvalidOperation("generateMipmap: Texture data at level zero is compressed.");
 
     if (IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture) &&
         (IsGLDepthFormat(internalformat) || IsGLDepthStencilFormat(internalformat)))
     {
         return ErrorInvalidOperation("generateMipmap: "
                                      "A texture that has a base internal format of "
@@ -1178,22 +1166,27 @@ WebGLContext::GetFramebufferAttachmentPa
         }
 
         ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: pname", pname);
         return JS::NullValue();
     } else if (fba.Texture()) {
         switch (pname) {
              case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT:
                 if (IsExtensionEnabled(WebGLExtensionID::EXT_sRGB)) {
-                    const TexInternalFormat internalformat =
-                        fba.Texture()->ImageInfoBase().InternalFormat();
-                    return (internalformat == LOCAL_GL_SRGB ||
-                            internalformat == LOCAL_GL_SRGB_ALPHA) ?
-                        JS::NumberValue(uint32_t(LOCAL_GL_SRGB)) :
-                        JS::NumberValue(uint32_t(LOCAL_GL_LINEAR));
+                    const TexInternalFormat effectiveinternalformat =
+                        fba.Texture()->ImageInfoBase().EffectiveInternalFormat();
+                    TexInternalFormat unsizedinternalformat = LOCAL_GL_NONE;
+                    TexType type = LOCAL_GL_NONE;
+                    UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(
+                        effectiveinternalformat, &unsizedinternalformat, &type);
+                    MOZ_ASSERT(unsizedinternalformat != LOCAL_GL_NONE);
+                    const bool srgb = unsizedinternalformat == LOCAL_GL_SRGB ||
+                                      unsizedinternalformat == LOCAL_GL_SRGB_ALPHA;
+                    return srgb ? JS::NumberValue(uint32_t(LOCAL_GL_SRGB))
+                                : JS::NumberValue(uint32_t(LOCAL_GL_LINEAR));
                 }
                 break;
 
             case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
                 return JS::NumberValue(uint32_t(LOCAL_GL_TEXTURE));
 
             case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
                 return WebGLObjectAsJSValue(cx, fba.Texture(), rv);
@@ -1219,28 +1212,29 @@ WebGLContext::GetFramebufferAttachmentPa
                     ErrorInvalidOperation("getFramebufferAttachmentParameter: cannot component"
                                           " type of depth-stencil attachments.");
                     return JS::NullValue();
                 }
 
                 if (!fba.IsComplete())
                     return JS::NumberValue(uint32_t(LOCAL_GL_NONE));
 
-                uint32_t ret = LOCAL_GL_NONE;
-                TexType type = fba.Texture()->ImageInfoAt(fba.ImageTarget(),
-                                                          fba.MipLevel()).Type();
+                TexInternalFormat effectiveinternalformat =
+                    fba.Texture()->ImageInfoAt(fba.ImageTarget(), fba.MipLevel()).EffectiveInternalFormat();
+                TexType type = TypeFromInternalFormat(effectiveinternalformat);
+                GLenum ret = LOCAL_GL_NONE;
                 switch (type.get()) {
                 case LOCAL_GL_UNSIGNED_BYTE:
                 case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
                 case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
                 case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
                     ret = LOCAL_GL_UNSIGNED_NORMALIZED;
                     break;
                 case LOCAL_GL_FLOAT:
-                case LOCAL_GL_HALF_FLOAT_OES:
+                case LOCAL_GL_HALF_FLOAT:
                     ret = LOCAL_GL_FLOAT;
                     break;
                 case LOCAL_GL_UNSIGNED_SHORT:
                 case LOCAL_GL_UNSIGNED_INT:
                     ret = LOCAL_GL_UNSIGNED_INT;
                     break;
                 default:
                     MOZ_ASSERT(false, "Unhandled RB component type.");
@@ -3348,17 +3342,17 @@ WebGLContext::CompressedTexImage2D(GLenu
         return ErrorInvalidOperation(
             "compressedTexImage2D: disallowed because the texture bound to "
             "this target has already been made immutable by texStorage2D");
     }
 
     MakeContextCurrent();
     gl->fCompressedTexImage2D(texImageTarget.get(), level, internalformat, width, height, border, byteLength, view.Data());
 
-    tex->SetImageInfo(texImageTarget, level, width, height, internalformat, LOCAL_GL_UNSIGNED_BYTE,
+    tex->SetImageInfo(texImageTarget, level, width, height, internalformat,
                       WebGLImageDataStatus::InitializedImageData);
 }
 
 void
 WebGLContext::CompressedTexSubImage2D(GLenum rawTexImgTarget, GLint level, GLint xoffset,
                                       GLint yoffset, GLsizei width, GLsizei height,
                                       GLenum internalformat,
                                       const ArrayBufferView& view)
@@ -3382,17 +3376,17 @@ WebGLContext::CompressedTexSubImage2D(GL
     }
 
     const TexImageTarget texImageTarget(rawTexImgTarget);
 
     WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget);
     MOZ_ASSERT(tex);
     WebGLTexture::ImageInfo& levelInfo = tex->ImageInfoAt(texImageTarget, level);
 
-    if (internalformat != levelInfo.InternalFormat()) {
+    if (internalformat != levelInfo.EffectiveInternalFormat()) {
         return ErrorInvalidOperation("compressedTexImage2D: internalformat does not match the existing image");
     }
 
     view.ComputeLengthAndData();
 
     uint32_t byteLength = view.Length();
     if (!ValidateCompTexImageDataSize(level, internalformat, width, height, byteLength, func))
         return;
@@ -3594,41 +3588,47 @@ WebGLContext::GetShaderTranslatedSource(
     if (!ValidateObject("getShaderTranslatedSource: shader", shader))
         return;
 
     retval.Assign(shader->TranslatedSource());
 }
 
 GLenum WebGLContext::CheckedTexImage2D(TexImageTarget texImageTarget,
                                        GLint level,
-                                       TexInternalFormat internalFormat,
+                                       TexInternalFormat internalformat,
                                        GLsizei width,
                                        GLsizei height,
                                        GLint border,
                                        TexFormat format,
                                        TexType type,
                                        const GLvoid *data)
 {
     WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget);
     MOZ_ASSERT(tex != nullptr, "no texture bound");
 
+    TexInternalFormat effectiveInternalFormat =
+        EffectiveInternalFormatFromInternalFormatAndType(internalformat, type);
     bool sizeMayChange = true;
 
     if (tex->HasImageInfoAt(texImageTarget, level)) {
         const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
         sizeMayChange = width != imageInfo.Width() ||
                         height != imageInfo.Height() ||
-                        internalFormat != imageInfo.InternalFormat();
+                        effectiveInternalFormat != imageInfo.EffectiveInternalFormat();
     }
 
     // Convert to format and type required by OpenGL 'driver'.
-    GLenum driverType = DriverTypeFromType(gl, type);
+    GLenum driverType = LOCAL_GL_NONE;
     GLenum driverInternalFormat = LOCAL_GL_NONE;
     GLenum driverFormat = LOCAL_GL_NONE;
-    DriverFormatsFromFormatAndType(gl, internalFormat, type, &driverInternalFormat, &driverFormat);
+    DriverFormatsFromEffectiveInternalFormat(gl,
+                                             effectiveInternalFormat,
+                                             &driverInternalFormat,
+                                             &driverFormat,
+                                             &driverType);
 
     if (sizeMayChange) {
         GetAndFlushUnderlyingGLErrors();
     }
 
     gl->fTexImage2D(texImageTarget.get(), level, driverInternalFormat, width, height, border, driverFormat, driverType, data);
 
     GLenum error = LOCAL_GL_NO_ERROR;
@@ -3647,16 +3647,20 @@ WebGLContext::TexImage2D_base(TexImageTa
                               GLenum format,
                               GLenum type,
                               void* data, uint32_t byteLength,
                               int jsArrayType, // a TypedArray format enum, or -1 if not relevant
                               WebGLTexelFormat srcFormat, bool srcPremultiplied)
 {
     const WebGLTexImageFunc func = WebGLTexImageFunc::TexImage;
 
+    if (type == LOCAL_GL_HALF_FLOAT_OES) {
+        type = LOCAL_GL_HALF_FLOAT;
+    }
+
     if (!ValidateTexImage(2, texImageTarget, level, internalformat,
                           0, 0, 0,
                           width, height, 0,
                           border, format, type, func))
     {
         return;
     }
 
@@ -3669,17 +3673,24 @@ WebGLContext::TexImage2D_base(TexImageTa
                                          "with format of DEPTH_COMPONENT or DEPTH_STENCIL, "
                                          "data must be nullptr, "
                                          "level must be zero");
     }
 
     if (!ValidateTexInputData(type, jsArrayType, func))
         return;
 
-    WebGLTexelFormat dstFormat = GetWebGLTexelFormat(internalformat, type);
+    TexInternalFormat effectiveinternalformat =
+        EffectiveInternalFormatFromInternalFormatAndType(internalformat, type);
+
+    if (effectiveinternalformat == LOCAL_GL_NONE) {
+        return ErrorInvalidOperation("texImage2D: bad combination of internalformat and type");
+    }
+
+    WebGLTexelFormat dstFormat = GetWebGLTexelFormat(effectiveinternalformat);
     WebGLTexelFormat actualSrcFormat = srcFormat == WebGLTexelFormat::Auto ? dstFormat : srcFormat;
 
     uint32_t srcTexelSize = WebGLTexelConversions::TexelBytesForFormat(actualSrcFormat);
 
     CheckedUint32 checked_neededByteLength =
         GetImageSize(height, width, srcTexelSize, mPixelStoreUnpackAlignment);
 
     CheckedUint32 checked_plainRowSize = CheckedUint32(width) * srcTexelSize;
@@ -3707,18 +3718,20 @@ WebGLContext::TexImage2D_base(TexImageTa
     }
     MakeContextCurrent();
 
     nsAutoArrayPtr<uint8_t> convertedData;
     void* pixels = nullptr;
     WebGLImageDataStatus imageInfoStatusIfSuccess = WebGLImageDataStatus::UninitializedImageData;
 
     if (byteLength) {
+        size_t   bitspertexel = GetBitsPerTexel(effectiveinternalformat);
+        MOZ_ASSERT((bitspertexel % 8) == 0); // should not have compressed formats here.
+        size_t   dstTexelSize = bitspertexel / 8;
         size_t   srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
-        uint32_t dstTexelSize = GetBitsPerTexel(internalformat, type) / 8;
         size_t   dstPlainRowSize = dstTexelSize * width;
         size_t   unpackAlignment = mPixelStoreUnpackAlignment;
         size_t   dstStride = ((dstPlainRowSize + unpackAlignment-1) / unpackAlignment) * unpackAlignment;
 
         if (actualSrcFormat == dstFormat &&
             srcPremultiplied == mPixelStorePremultiplyAlpha &&
             srcStride == dstStride &&
             !mPixelStoreFlipY)
@@ -3747,17 +3760,18 @@ WebGLContext::TexImage2D_base(TexImageTa
         return;
     }
 
     // in all of the code paths above, we should have either initialized data,
     // or allocated data and left it uninitialized, but in any case we shouldn't
     // have NoImageData at this point.
     MOZ_ASSERT(imageInfoStatusIfSuccess != WebGLImageDataStatus::NoImageData);
 
-    tex->SetImageInfo(texImageTarget, level, width, height, internalformat, type, imageInfoStatusIfSuccess);
+    tex->SetImageInfo(texImageTarget, level, width, height,
+                      effectiveinternalformat, imageInfoStatusIfSuccess);
 }
 
 void
 WebGLContext::TexImage2D(GLenum rawTarget, GLint level,
                          GLenum internalformat, GLsizei width,
                          GLsizei height, GLint border, GLenum format,
                          GLenum type, const Nullable<ArrayBufferView> &pixels, ErrorResult& rv)
 {
@@ -3825,39 +3839,53 @@ WebGLContext::TexSubImage2D_base(TexImag
                                  GLsizei width, GLsizei height, GLsizei srcStrideOrZero,
                                  GLenum format, GLenum type,
                                  void* data, uint32_t byteLength,
                                  int jsArrayType,
                                  WebGLTexelFormat srcFormat, bool srcPremultiplied)
 {
     const WebGLTexImageFunc func = WebGLTexImageFunc::TexSubImage;
 
+    if (type == LOCAL_GL_HALF_FLOAT_OES) {
+        type = LOCAL_GL_HALF_FLOAT;
+    }
+
     WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget);
     if (!tex) {
         return ErrorInvalidOperation("texSubImage2D: no texture bound on active texture unit");
     }
+
+    if (!tex->HasImageInfoAt(texImageTarget, level)) {
+        return ErrorInvalidOperation("texSubImage2D: no previously defined texture image");
+    }
+
     const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
-    const TexInternalFormat internalformat =  imageInfo.InternalFormat();
-
-    if (!ValidateTexImage(2, texImageTarget, level, internalformat.get(),
+    const TexInternalFormat existingEffectiveInternalFormat = imageInfo.EffectiveInternalFormat();
+    TexInternalFormat existingUnsizedInternalFormat = LOCAL_GL_NONE;
+    TexType existingType = LOCAL_GL_NONE;
+    UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(existingEffectiveInternalFormat,
+                                                            &existingUnsizedInternalFormat,
+                                                            &existingType);
+
+    if (!ValidateTexImage(2, texImageTarget, level, existingUnsizedInternalFormat.get(),
                           xoffset, yoffset, 0,
                           width, height, 0,
                           0, format, type, func))
     {
         return;
     }
 
     if (!ValidateTexInputData(type, jsArrayType, func))
         return;
 
-    if (imageInfo.Type() != type) {
-        return ErrorInvalidOperation("texSubImage2D: type parameter does not match the existing image");
+    if (type != existingType) {
+        return ErrorInvalidOperation("texSubImage2D: type differs from that of the existing image");
     }
 
-    WebGLTexelFormat dstFormat = GetWebGLTexelFormat(internalformat, type);
+    WebGLTexelFormat dstFormat = GetWebGLTexelFormat(existingEffectiveInternalFormat);
     WebGLTexelFormat actualSrcFormat = srcFormat == WebGLTexelFormat::Auto ? dstFormat : srcFormat;
 
     uint32_t srcTexelSize = WebGLTexelConversions::TexelBytesForFormat(actualSrcFormat);
 
     if (width == 0 || height == 0)
         return; // ES 2.0 says it has no effect, we better return right now
 
     CheckedUint32 checked_neededByteLength =
@@ -3877,17 +3905,17 @@ WebGLContext::TexSubImage2D_base(TexImag
         return ErrorInvalidOperation("texSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, byteLength);
 
     if (imageInfo.HasUninitializedImageData())
         tex->DoDeferredImageInitialization(texImageTarget, level);
 
     MakeContextCurrent();
 
     size_t   srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
-    uint32_t dstTexelSize = GetBitsPerTexel(internalformat, type) / 8;
+    uint32_t dstTexelSize = GetBitsPerTexel(existingEffectiveInternalFormat) / 8;
     size_t   dstPlainRowSize = dstTexelSize * width;
     // There are checks above to ensure that this won't overflow.
     size_t   dstStride = RoundedToNextMultipleOf(dstPlainRowSize, mPixelStoreUnpackAlignment).value();
 
     void* pixels = data;
     nsAutoArrayPtr<uint8_t> convertedData;
 
     // no conversion, no flipping, so we avoid copying anything and just pass the source pointer
@@ -3901,20 +3929,24 @@ WebGLContext::TexSubImage2D_base(TexImag
         convertedData = new uint8_t[convertedDataSize];
         ConvertImage(width, height, srcStride, dstStride,
                     static_cast<const uint8_t*>(data), convertedData,
                     actualSrcFormat, srcPremultiplied,
                     dstFormat, mPixelStorePremultiplyAlpha, dstTexelSize);
         pixels = reinterpret_cast<void*>(convertedData.get());
     }
 
-    GLenum driverType = DriverTypeFromType(gl, type);
+    GLenum driverType = LOCAL_GL_NONE;
     GLenum driverInternalFormat = LOCAL_GL_NONE;
     GLenum driverFormat = LOCAL_GL_NONE;
-    DriverFormatsFromFormatAndType(gl, internalformat, type, &driverInternalFormat, &driverFormat);
+    DriverFormatsFromEffectiveInternalFormat(gl,
+                                             existingEffectiveInternalFormat,
+                                             &driverInternalFormat,
+                                             &driverFormat,
+                                             &driverType);
 
     gl->fTexSubImage2D(texImageTarget.get(), level, xoffset, yoffset, width, height, driverFormat, driverType, pixels);
 }
 
 void
 WebGLContext::TexSubImage2D(GLenum rawTarget, GLint level,
                             GLint xoffset, GLint yoffset,
                             GLsizei width, GLsizei height,
@@ -4061,129 +4093,47 @@ BaseTypeAndSizeFromUniformType(GLenum uT
         default:
             return false;
     }
 
     return true;
 }
 
 
-WebGLTexelFormat mozilla::GetWebGLTexelFormat(TexInternalFormat internalformat, TexType type)
+WebGLTexelFormat
+mozilla::GetWebGLTexelFormat(TexInternalFormat effectiveinternalformat)
 {
-    //
-    // WEBGL_depth_texture
-    if (internalformat == LOCAL_GL_DEPTH_COMPONENT) {
-        switch (type.get()) {
-            case LOCAL_GL_UNSIGNED_SHORT:
-                return WebGLTexelFormat::D16;
-            case LOCAL_GL_UNSIGNED_INT:
-                return WebGLTexelFormat::D32;
-        }
-
-        MOZ_CRASH("Invalid WebGL texture format/type?");
-    }
-
-    if (internalformat == LOCAL_GL_DEPTH_STENCIL) {
-        switch (type.get()) {
-            case LOCAL_GL_UNSIGNED_INT_24_8_EXT:
-                return WebGLTexelFormat::D24S8;
-        }
-
-        MOZ_CRASH("Invalid WebGL texture format/type?");
-    }
-
-    if (internalformat == LOCAL_GL_DEPTH_COMPONENT16) {
-        return WebGLTexelFormat::D16;
-    }
-
-    if (internalformat == LOCAL_GL_DEPTH_COMPONENT32) {
-        return WebGLTexelFormat::D32;
-    }
-
-    if (internalformat == LOCAL_GL_DEPTH24_STENCIL8) {
-        return WebGLTexelFormat::D24S8;
-    }
-
-    if (type == LOCAL_GL_UNSIGNED_BYTE) {
-        switch (internalformat.get()) {
-            case LOCAL_GL_RGBA:
-            case LOCAL_GL_SRGB_ALPHA_EXT:
-                return WebGLTexelFormat::RGBA8;
-            case LOCAL_GL_RGB:
-            case LOCAL_GL_SRGB_EXT:
-                return WebGLTexelFormat::RGB8;
-            case LOCAL_GL_ALPHA:
-                return WebGLTexelFormat::A8;
-            case LOCAL_GL_LUMINANCE:
-                return WebGLTexelFormat::R8;
-            case LOCAL_GL_LUMINANCE_ALPHA:
-                return WebGLTexelFormat::RA8;
-        }
-
-        MOZ_CRASH("Invalid WebGL texture format/type?");
-    }
-
-    if (type == LOCAL_GL_FLOAT) {
-        // OES_texture_float
-        switch (internalformat.get()) {
-            case LOCAL_GL_RGBA:
-            case LOCAL_GL_RGBA32F:
-                return WebGLTexelFormat::RGBA32F;
-            case LOCAL_GL_RGB:
-            case LOCAL_GL_RGB32F:
-                return WebGLTexelFormat::RGB32F;
-            case LOCAL_GL_ALPHA:
-            case LOCAL_GL_ALPHA32F_ARB:
-                return WebGLTexelFormat::A32F;
-            case LOCAL_GL_LUMINANCE:
-            case LOCAL_GL_LUMINANCE32F_ARB:
-                return WebGLTexelFormat::R32F;
-            case LOCAL_GL_LUMINANCE_ALPHA:
-            case LOCAL_GL_LUMINANCE_ALPHA32F_ARB:
-                return WebGLTexelFormat::RA32F;
-        }
-
-        MOZ_CRASH("Invalid WebGL texture format/type?");
-    } else if (type == LOCAL_GL_HALF_FLOAT_OES) {
-        // OES_texture_half_float
-        switch (internalformat.get()) {
-            case LOCAL_GL_RGBA:
-            case LOCAL_GL_RGBA16F:
-                return WebGLTexelFormat::RGBA16F;
-            case LOCAL_GL_RGB:
-            case LOCAL_GL_RGB16F:
-                return WebGLTexelFormat::RGB16F;
-            case LOCAL_GL_ALPHA:
-            case LOCAL_GL_ALPHA16F_ARB:
-                return WebGLTexelFormat::A16F;
-            case LOCAL_GL_LUMINANCE:
-            case LOCAL_GL_LUMINANCE16F_ARB:
-                return WebGLTexelFormat::R16F;
-            case LOCAL_GL_LUMINANCE_ALPHA:
-            case LOCAL_GL_LUMINANCE_ALPHA16F_ARB:
-                return WebGLTexelFormat::RA16F;
-            default:
-                MOZ_ASSERT(false, "Coding mistake?! Should never reach this point.");
-                return WebGLTexelFormat::BadFormat;
-        }
-    }
-
-    switch (type.get()) {
-        case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
-           return WebGLTexelFormat::RGBA4444;
-        case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
-           return WebGLTexelFormat::RGBA5551;
-        case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
-           return WebGLTexelFormat::RGB565;
+    switch (effectiveinternalformat.get()) {
+        case LOCAL_GL_DEPTH_COMPONENT16:      return WebGLTexelFormat::D16;
+        case LOCAL_GL_DEPTH_COMPONENT24:      return WebGLTexelFormat::D32;
+        case LOCAL_GL_DEPTH24_STENCIL8:       return WebGLTexelFormat::D24S8;
+        case LOCAL_GL_RGBA8:                  return WebGLTexelFormat::RGBA8;
+        case LOCAL_GL_SRGB8_ALPHA8:           return WebGLTexelFormat::RGBA8;
+        case LOCAL_GL_RGB8:                   return WebGLTexelFormat::RGB8;
+        case LOCAL_GL_SRGB8:                  return WebGLTexelFormat::RGB8;
+        case LOCAL_GL_ALPHA8:                 return WebGLTexelFormat::A8;
+        case LOCAL_GL_LUMINANCE8:             return WebGLTexelFormat::R8;
+        case LOCAL_GL_LUMINANCE8_ALPHA8:      return WebGLTexelFormat::RA8;
+        case LOCAL_GL_RGBA32F:                return WebGLTexelFormat::RGBA32F;
+        case LOCAL_GL_RGB32F:                 return WebGLTexelFormat::RGB32F;
+        case LOCAL_GL_ALPHA32F_EXT:           return WebGLTexelFormat::A32F;
+        case LOCAL_GL_LUMINANCE32F_EXT:       return WebGLTexelFormat::R32F;
+        case LOCAL_GL_LUMINANCE_ALPHA32F_EXT: return WebGLTexelFormat::RA32F;
+        case LOCAL_GL_RGBA16F:                return WebGLTexelFormat::RGBA16F;
+        case LOCAL_GL_RGB16F:                 return WebGLTexelFormat::RGB16F;
+        case LOCAL_GL_ALPHA16F_EXT:           return WebGLTexelFormat::A16F;
+        case LOCAL_GL_LUMINANCE16F_EXT:       return WebGLTexelFormat::R16F;
+        case LOCAL_GL_LUMINANCE_ALPHA16F_EXT: return WebGLTexelFormat::RA16F;
+        case LOCAL_GL_RGBA4:                  return WebGLTexelFormat::RGBA4444;
+        case LOCAL_GL_RGB5_A1:                return WebGLTexelFormat::RGBA5551;
+        case LOCAL_GL_RGB565:                 return WebGLTexelFormat::RGB565;
         default:
-            MOZ_ASSERT(false, "Coding mistake?! Should never reach this point.");
+            MOZ_CRASH("Unhandled format");
             return WebGLTexelFormat::BadFormat;
     }
-
-    MOZ_CRASH("Invalid WebGL texture format/type?");
 }
 
 void
 WebGLContext::BlendColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a) {
     if (IsContextLost())
         return;
     MakeContextCurrent();
     gl->fBlendColor(r, g, b, a);
--- a/dom/canvas/WebGLContextUtils.cpp
+++ b/dom/canvas/WebGLContextUtils.cpp
@@ -26,39 +26,38 @@
 
 #include "mozilla/dom/ScriptSettings.h"
 
 namespace mozilla {
 
 using namespace gl;
 
 bool
-IsGLDepthFormat(TexInternalFormat webGLFormat)
+IsGLDepthFormat(TexInternalFormat internalformat)
 {
-    return (webGLFormat == LOCAL_GL_DEPTH_COMPONENT ||
-            webGLFormat == LOCAL_GL_DEPTH_COMPONENT16 ||
-            webGLFormat == LOCAL_GL_DEPTH_COMPONENT32);
+    TexInternalFormat unsizedformat = UnsizedInternalFormatFromInternalFormat(internalformat);
+    return unsizedformat == LOCAL_GL_DEPTH_COMPONENT;
 }
 
 bool
-IsGLDepthStencilFormat(TexInternalFormat webGLFormat)
+IsGLDepthStencilFormat(TexInternalFormat internalformat)
 {
-    return (webGLFormat == LOCAL_GL_DEPTH_STENCIL ||
-            webGLFormat == LOCAL_GL_DEPTH24_STENCIL8);
+    TexInternalFormat unsizedformat = UnsizedInternalFormatFromInternalFormat(internalformat);
+    return unsizedformat == LOCAL_GL_DEPTH_STENCIL;
 }
 
 bool
-FormatHasAlpha(TexInternalFormat webGLFormat)
+FormatHasAlpha(TexInternalFormat internalformat)
 {
-    return webGLFormat == LOCAL_GL_RGBA ||
-           webGLFormat == LOCAL_GL_LUMINANCE_ALPHA ||
-           webGLFormat == LOCAL_GL_ALPHA ||
-           webGLFormat == LOCAL_GL_RGBA4 ||
-           webGLFormat == LOCAL_GL_RGB5_A1 ||
-           webGLFormat == LOCAL_GL_SRGB_ALPHA;
+    TexInternalFormat unsizedformat = UnsizedInternalFormatFromInternalFormat(internalformat);
+    return unsizedformat == LOCAL_GL_RGBA ||
+           unsizedformat == LOCAL_GL_LUMINANCE_ALPHA ||
+           unsizedformat == LOCAL_GL_ALPHA ||
+           unsizedformat == LOCAL_GL_SRGB_ALPHA ||
+           unsizedformat == LOCAL_GL_RGBA_INTEGER;
 }
 
 TexTarget
 TexImageTargetToTexTarget(TexImageTarget texImageTarget)
 {
     switch (texImageTarget.get()) {
     case LOCAL_GL_TEXTURE_2D:
         return LOCAL_GL_TEXTURE_2D;
@@ -71,21 +70,22 @@ TexImageTargetToTexTarget(TexImageTarget
         return LOCAL_GL_TEXTURE_CUBE_MAP;
     default:
         MOZ_ASSERT(false, "Bad texture conversion");
         // Should be caught by the constructor for TexTarget
         return LOCAL_GL_NONE;
     }
 }
 
-GLComponents::GLComponents(TexInternalFormat format)
+GLComponents::GLComponents(TexInternalFormat internalformat)
 {
+    TexInternalFormat unsizedformat = UnsizedInternalFormatFromInternalFormat(internalformat);
     mComponents = 0;
 
-    switch (format.get()) {
+    switch (unsizedformat.get()) {
         case LOCAL_GL_RGBA:
         case LOCAL_GL_RGBA4:
         case LOCAL_GL_RGBA8:
         case LOCAL_GL_RGB5_A1:
         // Luminance + Alpha can be converted
         // to and from RGBA
         case LOCAL_GL_LUMINANCE_ALPHA:
             mComponents |= Components::Alpha;
@@ -112,162 +112,287 @@ GLComponents::GLComponents(TexInternalFo
 }
 
 bool
 GLComponents::IsSubsetOf(const GLComponents& other) const
 {
     return (mComponents | other.mComponents) == other.mComponents;
 }
 
+TexType
+TypeFromInternalFormat(TexInternalFormat internalformat)
+{
+#define HANDLE_WEBGL_INTERNAL_FORMAT(table_effectiveinternalformat, table_internalformat, table_type) \
+    if (internalformat == table_effectiveinternalformat) { \
+        return table_type; \
+    }
+
+#include "WebGLInternalFormatsTable.h"
+
+    // if we're here, then internalformat is not an effective internalformat i.e. is an unsized internalformat.
+    return LOCAL_GL_NONE; // no size, no type
+}
+
+TexInternalFormat
+UnsizedInternalFormatFromInternalFormat(TexInternalFormat internalformat)
+{
+#define HANDLE_WEBGL_INTERNAL_FORMAT(table_effectiveinternalformat, table_internalformat, table_type) \
+    if (internalformat == table_effectiveinternalformat) { \
+        return table_internalformat; \
+    }
+
+#include "WebGLInternalFormatsTable.h"
+
+    // if we're here, then internalformat is not an effective internalformat i.e. is an unsized internalformat.
+    // so we can just return it.
+    return internalformat;
+}
+
+/*
+ * Note that the following two functions are inverse of each other:
+ * EffectiveInternalFormatFromInternalFormatAndType and
+ * InternalFormatAndTypeFromEffectiveInternalFormat both implement OpenGL ES 3.0.3 Table 3.2
+ * but in opposite directions.
+ */
+TexInternalFormat
+EffectiveInternalFormatFromUnsizedInternalFormatAndType(TexInternalFormat internalformat,
+                                                        TexType type)
+{
+    MOZ_ASSERT(TypeFromInternalFormat(internalformat) == LOCAL_GL_NONE);
+
+#define HANDLE_WEBGL_INTERNAL_FORMAT(table_effectiveinternalformat, table_internalformat, table_type) \
+    if (internalformat == table_internalformat && type == table_type) { \
+        return table_effectiveinternalformat; \
+    }
+
+#include "WebGLInternalFormatsTable.h"
+
+    // If we're here, that means that type was incompatible with the given internalformat.
+    return LOCAL_GL_NONE;
+}
+
+void
+UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(TexInternalFormat effectiveinternalformat,
+                                                        TexInternalFormat* out_internalformat,
+                                                        TexType* out_type)
+{
+    MOZ_ASSERT(TypeFromInternalFormat(effectiveinternalformat) != LOCAL_GL_NONE);
+
+    MOZ_ASSERT(out_internalformat);
+    MOZ_ASSERT(out_type);
+
+    GLenum internalformat = LOCAL_GL_NONE;
+    GLenum type = LOCAL_GL_NONE;
+
+    switch (effectiveinternalformat.get()) {
+
+#define HANDLE_WEBGL_INTERNAL_FORMAT(table_effectiveinternalformat, table_internalformat, table_type) \
+    case table_effectiveinternalformat: \
+        internalformat = table_internalformat; \
+        type = table_type; \
+        break;
+
+#include "WebGLInternalFormatsTable.h"
+
+        default:
+            MOZ_CRASH(); // impossible to get here
+    }
+
+    *out_internalformat = internalformat;
+    *out_type = type;
+}
+
+TexInternalFormat
+EffectiveInternalFormatFromInternalFormatAndType(TexInternalFormat internalformat,
+                                                 TexType type)
+{
+    TexType typeOfInternalFormat = TypeFromInternalFormat(internalformat);
+    if (typeOfInternalFormat == LOCAL_GL_NONE) {
+        return EffectiveInternalFormatFromUnsizedInternalFormatAndType(internalformat, type);
+    } else if (typeOfInternalFormat == type) {
+        return internalformat;
+    } else {
+        return LOCAL_GL_NONE;
+    }
+}
+
 /**
- * Convert WebGL/ES format and type into GL internal
- * format valid for underlying driver.
+ * Convert effective internalformat into GL function parameters
+ * valid for underlying driver.
  */
 void
-DriverFormatsFromFormatAndType(GLContext* gl, TexInternalFormat webGLInternalFormat, TexType webGLType,
-                               GLenum* out_driverInternalFormat, GLenum* out_driverFormat)
+DriverFormatsFromEffectiveInternalFormat(gl::GLContext* gl,
+                                         TexInternalFormat effectiveinternalformat,
+                                         GLenum* out_driverInternalFormat,
+                                         GLenum* out_driverFormat,
+                                         GLenum* out_driverType)
 {
     MOZ_ASSERT(out_driverInternalFormat);
     MOZ_ASSERT(out_driverFormat);
+    MOZ_ASSERT(out_driverType);
 
-    // ES2 requires that format == internalformat; floating-point is
-    // indicated purely by the type that's loaded.  For desktop GL, we
-    // have to specify a floating point internal format.
-    if (gl->IsGLES()) {
-        *out_driverFormat = *out_driverInternalFormat = webGLInternalFormat.get();
-        return;
+    TexInternalFormat unsizedinternalformat = LOCAL_GL_NONE;
+    TexType type = LOCAL_GL_NONE;
+
+    UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(effectiveinternalformat,
+                                                            &unsizedinternalformat, &type);
+
+    // driverType: almost always the generic type that we just got, except on ES
+    // we must replace HALF_FLOAT by HALF_FLOAT_OES
+    GLenum driverType = type.get();
+    if (gl->IsGLES() && type == LOCAL_GL_HALF_FLOAT) {
+        driverType = LOCAL_GL_HALF_FLOAT_OES;
     }
 
-    GLenum internalFormat = LOCAL_GL_NONE;
-    GLenum format = LOCAL_GL_NONE;
-
-    if (webGLInternalFormat == LOCAL_GL_DEPTH_COMPONENT) {
-        format = LOCAL_GL_DEPTH_COMPONENT;
-        if (webGLType == LOCAL_GL_UNSIGNED_SHORT)
-            internalFormat = LOCAL_GL_DEPTH_COMPONENT16;
-        else if (webGLType == LOCAL_GL_UNSIGNED_INT)
-            internalFormat = LOCAL_GL_DEPTH_COMPONENT32;
-    } else if (webGLInternalFormat == LOCAL_GL_DEPTH_STENCIL) {
-        format = LOCAL_GL_DEPTH_STENCIL;
-        if (webGLType == LOCAL_GL_UNSIGNED_INT_24_8_EXT)
-            internalFormat = LOCAL_GL_DEPTH24_STENCIL8;
-    } else {
-        switch (webGLType.get()) {
-        case LOCAL_GL_UNSIGNED_BYTE:
-        case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
-        case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
-        case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
-            format = internalFormat = webGLInternalFormat.get();
-            break;
-
-        case LOCAL_GL_FLOAT:
-            switch (webGLInternalFormat.get()) {
-            case LOCAL_GL_RGBA:
-                format = LOCAL_GL_RGBA;
-                internalFormat = LOCAL_GL_RGBA32F;
-                break;
-
-            case LOCAL_GL_RGB:
-                format = LOCAL_GL_RGB;
-                internalFormat = LOCAL_GL_RGB32F;
-                break;
-
-            case LOCAL_GL_ALPHA:
-                format = LOCAL_GL_ALPHA;
-                internalFormat = LOCAL_GL_ALPHA32F_ARB;
-                break;
+    // driverFormat: always just the unsized internalformat that we just got
+    GLenum driverFormat = unsizedinternalformat.get();
 
-            case LOCAL_GL_LUMINANCE:
-                format = LOCAL_GL_LUMINANCE;
-                internalFormat = LOCAL_GL_LUMINANCE32F_ARB;
-                break;
-
-            case LOCAL_GL_LUMINANCE_ALPHA:
-                format = LOCAL_GL_LUMINANCE_ALPHA;
-                internalFormat = LOCAL_GL_LUMINANCE_ALPHA32F_ARB;
-                break;
-            }
-            break;
-
-        case LOCAL_GL_HALF_FLOAT_OES:
-            switch (webGLInternalFormat.get()) {
-            case LOCAL_GL_RGBA:
-                format = LOCAL_GL_RGBA;
-                internalFormat = LOCAL_GL_RGBA16F;
-                break;
-
-            case LOCAL_GL_RGB:
-                format = LOCAL_GL_RGB;
-                internalFormat = LOCAL_GL_RGB16F;
-                break;
-
-            case LOCAL_GL_ALPHA:
-                format = LOCAL_GL_ALPHA;
-                internalFormat = LOCAL_GL_ALPHA16F_ARB;
-                break;
-
-            case LOCAL_GL_LUMINANCE:
-                format = LOCAL_GL_LUMINANCE;
-                internalFormat = LOCAL_GL_LUMINANCE16F_ARB;
-                break;
-
-            case LOCAL_GL_LUMINANCE_ALPHA:
-                format = LOCAL_GL_LUMINANCE_ALPHA;
-                internalFormat = LOCAL_GL_LUMINANCE_ALPHA16F_ARB;
-                break;
-            }
-            break;
-
-        default:
-            break;
+    // driverInternalFormat: almost always the same as driverFormat, but on desktop GL,
+    // in some cases we must pass a different value. On ES, they are equal by definition
+    // as it is an error to pass internalformat!=format.
+    GLenum driverInternalFormat = driverFormat;
+    if (!gl->IsGLES()) {
+        // Cases where desktop OpenGL requires a tweak to 'format'
+        if (driverFormat == LOCAL_GL_SRGB) {
+            driverFormat = LOCAL_GL_RGB;
+        } else if (driverFormat == LOCAL_GL_SRGB_ALPHA) {
+            driverFormat = LOCAL_GL_RGBA;
         }
 
-        // Handle ES2 and GL differences when supporting sRGB internal formats. GL ES
-        // requires that format == internalformat, but GL will fail in this case.
-        // GL requires:
-        //      format  ->  internalformat
-        //      GL_RGB      GL_SRGB_EXT
-        //      GL_RGBA     GL_SRGB_ALPHA_EXT
-        switch (webGLInternalFormat.get()) {
-        case LOCAL_GL_SRGB:
-            format = LOCAL_GL_RGB;
-            internalFormat = LOCAL_GL_SRGB;
-            break;
-        case LOCAL_GL_SRGB_ALPHA:
-            format = LOCAL_GL_RGBA;
-            internalFormat = LOCAL_GL_SRGB_ALPHA;
-            break;
+        // Cases where desktop OpenGL requires a sized internalformat,
+        // as opposed to the unsized internalformat that had the same
+        // GLenum value as 'format', in order to get the precise
+        // semantics that we want. For example, for floating-point formats,
+        // we seem to need a sized internalformat to get non-clamped floating
+        // point texture sampling. Can't find the spec reference for that,
+        // but that's at least the case on my NVIDIA driver version 331.
+        if (unsizedinternalformat == LOCAL_GL_DEPTH_COMPONENT ||
+            unsizedinternalformat == LOCAL_GL_DEPTH_STENCIL ||
+            type == LOCAL_GL_FLOAT ||
+            type == LOCAL_GL_HALF_FLOAT)
+        {
+            driverInternalFormat = effectiveinternalformat.get();
         }
     }
 
-    MOZ_ASSERT(webGLInternalFormat != LOCAL_GL_NONE && internalFormat != LOCAL_GL_NONE,
-               "Coding mistake -- bad format/type passed?");
-
-    *out_driverInternalFormat = internalFormat;
-    *out_driverFormat = format;
+    *out_driverInternalFormat = driverInternalFormat;
+    *out_driverFormat = driverFormat;
+    *out_driverType = driverType;
 }
 
-GLenum
-DriverTypeFromType(GLContext* gl, TexType webGLType)
+/**
+ * Return the bits per texel for format & type combination.
+ * Assumes that format & type are a valid combination as checked with
+ * ValidateTexImageFormatAndType().
+ */
+size_t
+GetBitsPerTexel(TexInternalFormat effectiveinternalformat)
 {
-    GLenum type = webGLType.get();
+    switch (effectiveinternalformat.get()) {
+    case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
+    case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
+        return 2;
+
+    case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+    case LOCAL_GL_ATC_RGB:
+    case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
+    case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
+    case LOCAL_GL_ETC1_RGB8_OES:
+        return 4;
 
-    if (gl->IsGLES())
-        return type;
+    case LOCAL_GL_ALPHA8:
+    case LOCAL_GL_LUMINANCE8:
+    case LOCAL_GL_R8:
+    case LOCAL_GL_R8I:
+    case LOCAL_GL_R8UI:
+    case LOCAL_GL_R8_SNORM:
+    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+    case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
+    case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
+        return 8;
+
+    case LOCAL_GL_LUMINANCE8_ALPHA8:
+    case LOCAL_GL_RGBA4:
+    case LOCAL_GL_RGB5_A1:
+    case LOCAL_GL_DEPTH_COMPONENT16:
+    case LOCAL_GL_RG8:
+    case LOCAL_GL_R16I:
+    case LOCAL_GL_R16UI:
+    case LOCAL_GL_RGB565:
+    case LOCAL_GL_R16F:
+    case LOCAL_GL_RG8I:
+    case LOCAL_GL_RG8UI:
+    case LOCAL_GL_RG8_SNORM:
+    case LOCAL_GL_ALPHA16F_EXT:
+    case LOCAL_GL_LUMINANCE16F_EXT:
+        return 16;
 
-    // convert type for half float if not on GLES2
-    if (type == LOCAL_GL_HALF_FLOAT_OES) {
-        if (gl->IsSupported(gl::GLFeature::texture_half_float)) {
-            return LOCAL_GL_HALF_FLOAT;
-        } else {
-            MOZ_ASSERT(gl->IsExtensionSupported(gl::GLContext::OES_texture_half_float));
-        }
+    case LOCAL_GL_RGB8:
+    case LOCAL_GL_DEPTH_COMPONENT24:
+    case LOCAL_GL_SRGB8:
+    case LOCAL_GL_RGB8UI:
+    case LOCAL_GL_RGB8I:
+    case LOCAL_GL_RGB8_SNORM:
+        return 24;
+
+    case LOCAL_GL_RGBA8:
+    case LOCAL_GL_RGB10_A2:
+    case LOCAL_GL_R32F:
+    case LOCAL_GL_RG16F:
+    case LOCAL_GL_R32I:
+    case LOCAL_GL_R32UI:
+    case LOCAL_GL_RG16I:
+    case LOCAL_GL_RG16UI:
+    case LOCAL_GL_DEPTH24_STENCIL8:
+    case LOCAL_GL_R11F_G11F_B10F:
+    case LOCAL_GL_RGB9_E5:
+    case LOCAL_GL_SRGB8_ALPHA8:
+    case LOCAL_GL_DEPTH_COMPONENT32F:
+    case LOCAL_GL_RGBA8UI:
+    case LOCAL_GL_RGBA8I:
+    case LOCAL_GL_RGBA8_SNORM:
+    case LOCAL_GL_RGB10_A2UI:
+    case LOCAL_GL_LUMINANCE_ALPHA16F_EXT:
+    case LOCAL_GL_ALPHA32F_EXT:
+    case LOCAL_GL_LUMINANCE32F_EXT:
+        return 32;
+
+    case LOCAL_GL_DEPTH32F_STENCIL8:
+        return 40;
+
+    case LOCAL_GL_RGB16F:
+    case LOCAL_GL_RGB16UI:
+    case LOCAL_GL_RGB16I:
+        return 48;
+
+    case LOCAL_GL_RG32F:
+    case LOCAL_GL_RG32I:
+    case LOCAL_GL_RG32UI:
+    case LOCAL_GL_RGBA16F:
+    case LOCAL_GL_RGBA16UI:
+    case LOCAL_GL_RGBA16I:
+    case LOCAL_GL_LUMINANCE_ALPHA32F_EXT:
+        return 64;
+
+    case LOCAL_GL_RGB32F:
+    case LOCAL_GL_RGB32UI:
+    case LOCAL_GL_RGB32I:
+        return 96;
+
+    case LOCAL_GL_RGBA32F:
+    case LOCAL_GL_RGBA32UI:
+    case LOCAL_GL_RGBA32I:
+        return 128;
+
+    default:
+        MOZ_ASSERT(false, "Unhandled format");
+        return 0;
     }
-
-    return type;
 }
 
 void
 WebGLContext::GenerateWarning(const char *fmt, ...)
 {
     va_list ap;
     va_start(ap, fmt);
 
--- a/dom/canvas/WebGLContextUtils.h
+++ b/dom/canvas/WebGLContextUtils.h
@@ -11,19 +11,38 @@
 #include "mozilla/Assertions.h"
 #include "mozilla/dom/BindingUtils.h"
 
 namespace mozilla {
 
 bool IsGLDepthFormat(TexInternalFormat webGLFormat);
 bool IsGLDepthStencilFormat(TexInternalFormat webGLFormat);
 bool FormatHasAlpha(TexInternalFormat webGLFormat);
-void DriverFormatsFromFormatAndType(gl::GLContext* gl, TexInternalFormat webGLFormat, TexType webGLType,
-                                    GLenum* out_driverInternalFormat, GLenum* out_driverFormat);
-GLenum DriverTypeFromType(gl::GLContext* gl, TexType webGLType);
+void
+DriverFormatsFromEffectiveInternalFormat(gl::GLContext* gl,
+                                         TexInternalFormat internalformat,
+                                         GLenum* out_driverInternalFormat,
+                                         GLenum* out_driverFormat,
+                                         GLenum* out_driverType);
+TexInternalFormat
+EffectiveInternalFormatFromInternalFormatAndType(TexInternalFormat internalformat,
+                                                 TexType type);
+TexInternalFormat
+EffectiveInternalFormatFromUnsizedInternalFormatAndType(TexInternalFormat internalformat,
+                                                        TexType type);
+void
+UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(TexInternalFormat effectiveinternalformat,
+                                                        TexInternalFormat* out_internalformat,
+                                                        TexType* out_type);
+TexType
+TypeFromInternalFormat(TexInternalFormat internalformat);
+TexInternalFormat
+UnsizedInternalFormatFromInternalFormat(TexInternalFormat internalformat);
+size_t
+GetBitsPerTexel(TexInternalFormat effectiveinternalformat);
 
 // For use with the different texture calls, i.e.
 //   TexImage2D, CopyTex[Sub]Image2D, ...
 // that take a "target" parameter. This parameter is not always the same as
 // the texture binding location, like GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP.
 // For example, cube maps would pass GL_TEXTURE_CUBE_MAP_[POS|NEG]_[X|Y|Z]
 // instead of just GL_TEXTURE_CUBE_MAP.
 //
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -668,17 +668,17 @@ WebGLContext::ValidateTexImageType(GLenu
         bool validType = IsExtensionEnabled(WebGLExtensionID::OES_texture_float);
         if (!validType)
             ErrorInvalidEnum("%s: invalid type %s: need OES_texture_float enabled",
                              InfoFrom(func), WebGLContext::EnumName(type));
         return validType;
     }
 
     /* OES_texture_half_float add types */
-    if (type == LOCAL_GL_HALF_FLOAT_OES) {
+    if (type == LOCAL_GL_HALF_FLOAT) {
         bool validType = IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float);
         if (!validType)
             ErrorInvalidEnum("%s: invalid type %s: need OES_texture_half_float enabled",
                              InfoFrom(func), WebGLContext::EnumName(type));
         return validType;
     }
 
     /* WEBGL_depth_texture added types */
@@ -1021,105 +1021,16 @@ WebGLContext::ValidateTexSubImageSize(GL
         ErrorInvalidValue("%s: subtexture rectangle out-of-bounds", InfoFrom(func));
         return false;
     }
 
     return true;
 }
 
 /**
- * Return the bits per texel for format & type combination.
- * Assumes that format & type are a valid combination as checked with
- * ValidateTexImageFormatAndType().
- */
-uint32_t
-WebGLContext::GetBitsPerTexel(TexInternalFormat format, TexType type)
-{
-    /* Known fixed-sized types */
-    if (type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
-        type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 ||
-        type == LOCAL_GL_UNSIGNED_SHORT_5_6_5)
-    {
-        return 16;
-    }
-
-    if (type == LOCAL_GL_UNSIGNED_INT_24_8)
-        return 32;
-
-    int bitsPerComponent = 0;
-    switch (type.get()) {
-    case LOCAL_GL_UNSIGNED_BYTE:
-        bitsPerComponent = 8;
-        break;
-
-    case LOCAL_GL_HALF_FLOAT:
-    case LOCAL_GL_HALF_FLOAT_OES:
-    case LOCAL_GL_UNSIGNED_SHORT:
-        bitsPerComponent = 16;
-        break;
-
-    case LOCAL_GL_FLOAT:
-    case LOCAL_GL_UNSIGNED_INT:
-        bitsPerComponent = 32;
-        break;
-
-    default:
-        MOZ_ASSERT(false, "Unhandled type.");
-        break;
-    }
-
-    switch (format.get()) {
-        // Uncompressed formats
-    case LOCAL_GL_ALPHA:
-    case LOCAL_GL_LUMINANCE:
-    case LOCAL_GL_DEPTH_COMPONENT:
-    case LOCAL_GL_DEPTH_STENCIL:
-        return 1 * bitsPerComponent;
-
-    case LOCAL_GL_LUMINANCE_ALPHA:
-        return 2 * bitsPerComponent;
-
-    case LOCAL_GL_RGB:
-    case LOCAL_GL_RGB32F:
-    case LOCAL_GL_SRGB_EXT:
-        return 3 * bitsPerComponent;
-
-    case LOCAL_GL_RGBA:
-    case LOCAL_GL_RGBA32F:
-    case LOCAL_GL_SRGB_ALPHA_EXT:
-        return 4 * bitsPerComponent;
-
-        // Compressed formats
-    case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
-    case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
-        return 2;
-
-    case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
-    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
-    case LOCAL_GL_ATC_RGB:
-    case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
-    case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
-    case LOCAL_GL_ETC1_RGB8_OES:
-        return 4;
-
-    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
-    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
-    case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
-    case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
-        return 8;
-
-    default:
-        break;
-    }
-
-    MOZ_ASSERT(false, "Unhandled format+type combo.");
-    return 0;
-}
-
-/**
  * Perform validation of format/type combinations for TexImage variants.
  * Returns true if the format/type is a valid combination, false otherwise.
  */
 bool
 WebGLContext::ValidateTexImageFormatAndType(GLenum format,
                                             GLenum type, WebGLTexImageFunc func)
 {
     if (IsCompressedFunc(func) || IsCopyFunc(func))
@@ -1136,36 +1047,33 @@ WebGLContext::ValidateTexImageFormatAndT
     bool validCombo = false;
 
     switch (format) {
     case LOCAL_GL_ALPHA:
     case LOCAL_GL_LUMINANCE:
     case LOCAL_GL_LUMINANCE_ALPHA:
         validCombo = (type == LOCAL_GL_UNSIGNED_BYTE ||
                       type == LOCAL_GL_HALF_FLOAT ||
-                      type == LOCAL_GL_HALF_FLOAT_OES ||
                       type == LOCAL_GL_FLOAT);
         break;
 
     case LOCAL_GL_RGB:
     case LOCAL_GL_SRGB:
         validCombo = (type == LOCAL_GL_UNSIGNED_BYTE ||
                       type == LOCAL_GL_UNSIGNED_SHORT_5_6_5 ||
                       type == LOCAL_GL_HALF_FLOAT ||
-                      type == LOCAL_GL_HALF_FLOAT_OES ||
                       type == LOCAL_GL_FLOAT);
         break;
 
     case LOCAL_GL_RGBA:
     case LOCAL_GL_SRGB_ALPHA:
         validCombo = (type == LOCAL_GL_UNSIGNED_BYTE ||
                       type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
                       type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 ||
                       type == LOCAL_GL_HALF_FLOAT ||
-                      type == LOCAL_GL_HALF_FLOAT_OES ||
                       type == LOCAL_GL_FLOAT);
         break;
 
     case LOCAL_GL_DEPTH_COMPONENT:
         validCombo = (type == LOCAL_GL_UNSIGNED_SHORT ||
                       type == LOCAL_GL_UNSIGNED_INT);
         break;
 
@@ -1286,17 +1194,16 @@ WebGLContext::ValidateTexInputData(GLenu
 
     // First, we check for packed types
     switch (type) {
     case LOCAL_GL_UNSIGNED_BYTE:
         validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Uint8);
         break;
 
     case LOCAL_GL_HALF_FLOAT:
-    case LOCAL_GL_HALF_FLOAT_OES:
     case LOCAL_GL_UNSIGNED_SHORT:
     case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
     case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
     case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
         validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Uint16);
         break;
 
     case LOCAL_GL_UNSIGNED_INT:
@@ -1444,16 +1351,17 @@ WebGLContext::ValidateTexImage(GLuint di
     if (IsSubFunc(func)) {
         if (!tex->HasImageInfoAt(texImageTarget, level)) {
             ErrorInvalidOperation("%s: no texture image previously defined for target %s at level %d",
                                   info, WebGLContext::EnumName(texImageTarget.get()), level);
             return false;
         }
 
         const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
+
         if (!ValidateTexSubImageSize(xoffset, yoffset, zoffset,
                                      width, height, depth,
                                      imageInfo.Width(), imageInfo.Height(), 0,
                                      func))
         {
             return false;
         }
     }
--- a/dom/canvas/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -74,73 +74,66 @@ WebGLFramebuffer::Attachment::IsDefined(
 }
 
 bool
 WebGLFramebuffer::Attachment::HasAlpha() const
 {
     MOZ_ASSERT(HasImage());
 
     if (Texture() && Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel))
-        return FormatHasAlpha(Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).InternalFormat());
+        return FormatHasAlpha(Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).EffectiveInternalFormat());
     else if (Renderbuffer())
         return FormatHasAlpha(Renderbuffer()->InternalFormat());
     else return false;
 }
 
 GLenum
 WebGLFramebuffer::GetFormatForAttachment(const WebGLFramebuffer::Attachment& attachment) const
 {
     MOZ_ASSERT(attachment.IsDefined());
     MOZ_ASSERT(attachment.Texture() || attachment.Renderbuffer());
 
     if (attachment.Texture()) {
         const WebGLTexture& tex = *attachment.Texture();
         MOZ_ASSERT(tex.HasImageInfoAt(attachment.ImageTarget(), 0));
 
         const WebGLTexture::ImageInfo& imgInfo = tex.ImageInfoAt(attachment.ImageTarget(), 0);
-        return imgInfo.InternalFormat().get();
+        return imgInfo.EffectiveInternalFormat().get();
     }
 
     if (attachment.Renderbuffer())
         return attachment.Renderbuffer()->InternalFormat();
 
     return LOCAL_GL_NONE;
 }
 
-bool
-WebGLFramebuffer::Attachment::IsReadableFloat() const
+TexInternalFormat
+WebGLFramebuffer::Attachment::EffectiveInternalFormat() const
 {
     const WebGLTexture* tex = Texture();
     if (tex && tex->HasImageInfoAt(mTexImageTarget, mTexImageLevel)) {
-        GLenum type = tex->ImageInfoAt(mTexImageTarget, mTexImageLevel).Type().get();
-        switch (type) {
-        case LOCAL_GL_FLOAT:
-        case LOCAL_GL_HALF_FLOAT_OES:
-            return true;
-        }
-        return false;
+        return tex->ImageInfoAt(mTexImageTarget, mTexImageLevel).EffectiveInternalFormat();
     }
 
     const WebGLRenderbuffer* rb = Renderbuffer();
     if (rb) {
-        GLenum format = rb->InternalFormat();
-        switch (format) {
-        case LOCAL_GL_RGB16F:
-        case LOCAL_GL_RGBA16F:
-        case LOCAL_GL_RGB32F:
-        case LOCAL_GL_RGBA32F:
-            return true;
-        }
-        return false;
+        return rb->InternalFormat();
     }
 
-    // If we arrive here Attachment isn't correct setup because it has
-    // no texture nor render buffer pointer.
-    MOZ_ASSERT(false, "Should not get here.");
-    return false;
+    return LOCAL_GL_NONE;
+}
+
+bool
+WebGLFramebuffer::Attachment::IsReadableFloat() const
+{
+    TexInternalFormat internalformat = EffectiveInternalFormat();
+    MOZ_ASSERT(internalformat != LOCAL_GL_NONE);
+    TexType type = TypeFromInternalFormat(internalformat);
+    return type == LOCAL_GL_FLOAT ||
+           type == LOCAL_GL_HALF_FLOAT;
 }
 
 void
 WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level)
 {
     mTexturePtr = tex;
     mRenderbufferPtr = nullptr;
     mTexImageTarget = target;
@@ -225,65 +218,45 @@ WebGLFramebuffer::Attachment::RectangleO
     MOZ_CRASH("Should not get here.");
 }
 
 /* The following IsValidFBOTextureXXX functions check the internal
    format that is used by GL or GL ES texture formats.  This
    corresponds to the state that is stored in
    WebGLTexture::ImageInfo::InternalFormat()*/
 static inline bool
-IsValidFBOTextureColorFormat(GLenum internalFormat)
+IsValidFBOTextureColorFormat(TexInternalFormat internalformat)
 {
     /* These formats are internal formats for each texture -- the actual
      * low level format, which we might have to do conversions for when
      * running against desktop GL (e.g. GL_RGBA + GL_FLOAT -> GL_RGBA32F).
      *
      * This function just handles all of them whether desktop GL or ES.
      */
 
-    return (
-        /* linear 8-bit formats */
-        internalFormat == LOCAL_GL_ALPHA ||
-        internalFormat == LOCAL_GL_LUMINANCE ||
-        internalFormat == LOCAL_GL_LUMINANCE_ALPHA ||
-        internalFormat == LOCAL_GL_RGB ||
-        internalFormat == LOCAL_GL_RGBA ||
-        /* sRGB 8-bit formats */
-        internalFormat == LOCAL_GL_SRGB_EXT ||
-        internalFormat == LOCAL_GL_SRGB_ALPHA_EXT ||
-        /* linear float32 formats */
-        internalFormat == LOCAL_GL_ALPHA32F_ARB ||
-        internalFormat == LOCAL_GL_LUMINANCE32F_ARB ||
-        internalFormat == LOCAL_GL_LUMINANCE_ALPHA32F_ARB ||
-        internalFormat == LOCAL_GL_RGB32F_ARB ||
-        internalFormat == LOCAL_GL_RGBA32F_ARB ||
-        /* texture_half_float formats */
-        internalFormat == LOCAL_GL_ALPHA16F_ARB ||
-        internalFormat == LOCAL_GL_LUMINANCE16F_ARB ||
-        internalFormat == LOCAL_GL_LUMINANCE_ALPHA16F_ARB ||
-        internalFormat == LOCAL_GL_RGB16F_ARB ||
-        internalFormat == LOCAL_GL_RGBA16F_ARB
-    );
+    TexInternalFormat unsizedformat = UnsizedInternalFormatFromInternalFormat(internalformat);
+    return unsizedformat == LOCAL_GL_ALPHA ||
+           unsizedformat == LOCAL_GL_LUMINANCE ||
+           unsizedformat == LOCAL_GL_LUMINANCE_ALPHA ||
+           unsizedformat == LOCAL_GL_RGB ||
+           unsizedformat == LOCAL_GL_RGBA ||
+           unsizedformat == LOCAL_GL_SRGB ||
+           unsizedformat == LOCAL_GL_SRGB_ALPHA;
 }
 
 static inline bool
-IsValidFBOTextureDepthFormat(GLenum internalFormat)
+IsValidFBOTextureDepthFormat(GLenum internalformat)
 {
-    return (
-        internalFormat == LOCAL_GL_DEPTH_COMPONENT ||
-        internalFormat == LOCAL_GL_DEPTH_COMPONENT16 ||
-        internalFormat == LOCAL_GL_DEPTH_COMPONENT32);
+    return IsGLDepthFormat(internalformat);
 }
 
 static inline bool
-IsValidFBOTextureDepthStencilFormat(GLenum internalFormat)
+IsValidFBOTextureDepthStencilFormat(GLenum internalformat)
 {
-    return (
-        internalFormat == LOCAL_GL_DEPTH_STENCIL ||
-        internalFormat == LOCAL_GL_DEPTH24_STENCIL8);
+    return IsGLDepthStencilFormat(internalformat);
 }
 
 /* The following IsValidFBORenderbufferXXX functions check the internal
    format that is stored by WebGLRenderbuffer::InternalFormat(). Valid
    values can be found in WebGLContext::RenderbufferStorage. */
 static inline bool
 IsValidFBORenderbufferColorFormat(GLenum internalFormat)
 {
@@ -325,17 +298,17 @@ WebGLFramebuffer::Attachment::IsComplete
     {
         return false;
     }
 
     if (Texture()) {
         MOZ_ASSERT(Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel));
         const WebGLTexture::ImageInfo& imageInfo =
             Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel);
-        GLenum internalformat = imageInfo.InternalFormat().get();
+        GLenum internalformat = imageInfo.EffectiveInternalFormat().get();
 
         if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT)
             return IsValidFBOTextureDepthFormat(internalformat);
 
         if (mAttachmentPoint == LOCAL_GL_STENCIL_ATTACHMENT)
             return false; // Textures can't have the correct format for stencil buffers
 
         if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
--- a/dom/canvas/WebGLFramebuffer.h
+++ b/dom/canvas/WebGLFramebuffer.h
@@ -48,16 +48,18 @@ public:
 
         explicit Attachment(FBAttachment aAttachmentPoint = LOCAL_GL_COLOR_ATTACHMENT0);
         ~Attachment();
 
         bool IsDefined() const;
 
         bool IsDeleteRequested() const;
 
+        TexInternalFormat EffectiveInternalFormat() const;
+
         bool HasAlpha() const;
         bool IsReadableFloat() const;
 
         void SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level);
         void SetRenderbuffer(WebGLRenderbuffer* rb);
 
         const WebGLTexture* Texture() const {
             return mTexturePtr;
new file mode 100644
--- /dev/null
+++ b/dom/canvas/WebGLInternalFormatsTable.h
@@ -0,0 +1,82 @@
+// intentionally no include guard here.
+
+#ifndef HANDLE_WEBGL_INTERNAL_FORMAT
+#error This header is meant to be included by other files defining HANDLE_WEBGL_INTERNAL_FORMAT.
+#endif
+
+#define WEBGL_INTERNAL_FORMAT(effectiveinternalformat, unsizedinternalformat, type) \
+  HANDLE_WEBGL_INTERNAL_FORMAT(LOCAL_GL_##effectiveinternalformat, \
+                               LOCAL_GL_##unsizedinternalformat, \
+                               LOCAL_GL_##type)
+
+// OpenGL ES 3.0.3, Table 3.2
+//
+// Maps effective internal formats to (unsized internal format, type) pairs.
+//
+//                    Effective int. fmt.     Unsized int. fmt.   Type
+WEBGL_INTERNAL_FORMAT(ALPHA8,                 ALPHA,              UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(LUMINANCE8,             LUMINANCE,          UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(LUMINANCE8_ALPHA8,      LUMINANCE_ALPHA,    UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(RGB8,                   RGB,                UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(RGBA4,                  RGBA,               UNSIGNED_SHORT_4_4_4_4)
+WEBGL_INTERNAL_FORMAT(RGB5_A1,                RGBA,               UNSIGNED_SHORT_5_5_5_1)
+WEBGL_INTERNAL_FORMAT(RGBA8,                  RGBA,               UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(RGB10_A2,               RGB,                UNSIGNED_INT_2_10_10_10_REV)
+WEBGL_INTERNAL_FORMAT(DEPTH_COMPONENT16,      DEPTH_COMPONENT,    UNSIGNED_SHORT)
+WEBGL_INTERNAL_FORMAT(DEPTH_COMPONENT24,      DEPTH_COMPONENT,    UNSIGNED_INT)
+WEBGL_INTERNAL_FORMAT(R8,                     RED,                UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(RG8,                    RG,                 UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(R16F,                   RED,                HALF_FLOAT)
+WEBGL_INTERNAL_FORMAT(R32F,                   RED,                FLOAT)
+WEBGL_INTERNAL_FORMAT(RG16F,                  RG,                 HALF_FLOAT)
+WEBGL_INTERNAL_FORMAT(RG32F,                  RG,                 UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(R8I,                    RED_INTEGER,        BYTE)
+WEBGL_INTERNAL_FORMAT(R8UI,                   RED_INTEGER,        UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(R16I,                   RED_INTEGER,        BYTE)
+WEBGL_INTERNAL_FORMAT(R16UI,                  RED_INTEGER,        UNSIGNED_SHORT)
+WEBGL_INTERNAL_FORMAT(R32I,                   RED_INTEGER,        INT)
+WEBGL_INTERNAL_FORMAT(R32UI,                  RED_INTEGER,        UNSIGNED_INT)
+WEBGL_INTERNAL_FORMAT(RG8I,                   RG_INTEGER,         BYTE)
+WEBGL_INTERNAL_FORMAT(RG8UI,                  RG_INTEGER,         UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(RG16I,                  RG_INTEGER,         SHORT)
+WEBGL_INTERNAL_FORMAT(RG16UI,                 RG_INTEGER,         UNSIGNED_SHORT)
+WEBGL_INTERNAL_FORMAT(RG32I,                  RG_INTEGER,         INT)
+WEBGL_INTERNAL_FORMAT(RG32UI,                 RG_INTEGER,         UNSIGNED_INT)
+WEBGL_INTERNAL_FORMAT(RGBA32F,                RGBA,               FLOAT)
+WEBGL_INTERNAL_FORMAT(RGB32F,                 RGB,                FLOAT)
+WEBGL_INTERNAL_FORMAT(ALPHA32F_EXT,           ALPHA,              FLOAT)
+WEBGL_INTERNAL_FORMAT(LUMINANCE32F_EXT,       LUMINANCE,          FLOAT)
+WEBGL_INTERNAL_FORMAT(LUMINANCE_ALPHA32F_EXT, LUMINANCE_ALPHA,    FLOAT)
+WEBGL_INTERNAL_FORMAT(RGBA16F,                RGBA,               HALF_FLOAT)
+WEBGL_INTERNAL_FORMAT(RGB16F,                 RGB,                HALF_FLOAT)
+WEBGL_INTERNAL_FORMAT(ALPHA16F_EXT,           ALPHA,              HALF_FLOAT)
+WEBGL_INTERNAL_FORMAT(LUMINANCE16F_EXT,       LUMINANCE,          HALF_FLOAT)
+WEBGL_INTERNAL_FORMAT(LUMINANCE_ALPHA16F_EXT, LUMINANCE_ALPHA,    HALF_FLOAT)
+WEBGL_INTERNAL_FORMAT(DEPTH24_STENCIL8,       DEPTH_STENCIL,      UNSIGNED_INT_24_8)
+WEBGL_INTERNAL_FORMAT(R11F_G11F_B10F,         RGB,                UNSIGNED_INT_10F_11F_11F_REV)
+WEBGL_INTERNAL_FORMAT(RGB9_E5,                RGB,                UNSIGNED_INT_5_9_9_9_REV)
+WEBGL_INTERNAL_FORMAT(SRGB8,                  SRGB,               UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(SRGB8_ALPHA8,           SRGB_ALPHA,         UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(DEPTH_COMPONENT32F,     DEPTH_COMPONENT,    FLOAT)
+WEBGL_INTERNAL_FORMAT(DEPTH32F_STENCIL8,      DEPTH_STENCIL,      FLOAT_32_UNSIGNED_INT_24_8_REV)
+WEBGL_INTERNAL_FORMAT(RGB565,                 RGB,                UNSIGNED_SHORT_5_6_5)
+WEBGL_INTERNAL_FORMAT(RGBA32UI,               RGBA_INTEGER,       UNSIGNED_INT)
+WEBGL_INTERNAL_FORMAT(RGB32UI,                RGB_INTEGER,        UNSIGNED_INT)
+WEBGL_INTERNAL_FORMAT(RGBA16UI,               RGBA_INTEGER,       UNSIGNED_SHORT)
+WEBGL_INTERNAL_FORMAT(RGB16UI,                RGB_INTEGER,        UNSIGNED_SHORT)
+WEBGL_INTERNAL_FORMAT(RGBA8UI,                RGBA_INTEGER,       UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(RGB8UI,                 RGB_INTEGER,        UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(RGBA32I,                RGBA_INTEGER,       INT)
+WEBGL_INTERNAL_FORMAT(RGB32I,                 RGB_INTEGER,        INT)
+WEBGL_INTERNAL_FORMAT(RGBA16I,                RGBA_INTEGER,       SHORT)
+WEBGL_INTERNAL_FORMAT(RGB16I,                 RGB_INTEGER,        SHORT)
+WEBGL_INTERNAL_FORMAT(RGBA8I,                 RGBA_INTEGER,       BYTE)
+WEBGL_INTERNAL_FORMAT(RGB8I,                  RGB_INTEGER,        BYTE)
+WEBGL_INTERNAL_FORMAT(R8_SNORM,               RED,                BYTE)
+WEBGL_INTERNAL_FORMAT(RG8_SNORM,              RG,                 BYTE)
+WEBGL_INTERNAL_FORMAT(RGB8_SNORM,             RGB,                BYTE)
+WEBGL_INTERNAL_FORMAT(RGBA8_SNORM,            RGBA,               BYTE)
+WEBGL_INTERNAL_FORMAT(RGB10_A2UI,             RGBA_INTEGER,       UNSIGNED_INT_2_10_10_10_REV)
+
+#undef WEBGL_INTERNAL_FORMAT
+#undef HANDLE_WEBGL_INTERNAL_FORMAT
--- a/dom/canvas/WebGLStrongTypes.h
+++ b/dom/canvas/WebGLStrongTypes.h
@@ -294,16 +294,19 @@ STRONG_GLENUM_END(TexFormat)
 STRONG_GLENUM_BEGIN(TexInternalFormat)
     STRONG_GLENUM_VALUE(NONE),
     STRONG_GLENUM_VALUE(DEPTH_COMPONENT),
     STRONG_GLENUM_VALUE(ALPHA),
     STRONG_GLENUM_VALUE(RGB),
     STRONG_GLENUM_VALUE(RGBA),
     STRONG_GLENUM_VALUE(LUMINANCE),
     STRONG_GLENUM_VALUE(LUMINANCE_ALPHA),
+    STRONG_GLENUM_VALUE(ALPHA8),
+    STRONG_GLENUM_VALUE(LUMINANCE8),
+    STRONG_GLENUM_VALUE(LUMINANCE8_ALPHA8),
     STRONG_GLENUM_VALUE(RGB8),
     STRONG_GLENUM_VALUE(RGBA4),
     STRONG_GLENUM_VALUE(RGB5_A1),
     STRONG_GLENUM_VALUE(RGBA8),
     STRONG_GLENUM_VALUE(RGB10_A2),
     STRONG_GLENUM_VALUE(DEPTH_COMPONENT16),
     STRONG_GLENUM_VALUE(DEPTH_COMPONENT24),
     STRONG_GLENUM_VALUE(R8),
@@ -327,18 +330,24 @@ STRONG_GLENUM_BEGIN(TexInternalFormat)
     STRONG_GLENUM_VALUE(COMPRESSED_RGB_S3TC_DXT1_EXT),
     STRONG_GLENUM_VALUE(COMPRESSED_RGBA_S3TC_DXT1_EXT),
     STRONG_GLENUM_VALUE(COMPRESSED_RGBA_S3TC_DXT3_EXT),
     STRONG_GLENUM_VALUE(COMPRESSED_RGBA_S3TC_DXT5_EXT),
     STRONG_GLENUM_VALUE(DEPTH_STENCIL),
     STRONG_GLENUM_VALUE(ATC_RGBA_INTERPOLATED_ALPHA),
     STRONG_GLENUM_VALUE(RGBA32F),
     STRONG_GLENUM_VALUE(RGB32F),
+    STRONG_GLENUM_VALUE(ALPHA32F_EXT),
+    STRONG_GLENUM_VALUE(LUMINANCE32F_EXT),
+    STRONG_GLENUM_VALUE(LUMINANCE_ALPHA32F_EXT),
     STRONG_GLENUM_VALUE(RGBA16F),
     STRONG_GLENUM_VALUE(RGB16F),
+    STRONG_GLENUM_VALUE(ALPHA16F_EXT),
+    STRONG_GLENUM_VALUE(LUMINANCE16F_EXT),
+    STRONG_GLENUM_VALUE(LUMINANCE_ALPHA16F_EXT),
     STRONG_GLENUM_VALUE(DEPTH24_STENCIL8),
     STRONG_GLENUM_VALUE(COMPRESSED_RGB_PVRTC_4BPPV1),
     STRONG_GLENUM_VALUE(COMPRESSED_RGB_PVRTC_2BPPV1),
     STRONG_GLENUM_VALUE(COMPRESSED_RGBA_PVRTC_4BPPV1),
     STRONG_GLENUM_VALUE(COMPRESSED_RGBA_PVRTC_2BPPV1),
     STRONG_GLENUM_VALUE(R11F_G11F_B10F),
     STRONG_GLENUM_VALUE(RGB9_E5),
     STRONG_GLENUM_VALUE(SRGB),
--- a/dom/canvas/WebGLTexture.cpp
+++ b/dom/canvas/WebGLTexture.cpp
@@ -47,17 +47,17 @@ WebGLTexture::Delete() {
     mContext->gl->fDeleteTextures(1, &mGLName);
     LinkedListElement<WebGLTexture>::removeFrom(mContext->mTextures);
 }
 
 int64_t
 WebGLTexture::ImageInfo::MemoryUsage() const {
     if (mImageDataStatus == WebGLImageDataStatus::NoImageData)
         return 0;
-    int64_t bitsPerTexel = WebGLContext::GetBitsPerTexel(mInternalFormat, mType);
+    int64_t bitsPerTexel = GetBitsPerTexel(mEffectiveInternalFormat);
     return int64_t(mWidth) * int64_t(mHeight) * bitsPerTexel/8;
 }
 
 int64_t
 WebGLTexture::MemoryUsage() const {
     if (IsDeleted())
         return 0;
     int64_t result = 0;
@@ -133,26 +133,25 @@ WebGLTexture::Bind(TexTarget aTexTarget)
         if (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP && !mContext->gl->IsGLES())
             mContext->gl->fTexParameteri(aTexTarget.get(), LOCAL_GL_TEXTURE_WRAP_R, LOCAL_GL_CLAMP_TO_EDGE);
     }
 }
 
 void
 WebGLTexture::SetImageInfo(TexImageTarget aTexImageTarget, GLint aLevel,
                            GLsizei aWidth, GLsizei aHeight,
-                           TexInternalFormat aInternalFormat, TexType aType,
-                           WebGLImageDataStatus aStatus)
+                           TexInternalFormat aEffectiveInternalFormat, WebGLImageDataStatus aStatus)
 {
     MOZ_ASSERT(TexImageTargetToTexTarget(aTexImageTarget) == mTarget);
     if (TexImageTargetToTexTarget(aTexImageTarget) != mTarget)
         return;
 
     EnsureMaxLevelWithCustomImagesAtLeast(aLevel);
 
-    ImageInfoAt(aTexImageTarget, aLevel) = ImageInfo(aWidth, aHeight, aInternalFormat, aType, aStatus);
+    ImageInfoAt(aTexImageTarget, aLevel) = ImageInfo(aWidth, aHeight, aEffectiveInternalFormat, aStatus);
 
     if (aLevel > 0)
         SetCustomMipmap();
 
     // Invalidate framebuffer status cache
     NotifyFBsStatusChanged();
 
     SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
@@ -324,17 +323,19 @@ WebGLTexture::ResolvedFakeBlackStatus() 
                 mContext->GenerateWarning("%s is a cube map texture, with a minification filter not requiring a mipmap, "
                             "with some level 0 image having width or height not a power of two, and with a wrap mode "
                             "different from CLAMP_TO_EDGE.", msg_rendering_as_black);
                 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
             }
         }
     }
 
-    if (ImageInfoBase().mType == LOCAL_GL_FLOAT &&
+    TexType type = TypeFromInternalFormat(ImageInfoBase().mEffectiveInternalFormat);
+
+    if (type == LOCAL_GL_FLOAT &&
         !Context()->IsExtensionEnabled(WebGLExtensionID::OES_texture_float_linear))
     {
         if (mMinFilter == LOCAL_GL_LINEAR ||
             mMinFilter == LOCAL_GL_LINEAR_MIPMAP_LINEAR ||
             mMinFilter == LOCAL_GL_LINEAR_MIPMAP_NEAREST ||
             mMinFilter == LOCAL_GL_NEAREST_MIPMAP_LINEAR)
         {
             mContext->GenerateWarning("%s is a texture with a linear minification filter, "
@@ -344,17 +345,17 @@ WebGLTexture::ResolvedFakeBlackStatus() 
         }
         else if (mMagFilter == LOCAL_GL_LINEAR)
         {
             mContext->GenerateWarning("%s is a texture with a linear magnification filter, "
                                       "which is not compatible with gl.FLOAT by default. "
                                       "Try enabling the OES_texture_float_linear extension if supported.", msg_rendering_as_black);
             mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
         }
-    } else if (ImageInfoBase().mType == LOCAL_GL_HALF_FLOAT_OES &&
+    } else if (type == LOCAL_GL_HALF_FLOAT &&
                !Context()->IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float_linear))
     {
         if (mMinFilter == LOCAL_GL_LINEAR ||
             mMinFilter == LOCAL_GL_LINEAR_MIPMAP_LINEAR ||
             mMinFilter == LOCAL_GL_LINEAR_MIPMAP_NEAREST ||
             mMinFilter == LOCAL_GL_NEAREST_MIPMAP_LINEAR)
         {
             mContext->GenerateWarning("%s is a texture with a linear minification filter, "
@@ -529,47 +530,49 @@ void
 WebGLTexture::DoDeferredImageInitialization(TexImageTarget imageTarget, GLint level)
 {
     const ImageInfo& imageInfo = ImageInfoAt(imageTarget, level);
     MOZ_ASSERT(imageInfo.mImageDataStatus == WebGLImageDataStatus::UninitializedImageData);
 
     mContext->MakeContextCurrent();
 
     // Try to clear with glCLear.
-    TexInternalFormat internalformat = imageInfo.mInternalFormat;
-    TexType type = imageInfo.mType;
-    WebGLTexelFormat texelformat = GetWebGLTexelFormat(internalformat, type);
 
     bool cleared = ClearWithTempFB(mContext, GLName(),
                                    imageTarget, level,
-                                   internalformat, imageInfo.mHeight, imageInfo.mWidth);
+                                   imageInfo.mEffectiveInternalFormat,
+                                   imageInfo.mHeight, imageInfo.mWidth);
     if (cleared) {
         SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData);
         return;
     }
 
     // That didn't work. Try uploading zeros then.
     gl::ScopedBindTexture autoBindTex(mContext->gl, GLName(), mTarget.get());
 
-    uint32_t texelsize = WebGLTexelConversions::TexelBytesForFormat(texelformat);
+    size_t bitspertexel = GetBitsPerTexel(imageInfo.mEffectiveInternalFormat);
+    MOZ_ASSERT((bitspertexel % 8) == 0); // that would only happen for compressed images, which
+                                         // cannot use deferred initialization.
+    size_t bytespertexel = bitspertexel / 8;
     CheckedUint32 checked_byteLength
         = WebGLContext::GetImageSize(
                         imageInfo.mHeight,
                         imageInfo.mWidth,
-                        texelsize,
+                        bytespertexel,
                         mContext->mPixelStoreUnpackAlignment);
     MOZ_ASSERT(checked_byteLength.isValid()); // should have been checked earlier
     ScopedFreePtr<void> zeros;
     zeros = calloc(1, checked_byteLength.value());
 
     gl::GLContext* gl = mContext->gl;
-    GLenum driverType = DriverTypeFromType(gl, type);
     GLenum driverInternalFormat = LOCAL_GL_NONE;
     GLenum driverFormat = LOCAL_GL_NONE;
-    DriverFormatsFromFormatAndType(gl, internalformat, type, &driverInternalFormat, &driverFormat);
+    GLenum driverType = LOCAL_GL_NONE;
+    DriverFormatsFromEffectiveInternalFormat(gl, imageInfo.mEffectiveInternalFormat,
+                                             &driverInternalFormat, &driverFormat, &driverType);
 
     mContext->GetAndFlushUnderlyingGLErrors();
     gl->fTexImage2D(imageTarget.get(), level, driverInternalFormat,
                     imageInfo.mWidth, imageInfo.mHeight,
                     0, driverFormat, driverType,
                     zeros);
     GLenum error = mContext->GetAndFlushUnderlyingGLErrors();
     if (error) {
--- a/dom/canvas/WebGLTexture.h
+++ b/dom/canvas/WebGLTexture.h
@@ -62,41 +62,37 @@ protected:
 
 public:
 
     class ImageInfo
         : public WebGLRectangleObject
     {
     public:
         ImageInfo()
-            : mInternalFormat(LOCAL_GL_NONE)
-            , mType(LOCAL_GL_NONE)
+            : mEffectiveInternalFormat(LOCAL_GL_NONE)
             , mImageDataStatus(WebGLImageDataStatus::NoImageData)
         {}
 
         ImageInfo(GLsizei width,
                   GLsizei height,
-                  TexInternalFormat internalFormat,
-                  TexType type,
+                  TexInternalFormat effectiveInternalFormat,
                   WebGLImageDataStatus status)
             : WebGLRectangleObject(width, height)
-            , mInternalFormat(internalFormat)
-            , mType(type)
+            , mEffectiveInternalFormat(effectiveInternalFormat)
             , mImageDataStatus(status)
         {
             // shouldn't use this constructor to construct a null ImageInfo
             MOZ_ASSERT(status != WebGLImageDataStatus::NoImageData);
         }
 
         bool operator==(const ImageInfo& a) const {
             return mImageDataStatus == a.mImageDataStatus &&
                    mWidth == a.mWidth &&
                    mHeight == a.mHeight &&
-                   mInternalFormat == a.mInternalFormat &&
-                   mType == a.mType;
+                   mEffectiveInternalFormat == a.mEffectiveInternalFormat;
         }
         bool operator!=(const ImageInfo& a) const {
             return !(*this == a);
         }
         bool IsSquare() const {
             return mWidth == mHeight;
         }
         bool IsPositive() const {
@@ -105,31 +101,27 @@ public:
         bool IsPowerOfTwo() const {
             return is_pot_assuming_nonnegative(mWidth) &&
                    is_pot_assuming_nonnegative(mHeight); // negative sizes should never happen (caught in texImage2D...)
         }
         bool HasUninitializedImageData() const {
             return mImageDataStatus == WebGLImageDataStatus::UninitializedImageData;
         }
         int64_t MemoryUsage() const;
-        /*! This is the format passed from JS to WebGL.
-         * It can be converted to a value to be passed to driver with
-         * DriverFormatsFromFormatAndType().
-         */
-        TexInternalFormat InternalFormat() const { return mInternalFormat; }
 
-        /*! This is the type passed from JS to WebGL.
-         * It can be converted to a value to be passed to driver with
-         * DriverTypeFromType().
-         */
-        TexType Type() const { return mType; }
+        TexInternalFormat EffectiveInternalFormat() const { return mEffectiveInternalFormat; }
 
     protected:
-        TexInternalFormat mInternalFormat; //!< This is the WebGL/GLES internal format.
-        TexType mType;   //!< This is the WebGL/GLES type
+        /*
+         * This is the "effective internal format" of the texture,
+         * an official OpenGL spec concept, see
+         * OpenGL ES 3.0.3 spec, section 3.8.3, page 126 and below.
+         */
+        TexInternalFormat mEffectiveInternalFormat;
+
         WebGLImageDataStatus mImageDataStatus;
 
         friend class WebGLTexture;
     };
 
 private:
     static size_t FaceForTarget(TexImageTarget texImageTarget) {
         if (texImageTarget == LOCAL_GL_TEXTURE_2D)
@@ -225,18 +217,17 @@ protected:
     bool DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImageTarget) const;
 
 public:
 
     void Bind(TexTarget aTexTarget);
 
     void SetImageInfo(TexImageTarget aTarget, GLint aLevel,
                       GLsizei aWidth, GLsizei aHeight,
-                      TexInternalFormat aInternalFormat, TexType aType,
-                      WebGLImageDataStatus aStatus);
+                      TexInternalFormat aFormat, WebGLImageDataStatus aStatus);
 
     void SetMinFilter(TexMinFilter aMinFilter) {
         mMinFilter = aMinFilter;
         SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
     }
     void SetMagFilter(TexMagFilter aMagFilter) {
         mMagFilter = aMagFilter;
         SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
--- a/dom/cellbroadcast/CellBroadcast.cpp
+++ b/dom/cellbroadcast/CellBroadcast.cpp
@@ -27,17 +27,17 @@ class CellBroadcast::Listener MOZ_FINAL 
 {
 private:
   CellBroadcast* mCellBroadcast;
 
 public:
   NS_DECL_ISUPPORTS
   NS_FORWARD_SAFE_NSICELLBROADCASTLISTENER(mCellBroadcast)
 
-  Listener(CellBroadcast* aCellBroadcast)
+  explicit Listener(CellBroadcast* aCellBroadcast)
     : mCellBroadcast(aCellBroadcast)
   {
     MOZ_ASSERT(mCellBroadcast);
   }
 
   void Disconnect()
   {
     MOZ_ASSERT(mCellBroadcast);
--- a/dom/encoding/test/unit/xpcshell.ini
+++ b/dom/encoding/test/unit/xpcshell.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 head = head.js
 tail =
+skip-if = toolkit == 'gonk'
 
 [test_misc.js]
 [test_utf.js]
 
 [test_big5.js]
 [test_euc-jp.js]
 [test_euc-kr.js]
 [test_gbk.js]
--- a/dom/fetch/Response.h
+++ b/dom/fetch/Response.h
@@ -22,17 +22,17 @@ class Promise;
 
 class Response MOZ_FINAL : public nsISupports
                          , public nsWrapperCache
 {
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Response)
 
 public:
-  Response(nsISupports* aOwner);
+  explicit Response(nsISupports* aOwner);
 
   JSObject*
   WrapObject(JSContext* aCx)
   {
     return ResponseBinding::Wrap(aCx, this);
   }
 
   ResponseType
--- a/dom/indexedDB/test/mochitest.ini
+++ b/dom/indexedDB/test/mochitest.ini
@@ -110,16 +110,18 @@ skip-if = (buildapp == 'b2g' && toolkit 
 [test_bfcache.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_blob_archive.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_blob_simple.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_blob_worker_crash.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
+[test_blob_worker_xhr_post.html]
+skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_blocked_order.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_bug937006.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_clear.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_complex_keyPaths.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/test_blob_worker_xhr_post.html
@@ -0,0 +1,113 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>Indexed Database Property Test</title>
+
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+  <script type="text/javascript;version=1.7">
+  function testSteps()
+  {
+    const BLOB_DATA = ["fun ", "times ", "all ", "around!"];
+    const BLOB_TYPE = "text/plain";
+    const BLOB_SIZE = BLOB_DATA.join("").length;
+
+    info("Setting up");
+
+    let request = indexedDB.open(window.location.pathname, 1);
+    request.onerror = errorHandler;
+    request.onupgradeneeded = grabEventAndContinueHandler;
+    request.onsuccess = unexpectedSuccessHandler;
+    let event = yield undefined;
+
+    let db = event.target.result;
+    db.onerror = errorHandler;
+
+    ok(db, "Created database");
+
+    info("Creating objectStore");
+
+    let objectStore = db.createObjectStore("foo", { autoIncrement: true });
+
+    request.onupgradeneeded = unexpectedSuccessHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
+
+    ok(true, "Opened database");
+
+    let blob = new Blob(BLOB_DATA, { type: BLOB_TYPE });
+
+    info("Adding blob to database");
+
+    objectStore = db.transaction("foo", "readwrite").objectStore("foo");
+    objectStore.add(blob).onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
+
+    let blobKey = event.target.result;
+    ok(blobKey, "Got a key for the blob");
+
+    info("Getting blob from the database");
+
+    objectStore = db.transaction("foo").objectStore("foo");
+    objectStore.get(blobKey).onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
+
+    blob = event.target.result;
+
+    ok(blob instanceof Blob, "Got a blob");
+    is(blob.size, BLOB_SIZE, "Correct size");
+    is(blob.type, BLOB_TYPE, "Correct type");
+
+    let slice = blob.slice(0, BLOB_DATA[0].length, BLOB_TYPE);
+
+    ok(slice instanceof Blob, "Slice returned a blob");
+    is(slice.size, BLOB_DATA[0].length, "Correct size for slice");
+    is(slice.type, BLOB_TYPE, "Correct type for slice");
+
+    info("Sending slice to a worker");
+
+    function workerScript() {
+      onmessage = function(event) {
+        var blob = event.data;
+        var xhr = new XMLHttpRequest();
+        // We just want to make sure the error case doesn't fire; it's fine for
+        // us to just want a 404.
+        xhr.open('POST', 'http://mochi.test:8888/does-not-exist', true);
+        xhr.onload = function() {
+          postMessage({ status: xhr.status });
+        };
+        xhr.onerror = function() {
+          postMessage({ status: 'error' });
+        }
+        xhr.send(blob);
+      }
+    }
+
+    let workerScriptUrl =
+      URL.createObjectURL(new Blob(["(", workerScript.toSource(), ")()"]));
+
+    let xhrWorker = new Worker(workerScriptUrl);
+    xhrWorker.postMessage(slice);
+    xhrWorker.onmessage = grabEventAndContinueHandler;
+    event = yield undefined;
+
+    is(event.data.status, 404, "XHR generated the expected 404");
+    xhrWorker.terminate();
+
+    URL.revokeObjectURL(workerScriptUrl);
+
+    finishTest();
+    yield undefined;
+  }
+  </script>
+  <script type="text/javascript;version=1.7" src="helpers.js"></script>
+
+</head>
+
+<body onload="runTest();"></body>
+
+</html>
--- a/dom/indexedDB/test/unit/xpcshell-child-process.ini
+++ b/dom/indexedDB/test/unit/xpcshell-child-process.ini
@@ -1,16 +1,17 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 [DEFAULT]
 dupe-manifest =
 head = xpcshell-head-child-process.js
 tail =
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 support-files =
   GlobalObjectsChild.js
   GlobalObjectsComponent.js
   GlobalObjectsComponent.manifest
   GlobalObjectsModule.jsm
   GlobalObjectsSandbox.js
   xpcshell-head-parent-process.js
   xpcshell-shared.ini
--- a/dom/indexedDB/test/unit/xpcshell-parent-process.ini
+++ b/dom/indexedDB/test/unit/xpcshell-parent-process.ini
@@ -1,16 +1,17 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 [DEFAULT]
 dupe-manifest =
 head = xpcshell-head-parent-process.js
 tail =
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 support-files =
   GlobalObjectsChild.js
   GlobalObjectsComponent.js
   GlobalObjectsComponent.manifest
   GlobalObjectsModule.jsm
   GlobalObjectsSandbox.js
   xpcshell-shared.ini
 
--- a/dom/indexedDB/test/unit/xpcshell-shared.ini
+++ b/dom/indexedDB/test/unit/xpcshell-shared.ini
@@ -1,11 +1,13 @@
 # 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/.
+[DEFAULT]
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 
 [test_add_put.js]
 [test_add_twice_failure.js]
 [test_advance.js]
 [test_autoIncrement.js]
 [test_autoIncrement_indexes.js]
 [test_blocked_order.js]
 [test_clear.js]
--- a/dom/ipc/Blob.cpp
+++ b/dom/ipc/Blob.cpp
@@ -324,17 +324,17 @@ class RemoteInputStream MOZ_FINAL
   nsCOMPtr<nsIInputStream> mStream;
   nsRefPtr<DOMFileImpl> mBlobImpl;
   nsCOMPtr<nsIEventTarget> mEventTarget;
   nsISeekableStream* mWeakSeekableStream;
 
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
 
-  RemoteInputStream(DOMFileImpl* aBlobImpl)
+  explicit RemoteInputStream(DOMFileImpl* aBlobImpl)
     : mMonitor("RemoteInputStream.mMonitor")
     , mBlobImpl(aBlobImpl)
     , mWeakSeekableStream(nullptr)
   {
     MOZ_ASSERT(IsOnOwningThread());
     MOZ_ASSERT(aBlobImpl);
 
     if (!NS_IsMainThread()) {
@@ -354,27 +354,29 @@ public:
   {
     MOZ_ASSERT(IsOnOwningThread());
   }
 
   void
   Serialize(InputStreamParams& aParams,
             FileDescriptorArray& /* aFileDescriptors */)
   {
+    MOZ_RELEASE_ASSERT(mBlobImpl);
+
     nsCOMPtr<nsIRemoteBlob> remote = do_QueryInterface(mBlobImpl);
     MOZ_ASSERT(remote);
-    MOZ_ASSERT(remote->GetBlobChild());
-
-    aParams = RemoteInputStreamParams(
-      nullptr /* sourceParent */,
-      remote->GetBlobChild() /* sourceChild */);
+
+    BlobChild* actor = remote->GetBlobChild();
+    MOZ_ASSERT(actor);
+
+    aParams = RemoteInputStreamParams(actor->ParentID());
   }
 
   bool
-  Deserialize(const InputStreamParams& aParams,
+  Deserialize(const InputStreamParams& /* aParams */,
               const FileDescriptorArray& /* aFileDescriptors */)
   {
     // See InputStreamUtils.cpp to see how deserialization of a
     // RemoteInputStream is special-cased.
     MOZ_CRASH("RemoteInputStream should never be deserialized");
   }
 
   void
@@ -414,25 +416,58 @@ public:
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
   }
 
   NS_IMETHOD
   Available(uint64_t* aAvailable) MOZ_OVERRIDE
   {
-    // See large comment in FileInputStreamWrapper::Available.
-    if (IsOnOwningThread()) {
+    if (!IsOnOwningThread()) {
+      nsresult rv = BlockAndWaitForStream();
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      rv = mStream->Available(aAvailable);
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+
+#ifdef DEBUG
+    if (NS_IsMainThread()) {
+      NS_WARNING("Someone is trying to do main-thread I/O...");
+    }
+#endif
+
+    nsresult rv;
+
+    // See if we already have our real stream.
+    nsCOMPtr<nsIInputStream> inputStream;
+    {
+      MonitorAutoLock lock(mMonitor);
+
+      inputStream = mStream;
+    }
+
+    // If we do then just call through.
+    if (inputStream) {
+      rv = inputStream->Available(aAvailable);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      return NS_OK;
+    }
+
+    // If the stream is already closed then we can't do anything.
+    if (!mBlobImpl) {
       return NS_BASE_STREAM_CLOSED;
     }
 
-    nsresult rv = BlockAndWaitForStream();
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = mStream->Available(aAvailable);
+    // Otherwise fake it...
+    NS_WARNING("Available() called before real stream has been delivered, "
+               "guessing the amount of data available!");
+
+    rv = mBlobImpl->GetSize(aAvailable);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
   }
 
   NS_IMETHOD
   Read(char* aBuffer, uint32_t aCount, uint32_t* aResult) MOZ_OVERRIDE
   {
@@ -685,43 +720,57 @@ public:
     DebugOnly<bool> isMutable;
     MOZ_ASSERT(NS_SUCCEEDED(aBlobImpl->GetMutable(&isMutable)));
     MOZ_ASSERT(!isMutable);
 
     return GetOrCreateInternal(aID,
                                aProcessID,
                                aBlobImpl,
                                /* aMayCreate */ true,
-                               /* aMayGet */ false);
+                               /* aMayGet */ false,
+                               /* aIgnoreProcessID */ false);
   }
 
   static already_AddRefed<IDTableEntry>
   Get(const nsID& aID, intptr_t aProcessID)
   {
     return GetOrCreateInternal(aID,
                                aProcessID,
                                nullptr,
                                /* aMayCreate */ false,
-                               /* aMayGet */ true);
+                               /* aMayGet */ true,
+                               /* aIgnoreProcessID */ false);
+  }
+
+  static already_AddRefed<IDTableEntry>
+  Get(const nsID& aID)
+  {
+    return GetOrCreateInternal(aID,
+                               0,
+                               nullptr,
+                               /* aMayCreate */ false,
+                               /* aMayGet */ true,
+                               /* aIgnoreProcessID */ true);
   }
 
   static already_AddRefed<IDTableEntry>
   GetOrCreate(const nsID& aID, intptr_t aProcessID, DOMFileImpl* aBlobImpl)
   {
     MOZ_ASSERT(aBlobImpl);
 
     DebugOnly<bool> isMutable;
     MOZ_ASSERT(NS_SUCCEEDED(aBlobImpl->GetMutable(&isMutable)));
     MOZ_ASSERT(!isMutable);
 
     return GetOrCreateInternal(aID,
                                aProcessID,
                                aBlobImpl,
                                /* aMayCreate */ true,
-                               /* aMayGet */ true);
+                               /* aMayGet */ true,
+                               /* aIgnoreProcessID */ false);
   }
 
   const nsID&
   ID() const
   {
     return mID;
   }
 
@@ -743,17 +792,18 @@ private:
   IDTableEntry(const nsID& aID, intptr_t aProcessID, DOMFileImpl* aBlobImpl);
   ~IDTableEntry();
 
   static already_AddRefed<IDTableEntry>
   GetOrCreateInternal(const nsID& aID,
                       intptr_t aProcessID,
                       DOMFileImpl* aBlobImpl,
                       bool aMayCreate,
-                      bool aMayGet);
+                      bool aMayGet,
+                      bool aIgnoreProcessID);
 };
 
 // Each instance of this class will be dispatched to the network stream thread
 // pool to run the first time where it will open the file input stream. It will
 // then dispatch itself back to the owning thread to send the child process its
 // response (assuming that the child has not crashed). The runnable will then
 // dispatch itself to the thread pool again in order to close the file input
 // stream.
@@ -2913,16 +2963,36 @@ BlobParent::Create(PBackgroundParent* aM
 {
   AssertCorrectThreadForManager(aManager);
   MOZ_ASSERT(aManager);
 
   return CreateFromParams(aManager, aParams);
 }
 
 // static
+already_AddRefed<DOMFileImpl>
+BlobParent::GetBlobImplForID(const nsID& aID)
+{
+  if (NS_WARN_IF(gProcessType != GeckoProcessType_Default)) {
+    ASSERT_UNLESS_FUZZING();
+    return nullptr;
+  }
+
+  nsRefPtr<IDTableEntry> idTableEntry = IDTableEntry::Get(aID);
+  if (NS_WARN_IF(!idTableEntry)) {
+    return nullptr;
+  }
+
+  nsRefPtr<DOMFileImpl> blobImpl = idTableEntry->BlobImpl();
+  MOZ_ASSERT(blobImpl);
+
+  return blobImpl.forget();
+}
+
+// static
 template <class ParentManagerType>
 BlobParent*
 BlobParent::GetOrCreateFromImpl(ParentManagerType* aManager,
                                 DOMFileImpl* aBlobImpl)
 {
   AssertCorrectThreadForManager(aManager);
   MOZ_ASSERT(aManager);
   MOZ_ASSERT(aBlobImpl);
@@ -3545,17 +3615,18 @@ IDTableEntry::~IDTableEntry()
 
 // static
 already_AddRefed<BlobParent::IDTableEntry>
 BlobParent::
 IDTableEntry::GetOrCreateInternal(const nsID& aID,
                                   intptr_t aProcessID,
                                   DOMFileImpl* aBlobImpl,
                                   bool aMayCreate,
-                                  bool aMayGet)
+                                  bool aMayGet,
+                                  bool aIgnoreProcessID)
 {
   MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
   MOZ_ASSERT(sIDTableMutex);
   sIDTableMutex->AssertNotCurrentThreadOwns();
 
   nsRefPtr<IDTableEntry> entry;
 
   {
@@ -3573,17 +3644,17 @@ IDTableEntry::GetOrCreateInternal(const 
 
     if (entry) {
       MOZ_ASSERT_IF(aBlobImpl, entry->BlobImpl() == aBlobImpl);
 
       if (NS_WARN_IF(!aMayGet)) {
         return nullptr;
       }
 
-      if (NS_WARN_IF(entry->mProcessID != aProcessID)) {
+      if (!aIgnoreProcessID && NS_WARN_IF(entry->mProcessID != aProcessID)) {
         return nullptr;
       }
     } else {
       if (NS_WARN_IF(!aMayCreate)) {
         return nullptr;
       }
 
       MOZ_ASSERT(aBlobImpl);
--- a/dom/ipc/BlobParent.h
+++ b/dom/ipc/BlobParent.h
@@ -102,16 +102,19 @@ public:
          const ParentBlobConstructorParams& aParams);
 
   static void
   Destroy(PBlobParent* aActor)
   {
     delete static_cast<BlobParent*>(aActor);
   }
 
+  static already_AddRefed<DOMFileImpl>
+  GetBlobImplForID(const nsID& aID);
+
   bool
   HasManager() const
   {
     return mBackgroundManager || mContentManager;
   }
 
   PBackgroundParent*
   GetBackgroundManager() const
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -3512,24 +3512,24 @@ ContentParent::RecvSyncMessage(const nsS
                                const IPC::Principal& aPrincipal,
                                InfallibleTArray<nsString>* aRetvals)
 {
     return nsIContentParent::RecvSyncMessage(aMsg, aData, aCpows, aPrincipal,
                                              aRetvals);
 }
 
 bool
-ContentParent::AnswerRpcMessage(const nsString& aMsg,
-                                const ClonedMessageData& aData,
-                                const InfallibleTArray<CpowEntry>& aCpows,
-                                const IPC::Principal& aPrincipal,
-                                InfallibleTArray<nsString>* aRetvals)
+ContentParent::RecvRpcMessage(const nsString& aMsg,
+                              const ClonedMessageData& aData,
+                              const InfallibleTArray<CpowEntry>& aCpows,
+                              const IPC::Principal& aPrincipal,
+                              InfallibleTArray<nsString>* aRetvals)
 {
-    return nsIContentParent::AnswerRpcMessage(aMsg, aData, aCpows, aPrincipal,
-                                              aRetvals);
+    return nsIContentParent::RecvRpcMessage(aMsg, aData, aCpows, aPrincipal,
+                                            aRetvals);
 }
 
 bool
 ContentParent::RecvAsyncMessage(const nsString& aMsg,
                                 const ClonedMessageData& aData,
                                 const InfallibleTArray<CpowEntry>& aCpows,
                                 const IPC::Principal& aPrincipal)
 {
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -558,21 +558,21 @@ private:
 
     virtual bool RecvLoadURIExternal(const URIParams& uri) MOZ_OVERRIDE;
 
     virtual bool RecvSyncMessage(const nsString& aMsg,
                                  const ClonedMessageData& aData,
                                  const InfallibleTArray<CpowEntry>& aCpows,
                                  const IPC::Principal& aPrincipal,
                                  InfallibleTArray<nsString>* aRetvals) MOZ_OVERRIDE;
-    virtual bool AnswerRpcMessage(const nsString& aMsg,
-                                  const ClonedMessageData& aData,
-                                  const InfallibleTArray<CpowEntry>& aCpows,
-                                  const IPC::Principal& aPrincipal,
-                                  InfallibleTArray<nsString>* aRetvals) MOZ_OVERRIDE;
+    virtual bool RecvRpcMessage(const nsString& aMsg,
+                                const ClonedMessageData& aData,
+                                const InfallibleTArray<CpowEntry>& aCpows,
+                                const IPC::Principal& aPrincipal,
+                                InfallibleTArray<nsString>* aRetvals) MOZ_OVERRIDE;
     virtual bool RecvAsyncMessage(const nsString& aMsg,
                                   const ClonedMessageData& aData,
                                   const InfallibleTArray<CpowEntry>& aCpows,
                                   const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
 
     virtual bool RecvFilePathUpdateNotify(const nsString& aType,
                                           const nsString& aStorageName,
                                           const nsString& aFilePath,
--- a/dom/ipc/DOMTypes.ipdlh
+++ b/dom/ipc/DOMTypes.ipdlh
@@ -2,19 +2,16 @@
 /* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PBlob;
 include InputStreamParams;
 
-using struct nsID
-  from "nsID.h";
-
 using struct mozilla::void_t
   from "ipc/IPCMessageUtils.h";
 
 using struct mozilla::SerializedStructuredCloneBuffer
   from "ipc/IPCMessageUtils.h";
 
 namespace mozilla {
 namespace dom {
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -64,17 +64,17 @@ struct NativeKeyBinding
 };
 
 union MaybeNativeKeyBinding
 {
   NativeKeyBinding;
   void_t;
 };
 
-intr protocol PBrowser
+prio(normal upto high) intr protocol PBrowser
 {
     manager PContent or PContentBridge;
 
     manages PColorPicker;
     manages PDocumentRenderer;
     manages PContentPermissionRequest;
     manages PFilePicker;
     manages PIndexedDBPermissionRequest;
@@ -103,18 +103,18 @@ parent:
                       nsString aFeatures,
                       nsString aBaseURI)
       returns (bool windowIsNew, PBrowser window);
 
     sync SyncMessage(nsString aMessage, ClonedMessageData aData,
                      CpowEntry[] aCpows, Principal aPrincipal)
       returns (nsString[] retval);
 
-    rpc RpcMessage(nsString aMessage, ClonedMessageData aData,
-                   CpowEntry[] aCpows, Principal aPrincipal)
+    prio(high) sync RpcMessage(nsString aMessage, ClonedMessageData aData,
+                               CpowEntry[] aCpows, Principal aPrincipal)
       returns (nsString[] retval);
 
     /**
      * The IME sequence number (seqno) parameter is used to make sure
      * that a notification is discarded if it arrives at the chrome process
      * too late. If the notification is late and we accept it, we will have
      * an out-of-date view of the content process, which means events that we
      * dispatch based on this out-of-date view will be wrong also.
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -314,17 +314,17 @@ struct VolumeInfo {
   bool isUnmounting;
 };
 
 union MaybeFileDesc {
     FileDescriptor;
     void_t;
 };
 
-intr protocol PContent
+prio(normal upto high) intr protocol PContent
 {
     parent opens PCompositor;
     parent opens PSharedBufferManager;
     parent opens PImageBridge;
     child opens PBackground;
 
     manages PAsmJSCacheEntry;
     manages PBlob;
@@ -532,17 +532,17 @@ parent:
         returns (bool isSecureURI);
 
     PHal();
 
     PMobileConnection(uint32_t clientId);
 
     PNecko();
 
-    rpc PScreenManager()
+    prio(high) sync PScreenManager()
         returns (uint32_t numberOfScreens,
                  float systemDefaultScale,
                  bool success);
 
     PCellBroadcast();
 
     PSms();
 
@@ -572,18 +572,18 @@ parent:
     sync ReadPrefsArray() returns (PrefSetting[] prefs);
 
     sync ReadFontList() returns (FontListEntry[] retValue);
 
     sync SyncMessage(nsString aMessage, ClonedMessageData aData,
                      CpowEntry[] aCpows, Principal aPrincipal)
       returns (nsString[] retval);
 
-    rpc RpcMessage(nsString aMessage, ClonedMessageData aData,
-                   CpowEntry[] aCpows, Principal aPrincipal)
+    prio(high) sync RpcMessage(nsString aMessage, ClonedMessageData aData,
+                               CpowEntry[] aCpows, Principal aPrincipal)
       returns (nsString[] retval);
 
     ShowAlertNotification(nsString imageUrl,
                           nsString title,
                           nsString text,
                           bool textClickable,
                           nsString cookie,
                           nsString name,
--- a/dom/ipc/PContentBridge.ipdl
+++ b/dom/ipc/PContentBridge.ipdl
@@ -21,17 +21,17 @@ namespace dom {
 /*
  * PContentBridge allows us to represent a parent/child relationship between two
  * child processes.  When a child process wants to open its own child, it asks
  * the root process to create a new process and then bridge them.  The first
  * child will allocate the PContentBridgeParent, and the newly opened child will
  * allocate the PContentBridgeChild.  This protocol allows these processes to
  * share PBrowsers and send messages to each other.
  */
-intr protocol PContentBridge
+prio(normal upto high) intr protocol PContentBridge
 {
     bridges PContent, PContent;
 
     manages PBlob;
     manages PBrowser;
     manages PJavaScript;
 
 parent:
--- a/dom/ipc/PCrashReporter.ipdl
+++ b/dom/ipc/PCrashReporter.ipdl
@@ -14,17 +14,17 @@ namespace dom {
 struct Mapping {
   nsCString library_name;
   nsCString file_id;
   uintptr_t start_address;
   size_t mapping_length;
   size_t file_offset;
 };
 
-intr protocol PCrashReporter {
+async protocol PCrashReporter {
   manager PContent or PPluginModule or PGMP;
 parent:
   AnnotateCrashReport(nsCString key, nsCString data);
   AppendAppNotes(nsCString data);
   __delete__();
 };
 
 }
--- a/dom/ipc/PScreenManager.ipdl
+++ b/dom/ipc/PScreenManager.ipdl
@@ -17,42 +17,42 @@ struct ScreenDetails {
   nsIntRect rectDisplayPix;
   nsIntRect availRect;
   nsIntRect availRectDisplayPix;
   int32_t pixelDepth;
   int32_t colorDepth;
   double contentsScaleFactor;
 };
 
-rpc protocol PScreenManager
+prio(normal upto high) sync protocol PScreenManager
 {
   manager PContent;
 
 parent:
-    rpc Refresh()
+    prio(high) sync Refresh()
       returns (uint32_t numberOfScreens,
                float systemDefaultScale,
                bool success);
 
-    rpc ScreenRefresh(uint32_t aId)
+    prio(high) sync ScreenRefresh(uint32_t aId)
       returns (ScreenDetails screen,
                bool success);
 
-    rpc GetPrimaryScreen()
+    prio(high) sync GetPrimaryScreen()
       returns (ScreenDetails screen,
                bool success);
 
-    rpc ScreenForRect(int32_t aLeft,
+    prio(high) sync ScreenForRect(int32_t aLeft,
                        int32_t aTop,
                        int32_t aWidth,
                        int32_t aHeight)
       returns (ScreenDetails screen,
                bool success);
 
-    rpc ScreenForBrowser(PBrowser aBrowser)
+    prio(high) sync ScreenForBrowser(PBrowser aBrowser)
       returns (ScreenDetails screen,
                bool success);
 
 child:
     __delete__();
 };
 
 } // namespace dom
--- a/dom/ipc/ScreenManagerParent.cpp
+++ b/dom/ipc/ScreenManagerParent.cpp
@@ -19,23 +19,23 @@ ScreenManagerParent::ScreenManagerParent
                                          float* aSystemDefaultScale,
                                          bool* aSuccess)
 {
   mScreenMgr = do_GetService(sScreenManagerContractID);
   if (!mScreenMgr) {
     MOZ_CRASH("Couldn't get nsIScreenManager from ScreenManagerParent.");
   }
 
-  unused << AnswerRefresh(aNumberOfScreens, aSystemDefaultScale, aSuccess);
+  unused << RecvRefresh(aNumberOfScreens, aSystemDefaultScale, aSuccess);
 }
 
 bool
-ScreenManagerParent::AnswerRefresh(uint32_t* aNumberOfScreens,
-                                   float* aSystemDefaultScale,
-                                   bool* aSuccess)
+ScreenManagerParent::RecvRefresh(uint32_t* aNumberOfScreens,
+                                 float* aSystemDefaultScale,
+                                 bool* aSuccess)
 {
   *aSuccess = false;
 
   nsresult rv = mScreenMgr->GetNumberOfScreens(aNumberOfScreens);
   if (NS_FAILED(rv)) {
     return true;
   }
 
@@ -44,19 +44,19 @@ ScreenManagerParent::AnswerRefresh(uint3
     return true;
   }
 
   *aSuccess = true;
   return true;
 }
 
 bool
-ScreenManagerParent::AnswerScreenRefresh(const uint32_t& aId,
-                                         ScreenDetails* aRetVal,
-                                         bool* aSuccess)
+ScreenManagerParent::RecvScreenRefresh(const uint32_t& aId,
+                                       ScreenDetails* aRetVal,
+                                       bool* aSuccess)
 {
   *aSuccess = false;
 
   nsCOMPtr<nsIScreen> screen;
   nsresult rv = mScreenMgr->ScreenForId(aId, getter_AddRefs(screen));
   if (NS_FAILED(rv)) {
     return true;
   }
@@ -65,18 +65,18 @@ ScreenManagerParent::AnswerScreenRefresh
   unused << ExtractScreenDetails(screen, details);
 
   *aRetVal = details;
   *aSuccess = true;
   return true;
 }
 
 bool
-ScreenManagerParent::AnswerGetPrimaryScreen(ScreenDetails* aRetVal,
-                                            bool* aSuccess)
+ScreenManagerParent::RecvGetPrimaryScreen(ScreenDetails* aRetVal,
+                                          bool* aSuccess)
 {
   *aSuccess = false;
 
   nsCOMPtr<nsIScreen> screen;
   nsresult rv = mScreenMgr->GetPrimaryScreen(getter_AddRefs(screen));
 
   NS_ENSURE_SUCCESS(rv, true);
 
@@ -86,22 +86,22 @@ ScreenManagerParent::AnswerGetPrimaryScr
   }
 
   *aRetVal = details;
   *aSuccess = true;
   return true;
 }
 
 bool
-ScreenManagerParent::AnswerScreenForRect(const int32_t& aLeft,
-                                         const int32_t& aTop,
-                                         const int32_t& aWidth,
-                                         const int32_t& aHeight,
-                                         ScreenDetails* aRetVal,
-                                         bool* aSuccess)
+ScreenManagerParent::RecvScreenForRect(const int32_t& aLeft,
+                                       const int32_t& aTop,
+                                       const int32_t& aWidth,
+                                       const int32_t& aHeight,
+                                       ScreenDetails* aRetVal,
+                                       bool* aSuccess)
 {
   *aSuccess = false;
 
   nsCOMPtr<nsIScreen> screen;
   nsresult rv = mScreenMgr->ScreenForRect(aLeft, aTop, aWidth, aHeight, getter_AddRefs(screen));
 
   NS_ENSURE_SUCCESS(rv, true);
 
@@ -111,19 +111,19 @@ ScreenManagerParent::AnswerScreenForRect
   }
 
   *aRetVal = details;
   *aSuccess = true;
   return true;
 }
 
 bool
-ScreenManagerParent::AnswerScreenForBrowser(PBrowserParent* aBrowser,
-                                            ScreenDetails* aRetVal,
-                                            bool* aSuccess)
+ScreenManagerParent::RecvScreenForBrowser(PBrowserParent* aBrowser,
+                                          ScreenDetails* aRetVal,
+                                          bool* aSuccess)
 {
   *aSuccess = false;
 
   // Find the mWidget associated with the tabparent, and then return
   // the nsIScreen it's on.
   TabParent* tabParent = static_cast<TabParent*>(aBrowser);
   nsCOMPtr<nsIWidget> widget = tabParent->GetWidget();
   if (!widget) {
--- a/dom/ipc/ScreenManagerParent.h
+++ b/dom/ipc/ScreenManagerParent.h
@@ -16,39 +16,39 @@ namespace dom {
 class ScreenManagerParent : public PScreenManagerParent
 {
  public:
   ScreenManagerParent(uint32_t* aNumberOfScreens,
                       float* aSystemDefaultScale,
                       bool* aSuccess);
   ~ScreenManagerParent() {};
 
-  virtual bool AnswerRefresh(uint32_t* aNumberOfScreens,
-                             float* aSystemDefaultScale,
-                             bool* aSuccess) MOZ_OVERRIDE;
+  virtual bool RecvRefresh(uint32_t* aNumberOfScreens,
+                           float* aSystemDefaultScale,
+                           bool* aSuccess) MOZ_OVERRIDE;
 
-  virtual bool AnswerScreenRefresh(const uint32_t& aId,
-                                   ScreenDetails* aRetVal,
-                                   bool* aSuccess) MOZ_OVERRIDE;
+  virtual bool RecvScreenRefresh(const uint32_t& aId,
+                                 ScreenDetails* aRetVal,
+                                 bool* aSuccess) MOZ_OVERRIDE;
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
 
-  virtual bool AnswerGetPrimaryScreen(ScreenDetails* aRetVal,
-                                      bool* aSuccess) MOZ_OVERRIDE;
+  virtual bool RecvGetPrimaryScreen(ScreenDetails* aRetVal,
+                                    bool* aSuccess) MOZ_OVERRIDE;
 
-  virtual bool AnswerScreenForRect(const int32_t& aLeft,
-                                   const int32_t& aTop,
-                                   const int32_t& aWidth,
-                                   const int32_t& aHeight,
-                                   ScreenDetails* aRetVal,
-                                   bool* aSuccess) MOZ_OVERRIDE;
+  virtual bool RecvScreenForRect(const int32_t& aLeft,
+                                 const int32_t& aTop,
+                                 const int32_t& aWidth,
+                                 const int32_t& aHeight,
+                                 ScreenDetails* aRetVal,
+                                 bool* aSuccess) MOZ_OVERRIDE;
 
-  virtual bool AnswerScreenForBrowser(PBrowserParent* aBrowser,
-                                      ScreenDetails* aRetVal,
-                                      bool* aSuccess);
+  virtual bool RecvScreenForBrowser(PBrowserParent* aBrowser,
+                                    ScreenDetails* aRetVal,
+                                    bool* aSuccess);
 
  private:
   bool ExtractScreenDetails(nsIScreen* aScreen, ScreenDetails &aDetails);
   nsCOMPtr<nsIScreenManager> mScreenMgr;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -2917,17 +2917,17 @@ TabChild::DoSendBlockingMessage(JSContex
   if (aCpows && !Manager()->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
     return false;
   }
   if (aIsSync) {
     return SendSyncMessage(PromiseFlatString(aMessage), data, cpows,
                            Principal(aPrincipal), aJSONRetVal);
   }
 
-  return CallRpcMessage(PromiseFlatString(aMessage), data, cpows,
+  return SendRpcMessage(PromiseFlatString(aMessage), data, cpows,
                         Principal(aPrincipal), aJSONRetVal);
 }
 
 bool
 TabChild::DoSendAsyncMessage(JSContext* aCx,
                              const nsAString& aMessage,
                              const StructuredCloneData& aData,
                              JS::Handle<JSObject *> aCpows,
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1123,21 +1123,21 @@ TabParent::RecvSyncMessage(const nsStrin
   }
 
   StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
   CpowIdHolder cpows(Manager(), aCpows);
   return ReceiveMessage(aMessage, true, &cloneData, &cpows, aPrincipal, aJSONRetVal);
 }
 
 bool
-TabParent::AnswerRpcMessage(const nsString& aMessage,
-                            const ClonedMessageData& aData,
-                            const InfallibleTArray<CpowEntry>& aCpows,
-                            const IPC::Principal& aPrincipal,
-                            InfallibleTArray<nsString>* aJSONRetVal)
+TabParent::RecvRpcMessage(const nsString& aMessage,
+                          const ClonedMessageData& aData,
+                          const InfallibleTArray<CpowEntry>& aCpows,
+                          const IPC::Principal& aPrincipal,
+                          InfallibleTArray<nsString>* aJSONRetVal)
 {
   // FIXME Permission check for TabParent in Content process
   nsIPrincipal* principal = aPrincipal;
   if (Manager()->IsContentParent()) {
     ContentParent* parent = Manager()->AsContentParent();
     if (!ContentParent::IgnoreIPCPrincipal() &&
         parent && principal && !AssertAppPrincipal(parent, principal)) {
       return false;
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -142,21 +142,21 @@ public:
                                     const nsString& aBaseURI,
                                     bool* aWindowIsNew,
                                     PBrowserParent** aRetVal) MOZ_OVERRIDE;
     virtual bool RecvSyncMessage(const nsString& aMessage,
                                  const ClonedMessageData& aData,
                                  const InfallibleTArray<CpowEntry>& aCpows,
                                  const IPC::Principal& aPrincipal,
                                  InfallibleTArray<nsString>* aJSONRetVal) MOZ_OVERRIDE;
-    virtual bool AnswerRpcMessage(const nsString& aMessage,
-                                  const ClonedMessageData& aData,
-                                  const InfallibleTArray<CpowEntry>& aCpows,
-                                  const IPC::Principal& aPrincipal,
-                                  InfallibleTArray<nsString>* aJSONRetVal) MOZ_OVERRIDE;
+    virtual bool RecvRpcMessage(const nsString& aMessage,
+                                const ClonedMessageData& aData,
+                                const InfallibleTArray<CpowEntry>& aCpows,
+                                const IPC::Principal& aPrincipal,
+                                InfallibleTArray<nsString>* aJSONRetVal) MOZ_OVERRIDE;
     virtual bool RecvAsyncMessage(const nsString& aMessage,
                                   const ClonedMessageData& aData,
                                   const InfallibleTArray<CpowEntry>& aCpows,
                                   const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
     virtual bool RecvNotifyIMEFocus(const bool& aFocus,
                                     nsIMEUpdatePreference* aPreference,
                                     uint32_t* aSeqno) MOZ_OVERRIDE;
     virtual bool RecvNotifyIMETextChange(const uint32_t& aStart,
--- a/dom/ipc/nsIContentParent.cpp
+++ b/dom/ipc/nsIContentParent.cpp
@@ -188,21 +188,21 @@ nsIContentParent::RecvSyncMessage(const 
     CpowIdHolder cpows(this, aCpows);
     ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
                         aMsg, true, &cloneData, &cpows, aPrincipal, aRetvals);
   }
   return true;
 }
 
 bool
-nsIContentParent::AnswerRpcMessage(const nsString& aMsg,
-                                   const ClonedMessageData& aData,
-                                   const InfallibleTArray<CpowEntry>& aCpows,
-                                   const IPC::Principal& aPrincipal,
-                                   InfallibleTArray<nsString>* aRetvals)
+nsIContentParent::RecvRpcMessage(const nsString& aMsg,
+                                 const ClonedMessageData& aData,
+                                 const InfallibleTArray<CpowEntry>& aCpows,
+                                 const IPC::Principal& aPrincipal,
+                                 InfallibleTArray<nsString>* aRetvals)
 {
   // FIXME Permission check in Content process
   nsIPrincipal* principal = aPrincipal;
   if (IsContentParent()) {
     ContentParent* parent = AsContentParent();
     if (!ContentParent::IgnoreIPCPrincipal() &&
         parent && principal && !AssertAppPrincipal(parent, principal)) {
       return false;
--- a/dom/ipc/nsIContentParent.h
+++ b/dom/ipc/nsIContentParent.h
@@ -86,21 +86,21 @@ protected: // IPDL methods
 
   virtual bool DeallocPBlobParent(PBlobParent* aActor);
 
   virtual bool RecvSyncMessage(const nsString& aMsg,
                                const ClonedMessageData& aData,
                                const InfallibleTArray<jsipc::CpowEntry>& aCpows,
                                const IPC::Principal& aPrincipal,
                                InfallibleTArray<nsString>* aRetvals);
-  virtual bool AnswerRpcMessage(const nsString& aMsg,
-                                const ClonedMessageData& aData,
-                                const InfallibleTArray<jsipc::CpowEntry>& aCpows,
-                                const IPC::Principal& aPrincipal,
-                                InfallibleTArray<nsString>* aRetvals);
+  virtual bool RecvRpcMessage(const nsString& aMsg,
+                              const ClonedMessageData& aData,
+                              const InfallibleTArray<jsipc::CpowEntry>& aCpows,
+                              const IPC::Principal& aPrincipal,
+                              InfallibleTArray<nsString>* aRetvals);
   virtual bool RecvAsyncMessage(const nsString& aMsg,
                                 const ClonedMessageData& aData,
                                 const InfallibleTArray<jsipc::CpowEntry>& aCpows,
                                 const IPC::Principal& aPrincipal);
 
 protected: // members
   nsRefPtr<nsFrameMessageManager> mMessageManager;
 };
--- a/dom/json/test/unit/xpcshell.ini
+++ b/dom/json/test/unit/xpcshell.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 head =
 tail =
+skip-if = toolkit == 'gonk'
 support-files =
   decodeFromStream-01.json
   decodeFromStream-small.json
 
 [test_decodeFromStream.js]
 [test_decode_long_input.js]
 [test_encode.js]
 
--- a/dom/network/tests/unit/xpcshell.ini
+++ b/dom/network/tests/unit/xpcshell.ini
@@ -1,9 +1,10 @@
 [DEFAULT]
 head =
 tail =
+skip-if = toolkit == 'gonk'
 
 [test_tcpsocket.js]
 [test_multisend.js]
 [test_tcpserversocket.js]
 run-sequentially = Uses hardcoded port, bug 903830.
 skip-if = os == 'mac' # bug 953208 - frequent timeouts on OSX
--- a/dom/network/tests/unit_ipc/xpcshell.ini
+++ b/dom/network/tests/unit_ipc/xpcshell.ini
@@ -1,7 +1,8 @@
 [DEFAULT]
 head =
 tail =
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 
 [test_tcpsocket_ipc.js]
 [test_tcpserversocket_ipc.js]
 run-sequentially = Uses hardcoded port, bug 903830.
--- a/dom/notification/test/unit/xpcshell.ini
+++ b/dom/notification/test/unit/xpcshell.ini
@@ -1,6 +1,7 @@
 [DEFAULT]
 head = common_test_notificationdb.js
 tail =
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 
 [test_notificationdb.js]
 [test_notificationdb_bug1024090.js]
--- a/dom/payment/tests/unit/xpcshell.ini
+++ b/dom/payment/tests/unit/xpcshell.ini
@@ -1,5 +1,6 @@
 [DEFAULT]
 head = header_helper.js
 tail =
+skip-if = toolkit == 'gonk'
 
 [test_paymanager_get_payment_request.js]
--- a/dom/permission/tests/unit/xpcshell.ini
+++ b/dom/permission/tests/unit/xpcshell.ini
@@ -1,5 +1,6 @@
 [DEFAULT]
 head =
 tail =
+skip-if = toolkit == 'gonk'
 
 [test_bug808734.js]
--- a/dom/plugins/test/unit/xpcshell.ini
+++ b/dom/plugins/test/unit/xpcshell.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-skip-if = buildapp == 'mulet'
+skip-if = buildapp == 'mulet' || toolkit == 'android' || toolkit == 'gonk'
 head = head_plugins.js
 tail = 
 
 [test_bug455213.js]
 # Bug 676953: test fails consistently on Android
 fail-if = os == "android"
 [test_bug471245.js]
 # Bug 676953: test fails consistently on Android
--- a/dom/system/gonk/AudioManager.cpp
+++ b/dom/system/gonk/AudioManager.cpp
@@ -73,16 +73,17 @@ static int sMaxStreamVolumeTbl[AUDIO_STR
   15,  // BT SCO
   15,  // enforced audible
   15,  // DTMF
   15,  // TTS
   15,  // FM
 };
 // A bitwise variable for recording what kind of headset is attached.
 static int sHeadsetState;
+static bool sBluetoothA2dpEnabled;
 static const int kBtSampleRate = 8000;
 static bool sSwitchDone = true;
 static bool sA2dpSwitchDone = true;
 
 namespace mozilla {
 namespace dom {
 namespace gonk {
 class RecoverTask : public nsRunnable
@@ -285,17 +286,23 @@ AudioManager::HandleBluetoothStatusChang
     } else {
       AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
                                             audioState, aAddress.get());
       String8 cmd("bluetooth_enabled=true");
       AudioSystem::setParameters(0, cmd);
       cmd.setTo("A2dpSuspended=false");
       AudioSystem::setParameters(0, cmd);
       sA2dpSwitchDone = true;
+#if ANDROID_VERSION >= 17
+      if (AudioSystem::getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) == AUDIO_POLICY_FORCE_NO_BT_A2DP) {
+        SetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, AUDIO_POLICY_FORCE_NONE);
+      }
+#endif
     }
+    sBluetoothA2dpEnabled = audioState == AUDIO_POLICY_DEVICE_STATE_AVAILABLE;
   } else if (!strcmp(aTopic, BLUETOOTH_HFP_STATUS_CHANGED_ID)) {
     AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
                                           audioState, aAddress.get());
     AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET,
                                           audioState, aAddress.get());
   }
 #endif
 }
@@ -391,33 +398,47 @@ NotifyHeadphonesStatus(SwitchState aStat
       obs->NotifyObservers(nullptr, HEADPHONES_STATUS_CHANGED, HEADPHONES_STATUS_UNKNOWN);
     }
   }
 }
 
 class HeadphoneSwitchObserver : public SwitchObserver
 {
 public:
+  HeadphoneSwitchObserver(AudioManager* aAudioManager)
+  : mAudioManager(aAudioManager) { }
   void Notify(const SwitchEvent& aEvent) {
     NotifyHeadphonesStatus(aEvent.status());
     // When user pulled out the headset, a delay of routing here can avoid the leakage of audio from speaker.
     if (aEvent.status() == SWITCH_STATE_OFF && sSwitchDone) {
       MessageLoop::current()->PostDelayedTask(
         FROM_HERE, NewRunnableFunction(&ProcessDelayedAudioRoute, SWITCH_STATE_OFF), 1000);
       sSwitchDone = false;
     } else if (aEvent.status() != SWITCH_STATE_OFF) {
       InternalSetAudioRoutes(aEvent.status());
       sSwitchDone = true;
     }
+    // Handle the coexistence of a2dp / headset device, latest one wins.
+#if ANDROID_VERSION >= 17
+    int32_t forceUse = 0;
+    mAudioManager->GetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, &forceUse);
+    if (aEvent.status() != SWITCH_STATE_OFF && sBluetoothA2dpEnabled) {
+      mAudioManager->SetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, AUDIO_POLICY_FORCE_NO_BT_A2DP);
+    } else if (forceUse == AUDIO_POLICY_FORCE_NO_BT_A2DP) {
+      mAudioManager->SetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, AUDIO_POLICY_FORCE_NONE);
+    }
+#endif
   }
+private:
+  AudioManager* mAudioManager;
 };
 
 AudioManager::AudioManager()
   : mPhoneState(PHONE_STATE_CURRENT)
-  , mObserver(new HeadphoneSwitchObserver())
+  , mObserver(new HeadphoneSwitchObserver(this))
 #ifdef MOZ_B2G_RIL
   , mMuteCallToRIL(false)
 #endif
 {
   RegisterSwitchObserver(SWITCH_HEADPHONES, mObserver);
 
   InternalSetAudioRoutes(GetCurrentSwitchState(SWITCH_HEADPHONES));
   NotifyHeadphonesStatus(GetCurrentSwitchState(SWITCH_HEADPHONES));
--- a/dom/system/gonk/android_audio/AudioSystem.h
+++ b/dom/system/gonk/android_audio/AudioSystem.h
@@ -37,22 +37,19 @@ typedef enum {
     AUDIO_POLICY_FORCE_NONE,
     AUDIO_POLICY_FORCE_SPEAKER,
     AUDIO_POLICY_FORCE_HEADPHONES,
     AUDIO_POLICY_FORCE_BT_SCO,
     AUDIO_POLICY_FORCE_BT_A2DP,
     AUDIO_POLICY_FORCE_WIRED_ACCESSORY,
     AUDIO_POLICY_FORCE_BT_CAR_DOCK,
     AUDIO_POLICY_FORCE_BT_DESK_DOCK,
-
-#ifdef VANILLA_ANDROID
     AUDIO_POLICY_FORCE_ANALOG_DOCK,
     AUDIO_POLICY_FORCE_DIGITAL_DOCK,
-#endif
-
+    AUDIO_POLICY_FORCE_NO_BT_A2DP,
     AUDIO_POLICY_FORCE_CFG_CNT,
     AUDIO_POLICY_FORCE_CFG_MAX = AUDIO_POLICY_FORCE_CFG_CNT - 1,
 
     AUDIO_POLICY_FORCE_DEFAULT = AUDIO_POLICY_FORCE_NONE,
 } audio_policy_forced_cfg_t;
 
 /* usages used for audio_policy->set_force_use() */
 typedef enum {
@@ -719,16 +716,19 @@ public:
         FORCE_NONE,
         FORCE_SPEAKER,
         FORCE_HEADPHONES,
         FORCE_BT_SCO,
         FORCE_BT_A2DP,
         FORCE_WIRED_ACCESSORY,
         FORCE_BT_CAR_DOCK,
         FORCE_BT_DESK_DOCK,
+        FORCE_ANALOG_DOCK,
+        FORCE_DIGITAL_DOCK,
+        FORCE_NO_BT_A2DP,
         NUM_FORCE_CONFIG,
         FORCE_DEFAULT = FORCE_NONE
     };
 
     // usages used for setForceUse()
     enum force_use {
         FOR_COMMUNICATION,
         FOR_MEDIA,
--- a/dom/system/gonk/nsIAudioManager.idl
+++ b/dom/system/gonk/nsIAudioManager.idl
@@ -11,17 +11,17 @@ interface nsIAudioManager : nsISupports
    * Microphone muted?
    */
   attribute boolean microphoneMuted;
 
   /**
    * Are we playing audio from the FM radio?
    */
   attribute boolean fmRadioAudioEnabled;
- 
+
   /**
    * Set the phone's audio mode.
    */
   const long PHONE_STATE_INVALID          = -2;
   const long PHONE_STATE_CURRENT          = -1;
   const long PHONE_STATE_NORMAL           = 0;
   const long PHONE_STATE_RINGTONE         = 1;
   const long PHONE_STATE_IN_CALL          = 2;
@@ -36,17 +36,19 @@ interface nsIAudioManager : nsISupports
   const long FORCE_NONE            = 0; // the default
   const long FORCE_SPEAKER         = 1;
   const long FORCE_HEADPHONES      = 2;
   const long FORCE_BT_SCO          = 3;
   const long FORCE_BT_A2DP         = 4;
   const long FORCE_WIRED_ACCESSORY = 5;
   const long FORCE_BT_CAR_DOCK     = 6;
   const long FORCE_BT_DESK_DOCK    = 7;
-
+  const long FORCE_ANALOG_DOCK     = 8;
+  const long FORCE_DIGITAL_DOCK    = 9;
+  const long FORCE_NO_BT_A2DP      = 10;
   const long USE_COMMUNICATION     = 0;
   const long USE_MEDIA             = 1;
   const long USE_RECORD            = 2;
   const long USE_DOCK              = 3;
 
   void setForceForUse(in long usage, in long force);
   long getForceForUse(in long usage);
 
--- a/dom/tests/unit/xpcshell.ini
+++ b/dom/tests/unit/xpcshell.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 head = 
 tail = 
+skip-if = toolkit == 'gonk'
 
 [test_bug319968.js]
 [test_bug465752.js]
 [test_geolocation_provider.js]
 # Bug 684962: test hangs consistently on Android
 skip-if = os == "android"
 [test_geolocation_timeout.js]
 # Bug 919946: test hangs consistently on Android
--- a/dom/voicemail/Voicemail.cpp
+++ b/dom/voicemail/Voicemail.cpp
@@ -28,17 +28,17 @@ using mozilla::ErrorResult;
 class Voicemail::Listener MOZ_FINAL : public nsIVoicemailListener
 {
   Voicemail* mVoicemail;
 
 public:
   NS_DECL_ISUPPORTS
   NS_FORWARD_SAFE_NSIVOICEMAILLISTENER(mVoicemail)
 
-  Listener(Voicemail* aVoicemail)
+  explicit Listener(Voicemail* aVoicemail)
     : mVoicemail(aVoicemail)
   {
     MOZ_ASSERT(mVoicemail);
   }
 
   void Disconnect()
   {
     MOZ_ASSERT(mVoicemail);
--- a/dom/voicemail/ipc/VoicemailIPCService.cpp
+++ b/dom/voicemail/ipc/VoicemailIPCService.cpp
@@ -18,17 +18,17 @@ namespace voicemail {
 class VoicemailIPCProvider MOZ_FINAL : public nsIVoicemailProvider
 {
   friend class VoicemailIPCService;
 
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIVOICEMAILPROVIDER
 
-  VoicemailIPCProvider(uint32_t aServiceId);
+  explicit VoicemailIPCProvider(uint32_t aServiceId);
 
 private:
   // MOZ_FINAL suppresses -Werror,-Wdelete-non-virtual-dtor
   ~VoicemailIPCProvider() {}
 
 private:
   uint32_t mServiceId;
   nsString mNumber;
--- a/dom/workers/test/urlSearchParams_worker.js
+++ b/dom/workers/test/urlSearchParams_worker.js
@@ -17,17 +17,17 @@ onmessage = function() {
   } catch(e) {
   }
   ok(status, "URLSearchParams in workers \\o/");
 
   function testSimpleURLSearchParams() {
     var u = new URLSearchParams();
     ok(u, "URLSearchParams created");
     is(u.has('foo'), false, 'URLSearchParams.has(foo)');
-    is(u.get('foo'), '', 'URLSearchParams.get(foo)');
+    is(u.get('foo'), null, 'URLSearchParams.get(foo)');
     is(u.getAll('foo').length, 0, 'URLSearchParams.getAll(foo)');
 
     u.append('foo', 'bar');
     is(u.has('foo'), true, 'URLSearchParams.has(foo)');
     is(u.get('foo'), 'bar', 'URLSearchParams.get(foo)');
     is(u.getAll('foo').length, 1, 'URLSearchParams.getAll(foo)');
 
     u.set('foo', 'bar2');
--- a/dom/workers/test/xpcshell/xpcshell.ini
+++ b/dom/workers/test/xpcshell/xpcshell.ini
@@ -1,8 +1,9 @@
 [DEFAULT]
 head =
 tail =
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 support-files =
   data/worker.js
   data/chrome.manifest
 
 [test_workers.js]
--- a/embedding/tests/unit/xpcshell.ini
+++ b/embedding/tests/unit/xpcshell.ini
@@ -1,6 +1,7 @@
 [DEFAULT]
 head = 
 tail = 
+skip-if = toolkit == 'gonk'
 
 [test_wwauthpromptfactory.js]
 [test_wwpromptfactory.js]
--- a/extensions/cookie/test/unit/xpcshell.ini
+++ b/extensions/cookie/test/unit/xpcshell.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 head = head_cookies.js
 tail =
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 support-files =
   cookieprompt.js
   cookieprompt.manifest
 
 [test_bug526789.js]
 [test_bug650522.js]
 [test_bug667087.js]
 [test_cookies_async_failure.js]
--- a/extensions/cookie/test/unit_ipc/xpcshell.ini
+++ b/extensions/cookie/test/unit_ipc/xpcshell.ini
@@ -1,6 +1,7 @@
 [DEFAULT]
 head = 
 tail = 
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 
 [test_child.js]
 [test_parent.js]
--- a/extensions/spellcheck/hunspell/tests/unit/xpcshell.ini
+++ b/extensions/spellcheck/hunspell/tests/unit/xpcshell.ini
@@ -1,6 +1,7 @@
 [DEFAULT]
 head =
 tail =
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 support-files = data/**
 
 [test_hunspell.js]
--- a/gfx/2d/FilterNodeSoftware.cpp
+++ b/gfx/2d/FilterNodeSoftware.cpp
@@ -1151,51 +1151,41 @@ FilterNodeTransformSoftware::SourceRectF
 }
 
 TemporaryRef<DataSourceSurface>
 FilterNodeTransformSoftware::Render(const IntRect& aRect)
 {
   IntRect srcRect = SourceRectForOutputRect(aRect);
 
   RefPtr<DataSourceSurface> input =
-    GetInputDataSourceSurface(IN_TRANSFORM_IN, srcRect);
+    GetInputDataSourceSurface(IN_TRANSFORM_IN, srcRect, NEED_COLOR_CHANNELS);
 
   if (!input) {
     return nullptr;
   }
 
   Matrix transform = Matrix::Translation(srcRect.x, srcRect.y) * mMatrix *
                      Matrix::Translation(-aRect.x, -aRect.y);
   if (transform.IsIdentity() && srcRect.Size() == aRect.Size()) {
     return input.forget();
   }
 
-  RefPtr<DataSourceSurface> surf =
-    Factory::CreateDataSourceSurface(aRect.Size(), input->GetFormat());
-
-  DataSourceSurface::MappedSurface mapping;
-  surf->Map(DataSourceSurface::MapType::WRITE, &mapping);
-
   RefPtr<DrawTarget> dt =
-    Factory::CreateDrawTargetForData(BackendType::CAIRO,
-                                     mapping.mData,
-                                     surf->GetSize(),
-                                     mapping.mStride,
-                                     surf->GetFormat());
+    Factory::CreateDrawTarget(BackendType::CAIRO, aRect.Size(), input->GetFormat());
   if (!dt) {
     return nullptr;
   }
 
   Rect r(0, 0, srcRect.width, srcRect.height);
   dt->SetTransform(transform);
   dt->DrawSurface(input, r, r, DrawSurfaceOptions(mFilter));
 
-  dt->Flush();
-  surf->Unmap();
-  return surf.forget();
+  RefPtr<SourceSurface> result = dt->Snapshot();
+  RefPtr<DataSourceSurface> resultData = result->GetDataSurface();
+  return resultData.forget();
 }
 
 void
 FilterNodeTransformSoftware::RequestFromInputsForRect(const IntRect &aRect)
 {
   RequestInputRect(IN_TRANSFORM_IN, SourceRectForOutputRect(aRect));
 }
 
--- a/gfx/2d/Matrix.h
+++ b/gfx/2d/Matrix.h
@@ -78,18 +78,18 @@ public:
   /**
    * Apply a translation to this matrix.
    *
    * The "Pre" in this method's name means that the translation is applied
    * -before- this matrix's existing transformation. That is, any vector that
    * is multiplied by the resulting matrix will first be translated, then be
    * transformed by the original transform.
    *
-   * Thus calling this method will result in this matrix having the same value
-   * as the result of:
+   * Calling this method will result in this matrix having the same value as
+   * the result of:
    *
    *   Matrix::Translation(x, y) * this
    *
    * (Note that in performance critical code multiplying by the result of a
    * Translation()/Scaling() call is not recommended since that results in a
    * full matrix multiply involving 12 floating-point multiplications. Calling
    * this method would be preferred since it only involves four floating-point
    * multiplications.)
@@ -132,32 +132,32 @@ public:
   }
 
   static Matrix Scaling(Float aScaleX, Float aScaleY)
   {
     return Matrix(aScaleX, 0.0f, 0.0f, aScaleY, 0.0f, 0.0f);
   }
   
   /**
-   * Similar to PreTranslate, but applies a scale to this matrix.
+   * Similar to PreTranslate, but applies a scale instead of a translation.
    */
   Matrix &PreScale(Float aX, Float aY)
   {
     _11 *= aX;
     _12 *= aX;
     _21 *= aY;
     _22 *= aY;
 
     return *this;
   }
   
   GFX2D_API static Matrix Rotation(Float aAngle);
 
   /**
-   * Similar to PreTranslate, but applies a rotation to this matrix.
+   * Similar to PreTranslate, but applies a rotation instead of a translation.
    */
   Matrix &PreRotate(Float aAngle)
   {
     return *this = Matrix::Rotation(aAngle) * *this;
   }
 
   bool Invert()
   {
@@ -360,16 +360,26 @@ class Matrix4x4
 public:
   Matrix4x4()
     : _11(1.0f), _12(0.0f), _13(0.0f), _14(0.0f)
     , _21(0.0f), _22(1.0f), _23(0.0f), _24(0.0f)
     , _31(0.0f), _32(0.0f), _33(1.0f), _34(0.0f)
     , _41(0.0f), _42(0.0f), _43(0.0f), _44(1.0f)
   {}
 
+  Matrix4x4(Float a11, Float a12, Float a13, Float a14,
+            Float a21, Float a22, Float a23, Float a24,
+            Float a31, Float a32, Float a33, Float a34,
+            Float a41, Float a42, Float a43, Float a44)
+    : _11(a11), _12(a12), _13(a13), _14(a14)
+    , _21(a21), _22(a22), _23(a23), _24(a24)
+    , _31(a31), _32(a32), _33(a33), _34(a34)
+    , _41(a41), _42(a42), _43(a43), _44(a44)
+  {}
+
   Float _11, _12, _13, _14;
   Float _21, _22, _23, _24;
   Float _31, _32, _33, _34;
   Float _41, _42, _43, _44;
 
   Point4D& operator[](int aIndex)
   {
       MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index");
@@ -453,16 +463,18 @@ public:
 
     // Solving for z when z' = 0 gives us:
     float z = -(aPoint.x * _13 + aPoint.y * _23 + _43) / _33;
 
     // Compute the transformed point
     return *this * Point4D(aPoint.x, aPoint.y, z, 1);
   }
 
+  Rect ProjectRectBounds(const Rect& aRect) const;
+
   static Matrix4x4 From2D(const Matrix &aMatrix) {
     Matrix4x4 matrix;
     matrix._11 = aMatrix._11;
     matrix._12 = aMatrix._12;
     matrix._21 = aMatrix._21;
     matrix._22 = aMatrix._22;
     matrix._41 = aMatrix._31;
     matrix._42 = aMatrix._32;
@@ -513,59 +525,127 @@ public:
     temp = *this * temp;
     temp /= temp.w;
 
     return Point(temp.x, temp.y);
   }
 
   GFX2D_API Rect TransformBounds(const Rect& rect) const;
 
-  // Apply a scale to this matrix. This scale will be applied -before- the
-  // existing transformation of the matrix.
+
+  static Matrix4x4 Translation(Float aX, Float aY, Float aZ)
+  {
+    return Matrix4x4(1.0f, 0.0f, 0.0f, 0.0f,
+                     0.0f, 1.0f, 0.0f, 0.0f,
+                     0.0f, 0.0f, 1.0f, 0.0f,
+                       aX,   aY,   aZ, 1.0f);
+  }
+
+  /**
+   * Apply a translation to this matrix.
+   *
+   * The "Pre" in this method's name means that the translation is applied
+   * -before- this matrix's existing transformation. That is, any vector that
+   * is multiplied by the resulting matrix will first be translated, then be
+   * transformed by the original transform.
+   *
+   * Calling this method will result in this matrix having the same value as
+   * the result of:
+   *
+   *   Matrix4x4::Translation(x, y) * this
+   *
+   * (Note that in performance critical code multiplying by the result of a
+   * Translation()/Scaling() call is not recommended since that results in a
+   * full matrix multiply involving 64 floating-point multiplications. Calling
+   * this method would be preferred since it only involves 12 floating-point
+   * multiplications.)
+   */
+  Matrix4x4 &Translate(Float aX, Float aY, Float aZ)
+  {
+    _41 += aX * _11 + aY * _21 + aZ * _31;
+    _42 += aX * _12 + aY * _22 + aZ * _32;
+    _43 += aX * _13 + aY * _23 + aZ * _33;
+    _44 += aX * _14 + aY * _24 + aZ * _34;
+
+    return *this;
+  }
+
+  /**
+   * Similar to PreTranslate, but the translation is applied -after- this
+   * matrix's existing transformation instead of before it.
+   *
+   * This method is generally less used than PreTranslate since typically code
+   * wants to adjust an existing user space to device space matrix to create a
+   * transform to device space from a -new- user space (translated from the
+   * previous user space). In that case consumers will need to use the Pre*
+   * variants of the matrix methods rather than using the Post* methods, since
+   * the Post* methods add a transform to the device space end of the
+   * transformation.
+   */
+  Matrix4x4 &PostTranslate(Float aX, Float aY, Float aZ)
+  {
+    _11 += _14 * aX;
+    _21 += _24 * aX;
+    _31 += _34 * aX;
+    _41 += _44 * aX;
+    _12 += _14 * aY;
+    _22 += _24 * aY;
+    _32 += _34 * aY;
+    _42 += _44 * aY;
+    _13 += _14 * aZ;
+    _23 += _24 * aZ;
+    _33 += _34 * aZ;
+    _43 += _44 * aZ;
+
+    return *this;
+  }
+
+  static Matrix4x4 Scaling(Float aScaleX, Float aScaleY, float aScaleZ)
+  {
+    return Matrix4x4(aScaleX, 0.0f, 0.0f, 0.0f,
+                     0.0f, aScaleY, 0.0f, 0.0f,
+                     0.0f, 0.0f, aScaleZ, 0.0f,
+                     0.0f, 0.0f, 0.0f, 1.0f);
+  }
+
+  /**
+   * Similar to PreTranslate, but applies a scale instead of a translation.
+   */
   Matrix4x4 &Scale(Float aX, Float aY, Float aZ)
   {
     _11 *= aX;
     _12 *= aX;
     _13 *= aX;
     _21 *= aY;
     _22 *= aY;
     _23 *= aY;
     _31 *= aZ;
     _32 *= aZ;
     _33 *= aZ;
 
     return *this;
   }
 
-  Matrix4x4 &Translate(Float aX, Float aY, Float aZ)
+  /**
+   * Similar to PostTranslate, but applies a scale instead of a translation.
+   */
+  Matrix4x4 &PostScale(Float aScaleX, Float aScaleY, Float aScaleZ)
   {
-    _41 += aX * _11 + aY * _21 + aZ * _31;
-    _42 += aX * _12 + aY * _22 + aZ * _32;
-    _43 += aX * _13 + aY * _23 + aZ * _33;
-    _44 += aX * _14 + aY * _24 + aZ * _34;
-
-    return *this;
-  }
-
-  Rect ProjectRectBounds(const Rect& aRect) const;
-
-  Matrix4x4 &PostTranslate(Float aX, Float aY, Float aZ)
-  {
-    _11 += _14 * aX;
-    _21 += _24 * aX;
-    _31 += _34 * aX;
-    _41 += _44 * aX;
-    _12 += _14 * aY;
-    _22 += _24 * aY;
-    _32 += _34 * aY;
-    _42 += _44 * aY;
-    _13 += _14 * aZ;
-    _23 += _24 * aZ;
-    _33 += _34 * aZ;
-    _43 += _44 * aZ;
+    _11 *= aScaleX;
+    _21 *= aScaleX;
+    _31 *= aScaleX;
+    _41 *= aScaleX;
+    _12 *= aScaleY;
+    _22 *= aScaleY;
+    _32 *= aScaleY;
+    _42 *= aScaleY;
+    _13 *= aScaleZ;
+    _23 *= aScaleZ;
+    _33 *= aScaleZ;
+    _43 *= aScaleZ;
 
     return *this;
   }
 
   void SkewXY(Float aSkew)
   {
     (*this)[1] += (*this)[0] * aSkew;
   }
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -2360,17 +2360,16 @@ bool
 GLContext::ResizeScreenBuffer(const IntSize& size)
 {
     if (!IsOffscreenSizeAllowed(size))
         return false;
 
     return mScreen->Resize(size);
 }
 
-
 void
 GLContext::DestroyScreenBuffer()
 {
     mScreen = nullptr;
 }
 
 void
 GLContext::ForceDirtyScreen()
--- a/gfx/gl/GLTextureImage.cpp
+++ b/gfx/gl/GLTextureImage.cpp
@@ -227,24 +227,37 @@ BasicTextureImage::DirectUpdate(gfx::Dat
 
 void
 BasicTextureImage::Resize(const gfx::IntSize& aSize)
 {
     NS_ASSERTION(!mUpdateDrawTarget, "Resize() while in update?");
 
     mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
 
+    // This matches the logic in UploadImageDataToTexture so that
+    // we avoid mixing formats.
+    GLenum format;
+    GLenum type;
+    if (mGLContext->GetPreferredARGB32Format() == LOCAL_GL_BGRA) {
+        MOZ_ASSERT(!mGLContext->IsGLES());
+        format = LOCAL_GL_BGRA;
+        type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
+    } else {
+        format = LOCAL_GL_RGBA;
+        type = LOCAL_GL_UNSIGNED_BYTE;
+    }
+
     mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D,
                             0,
                             LOCAL_GL_RGBA,
                             aSize.width,
                             aSize.height,
                             0,
-                            LOCAL_GL_RGBA,
-                            LOCAL_GL_UNSIGNED_BYTE,
+                            format,
+                            type,
                             nullptr);
 
     mTextureState = Allocated;
     mSize = aSize;
 }
 
 gfx::IntSize TextureImage::GetSize() const {
   return mSize;
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -710,35 +710,36 @@ Layer::IsScrollInfoLayer() const
       && HasScrollableFrameMetrics()
       && !GetFirstChild();
 }
 
 const Matrix4x4
 Layer::GetTransform() const
 {
   Matrix4x4 transform = mTransform;
+  transform.PostScale(mPostXScale, mPostYScale, 1.0f);
   if (const ContainerLayer* c = AsContainerLayer()) {
     transform.Scale(c->GetPreXScale(), c->GetPreYScale(), 1.0f);
   }
-  transform = transform * Matrix4x4().Scale(mPostXScale, mPostYScale, 1.0f);
   return transform;
 }
 
 const Matrix4x4
 Layer::GetLocalTransform()
 {
   Matrix4x4 transform;
   if (LayerComposite* shadow = AsLayerComposite())
     transform = shadow->GetShadowTransform();
   else
     transform = mTransform;
+
+  transform.PostScale(mPostXScale, mPostYScale, 1.0f);
   if (ContainerLayer* c = AsContainerLayer()) {
     transform.Scale(c->GetPreXScale(), c->GetPreYScale(), 1.0f);
   }
-  transform = transform * Matrix4x4().Scale(mPostXScale, mPostYScale, 1.0f);
 
   return transform;
 }
 
 void
 Layer::ApplyPendingUpdatesForThisTransaction()
 {
   if (mPendingTransform && *mPendingTransform != mTransform) {
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -2493,17 +2493,17 @@ Matrix4x4 AsyncPanZoomController::GetOve
   if (mY.IsOverscrolled() && mY.GetOverscroll() > 0) {
     // Overscrolled at the bottomn.
     ScreenCoord overscrolledCompositionHeight = scaleY * compositionSize.height;
     ScreenCoord extraCompositionHeight = overscrolledCompositionHeight - compositionSize.height;
     translation.y = -extraCompositionHeight;
   }
 
   // Combine the transformations into a matrix.
-  return Matrix4x4().Scale(scaleX, scaleY, 1)
+  return Matrix4x4::Scaling(scaleX, scaleY, 1)
                     .PostTranslate(translation.x, translation.y, 0);
 }
 
 bool AsyncPanZoomController::AdvanceAnimations(const TimeStamp& aSampleTime)
 {
   AssertOnCompositorThread();
 
   // Don't send any state-change notifications until the end of the function,
@@ -2618,19 +2618,19 @@ ViewTransform AsyncPanZoomController::Ge
   ScreenPoint translation = (currentScrollOffset - lastPaintScrollOffset)
                           * mFrameMetrics.GetZoom();
 
   return ViewTransform(scale, -translation);
 }
 
 Matrix4x4 AsyncPanZoomController::GetNontransientAsyncTransform() const {
   ReentrantMonitorAutoEnter lock(mMonitor);
-  return Matrix4x4().Scale(mLastContentPaintMetrics.mResolution.scale,
-                           mLastContentPaintMetrics.mResolution.scale,
-                           1.0f);
+  return Matrix4x4::Scaling(mLastContentPaintMetrics.mResolution.scale,
+                            mLastContentPaintMetrics.mResolution.scale,
+                            1.0f);
 }
 
 Matrix4x4 AsyncPanZoomController::GetTransformToLastDispatchedPaint() const {
   ReentrantMonitorAutoEnter lock(mMonitor);
 
   // Technically we should be taking the scroll delta in the coordinate space
   // of transformed layer pixels (i.e. this layer's LayerPixels, with the layer
   // transform applied). However in the absence of actual CSS transforms, we
@@ -2639,18 +2639,18 @@ Matrix4x4 AsyncPanZoomController::GetTra
   // to revisit this.
   ParentLayerPoint scrollChange =
     (mLastContentPaintMetrics.GetScrollOffset() - mLastDispatchedPaintMetrics.GetScrollOffset())
     * mLastContentPaintMetrics.mDevPixelsPerCSSPixel
     * mLastContentPaintMetrics.GetParentResolution();
 
   float zoomChange = mLastContentPaintMetrics.GetZoom().scale / mLastDispatchedPaintMetrics.GetZoom().scale;
 
-  return Matrix4x4().Translate(scrollChange.x, scrollChange.y, 0) *
-         Matrix4x4().Scale(zoomChange, zoomChange, 1);
+  return Matrix4x4::Translation(scrollChange.x, scrollChange.y, 0).
+           PostScale(zoomChange, zoomChange, 1);
 }
 
 bool AsyncPanZoomController::IsCurrentlyCheckerboarding() const {
   ReentrantMonitorAutoEnter lock(mMonitor);
 
   if (!gfxPrefs::APZAllowCheckerboarding()) {
     return false;
   }
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -602,17 +602,17 @@ ClientLayerManager::ForwardTransaction(b
   if (!sent) {
     // Clear the transaction id so that it doesn't get returned
     // unless we forwarded to somewhere that doesn't actually
     // have a compositor.
     mTransactionIdAllocator->RevokeTransactionId(mLatestTransactionId);
   }
 
   mForwarder->RemoveTexturesIfNecessary();
-  mForwarder->SendPendingAsyncMessge();
+  mForwarder->SendPendingAsyncMessges();
   mPhase = PHASE_NONE;
 
   // this may result in Layers being deleted, which results in
   // PLayer::Send__delete__() and DeallocShmem()
   mKeepAlive.Clear();
 }
 
 ShadowableLayer*
--- a/gfx/layers/client/ClientTiledPaintedLayer.cpp
+++ b/gfx/layers/client/ClientTiledPaintedLayer.cpp
@@ -70,17 +70,17 @@ GetTransformToAncestorsParentLayer(Layer
   const LayerMetricsWrapper& ancestorParent = aAncestor.GetParent();
   for (LayerMetricsWrapper iter(aStart, LayerMetricsWrapper::StartAt::BOTTOM);
        ancestorParent ? iter != ancestorParent : iter.IsValid();
        iter = iter.GetParent()) {
     transform = transform * iter.GetTransform();
     // If the layer has a non-transient async transform then we need to apply it here
     // because it will get applied by the APZ in the compositor as well
     const FrameMetrics& metrics = iter.Metrics();
-    transform = transform * gfx::Matrix4x4().Scale(metrics.mResolution.scale, metrics.mResolution.scale, 1.f);
+    transform.PostScale(metrics.mResolution.scale, metrics.mResolution.scale, 1.f);
   }
   return transform;
 }
 
 void
 ClientTiledPaintedLayer::GetAncestorLayers(LayerMetricsWrapper* aOutScrollAncestor,
                                           LayerMetricsWrapper* aOutDisplayPortAncestor)
 {
--- a/gfx/layers/client/ClientTiledPaintedLayer.h
+++ b/gfx/layers/client/ClientTiledPaintedLayer.h
@@ -50,18 +50,19 @@ protected:
 public:
   // Override name to distinguish it from ClientPaintedLayer in layer dumps
   virtual const char* Name() const { return "TiledPaintedLayer"; }
 
   // PaintedLayer
   virtual Layer* AsLayer() { return this; }
   virtual void InvalidateRegion(const nsIntRegion& aRegion) {
     mInvalidRegion.Or(mInvalidRegion, aRegion);
-    mValidRegion.Sub(mValidRegion, aRegion);
-    mLowPrecisionValidRegion.Sub(mLowPrecisionValidRegion, aRegion);
+    mInvalidRegion.SimplifyOutward(20);
+    mValidRegion.Sub(mValidRegion, mInvalidRegion);
+    mLowPrecisionValidRegion.Sub(mLowPrecisionValidRegion, mInvalidRegion);
   }
 
   // Shadow methods
   virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs);
   virtual ShadowableLayer* AsShadowableLayer() { return this; }
 
   virtual void Disconnect()
   {
--- a/gfx/layers/client/CompositableClient.cpp
+++ b/gfx/layers/client/CompositableClient.cpp
@@ -166,16 +166,20 @@ CompositableClient::Connect()
 }
 
 void
 CompositableClient::Destroy()
 {
   if (!mCompositableChild) {
     return;
   }
+  // Send pending AsyncMessages before deleting CompositableChild.
+  // They might have dependency to the mCompositableChild.
+  mForwarder->SendPendingAsyncMessges();
+  // Delete CompositableChild.
   mCompositableChild->mCompositableClient = nullptr;
   PCompositableChild::Send__delete__(mCompositableChild);
   mCompositableChild = nullptr;
 }
 
 uint64_t
 CompositableClient::GetAsyncID() const
 {
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -1361,17 +1361,17 @@ ClientTiledLayerBuffer::ValidateTile(Til
  * transformed into the painted layer's LayerPixel coordinates, accounting
  * for the compositor state.
  */
 static LayerRect
 GetCompositorSideCompositionBounds(const LayerMetricsWrapper& aScrollAncestor,
                                    const Matrix4x4& aTransformToCompBounds,
                                    const ViewTransform& aAPZTransform)
 {
-  Matrix4x4 nonTransientAPZUntransform = Matrix4x4().Scale(
+  Matrix4x4 nonTransientAPZUntransform = Matrix4x4::Scaling(
     aScrollAncestor.Metrics().mResolution.scale,
     aScrollAncestor.Metrics().mResolution.scale,
     1.f);
   nonTransientAPZUntransform.Invert();
 
   // Take off the last "term" of aTransformToCompBounds, which
   // is the APZ's nontransient async transform. Replace it with
   // the APZ's async transform (this includes the nontransient
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -173,27 +173,26 @@ TranslateShadowLayer2D(Layer* aLayer,
   // will apply the resolution scale again when computing the effective
   // transform, we must apply the inverse resolution scale here.
   Matrix4x4 layerTransform3D = Matrix4x4::From2D(layerTransform);
   if (ContainerLayer* c = aLayer->AsContainerLayer()) {
     layerTransform3D.Scale(1.0f/c->GetPreXScale(),
                            1.0f/c->GetPreYScale(),
                            1);
   }
-  layerTransform3D = layerTransform3D *
-    Matrix4x4().Scale(1.0f/aLayer->GetPostXScale(),
-                      1.0f/aLayer->GetPostYScale(),
-                      1);
+  layerTransform3D.PostScale(1.0f/aLayer->GetPostXScale(),
+                             1.0f/aLayer->GetPostYScale(),
+                             1);
 
   LayerComposite* layerComposite = aLayer->AsLayerComposite();
   layerComposite->SetShadowTransform(layerTransform3D);
   layerComposite->SetShadowTransformSetByAnimation(false);
 
   if (aAdjustClipRect) {
-    TransformClipRect(aLayer, Matrix4x4().Translate(aTranslation.x, aTranslation.y, 0));
+    TransformClipRect(aLayer, Matrix4x4::Translation(aTranslation.x, aTranslation.y, 0));
   }
 }
 
 static bool
 AccumulateLayerTransforms2D(Layer* aLayer,
                             Layer* aAncestor,
                             Matrix& aMatrix)
 {
@@ -495,19 +494,17 @@ SampleAnimations(Layer* aLayer, TimeStam
     {
       layerComposite->SetShadowOpacity(interpolatedValue.get_float());
       break;
     }
     case eCSSProperty_transform:
     {
       Matrix4x4 matrix = interpolatedValue.get_ArrayOfTransformFunction()[0].get_TransformMatrix().value();
       if (ContainerLayer* c = aLayer->AsContainerLayer()) {
-        matrix = matrix * Matrix4x4().Scale(c->GetInheritedXScale(),
-                                            c->GetInheritedYScale(),
-                                            1);
+        matrix.PostScale(c->GetInheritedXScale(), c->GetInheritedYScale(), 1);
       }
       layerComposite->SetShadowTransform(matrix);
       layerComposite->SetShadowTransformSetByAnimation(true);
       break;
     }
     default:
       NS_WARNING("Unhandled animated property");
     }
@@ -622,19 +619,19 @@ AsyncCompositionManager::ApplyAsyncConte
     // GetTransform already takes the pre- and post-scale into account.  Since we
     // will apply the pre- and post-scale again when computing the effective
     // transform, we must apply the inverses here.
     if (ContainerLayer* container = aLayer->AsContainerLayer()) {
       transform.Scale(1.0f/container->GetPreXScale(),
                       1.0f/container->GetPreYScale(),
                       1);
     }
-    transform = transform * Matrix4x4().Scale(1.0f/aLayer->GetPostXScale(),
-                                              1.0f/aLayer->GetPostYScale(),
-                                              1);
+    transform.PostScale(1.0f/aLayer->GetPostXScale(),
+                        1.0f/aLayer->GetPostYScale(),
+                        1);
     layerComposite->SetShadowTransform(transform);
     NS_ASSERTION(!layerComposite->GetShadowTransformSetByAnimation(),
                  "overwriting animated transform!");
 
     const FrameMetrics& bottom = LayerMetricsWrapper::BottommostScrollableMetrics(aLayer);
     MOZ_ASSERT(bottom.IsScrollable());  // must be true because hasAsyncTransform is true
 
     // Apply resolution scaling to the old transform - the layer tree as it is
@@ -710,23 +707,23 @@ ApplyAsyncTransformToScrollbarForContent
   //   translation (representing the scroll). This is because scrolling down, which
   //   translates the layer content up, should result in moving the scroll thumb down.
   //   The amount of the translation to the scroll thumb should be such that the ratio
   //   of the translation to the size of the scroll port is the same as the ratio
   //   of the scroll amount to the size of the scrollable rect.
   Matrix4x4 scrollbarTransform;
   if (aScrollbar->GetScrollbarDirection() == Layer::VERTICAL) {
     float scale = metrics.CalculateCompositedSizeInCssPixels().height / metrics.mScrollableRect.height;
-    scrollbarTransform = scrollbarTransform * Matrix4x4().Scale(1.f, 1.f / transientTransform._22, 1.f);
-    scrollbarTransform = scrollbarTransform * Matrix4x4().Translate(0, -transientTransform._42 * scale, 0);
+    scrollbarTransform.PostScale(1.f, 1.f / transientTransform._22, 1.f);
+    scrollbarTransform.PostTranslate(0, -transientTransform._42 * scale, 0);
   }
   if (aScrollbar->GetScrollbarDirection() == Layer::HORIZONTAL) {
     float scale = metrics.CalculateCompositedSizeInCssPixels().width / metrics.mScrollableRect.width;
-    scrollbarTransform = scrollbarTransform * Matrix4x4().Scale(1.f / transientTransform._11, 1.f, 1.f);
-    scrollbarTransform = scrollbarTransform * Matrix4x4().Translate(-transientTransform._41 * scale, 0, 0);
+    scrollbarTransform.PostScale(1.f / transientTransform._11, 1.f, 1.f);
+    scrollbarTransform.PostTranslate(-transientTransform._41 * scale, 0, 0);
   }
 
   Matrix4x4 transform = scrollbarTransform * aScrollbar->GetTransform();
 
   if (aScrollbarIsDescendant) {
     // If the scrollbar layer is a child of the content it is a scrollbar for, then we
     // need to do an extra untransform to cancel out the transient async transform on
     // the content. This is needed because otherwise that transient async transform is
@@ -755,19 +752,19 @@ ApplyAsyncTransformToScrollbarForContent
   // GetTransform already takes the pre- and post-scale into account.  Since we
   // will apply the pre- and post-scale again when computing the effective
   // transform, we must apply the inverses here.
   if (ContainerLayer* container = aScrollbar->AsContainerLayer()) {
     transform.Scale(1.0f/container->GetPreXScale(),
                     1.0f/container->GetPreYScale(),
                     1);
   }
-  transform = transform * Matrix4x4().Scale(1.0f/aScrollbar->GetPostXScale(),
-                                            1.0f/aScrollbar->GetPostYScale(),
-                                            1);
+  transform.PostScale(1.0f/aScrollbar->GetPostXScale(),
+                      1.0f/aScrollbar->GetPostYScale(),
+                      1);
   aScrollbar->AsLayerComposite()->SetShadowTransform(transform);
 }
 
 static LayerMetricsWrapper
 FindScrolledLayerRecursive(Layer* aScrollbar, const LayerMetricsWrapper& aSubtreeRoot)
 {
   if (LayerIsScrollbarTarget(aSubtreeRoot, aScrollbar)) {
     return aSubtreeRoot;
--- a/gfx/layers/composite/AsyncCompositionManager.h
+++ b/gfx/layers/composite/AsyncCompositionManager.h
@@ -32,17 +32,17 @@ struct ViewTransform {
                          ScreenPoint aTranslation = ScreenPoint())
     : mScale(aScale)
     , mTranslation(aTranslation)
   {}
 
   operator gfx::Matrix4x4() const
   {
     return
-      gfx::Matrix4x4().Scale(mScale.scale, mScale.scale, 1)
+      gfx::Matrix4x4::Scaling(mScale.scale, mScale.scale, 1)
                       .PostTranslate(mTranslation.x, mTranslation.y, 0);
   }
 
   // For convenience, to avoid writing the cumbersome
   // "gfx::Matrix4x4(a) * gfx::Matrix4x4(b)".
   friend gfx::Matrix4x4 operator*(const ViewTransform& a, const ViewTransform& b) {
     return gfx::Matrix4x4(a) * gfx::Matrix4x4(b);
   }
--- a/gfx/layers/ipc/CompositableForwarder.h
+++ b/gfx/layers/ipc/CompositableForwarder.h
@@ -189,16 +189,18 @@ public:
                               TextureClient* aTexture,
                               nsIntRegion* aRegion) = 0;
 
 
   virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
                                PTextureChild* aTexture,
                                const FenceHandle& aFence) = 0;
 
+  virtual void SendPendingAsyncMessges() = 0;
+
   void IdentifyTextureHost(const TextureFactoryIdentifier& aIdentifier);
 
   virtual int32_t GetMaxTextureSize() const MOZ_OVERRIDE
   {
     return mTextureFactoryIdentifier.mMaxTextureSize;
   }
 
   bool IsOnCompositorSide() const MOZ_OVERRIDE { return false; }
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -550,17 +550,17 @@ ImageBridgeChild::EndTransaction()
         texture->SetReleaseFenceHandle(fence);
       }
       break;
     }
     default:
       NS_RUNTIMEABORT("not reached");
     }
   }
-  SendPendingAsyncMessge();
+  SendPendingAsyncMessges();
 }
 
 
 PImageBridgeChild*
 ImageBridgeChild::StartUpInChildProcess(Transport* aTransport,
                                         ProcessId aOtherProcess)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -959,17 +959,17 @@ void ImageBridgeChild::RemoveTexture(Tex
   }
 }
 
 bool ImageBridgeChild::IsSameProcess() const
 {
   return OtherProcess() == ipc::kInvalidProcessHandle;
 }
 
-void ImageBridgeChild::SendPendingAsyncMessge()
+void ImageBridgeChild::SendPendingAsyncMessges()
 {
   if (!IsCreated() ||
       mTransactionsToRespond.empty()) {
     return;
   }
   // Send OpReplyDeliverFence messages
   InfallibleTArray<AsyncChildMessageData> replies;
   replies.SetCapacity(mTransactionsToRespond.size());
--- a/gfx/layers/ipc/ImageBridgeChild.h
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -305,17 +305,17 @@ public:
    */
   virtual void DeallocShmem(mozilla::ipc::Shmem& aShmem);
 
   virtual PTextureChild* CreateTexture(const SurfaceDescriptor& aSharedData,
                                        TextureFlags aFlags) MOZ_OVERRIDE;
 
   virtual bool IsSameProcess() const MOZ_OVERRIDE;
 
-  void SendPendingAsyncMessge();
+  virtual void SendPendingAsyncMessges();
 
   void MarkShutDown();
 protected:
   ImageBridgeChild();
   bool DispatchAllocShmemInternal(size_t aSize,
                                   SharedMemory::SharedMemoryType aType,
                                   Shmem* aShmem,
                                   bool aUnsafe);
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -853,16 +853,18 @@ bool
 LayerTransactionParent::DeallocPTextureParent(PTextureParent* actor)
 {
   return TextureHost::DestroyIPDLActor(actor);
 }
 
 bool
 LayerTransactionParent::RecvChildAsyncMessages(const InfallibleTArray<AsyncChildMessageData>& aMessages)
 {
+  AutoLayerTransactionParentAsyncMessageSender autoAsyncMessageSender(this);
+
   for (AsyncChildMessageArray::index_type i = 0; i < aMessages.Length(); ++i) {
     const AsyncChildMessageData& message = aMessages[i];
 
     switch (message.type()) {
       case AsyncChildMessageData::TOpDeliverFenceFromChild: {
         const OpDeliverFenceFromChild& op = message.get_OpDeliverFenceFromChild();
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
         FenceHandle fence = FenceHandle(op.fence());
@@ -883,16 +885,40 @@ LayerTransactionParent::RecvChildAsyncMe
         mozilla::unused << SendParentAsyncMessages(replies);
         break;
       }
       case AsyncChildMessageData::TOpReplyDeliverFence: {
         const OpReplyDeliverFence& op = message.get_OpReplyDeliverFence();
         TransactionCompleteted(op.transactionId());
         break;
       }
+      case AsyncChildMessageData::TOpRemoveTextureAsync: {
+        const OpRemoveTextureAsync& op = message.get_OpRemoveTextureAsync();
+        CompositableHost* compositable = CompositableHost::FromIPDLActor(op.compositableParent());
+        RefPtr<TextureHost> tex = TextureHost::AsTextureHost(op.textureParent());
+
+        MOZ_ASSERT(tex.get());
+        compositable->RemoveTextureHost(tex);
+
+        // send FenceHandle if present via ImageBridge.
+        ImageBridgeParent::SendFenceHandleToTrackerIfPresent(
+                             GetChildProcessId(),
+                             op.holderId(),
+                             op.transactionId(),
+                             op.textureParent(),
+                             compositable);
+
+        // Send message back via PImageBridge.
+        ImageBridgeParent::ReplyRemoveTexture(
+                             GetChildProcessId(),
+                             OpReplyRemoveTexture(true, // isMain
+                                                  op.holderId(),
+                                                  op.transactionId()));
+        break;
+      }
       default:
         NS_ERROR("unknown AsyncChildMessageData type");
         return false;
     }
   }
   return true;
 }
 
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -487,12 +487,13 @@ union AsyncParentMessageData {
   OpDeliverFenceToTracker;
   OpReplyDeliverFence;
   OpReplyRemoveTexture;
 };
 
 union AsyncChildMessageData {
   OpDeliverFenceFromChild;
   OpReplyDeliverFence;
+  OpRemoveTextureAsync;
 };
 
 } // namespace
 } // namespace
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -130,16 +130,18 @@ public:
   bool Empty() const {
     return mCset.empty() && mPaints.empty() && mMutants.empty();
   }
   bool RotationChanged() const {
     return mRotationChanged;
   }
   bool Finished() const { return !mOpen && Empty(); }
 
+  bool Opened() const { return mOpen; }
+
   EditVector mCset;
   EditVector mPaints;
   ShadowableLayerSet mMutants;
   nsIntRect mTargetBounds;
   ScreenRotation mTargetRotation;
   dom::ScreenOrientation mTargetOrientation;
   bool mSwapRequired;
 
@@ -467,21 +469,29 @@ ShadowLayerForwarder::RemoveTextureFromC
   HoldUntilTransaction(aTexture);
 }
 
 void
 ShadowLayerForwarder::RemoveTextureFromCompositableAsync(AsyncTransactionTracker* aAsyncTransactionTracker,
                                                      CompositableClient* aCompositable,
                                                      TextureClient* aTexture)
 {
-  mTxn->AddEdit(OpRemoveTextureAsync(CompositableClient::GetTrackersHolderId(aCompositable->GetIPDLActor()),
-                                     aAsyncTransactionTracker->GetId(),
-                                     nullptr, aCompositable->GetIPDLActor(),
-                                     nullptr, aTexture->GetIPDLActor()));
-  // Hold AsyncTransactionTracker until receving reply
+  if (mTxn->Opened()) {
+    mTxn->AddEdit(OpRemoveTextureAsync(CompositableClient::GetTrackersHolderId(aCompositable->GetIPDLActor()),
+                                       aAsyncTransactionTracker->GetId(),
+                                       nullptr, aCompositable->GetIPDLActor(),
+                                       nullptr, aTexture->GetIPDLActor()));
+  } else {
+    // If the function is called outside of transaction,
+    // OpRemoveTextureAsync message is stored as pending message.
+    mPendingAsyncMessages.push_back(OpRemoveTextureAsync(CompositableClient::GetTrackersHolderId(aCompositable->GetIPDLActor()),
+                                    aAsyncTransactionTracker->GetId(),
+                                    nullptr, aCompositable->GetIPDLActor(),
+                                    nullptr, aTexture->GetIPDLActor()));
+  }
   CompositableClient::HoldUntilComplete(aCompositable->GetIPDLActor(),
                                         aAsyncTransactionTracker);
 }
 
 bool
 ShadowLayerForwarder::InWorkerThread()
 {
   return GetMessageLoop()->id() == MessageLoop::current()->id();
@@ -816,50 +826,61 @@ void ShadowLayerForwarder::SetShadowMana
 }
 
 void ShadowLayerForwarder::StopReceiveAsyncParentMessge()
 {
   if (!HasShadowManager() ||
       !mShadowManager->IPCOpen()) {
     return;
   }
-  SendPendingAsyncMessge();
+  SendPendingAsyncMessges();
   mShadowManager->SetForwarder(nullptr);
 }
 
 void ShadowLayerForwarder::ClearCachedResources()
 {
   if (!HasShadowManager() ||
       !mShadowManager->IPCOpen()) {
     return;
   }
-  SendPendingAsyncMessge();
+  SendPendingAsyncMessges();
   mShadowManager->SendClearCachedResources();
 }
 
 void ShadowLayerForwarder::Composite()
 {
   if (!HasShadowManager() ||
       !mShadowManager->IPCOpen()) {
     return;
   }
   mShadowManager->SendForceComposite();
 }
 
-void ShadowLayerForwarder::SendPendingAsyncMessge()
+void ShadowLayerForwarder::SendPendingAsyncMessges()
 {
   if (!HasShadowManager() ||
-      !mShadowManager->IPCOpen() ||
-      mTransactionsToRespond.empty()) {
+      !mShadowManager->IPCOpen()) {
+    mTransactionsToRespond.clear();
+    mPendingAsyncMessages.clear();
     return;
   }
-  // Send OpReplyDeliverFence messages
+
+  if (mTransactionsToRespond.empty() && mPendingAsyncMessages.empty()) {
+    return;
+  }
+
   InfallibleTArray<AsyncChildMessageData> replies;
   replies.SetCapacity(mTransactionsToRespond.size());
+  // Prepare OpReplyDeliverFence messages.
   for (size_t i = 0; i < mTransactionsToRespond.size(); i++) {
     replies.AppendElement(OpReplyDeliverFence(mTransactionsToRespond[i]));
   }
   mTransactionsToRespond.clear();
+  // Prepare pending messages.
+  for (size_t i = 0; i < mPendingAsyncMessages.size(); i++) {
+    replies.AppendElement(mPendingAsyncMessages[i]);
+  }
+  mPendingAsyncMessages.clear();
   mShadowManager->SendChildAsyncMessages(replies);
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -314,17 +314,17 @@ public:
   void SetShadowManager(PLayerTransactionChild* aShadowManager);
 
   void StopReceiveAsyncParentMessge();
 
   void ClearCachedResources();
 
   void Composite();
 
-  void SendPendingAsyncMessge();
+  virtual void SendPendingAsyncMessges();
 
   /**
    * True if this is forwarding to a LayerManagerComposite.
    */
   bool HasShadowManager() const { return !!mShadowManager; }
   LayerTransactionChild* GetShadowManager() const { return mShadowManager.get(); }
 
   virtual void WindowOverlayChanged() { mWindowOverlayChanged = true; }
@@ -398,16 +398,17 @@ protected:
 
   bool InWorkerThread();
 
   RefPtr<LayerTransactionChild> mShadowManager;
 
 private:
 
   Transaction* mTxn;
+  std::vector<AsyncChildMessageData> mPendingAsyncMessages;
   DiagnosticTypes mDiagnosticTypes;
   bool mIsFirstPaint;
   bool mWindowOverlayChanged;
 };
 
 class CompositableClient;
 
 /**
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -1696,17 +1696,17 @@ protected:
       nsIntRegion(nsIntRect(0,0,100,100)),
       nsIntRegion(nsIntRect(10,10,40,40)),
       nsIntRegion(nsIntRect(10,60,40,40)),
       nsIntRegion(nsIntRect(10,60,40,40)),
     };
     Matrix4x4 transforms[] = {
       Matrix4x4(),
       Matrix4x4(),
-      Matrix4x4().Scale(2, 1, 1),
+      Matrix4x4::Scaling(2, 1, 1),
       Matrix4x4(),
     };
     root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, lm, layers);
 
     SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID, CSSRect(0, 0, 200, 200));
     SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID + 1, CSSRect(0, 0, 80, 80));
     SetScrollableFrameMetrics(layers[3], FrameMetrics::START_SCROLL_ID + 2, CSSRect(0, 0, 80, 80));
   }
--- a/gfx/tests/unit/xpcshell.ini
+++ b/gfx/tests/unit/xpcshell.ini
@@ -1,5 +1,6 @@
 [DEFAULT]
 head = 
 tail = 
+skip-if = toolkit == 'gonk'
 
 [test_nsIScriptableRegion.js]
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -1138,32 +1138,16 @@ gfxContext::PopGroupToSource()
 
   Matrix mat = mTransform;
   mat.Invert();
   mat.PreTranslate(deviceOffset.x, deviceOffset.y); // device offset translation
 
   CurrentState().surfTransform = mat;
 }
 
-bool
-gfxContext::PointInFill(const gfxPoint& pt)
-{
-  EnsurePath();
-  return mPath->ContainsPoint(ToPoint(pt), Matrix());
-}
-
-bool
-gfxContext::PointInStroke(const gfxPoint& pt)
-{
-  EnsurePath();
-  return mPath->StrokeContainsPoint(CurrentState().strokeOptions,
-                                    ToPoint(pt),
-                                    Matrix());
-}
-
 void
 gfxContext::RoundedRectangle(const gfxRect& rect,
                              const gfxCornerSizes& corners,
                              bool draw_clockwise)
 {
     //
     // For CW drawing, this looks like:
     //
--- a/gfx/thebes/gfxContext.h
+++ b/gfx/thebes/gfxContext.h
@@ -586,22 +586,16 @@ public:
      */
     void PushGroupAndCopyBackground(gfxContentType content = gfxContentType::COLOR);
     already_AddRefed<gfxPattern> PopGroup();
     void PopGroupToSource();
 
     mozilla::TemporaryRef<mozilla::gfx::SourceSurface>
     PopGroupToSurface(mozilla::gfx::Matrix* aMatrix);
 
-    /**
-     ** Hit Testing - check if given point is in the current path
-     **/
-    bool PointInFill(const gfxPoint& pt);
-    bool PointInStroke(const gfxPoint& pt);
-
     mozilla::gfx::Point GetDeviceOffset() const;
 
     /**
      ** Flags
      **/
 
     enum {
         /* If this flag is set, operators other than CLEAR, SOURCE, or
--- a/image/test/unit/xpcshell.ini
+++ b/image/test/unit/xpcshell.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 head =
 tail =
+skip-if = toolkit == 'gonk'
 support-files =
   async_load_tests.js
   bug413512.ico
   bug815359.ico
   image1.png
   image1png16x16.jpg
   image1png64x64.jpg
   image2.jpg
--- a/intl/locale/tests/unit/xpcshell.ini
+++ b/intl/locale/tests/unit/xpcshell.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 head = 
 tail = 
+skip-if = toolkit == 'gonk'
 
 [test_bug22310.js]
 run-if = toolkit == "windows" || toolkit == "cocoa"
 
 [test_bug371611.js]
 [test_bug374040.js]
 skip-if = toolkit == "windows" || toolkit == "cocoa"
 
--- a/intl/strres/tests/unit/xpcshell.ini
+++ b/intl/strres/tests/unit/xpcshell.ini
@@ -1,9 +1,10 @@
 [DEFAULT]
 head =
 tail =
+skip-if = toolkit == 'gonk'
 support-files =
   397093.properties
   strres.properties
 
 [test_bug378839.js]
 [test_bug397093.js]
--- a/intl/uconv/tests/unit/xpcshell.ini
+++ b/intl/uconv/tests/unit/xpcshell.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 head =
 tail =
+skip-if = toolkit == 'gonk'
 support-files =
   CharsetConversionTests.js
   hangulTestStrings.js
   data/unicode-conversion.utf16.txt
   data/unicode-conversion.utf16be.txt
   data/unicode-conversion.utf16le.txt
   data/unicode-conversion.utf8.txt
 
--- a/intl/unicharutil/tests/unit/xpcshell.ini
+++ b/intl/unicharutil/tests/unit/xpcshell.ini
@@ -1,5 +1,6 @@
 [DEFAULT]
 head = 
 tail = 
+skip-if = toolkit == 'gonk'
 
 [test_bug_427350_1.js]
--- a/ipc/chromium/src/chrome/common/ipc_message.h
+++ b/ipc/chromium/src/chrome/common/ipc_message.h
@@ -48,19 +48,19 @@ class Message : public Pickle {
     // Sends the given IPC message.  The implementor takes ownership of the
     // given Message regardless of whether or not this method succeeds.  This
     // is done to make this method easier to use.  Returns true on success and
     // false otherwise.
     virtual bool Send(Message* msg) = 0;
   };
 
   enum PriorityValue {
-    PRIORITY_LOW = 1,
-    PRIORITY_NORMAL,
-    PRIORITY_HIGH
+    PRIORITY_NORMAL = 1,
+    PRIORITY_HIGH = 2,
+    PRIORITY_URGENT = 3
   };
 
   enum MessageCompression {
     COMPRESSION_NONE,
     COMPRESSION_ENABLED
   };
 
   virtual ~Message();
@@ -80,36 +80,31 @@ class Message : public Pickle {
 
   Message(const Message& other);
   Message& operator=(const Message& other);
 
   PriorityValue priority() const {
     return static_cast<PriorityValue>(header()->flags & PRIORITY_MASK);
   }
 
+  void set_priority(int prio) {
+    DCHECK((prio & ~PRIORITY_MASK) == 0);
+    header()->flags = (header()->flags & ~PRIORITY_MASK) | prio;
+  }
+
   // True if this is a synchronous message.
   bool is_sync() const {
     return (header()->flags & SYNC_BIT) != 0;
   }
 
   // True if this is a synchronous message.
   bool is_interrupt() const {
     return (header()->flags & INTERRUPT_BIT) != 0;
   }
 
-  // True if this is an urgent message.
-  bool is_urgent() const {
-    return (header()->flags & URGENT_BIT) != 0;
-  }
-
-  // True if this is an RPC message.
-  bool is_rpc() const {
-    return (header()->flags & RPC_BIT) != 0;
-  }
-
   // True if compression is enabled for this message.
   bool compress() const {
     return (header()->flags & COMPRESS_BIT) != 0;
   }
 
   // Set this on a reply to a synchronous message.
   void set_reply() {
     header()->flags |= REPLY_BIT;
@@ -291,41 +286,31 @@ class Message : public Pickle {
   void set_sync() {
     header()->flags |= SYNC_BIT;
   }
 
   void set_interrupt() {
     header()->flags |= INTERRUPT_BIT;
   }
 
-  void set_urgent() {
-    header()->flags |= URGENT_BIT;
-  }
-
-  void set_rpc() {
-    header()->flags |= RPC_BIT;
-  }
-
 #if !defined(OS_MACOSX)
  protected:
 #endif
 
   // flags
   enum {
     PRIORITY_MASK   = 0x0003,
     SYNC_BIT        = 0x0004,
     REPLY_BIT       = 0x0008,
     REPLY_ERROR_BIT = 0x0010,
     UNBLOCK_BIT     = 0x0020,
     PUMPING_MSGS_BIT= 0x0040,
     HAS_SENT_TIME_BIT = 0x0080,
     INTERRUPT_BIT   = 0x0100,
     COMPRESS_BIT    = 0x0200,
-    URGENT_BIT      = 0x0400,
-    RPC_BIT         = 0x0800
   };
 
   struct Header : Pickle::Header {
     int32_t routing;  // ID of the view that this message is destined for
     msgid_t type;   // specifies the user-defined message type
     uint32_t flags;   // specifies control flags for the message
 #if defined(OS_POSIX)
     uint32_t num_fds; // the number of descriptors included with this message
--- a/ipc/glue/InputStreamParams.ipdlh
+++ b/ipc/glue/InputStreamParams.ipdlh
@@ -2,16 +2,19 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 include protocol PBlob;
 include protocol PFileDescriptorSet;
 
+using struct nsID
+  from "nsID.h";
+
 namespace mozilla {
 namespace ipc {
 
 struct StringInputStreamParams
 {
   nsCString data;
 };
 
@@ -34,17 +37,17 @@ struct MultiplexInputStreamParams
   InputStreamParams[] streams;
   uint32_t currentStream;
   nsresult status;
   bool startedReadingCurrent;
 };
 
 struct RemoteInputStreamParams
 {
-  PBlob remoteBlob;
+  nsID id;
 };
 
 // XXX This may only be used for same-process inter-thread communication! The
 //     value should be reinterpret_cast'd to nsIInputStream. It carries a
 //     reference.
 struct SameProcessInputStreamParams
 {
   intptr_t addRefedInputStream;
--- a/ipc/glue/InputStreamUtils.cpp
+++ b/ipc/glue/InputStreamUtils.cpp
@@ -102,27 +102,23 @@ DeserializeInputStream(const InputStream
 
     case InputStreamParams::TMultiplexInputStreamParams:
       serializable = do_CreateInstance(kMultiplexInputStreamCID);
       break;
 
     // When the input stream already exists in this process, all we need to do
     // is retrieve the original instead of sending any data over the wire.
     case InputStreamParams::TRemoteInputStreamParams: {
-      const RemoteInputStreamParams& params =
-          aParams.get_RemoteInputStreamParams();
+      if (NS_WARN_IF(XRE_GetProcessType() != GeckoProcessType_Default)) {
+        return nullptr;
+      }
 
-      nsRefPtr<DOMFileImpl> blobImpl;
-      if (params.remoteBlobParent()) {
-        blobImpl =
-          static_cast<BlobParent*>(params.remoteBlobParent())->GetBlobImpl();
-      } else {
-        blobImpl =
-          static_cast<BlobChild*>(params.remoteBlobChild())->GetBlobImpl();
-      }
+      const nsID& id = aParams.get_RemoteInputStreamParams().id();
+
+      nsRefPtr<DOMFileImpl> blobImpl = BlobParent::GetBlobImplForID(id);
 
       MOZ_ASSERT(blobImpl, "Invalid blob contents");
 
       // If fetching the internal stream fails, we ignore it and return a
       // null stream.
       nsCOMPtr<nsIInputStream> stream;
       nsresult rv = blobImpl->GetInternalStream(getter_AddRefs(stream));
       if (NS_FAILED(rv) || !stream) {
--- a/ipc/glue/MessageChannel.cpp
+++ b/ipc/glue/MessageChannel.cpp
@@ -15,16 +15,72 @@
 #include "nsISupportsImpl.h"
 #include "nsContentUtils.h"
 
 #include "prprf.h"
 
 // Undo the damage done by mozzconf.h
 #undef compress
 
+/*
+ * IPC design:
+ *
+ * There are three kinds of messages: async, sync, and intr. Sync and intr
+ * messages are blocking. Only intr and high-priority sync messages can nest.
+ *
+ * Terminology: To dispatch a message Foo is to run the RecvFoo code for
+ * it. This is also called "handling" the message.
+ *
+ * Sync messages have priorities while async and intr messages always have
+ * normal priority. The three possible priorities are normal, high, and urgent.
+ * The intended uses of these priorities are:
+ *   NORMAL - most messages.
+ *   HIGH   - CPOW-related messages, which can go in either direction.
+ *   URGENT - messages where we don't want to dispatch
+ *            incoming CPOWs while waiting for the response.
+ *
+ * To avoid jank, the parent process is not allowed to send sync messages of
+ * normal priority. The parent also is not allowed to send urgent messages at
+ * all.  When a process is waiting for a response to a sync message M0, it will
+ * dispatch an incoming message M if:
+ *   1. M has a higher priority than M0, or
+ *   2. if M has the same priority as M0 and we're in the child, or
+ *   3. if M has the same priority as M0 and it was sent by the other side
+        while dispatching M0 (nesting).
+ * The idea is that higher priority messages should take precendence, and we
+ * also want to allow nesting. The purpose of rule 2 is to handle a race where
+ * both processes send to each other simultaneously. In this case, we resolve
+ * the race in favor of the parent (so the child dispatches first).
+ *
+ * Sync messages satisfy the following properties:
+ *   A. When waiting for a response to a sync message, we won't dispatch any
+ *      messages of lower priority.
+ *   B. Sync messages of the same priority will be dispatched roughly in the
+ *      order they were sent. The exception is when the parent and child send
+ *      sync messages to each other simulataneously. In this case, the parent's
+ *      message is dispatched first. While it is dispatched, the child may send
+ *      further nested messages, and these messages may be dispatched before the
+ *      child's original message. We can consider ordering to be preserved here
+ *      because we pretend that the child's original message wasn't sent until
+ *      after the parent's message is finished being dispatched.
+ *
+ * Intr messages are blocking but not prioritized. While waiting for an intr
+ * response, all incoming messages are dispatched until a response is
+ * received. Intr messages also can be nested. When two intr messages race with
+ * each other, a similar scheme is used to ensure that one side wins. The
+ * winning side is chosen based on the message type.
+ *
+ * Intr messages differ from sync messages in that, while sending an intr
+ * message, we may dispatch an async message. This causes some additional
+ * complexity. One issue is that replies can be received out of order. It's also
+ * more difficult to determine whether one message is nested inside
+ * another. Consequently, intr handling uses mOutOfTurnReplies and
+ * mRemoteStackDepthGuess, which are not needed for sync messages.
+ */
+
 using namespace mozilla;
 using namespace std;
 
 using mozilla::MonitorAutoLock;
 using mozilla::MonitorAutoUnlock;
 
 template<>
 struct RunnableMethodTraits<mozilla::ipc::MessageChannel>
@@ -34,17 +90,17 @@ struct RunnableMethodTraits<mozilla::ipc
 };
 
 #define IPC_ASSERT(_cond, ...)                                      \
     do {                                                            \
         if (!(_cond))                                               \
             DebugAbort(__FILE__, __LINE__, #_cond,## __VA_ARGS__);  \
     } while (0)
 
-static uintptr_t gDispatchingUrgentMessageCount;
+static bool gParentIsBlocked;
 
 namespace mozilla {
 namespace ipc {
 
 const int32_t MessageChannel::kNoTimeout = INT32_MIN;
 
 // static
 bool MessageChannel::sIsPumpingMessages = false;
@@ -190,19 +246,19 @@ private:
     CxxStackFrame(const CxxStackFrame&) MOZ_DELETE;
     CxxStackFrame& operator=(const CxxStackFrame&) MOZ_DELETE;
 };
 
 namespace {
 
 class MOZ_STACK_CLASS MaybeScriptBlocker {
 public:
-    explicit MaybeScriptBlocker(MessageChannel *aChannel
+    explicit MaybeScriptBlocker(MessageChannel *aChannel, bool aBlock
                                 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-        : mBlocked(aChannel->ShouldBlockScripts())
+        : mBlocked(aChannel->ShouldBlockScripts() && aBlock)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
         if (mBlocked) {
             nsContentUtils::AddScriptBlocker();
         }
     }
     ~MaybeScriptBlocker() {
         if (mBlocked) {
@@ -222,22 +278,21 @@ MessageChannel::MessageChannel(MessageLi
     mSide(UnknownSide),
     mLink(nullptr),
     mWorkerLoop(nullptr),
     mChannelErrorTask(nullptr),
     mWorkerLoopID(-1),
     mTimeoutMs(kNoTimeout),
     mInTimeoutSecondHalf(false),
     mNextSeqno(0),
-    mPendingSyncReplies(0),
-    mPendingUrgentReplies(0),
-    mPendingRPCReplies(0),
-    mCurrentRPCTransaction(0),
+    mAwaitingSyncReply(false),
+    mAwaitingSyncReplyPriority(0),
     mDispatchingSyncMessage(false),
-    mDispatchingUrgentMessageCount(0),
+    mDispatchingSyncMessagePriority(0),
+    mCurrentTransaction(0),
     mRemoteStackDepthGuess(false),
     mSawInterruptOutMsg(false),
     mAbortOnError(false),
     mBlockScripts(false),
     mFlags(REQUIRE_DEFAULT),
     mPeerPidSet(false),
     mPeerPid(-1)
 {
@@ -322,18 +377,17 @@ MessageChannel::Clear()
 
     if (mChannelErrorTask) {
         mChannelErrorTask->Cancel();
         mChannelErrorTask = nullptr;
     }
 
     // Free up any memory used by pending messages.
     mPending.clear();
-    mPendingUrgentRequest = nullptr;
-    mPendingRPCCall = nullptr;
+    mRecvd = nullptr;
     mOutOfTurnReplies.clear();
     while (!mDeferred.empty()) {
         mDeferred.pop();
     }
 }
 
 bool
 MessageChannel::Open(Transport* aTransport, MessageLoop* aIOLoop, Side aSide)
@@ -483,118 +537,117 @@ MessageChannel::MaybeInterceptSpecialIOM
             printf("NOTE: %s process received `Goodbye', closing down\n",
                    (mSide == ChildSide) ? "child" : "parent");
         }
         return true;
     }
     return false;
 }
 
+bool
+MessageChannel::ShouldDeferMessage(const Message& aMsg)
+{
+    // Never defer messages that have the highest priority, even async
+    // ones. This is safe because only the child can send these messages, so
+    // they can never nest.
+    if (aMsg.priority() == IPC::Message::PRIORITY_URGENT) {
+        MOZ_ASSERT(mSide == ParentSide);
+        return false;
+    }
+
+    // Unless they're urgent, we always defer async messages.
+    if (!aMsg.is_sync()) {
+        MOZ_ASSERT(aMsg.priority() == IPC::Message::PRIORITY_NORMAL);
+        return true;
+    }
+
+    int msgPrio = aMsg.priority();
+    int waitingPrio = AwaitingSyncReplyPriority();
+
+    // Always defer if the priority of the incoming message is less than the
+    // priority of the message we're awaiting.
+    if (msgPrio < waitingPrio)
+        return true;
+
+    // Never defer if the message has strictly greater priority.
+    if (msgPrio > waitingPrio)
+        return false;
+
+    // When both sides send sync messages of the same priority, we resolve the
+    // race by dispatching in the child and deferring the incoming message in
+    // the parent. However, the parent still needs to dispatch nested sync
+    // messages.
+    //
+    // Deferring in the parent only sort of breaks message ordering. When the
+    // child's message comes in, we can pretend the child hasn't quite
+    // finished sending it yet. Since the message is sync, we know that the
+    // child hasn't moved on yet.
+    return mSide == ParentSide && aMsg.transaction_id() != mCurrentTransaction;
+}
+
 void
 MessageChannel::OnMessageReceivedFromLink(const Message& aMsg)
 {
     AssertLinkThread();
     mMonitor->AssertCurrentThreadOwns();
 
     if (MaybeInterceptSpecialIOMessage(aMsg))
         return;
 
-    // Regardless of the Interrupt stack, if we're awaiting a sync or urgent reply,
+    // Regardless of the Interrupt stack, if we're awaiting a sync reply,
     // we know that it needs to be immediately handled to unblock us.
-    if ((AwaitingSyncReply() && aMsg.is_sync()) ||
-        (AwaitingUrgentReply() && aMsg.is_urgent()) ||
-        (AwaitingRPCReply() && aMsg.is_rpc()))
-    {
+    if (AwaitingSyncReply() && aMsg.is_sync() && aMsg.is_reply()) {
+        MOZ_ASSERT(!mRecvd);
         mRecvd = new Message(aMsg);
         NotifyWorkerThread();
         return;
     }
 
-    // Urgent messages cannot be compressed.
-    MOZ_ASSERT(!aMsg.compress() || !aMsg.is_urgent());
+    // Prioritized messages cannot be compressed.
+    MOZ_ASSERT(!aMsg.compress() || aMsg.priority() == IPC::Message::PRIORITY_NORMAL);
 
     bool compress = (aMsg.compress() && !mPending.empty() &&
                      mPending.back().type() == aMsg.type() &&
                      mPending.back().routing_id() == aMsg.routing_id());
     if (compress) {
         // This message type has compression enabled, and the back of the
         // queue was the same message type and routed to the same destination.
         // Replace it with the newer message.
         MOZ_ASSERT(mPending.back().compress());
         mPending.pop_back();
     }
 
     bool shouldWakeUp = AwaitingInterruptReply() ||
-                        // Allow incoming RPCs to be processed inside an urgent message.
-                        (AwaitingUrgentReply() && aMsg.is_rpc()) ||
-                        // Always process urgent messages while blocked.
-                        ((AwaitingSyncReply() || AwaitingRPCReply()) && aMsg.is_urgent());
+                        (AwaitingSyncReply() && !ShouldDeferMessage(aMsg));
 
-    // There are four cases we're concerned about, relating to the state of the
+    // There are three cases we're concerned about, relating to the state of the
     // main thread:
     //
-    // (1) We are waiting on a sync|rpc reply - main thread is blocked on the
+    // (1) We are waiting on a sync reply - main thread is blocked on the
     //     IPC monitor.
     //   - If the message is high priority, we wake up the main thread to
-    //     deliver the message. Otherwise, we leave it in the mPending queue,
-    //     posting a task to the main event loop, where it will be processed
-    //     once the synchronous reply has been received.
+    //     deliver the message depending on ShouldDeferMessage. Otherwise, we
+    //     leave it in the mPending queue, posting a task to the main event
+    //     loop, where it will be processed once the synchronous reply has been
+    //     received.
     //
     // (2) We are waiting on an Interrupt reply - main thread is blocked on the
     //     IPC monitor.
     //   - Always notify and wake up the main thread.
     //
     // (3) We are not waiting on a reply.
     //   - We post a task to the main event loop.
     //
     // Note that, we may notify the main thread even though the monitor is not
     // blocked. This is okay, since we always check for pending events before
     // blocking again.
 
-    if (shouldWakeUp && (AwaitingUrgentReply() && aMsg.is_rpc())) {
-        // If we're receiving an RPC message while blocked on an urgent message,
-        // we must defer any messages that were not sent as part of the child
-        // answering the urgent message.
-        //
-        // We must also be sure that we will not accidentally defer any RPC
-        // message that was sent while answering an urgent message. Otherwise,
-        // we will deadlock.
-        //
-        // On the parent side, the current transaction can only transition from 0
-        // to an ID, either by us issuing an urgent request while not blocked, or
-        // by receiving an RPC request while not blocked. When we unblock, the
-        // current transaction is reset to 0.
-        //
-        // When the child side receives an urgent message, any RPC messages sent
-        // before issuing the urgent reply will carry the urgent message's
-        // transaction ID.
-        //
-        // Since AwaitingUrgentReply() implies we are blocked, it also implies
-        // that we are within a transaction that will not change until we are
-        // completely unblocked (i.e, the transaction has completed).
-        if (aMsg.transaction_id() != mCurrentRPCTransaction)
-            shouldWakeUp = false;
-    }
-
-    if (aMsg.is_urgent()) {
-        MOZ_ASSERT(!mPendingUrgentRequest);
-        mPendingUrgentRequest = new Message(aMsg);
-    } else if (aMsg.is_rpc() && shouldWakeUp) {
-        // Only use this slot if we need to wake up for an RPC call. Otherwise
-        // we treat it like a normal async or sync message.
-        MOZ_ASSERT(!mPendingRPCCall);
-        mPendingRPCCall = new Message(aMsg);
-    } else {
-        mPending.push_back(aMsg);
-    }
+    mPending.push_back(aMsg);
 
     if (shouldWakeUp) {
-        // Always wake up Interrupt waiters, sync waiters for urgent messages,
-        // RPC waiters for urgent messages, and urgent waiters for RPCs in the
-        // same transaction.
         NotifyWorkerThread();
     } else {
         // Worker thread is either not blocked on a reply, or this is an
         // incoming Interrupt that raced with outgoing sync, and needs to be
         // deferred to a later event-loop iteration.
         if (!compress) {
             // If we compressed away the previous message, we'll re-use
             // its pending task.
@@ -602,103 +655,64 @@ MessageChannel::OnMessageReceivedFromLin
         }
     }
 }
 
 bool
 MessageChannel::Send(Message* aMsg, Message* aReply)
 {
     // See comment in DispatchUrgentMessage.
-    MaybeScriptBlocker scriptBlocker(this);
+    MaybeScriptBlocker scriptBlocker(this, true);
 
     // Sanity checks.
     AssertWorkerThread();
     mMonitor->AssertNotCurrentThreadOwns();
 
 #ifdef OS_WIN
     SyncStackFrame frame(this, false);
 #endif
 
     CxxStackFrame f(*this, OUT_MESSAGE, aMsg);
 
     MonitorAutoLock lock(*mMonitor);
 
     IPC_ASSERT(aMsg->is_sync(), "can only Send() sync messages here");
-    IPC_ASSERT(!DispatchingSyncMessage(), "violation of sync handler invariant");
-    IPC_ASSERT(!DispatchingUrgentMessage(), "sync messages forbidden while handling urgent message");
-    IPC_ASSERT(!AwaitingSyncReply(), "nested sync messages are not supported");
+    IPC_ASSERT(aMsg->priority() >= DispatchingSyncMessagePriority(),
+               "can't send sync message of a lesser priority than what's being dispatched");
+    IPC_ASSERT(mAwaitingSyncReplyPriority <= aMsg->priority(),
+               "nested sync message sends must be of increasing priority");
 
-    AutoEnterPendingReply replies(mPendingSyncReplies);
+    AutoSetValue<bool> replies(mAwaitingSyncReply, true);
+    AutoSetValue<int> prio(mAwaitingSyncReplyPriority, aMsg->priority());
+    AutoEnterTransaction transact(this);
+    aMsg->set_transaction_id(mCurrentTransaction);
+
     if (!SendAndWait(aMsg, aReply))
         return false;
 
     NS_ABORT_IF_FALSE(aReply->is_sync(), "reply is not sync");
     return true;
 }
 
-bool
-MessageChannel::UrgentCall(Message* aMsg, Message* aReply)
+struct AutoDeferMessages
 {
-    // See comment in DispatchUrgentMessage.
-    MaybeScriptBlocker scriptBlocker(this);
-
-    AssertWorkerThread();
-    mMonitor->AssertNotCurrentThreadOwns();
-    IPC_ASSERT(mSide == ParentSide, "cannot send urgent requests from child");
-
-#ifdef OS_WIN
-    SyncStackFrame frame(this, false);
-#endif
+    typedef IPC::Message Message;
 
-    CxxStackFrame f(*this, OUT_MESSAGE, aMsg);
-
-    MonitorAutoLock lock(*mMonitor);
-
-    IPC_ASSERT(!AwaitingInterruptReply(), "urgent calls cannot be issued within Interrupt calls");
-    IPC_ASSERT(!AwaitingSyncReply(), "urgent calls cannot be issued within sync sends");
-
-    AutoEnterRPCTransaction transact(this);
-    aMsg->set_transaction_id(mCurrentRPCTransaction);
-
-    AutoEnterPendingReply replies(mPendingUrgentReplies);
-    if (!SendAndWait(aMsg, aReply))
-        return false;
+    std::deque<Message>& mQueue;
+    mozilla::Vector<Message> mDeferred;
 
-    NS_ABORT_IF_FALSE(aReply->is_urgent(), "reply is not urgent");
-    return true;
-}
-
-bool
-MessageChannel::RPCCall(Message* aMsg, Message* aReply)
-{
-    // See comment in DispatchUrgentMessage.
-    MaybeScriptBlocker scriptBlocker(this);
-
-    AssertWorkerThread();
-    mMonitor->AssertNotCurrentThreadOwns();
-    IPC_ASSERT(mSide == ChildSide, "cannot send rpc messages from parent");
+    AutoDeferMessages(std::deque<Message>& queue) : mQueue(queue) {}
+    ~AutoDeferMessages() {
+        mQueue.insert(mQueue.begin(), mDeferred.begin(), mDeferred.end());
+    }
 
-#ifdef OS_WIN
-    SyncStackFrame frame(this, false);
-#endif
-
-    CxxStackFrame f(*this, OUT_MESSAGE, aMsg);
-
-    MonitorAutoLock lock(*mMonitor);
-
-    AutoEnterRPCTransaction transact(this);
-    aMsg->set_transaction_id(mCurrentRPCTransaction);
-
-    AutoEnterPendingReply replies(mPendingRPCReplies);
-    if (!SendAndWait(aMsg, aReply))
-        return false;
-
-    NS_ABORT_IF_FALSE(aReply->is_rpc(), "expected rpc reply");
-    return true;
-}
+    void Defer(Message aMsg) {
+        mDeferred.append(aMsg);
+    }
+};
 
 bool
 MessageChannel::SendAndWait(Message* aMsg, Message* aReply)
 {
     mMonitor->AssertCurrentThreadOwns();
 
     nsAutoPtr<Message> msg(aMsg);
 
@@ -709,80 +723,62 @@ MessageChannel::SendAndWait(Message* aMs
 
     msg->set_seqno(NextSeqno());
 
     DebugOnly<int32_t> replySeqno = msg->seqno();
     DebugOnly<msgid_t> replyType = msg->type() + 1;
 
     mLink->SendMessage(msg.forget());
 
-    while (true) {
-        // Wait for an event to occur.
-        while (true) {
-            if (mRecvd || mPendingUrgentRequest || mPendingRPCCall)
-                break;
-
-            bool maybeTimedOut = !WaitForSyncNotify();
+    AutoDeferMessages defer(mPending);
 
-            if (!Connected()) {
-                ReportConnectionError("MessageChannel::SendAndWait");
-                return false;
-            }
-
-            if (maybeTimedOut && !ShouldContinueFromTimeout())
-                return false;
+    while (true) {
+        while (!mPending.empty()) {
+            Message msg = mPending.front();
+            mPending.pop_front();
+            if (ShouldDeferMessage(msg))
+                defer.Defer(msg);
+            else
+                ProcessPendingRequest(msg);
         }
 
-        // We need to make sure that all messages deposited in mPendingRPCCall
-        // and mPendingUrgentRequest are dispatched before we leave this
-        // function. Otherwise, there's nothing to wake us up and force us to
-        // dispatch them.
-        while (mPendingUrgentRequest) {
-            if (!ProcessPendingUrgentRequest())
-                return false;
-        }
-
-        while (mPendingRPCCall) {
-            if (!ProcessPendingRPCCall())
-                return false;
-        }
-
+        // See if we've received a reply.
         if (mRecvd) {
-            NS_ABORT_IF_FALSE(mRecvd->is_reply(), "expected reply");
+            MOZ_ASSERT(mRecvd->is_reply(), "expected reply");
 
             if (mRecvd->is_reply_error()) {
                 mRecvd = nullptr;
                 return false;
             }
 
-            NS_ABORT_IF_FALSE(mRecvd->type() == replyType, "wrong reply type");
-            NS_ABORT_IF_FALSE(mRecvd->seqno() == replySeqno, "wrong sequence number");
+            MOZ_ASSERT(mRecvd->type() == replyType, "wrong reply type");
+            MOZ_ASSERT(mRecvd->seqno() == replySeqno);
 
             *aReply = *mRecvd;
             mRecvd = nullptr;
             return true;
         }
+
+        bool maybeTimedOut = !WaitForSyncNotify();
+
+        if (!Connected()) {
+            ReportConnectionError("MessageChannel::SendAndWait");
+            return false;
+        }
+
+        if (maybeTimedOut && !ShouldContinueFromTimeout())
+            return false;
     }
 
     return true;
 }
 
 bool
 MessageChannel::Call(Message* aMsg, Message* aReply)
 {
-    if (aMsg->is_urgent())
-        return UrgentCall(aMsg, aReply);
-    if (aMsg->is_rpc())
-        return RPCCall(aMsg, aReply);
-    return InterruptCall(aMsg, aReply);
-}
-
-bool
-MessageChannel::InterruptCall(Message* aMsg, Message* aReply)
-{
     AssertWorkerThread();
     mMonitor->AssertNotCurrentThreadOwns();
 
 #ifdef OS_WIN
     SyncStackFrame frame(this, true);
 #endif
 
     // This must come before MonitorAutoLock, as its destructor acquires the
@@ -791,39 +787,38 @@ MessageChannel::InterruptCall(Message* a
 
     MonitorAutoLock lock(*mMonitor);
     if (!Connected()) {
         ReportConnectionError("MessageChannel::Call");
         return false;
     }
 
     // Sanity checks.
-    IPC_ASSERT(!AwaitingSyncReply() && !AwaitingUrgentReply(),
-               "cannot issue Interrupt call whiel blocked on sync or urgent");
-    IPC_ASSERT(!DispatchingSyncMessage() || aMsg->priority() == IPC::Message::PRIORITY_HIGH,
+    IPC_ASSERT(!AwaitingSyncReply(),
+               "cannot issue Interrupt call while blocked on sync request");
+    IPC_ASSERT(!DispatchingSyncMessage(),
                "violation of sync handler invariant");
     IPC_ASSERT(aMsg->is_interrupt(), "can only Call() Interrupt messages here");
 
-
     nsAutoPtr<Message> msg(aMsg);
 
     msg->set_seqno(NextSeqno());
     msg->set_interrupt_remote_stack_depth_guess(mRemoteStackDepthGuess);
     msg->set_interrupt_local_stack_depth(1 + InterruptStackDepth());
     mInterruptStack.push(*msg);
     mLink->SendMessage(msg.forget());
 
     while (true) {
         // if a handler invoked by *Dispatch*() spun a nested event
         // loop, and the connection was broken during that loop, we
         // might have already processed the OnError event. if so,
         // trying another loop iteration will be futile because
         // channel state will have been cleared
         if (!Connected()) {
-            ReportConnectionError("MessageChannel::InterruptCall");
+            ReportConnectionError("MessageChannel::Call");
             return false;
         }
 
         // Now might be the time to process a message deferred because of race
         // resolution.
         MaybeUndeferIncall();
 
         // Wait for an event to occur.
@@ -840,24 +835,18 @@ MessageChannel::InterruptCall(Message* a
 
             if (maybeTimedOut && !ShouldContinueFromTimeout())
                 return false;
         }
 
         Message recvd;
         MessageMap::iterator it;
 
-        if (mPendingUrgentRequest) {
-            recvd = *mPendingUrgentRequest;
-            mPendingUrgentRequest = nullptr;
-        } else if (mPendingRPCCall) {
-            recvd = *mPendingRPCCall;
-            mPendingRPCCall = nullptr;
-        } else if ((it = mOutOfTurnReplies.find(mInterruptStack.top().seqno()))
-                    != mOutOfTurnReplies.end())
+        if ((it = mOutOfTurnReplies.find(mInterruptStack.top().seqno()))
+            != mOutOfTurnReplies.end())
         {
             recvd = it->second;
             mOutOfTurnReplies.erase(it);
         } else if (!mPending.empty()) {
             recvd = mPending.front();
             mPending.pop_front();
         } else {
             // because of subtleties with nested event loops, it's possible
@@ -865,21 +854,18 @@ MessageChannel::InterruptCall(Message* a
             // deferred in-call that needs to be processed.  either way, we
             // won't break the inner while loop again until something new
             // happens.
             continue;
         }
 
         // If the message is not Interrupt, we can dispatch it as normal.
         if (!recvd.is_interrupt()) {
-            // Other side should be blocked.
-            IPC_ASSERT(!recvd.is_sync() || mPending.empty(), "other side should be blocked");
-
             {
-                AutoEnterRPCTransaction transaction(this, &recvd);
+                AutoEnterTransaction transaction(this, &recvd);
                 MonitorAutoUnlock unlock(*mMonitor);
                 CxxStackFrame frame(*this, IN_MESSAGE, &recvd);
                 DispatchMessage(recvd);
             }
             if (!Connected()) {
                 ReportConnectionError("MessageChannel::DispatchMessage");
                 return false;
             }
@@ -950,90 +936,47 @@ bool
 MessageChannel::InterruptEventOccurred()
 {
     AssertWorkerThread();
     mMonitor->AssertCurrentThreadOwns();
     IPC_ASSERT(InterruptStackDepth() > 0, "not in wait loop");
 
     return (!Connected() ||
             !mPending.empty() ||
-            mPendingUrgentRequest ||
-            mPendingRPCCall ||
             (!mOutOfTurnReplies.empty() &&
              mOutOfTurnReplies.find(mInterruptStack.top().seqno()) !=
              mOutOfTurnReplies.end()));
 }
 
 bool
-MessageChannel::ProcessPendingUrgentRequest()
+MessageChannel::ProcessPendingRequest(Message aUrgent)
 {
     AssertWorkerThread();
     mMonitor->AssertCurrentThreadOwns();
 
     // Note that it is possible we could have sent a sync message at
     // the same time the parent process sent an urgent message, and
     // therefore mPendingUrgentRequest is set *and* mRecvd is set as
     // well, because the link thread received both before the worker
     // thread woke up.
     //
     // In this case, we process the urgent message first, but we need
     // to save the reply.
     nsAutoPtr<Message> savedReply(mRecvd.forget());
 
-    // We're the child process. We should not be receiving RPC calls.
-    IPC_ASSERT(!mPendingRPCCall, "unexpected RPC call");
-
-    nsAutoPtr<Message> recvd(mPendingUrgentRequest.forget());
     {
         // In order to send the parent RPC messages and guarantee it will
         // wake up, we must re-use its transaction.
-        AutoEnterRPCTransaction transaction(this, recvd);
+        AutoEnterTransaction transaction(this, &aUrgent);
 
         MonitorAutoUnlock unlock(*mMonitor);
-        DispatchUrgentMessage(*recvd);
+        DispatchMessage(aUrgent);
     }
     if (!Connected()) {
-        ReportConnectionError("MessageChannel::DispatchUrgentMessage");
-        return false;
-    }
-
-    // In between having dispatched our reply to the parent process, and
-    // re-acquiring the monitor, the parent process could have already
-    // processed that reply and sent the reply to our sync message. If so,
-    // our saved reply should be empty.
-    IPC_ASSERT(!mRecvd || !savedReply, "unknown reply");
-    if (!mRecvd)
-        mRecvd = savedReply.forget();
-    return true;
-}
-
-bool
-MessageChannel::ProcessPendingRPCCall()
-{
-    AssertWorkerThread();
-    mMonitor->AssertCurrentThreadOwns();
-
-    // See comment above re: mRecvd replies and incoming calls.
-    nsAutoPtr<Message> savedReply(mRecvd.forget());
-
-    IPC_ASSERT(!mPendingUrgentRequest, "unexpected urgent message");
-
-    nsAutoPtr<Message> recvd(mPendingRPCCall.forget());
-    {
-        // If we are not currently in a transaction, this will begin one,
-        // and the link thread will not wake us up for any RPC messages not
-        // apart of this transaction. If we are already in a transaction,
-        // then this will assert that we're still in the same transaction.
-        AutoEnterRPCTransaction transaction(this, recvd);
-
-        MonitorAutoUnlock unlock(*mMonitor);
-        DispatchRPCMessage(*recvd);
-    }
-    if (!Connected()) {
-        ReportConnectionError("MessageChannel::DispatchRPCMessage");
+        ReportConnectionError("MessageChannel::ProcessPendingRequest");
         return false;
     }
 
     // In between having dispatched our reply to the parent process, and
     // re-acquiring the monitor, the parent process could have already
     // processed that reply and sent the reply to our sync message. If so,
     // our saved reply should be empty.
     IPC_ASSERT(!mRecvd || !savedReply, "unknown reply");
@@ -1048,28 +991,16 @@ MessageChannel::DequeueOne(Message *recv
     AssertWorkerThread();
     mMonitor->AssertCurrentThreadOwns();
 
     if (!Connected()) {
         ReportConnectionError("OnMaybeDequeueOne");
         return false;
     }
 
-    if (mPendingUrgentRequest) {
-        *recvd = *mPendingUrgentRequest;
-        mPendingUrgentRequest = nullptr;
-        return true;
-    }
-
-    if (mPendingRPCCall) {
-        *recvd = *mPendingRPCCall;
-        mPendingRPCCall = nullptr;
-        return true;
-    }
-
     if (!mDeferred.empty())
         MaybeUndeferIncall();
 
     if (mPending.empty())
         return false;
 
     *recvd = mPending.front();
     mPending.pop_front();
@@ -1092,152 +1023,90 @@ MessageChannel::OnMaybeDequeueOne()
         // We probably just received a reply in a nested loop for an
         // Interrupt call sent before entering that loop.
         mOutOfTurnReplies[recvd.seqno()] = recvd;
         return false;
     }
 
     {
         // We should not be in a transaction yet if we're not blocked.
-        MOZ_ASSERT(mCurrentRPCTransaction == 0);
-        AutoEnterRPCTransaction transaction(this, &recvd);
+        MOZ_ASSERT(mCurrentTransaction == 0);
+        AutoEnterTransaction transaction(this, &recvd);
 
         MonitorAutoUnlock unlock(*mMonitor);
 
         CxxStackFrame frame(*this, IN_MESSAGE, &recvd);
         DispatchMessage(recvd);
     }
     return true;
 }
 
 void
 MessageChannel::DispatchMessage(const Message &aMsg)
 {
     if (aMsg.is_sync())
         DispatchSyncMessage(aMsg);
-    else if (aMsg.is_urgent())
-        DispatchUrgentMessage(aMsg);
     else if (aMsg.is_interrupt())
         DispatchInterruptMessage(aMsg, 0);
-    else if (aMsg.is_rpc())
-        DispatchRPCMessage(aMsg);
     else
         DispatchAsyncMessage(aMsg);
 }
 
 void
 MessageChannel::DispatchSyncMessage(const Message& aMsg)
 {
     AssertWorkerThread();
 
     Message *reply = nullptr;
 
-    mDispatchingSyncMessage = true;
-    Result rv = mListener->OnMessageReceived(aMsg, reply);
-    mDispatchingSyncMessage = false;
+    int prio = aMsg.priority();
+
+    // We don't want to run any code that might run a nested event loop here, so
+    // we avoid running event handlers. Once we've sent the response to the
+    // urgent message, it's okay to run event handlers again since the parent is
+    // no longer blocked.
+    MOZ_ASSERT_IF(prio > IPC::Message::PRIORITY_NORMAL, NS_IsMainThread());
+    MaybeScriptBlocker scriptBlocker(this, prio > IPC::Message::PRIORITY_NORMAL);
+
+    IPC_ASSERT(prio >= mDispatchingSyncMessagePriority,
+               "priority inversion while dispatching sync message");
+    IPC_ASSERT(prio >= mAwaitingSyncReplyPriority,
+               "dispatching a message of lower priority while waiting for a response");
+
+    bool dummy;
+    bool& blockingVar = ShouldBlockScripts() ? gParentIsBlocked : dummy;
+
+    Result rv;
+    {
+        AutoSetValue<bool> blocked(blockingVar, true);
+        AutoSetValue<bool> sync(mDispatchingSyncMessage, true);
+        AutoSetValue<int> prioSet(mDispatchingSyncMessagePriority, prio);
+        rv = mListener->OnMessageReceived(aMsg, reply);
+    }
 
     if (!MaybeHandleError(rv, aMsg, "DispatchSyncMessage")) {
         delete reply;
         reply = new Message();
         reply->set_sync();
+        reply->set_priority(aMsg.priority());
         reply->set_reply();
         reply->set_reply_error();
     }
     reply->set_seqno(aMsg.seqno());
 
     MonitorAutoLock lock(*mMonitor);
     if (ChannelConnected == mChannelState)
         mLink->SendMessage(reply);
 }
 
 void
-MessageChannel::DispatchUrgentMessage(const Message& aMsg)
-{
-    AssertWorkerThread();
-    MOZ_ASSERT(aMsg.is_urgent());
-
-    Message *reply = nullptr;
-
-    MOZ_ASSERT(NS_IsMainThread());
-
-    // We don't want to run any code that might run a nested event loop here, so
-    // we avoid running event handlers. Once we've sent the response to the
-    // urgent message, it's okay to run event handlers again since the parent is
-    // no longer blocked.
-    //
-    // We also put script blockers at the start of every synchronous send
-    // call. That way we won't run any scripts while waiting for a response to
-    // another message. Running scripts could cause us to send more sync
-    // messages, and the other side wouldn't know what to do if it received a
-    // sync message while dispatching another sync message. (In practice, the
-    // other side would queue the second sync message, while we would need it to
-    // dispatch that message before sending the reply to the original sync
-    // message. Otherwise the replies would come out of order.)
-    //
-    // We omit the script blocker for InterruptCall since interrupt messages are
-    // designed to handle this sort of re-entry. (For example, if the child
-    // sends an intr message to the parent, the child will process any queued
-    // async messages from the parent while waiting for the intr response. In
-    // doing so, the child could trigger sync messages to be sent to the parent
-    // while the parent is still dispatching the intr message. If the parent
-    // sends an intr reply while the child is waiting for a sync response, the
-    // intr reply will be queued in mPending. Once the sync reply is received,
-    // InterruptCall will find the intr reply in mPending and run it.)  The
-    // situation where we run event handlers while waiting for an intr reply is
-    // no different than the one where we process async messages while waiting
-    // for an intr reply.
-    MaybeScriptBlocker scriptBlocker(this);
-
-    gDispatchingUrgentMessageCount++;
-    mDispatchingUrgentMessageCount++;
-    Result rv = mListener->OnCallReceived(aMsg, reply);
-    mDispatchingUrgentMessageCount--;
-    gDispatchingUrgentMessageCount--;
-
-    if (!MaybeHandleError(rv, aMsg, "DispatchUrgentMessage")) {
-        delete reply;
-        reply = new Message();
-        reply->set_urgent();
-        reply->set_reply();
-        reply->set_reply_error();
-    }
-    reply->set_seqno(aMsg.seqno());
-
-    MonitorAutoLock lock(*mMonitor);
-    if (ChannelConnected == mChannelState)
-        mLink->SendMessage(reply);
-}
-
-void
-MessageChannel::DispatchRPCMessage(const Message& aMsg)
-{
-    AssertWorkerThread();
-    MOZ_ASSERT(aMsg.is_rpc());
-
-    Message *reply = nullptr;
-
-    if (!MaybeHandleError(mListener->OnCallReceived(aMsg, reply), aMsg, "DispatchRPCMessage")) {
-        delete reply;
-        reply = new Message();
-        reply->set_rpc();
-        reply->set_reply();
-        reply->set_reply_error();
-    }
-    reply->set_seqno(aMsg.seqno());
-    
-    MonitorAutoLock lock(*mMonitor);
-    if (ChannelConnected == mChannelState)
-        mLink->SendMessage(reply);
-}
-
-void
 MessageChannel::DispatchAsyncMessage(const Message& aMsg)
 {
     AssertWorkerThread();
-    MOZ_ASSERT(!aMsg.is_interrupt() && !aMsg.is_sync() && !aMsg.is_urgent());
+    MOZ_ASSERT(!aMsg.is_interrupt() && !aMsg.is_sync());
 
     if (aMsg.routing_id() == MSG_ROUTING_NONE) {
         NS_RUNTIMEABORT("unhandled special message!");
     }
 
     MaybeHandleError(mListener->OnMessageReceived(aMsg), aMsg, "DispatchAsyncMessage");
 }
 
@@ -1341,16 +1210,17 @@ MessageChannel::MaybeUndeferIncall()
     // maybe time to process this message
     Message call = mDeferred.top();
     mDeferred.pop();
 
     // fix up fudge factor we added to account for race
     IPC_ASSERT(0 < mRemoteStackDepthGuess, "fatal logic error");
     --mRemoteStackDepthGuess;
 
+    MOZ_ASSERT(call.priority() == IPC::Message::PRIORITY_NORMAL);
     mPending.push_back(call);
 }
 
 void
 MessageChannel::FlushPendingInterruptQueue()
 {
     AssertWorkerThread();
     mMonitor->AssertNotCurrentThreadOwns();
@@ -1613,17 +1483,17 @@ void
 MessageChannel::OnChannelErrorFromLink()
 {
     AssertLinkThread();
     mMonitor->AssertCurrentThreadOwns();
 
     if (InterruptStackDepth() > 0)
         NotifyWorkerThread();
 
-    if (AwaitingSyncReply() || AwaitingRPCReply() || AwaitingUrgentReply())
+    if (AwaitingSyncReply())
         NotifyWorkerThread();
 
     if (ChannelClosing != mChannelState) {
         if (mAbortOnError) {
             NS_RUNTIMEABORT("Aborting on channel error.");
         }
         mChannelState = ChannelError;
         mMonitor->Notify();
@@ -1851,15 +1721,15 @@ MessageChannel::DumpInterruptStack(const
         mCxxStackFrames[i].Describe(&id, &dir, &sems, &name);
 
         printf_stderr("%s[(%u) %s %s %s(actor=%d) ]\n", pfx,
                       i, dir, sems, name, id);
     }
 }
 
 bool
-ProcessingUrgentMessages()
+ParentProcessIsBlocked()
 {
-    return gDispatchingUrgentMessageCount > 0;
+    return gParentIsBlocked;
 }
 
 } // ipc
 } // mozilla
--- a/ipc/glue/MessageChannel.h
+++ b/ipc/glue/MessageChannel.h
@@ -221,24 +221,19 @@ class MessageChannel : HasResultCodes
     // SendAndWait() expects that the worker thread owns the monitor, and that
     // the message has been prepared to be sent over the link. It returns as
     // soon as a reply has been received, or an error has occurred.
     //
     // Note that while the child is blocked waiting for a sync reply, it can wake
     // up to process urgent calls from the parent.
     bool SendAndWait(Message* aMsg, Message* aReply);
 
-    bool RPCCall(Message* aMsg, Message* aReply);
-    bool InterruptCall(Message* aMsg, Message* aReply);
-    bool UrgentCall(Message* aMsg, Message* aReply);
-
     bool InterruptEventOccurred();
 
-    bool ProcessPendingUrgentRequest();
-    bool ProcessPendingRPCCall();
+    bool ProcessPendingRequest(Message aUrgent);
 
     void MaybeUndeferIncall();
     void EnqueuePendingMessages();
 
     // Executed on the worker thread. Dequeues one pending message.
     bool OnMaybeDequeueOne();
     bool DequeueOne(Message *recvd);
 
@@ -322,39 +317,36 @@ class MessageChannel : HasResultCodes
     size_t InterruptStackDepth() const {
         mMonitor->AssertCurrentThreadOwns();
         return mInterruptStack.size();
     }
 
     // Returns true if we're blocking waiting for a reply.
     bool AwaitingSyncReply() const {
         mMonitor->AssertCurrentThreadOwns();
-        return mPendingSyncReplies > 0;
+        return mAwaitingSyncReply;
     }
-    bool AwaitingUrgentReply() const {
+    int AwaitingSyncReplyPriority() const {
         mMonitor->AssertCurrentThreadOwns();
-        return mPendingUrgentReplies > 0;
-    }
-    bool AwaitingRPCReply() const {
-        mMonitor->AssertCurrentThreadOwns();
-        return mPendingRPCReplies > 0;
+        return mAwaitingSyncReplyPriority;
     }
     bool AwaitingInterruptReply() const {
         mMonitor->AssertCurrentThreadOwns();
         return !mInterruptStack.empty();
     }
 
     // Returns true if we're dispatching a sync message's callback.
     bool DispatchingSyncMessage() const {
+        AssertWorkerThread();
         return mDispatchingSyncMessage;
     }
 
-    // Returns true if we're dispatching an urgent message's callback.
-    bool DispatchingUrgentMessage() const {
-        return mDispatchingUrgentMessageCount > 0;
+    int DispatchingSyncMessagePriority() const {
+        AssertWorkerThread();
+        return mDispatchingSyncMessagePriority;
     }
 
     bool Connected() const;
 
   private:
     // Executed on the IO thread.
     void NotifyWorkerThread();
 
@@ -362,16 +354,17 @@ class MessageChannel : HasResultCodes
     // thread, in which case it shouldn't be delivered to the worker.
     bool MaybeInterceptSpecialIOMessage(const Message& aMsg);
 
     void OnChannelConnected(int32_t peer_id);
 
     // Tell the IO thread to close the channel and wait for it to ACK.
     void SynchronouslyClose();
 
+    bool ShouldDeferMessage(const Message& aMsg);
     void OnMessageReceivedFromLink(const Message& aMsg);
     void OnChannelErrorFromLink();
 
   private:
     // Run on the not current thread.
     void NotifyChannelClosed();
     void NotifyMaybeChannelError();
 
@@ -455,105 +448,100 @@ class MessageChannel : HasResultCodes
     bool mInTimeoutSecondHalf;
 
     // Worker-thread only; sequence numbers for messages that require
     // synchronous replies.
     int32_t mNextSeqno;
 
     static bool sIsPumpingMessages;
 
-    class AutoEnterPendingReply {
+    template<class T>
+    class AutoSetValue {
       public:
-        explicit AutoEnterPendingReply(size_t &replyVar)
-          : mReplyVar(replyVar)
+        explicit AutoSetValue(T &var, const T &newValue)
+          : mVar(var), mPrev(var)
         {
-            mReplyVar++;
+            mVar = newValue;
         }
-        ~AutoEnterPendingReply() {
-            mReplyVar--;
+        ~AutoSetValue() {
+            mVar = mPrev;
         }
       private:
-        size_t& mReplyVar;
+        T& mVar;
+        T mPrev;
     };
 
-    // Worker-thread only; type we're expecting for the reply to a sync
-    // out-message. This will never be greater than 1.
-    size_t mPendingSyncReplies;
+    // Worker thread only.
+    bool mAwaitingSyncReply;
+    int mAwaitingSyncReplyPriority;
 
-    // Worker-thread only; Number of urgent and rpc replies we're waiting on.
-    // These are mutually exclusive since one channel cannot have outcalls of
-    // both kinds.
-    size_t mPendingUrgentReplies;
-    size_t mPendingRPCReplies;
+    // Set while we are dispatching a synchronous message. Only for use on the
+    // worker thread.
+    bool mDispatchingSyncMessage;
+    int mDispatchingSyncMessagePriority;
 
     // When we send an urgent request from the parent process, we could race
     // with an RPC message that was issued by the child beforehand. In this
     // case, if the parent were to wake up while waiting for the urgent reply,
     // and process the RPC, it could send an additional urgent message. The
     // child would wake up to process the urgent message (as it always will),
     // then send a reply, which could be received by the parent out-of-order
     // with respect to the first urgent reply.
     //
     // To address this problem, urgent or RPC requests are associated with a
     // "transaction". Whenever one side of the channel wishes to start a
     // chain of RPC/urgent messages, it allocates a new transaction ID. Any
     // messages the parent receives, not apart of this transaction, are
     // deferred. When issuing RPC/urgent requests on top of a started
     // transaction, the initiating transaction ID is used.
-    // 
+    //
     // To ensure IDs are unique, we use sequence numbers for transaction IDs,
     // which grow in opposite directions from child to parent.
 
     // The current transaction ID.
-    int32_t mCurrentRPCTransaction;
+    int32_t mCurrentTransaction;
 
-    class AutoEnterRPCTransaction
+    class AutoEnterTransaction
     {
       public:
-       explicit AutoEnterRPCTransaction(MessageChannel *aChan)
+       explicit AutoEnterTransaction(MessageChannel *aChan)
         : mChan(aChan),
-          mOldTransaction(mChan->mCurrentRPCTransaction)
+          mOldTransaction(mChan->mCurrentTransaction)
        {
            mChan->mMonitor->AssertCurrentThreadOwns();
-           if (mChan->mCurrentRPCTransaction == 0)
-               mChan->mCurrentRPCTransaction = mChan->NextSeqno();
+           if (mChan->mCurrentTransaction == 0)
+               mChan->mCurrentTransaction = mChan->NextSeqno();
        }
-       AutoEnterRPCTransaction(MessageChannel *aChan, Message *message)
+       explicit AutoEnterTransaction(MessageChannel *aChan, Message *message)
         : mChan(aChan),
-          mOldTransaction(mChan->mCurrentRPCTransaction)
+          mOldTransaction(mChan->mCurrentTransaction)
        {
            mChan->mMonitor->AssertCurrentThreadOwns();
 
-           if (!message->is_rpc() && !message->is_urgent())
+           if (!message->is_sync())
                return;
 
-           MOZ_ASSERT_IF(mChan->mSide == ParentSide,
-                         !mOldTransaction || mOldTransaction == message->transaction_id());
-           mChan->mCurrentRPCTransaction = message->transaction_id();
+           MOZ_ASSERT_IF(mChan->mSide == ParentSide && mOldTransaction != message->transaction_id(),
+                         !mOldTransaction || message->priority() > mChan->AwaitingSyncReplyPriority());
+           mChan->mCurrentTransaction = message->transaction_id();
        }
-       ~AutoEnterRPCTransaction() {
+       ~AutoEnterTransaction() {
            mChan->mMonitor->AssertCurrentThreadOwns();
-           mChan->mCurrentRPCTransaction = mOldTransaction;
+           mChan->mCurrentTransaction = mOldTransaction;
        }
 
       private:
        MessageChannel *mChan;
        int32_t mOldTransaction;
     };
 
     // If waiting for the reply to a sync out-message, it will be saved here
     // on the I/O thread and then read and cleared by the worker thread.
     nsAutoPtr<Message> mRecvd;
 
-    // Set while we are dispatching a synchronous message.
-    bool mDispatchingSyncMessage;
-
-    // Count of the recursion depth of dispatching urgent messages.
-    size_t mDispatchingUrgentMessageCount;
-
     // Queue of all incoming messages, except for replies to sync and urgent
     // messages, which are delivered directly to mRecvd, and any pending urgent
     // incall, which is stored in mPendingUrgentRequest.
     //
     // If both this side and the other side are functioning correctly, the queue
     // can only be in certain configurations.  Let
     //
     //   |A<| be an async in-message,
@@ -582,28 +570,16 @@ class MessageChannel : HasResultCodes
     // then other side "finished with us," and went back to its own business.
     // That business might have included sending any number of async message
     // |A<*| until sending a blocking message |(S< | C<)|.  If we had more than
     // one Interrupt call on our stack, the other side *better* not have sent us
     // another blocking message, because it's blocked on a reply from us.
     //
     MessageQueue mPending;
 
-    // Note that these two pointers are mutually exclusive. One channel cannot
-    // send both urgent requests (parent -> child) and RPC calls (child->parent).
-    // Also note that since initiating either requires blocking, they cannot
-    // queue up on the other side. One message slot is enough.
-    //
-    // Normally, all other message types are deferred into into mPending, and
-    // only these two types have special treatment (since they wake up blocked
-    // requests). However, when an RPC in-call races with an urgent out-call,
-    // the RPC message will be put into mPending instead of its slot below.
-    nsAutoPtr<Message> mPendingUrgentRequest;
-    nsAutoPtr<Message> mPendingRPCCall;
-
     // Stack of all the out-calls on which this channel is awaiting responses.
     // Each stack refers to a different protocol and the stacks are mutually
     // exclusive: multiple outcalls of the same kind cannot be initiated while
     // another is active.
     std::stack<Message> mInterruptStack;
 
     // This is what we think the Interrupt stack depth is on the "other side" of this
     // Interrupt channel.  We maintain this variable so that we can detect racy Interrupt
@@ -671,14 +647,14 @@ class MessageChannel : HasResultCodes
     // safely.  This is necessary to be able to cancel notification if we are
     // closed at the same time.
     nsRefPtr<RefCountedTask> mOnChannelConnectedTask;
     DebugOnly<bool> mPeerPidSet;
     int32_t mPeerPid;
 };
 
 bool
-ProcessingUrgentMessages();
+ParentProcessIsBlocked();
 
 } // namespace ipc
 } // namespace mozilla
 
 #endif  // ifndef ipc_glue_MessageChannel_h
--- a/ipc/ipdl/ipdl/ast.py
+++ b/ipc/ipdl/ipdl/ast.py
@@ -1,14 +1,18 @@
 # 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/.
 
 import sys
 
+NORMAL_PRIORITY = 1
+HIGH_PRIORITY = 2
+URGENT_PRIORITY = 3
+
 class Visitor:
     def defaultVisit(self, node):
         raise Exception, "INTERNAL ERROR: no visitor for node type `%s'"% (
             node.__class__.__name__)
 
     def visitTranslationUnit(self, tu):
         for cxxInc in tu.cxxIncludes:
             cxxInc.accept(self)
@@ -209,18 +213,16 @@ class PrettyPrinted:
     def __str__(cls):  return cls.pretty
     
 class ASYNC(PrettyPrinted):
     pretty = 'async'
 class INTR(PrettyPrinted):
     pretty = 'intr'
 class SYNC(PrettyPrinted):
     pretty = 'sync'
-class RPC(PrettyPrinted):
-    pretty = 'rpc'
 
 class INOUT(PrettyPrinted):
     pretty = 'inout'
 class IN(PrettyPrinted):
     pretty = 'in'
 class OUT(PrettyPrinted):
     pretty = 'out'
 
@@ -229,16 +231,17 @@ class Namespace(Node):
     def __init__(self, loc, namespace):
         Node.__init__(self, loc)
         self.name = namespace
 
 class Protocol(NamespacedNode):
     def __init__(self, loc):
         NamespacedNode.__init__(self, loc)
         self.sendSemantics = ASYNC
+        self.priority = NORMAL_PRIORITY
         self.spawnsStmts = [ ]
         self.bridgesStmts = [ ]
         self.opensStmts = [ ]
         self.managers = [ ]
         self.managesStmts = [ ]
         self.messageDecls = [ ]
         self.transitionStmts = [ ]
         self.startStates = [ ]
@@ -288,30 +291,28 @@ class ManagesStmt(Node):
         Node.__init__(self, loc)
         self.name = managedName
 
 class MessageDecl(Node):
     def __init__(self, loc):
         Node.__init__(self, loc)
         self.name = None
         self.sendSemantics = ASYNC
+        self.priority = NORMAL_PRIORITY
         self.direction = None
         self.inParams = [ ]
         self.outParams = [ ]
         self.compress = ''
 
     def addInParams(self, inParamsList):
         self.inParams += inParamsList
 
     def addOutParams(self, outParamsList):
         self.outParams += outParamsList
 
-    def hasReply(self):
-        return self.sendSemantics is SYNC or self.sendSemantics is INTR
-
 class Transition(Node):
     def __init__(self, loc, trigger, msg, toStates):
         Node.__init__(self, loc)
         self.trigger = trigger
         self.msg = msg
         self.toStates = toStates
 
     def __cmp__(self, o):
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -272,23 +272,23 @@ def _putInNamespaces(cxxthing, namespace
         newns = Namespace(ns.name)
         innerns.addstmt(newns)
         innerns = newns
     innerns.addstmt(cxxthing)
     return outerns
 
 def _sendPrefix(msgtype):
     """Prefix of the name of the C++ method that sends |msgtype|."""
-    if msgtype.isInterrupt() or msgtype.isRpc():
+    if msgtype.isInterrupt():
         return 'Call'
     return 'Send'
 
 def _recvPrefix(msgtype):
     """Prefix of the name of the C++ method that handles |msgtype|."""
-    if msgtype.isInterrupt() or msgtype.isRpc():
+    if msgtype.isInterrupt():
         return 'Answer'
     return 'Recv'
 
 def _flatTypeName(ipdltype):
     """Return a 'flattened' IPDL type name that can be used as an
 identifier.
 E.g., |Foo[]| --> |ArrayOfFoo|."""
     # NB: this logic depends heavily on what IPDL types are allowed to
@@ -2979,17 +2979,17 @@ class _GenerateProtocolActorCode(ipdl.as
                 Whitespace.NL ])
 
             # Close()
             closemeth = MethodDefn(MethodDecl('Close'))
             closemeth.addstmt(StmtExpr(
                 ExprCall(ExprSelect(p.channelVar(), '.', 'Close'))))
             self.cls.addstmts([ closemeth, Whitespace.NL ])
 
-            if ptype.talksSync() or ptype.talksInterrupt():
+            if ptype.isSync() or ptype.isInterrupt():
                 # SetReplyTimeoutMs()
                 timeoutvar = ExprVar('aTimeoutMs')
                 settimeout = MethodDefn(MethodDecl(
                     'SetReplyTimeoutMs',
                     params=[ Decl(Type.INT32, timeoutvar.name) ]))
                 settimeout.addstmt(StmtExpr(
                     ExprCall(
                         ExprSelect(p.channelVar(), '.', 'SetReplyTimeoutMs'),
@@ -3048,38 +3048,40 @@ class _GenerateProtocolActorCode(ipdl.as
         # for ctor recv cases, we can't read the actor ID into a PFoo*
         # because it doesn't exist on this side yet.  Use a "special"
         # actor handle instead
         handlevar = ExprVar('__handle')
         self.handlevar = handlevar
 
         msgtype = ExprCall(ExprSelect(msgvar, '.', 'type'), [ ])
         self.asyncSwitch = StmtSwitch(msgtype)
-        if toplevel.talksSync():
+        self.syncSwitch = None
+        self.interruptSwitch = None
+        if toplevel.isSync() or toplevel.isInterrupt():
             self.syncSwitch = StmtSwitch(msgtype)
-            if toplevel.talksRpc():
+            if toplevel.isInterrupt():
                 self.interruptSwitch = StmtSwitch(msgtype)
 
         # implement Send*() methods and add dispatcher cases to
         # message switch()es
         for md in p.messageDecls:
             self.visitMessageDecl(md)
 
         # Handlers for the creation of actors when a new channel is
         # opened
         if len(channelOpenedActors):
             self.makeChannelOpenedHandlers(channelOpenedActors)
 
         # add default cases
         default = StmtBlock()
         default.addstmt(StmtReturn(_Result.NotKnown))
         self.asyncSwitch.addcase(DefaultLabel(), default)
-        if toplevel.talksSync():
+        if toplevel.isSync() or toplevel.isInterrupt():
             self.syncSwitch.addcase(DefaultLabel(), default)
-            if toplevel.talksRpc():
+            if toplevel.isInterrupt():
                 self.interruptSwitch.addcase(DefaultLabel(), default)
 
         # FIXME/bug 535053: only manager protocols and non-manager
         # protocols with union types need Lookup().  we'll give it to
         # all for the time being (simpler)
         if 1 or ptype.isManager():
             self.cls.addstmts(self.implementManagerIface())
 
@@ -3146,20 +3148,16 @@ class _GenerateProtocolActorCode(ipdl.as
             return method
 
         dispatches = (ptype.isToplevel() and ptype.isManager())
         self.cls.addstmts([
             makeHandlerMethod('OnMessageReceived', self.asyncSwitch,
                               hasReply=0, dispatches=dispatches),
             Whitespace.NL
         ])
-        if not toplevel.talksRpc():
-          self.interruptSwitch = None
-          if not toplevel.talksSync():
-            self.syncSwitch = None
         self.cls.addstmts([
             makeHandlerMethod('OnMessageReceived', self.syncSwitch,
                               hasReply=1, dispatches=dispatches),
             Whitespace.NL
         ])
         self.cls.addstmts([
             makeHandlerMethod('OnCallReceived', self.interruptSwitch,
                               hasReply=1, dispatches=dispatches),
@@ -3185,17 +3183,17 @@ class _GenerateProtocolActorCode(ipdl.as
 
         # int32_t GetProtocolTypeId() { return PFoo; }
         gettypetag = MethodDefn(
             MethodDecl('GetProtocolTypeId', ret=_actorTypeTagType()))
         gettypetag.addstmt(StmtReturn(_protocolId(ptype)))
         self.cls.addstmts([ gettypetag, Whitespace.NL ])
 
         # OnReplyTimeout()
-        if toplevel.talksSync() or toplevel.talksInterrupt():
+        if toplevel.isSync() or toplevel.isInterrupt():
             ontimeout = MethodDefn(
                 MethodDecl('OnReplyTimeout', ret=Type.BOOL))
 
             if ptype.isToplevel():
                 ontimeout.addstmt(StmtReturn(
                     ExprCall(p.shouldContinueFromTimeoutVar())))
             else:
                 ontimeout.addstmts([
@@ -3273,17 +3271,17 @@ class _GenerateProtocolActorCode(ipdl.as
             onconnected.addstmt(
                 _runtimeAbort("'OnConnected' called on non-toplevel actor"))
 
         self.cls.addstmts([ onconnected, Whitespace.NL ])
 
         # User-facing shmem methods
         self.cls.addstmts(self.makeShmemIface())
 
-        if (ptype.isToplevel() and ptype.talksInterrupt()):
+        if (ptype.isToplevel() and ptype.isInterrupt()):
 
             processnative = MethodDefn(
                 MethodDecl('ProcessNativeEventsInInterruptCall', ret=Type.VOID))
 
             processnative.addstmts([
                     CppDirective('ifdef', 'OS_WIN'),
                     StmtExpr(ExprCall(
                             ExprSelect(p.channelVar(), '.',
@@ -4775,32 +4773,32 @@ class _GenerateProtocolActorCode(ipdl.as
         if this:  read = ExprSelect(this, '->', read.name)
         return self.maybeAddNullabilityArg(
             ipdltype, ExprCall(read, args=[ expr, from_, iterexpr ]))
 
 
     def visitMessageDecl(self, md):
         isctor = md.decl.type.isCtor()
         isdtor = md.decl.type.isDtor()
-        sems = md.decl.type.sendSemantics
+        decltype = md.decl.type
         sendmethod = None
         helpermethod = None
         recvlbl, recvcase = None, None
 
         def addRecvCase(lbl, case):
-            if sems is ipdl.ast.ASYNC:
+            if decltype.isAsync():
                 self.asyncSwitch.addcase(lbl, case)
-            elif sems is ipdl.ast.SYNC:
+            elif decltype.isSync():
                 self.syncSwitch.addcase(lbl, case)
-            elif sems is ipdl.ast.INTR or sems is ipdl.ast.RPC:
+            elif decltype.isInterrupt():
                 self.interruptSwitch.addcase(lbl, case)
             else: assert 0
 
         if self.sendsMessage(md):
-            isasync = (sems is ipdl.ast.ASYNC)
+            isasync = decltype.isAsync()
 
             if isctor:
                 self.cls.addstmts([ self.genHelperCtor(md), Whitespace.NL ])
 
             if isctor and isasync:
                 sendmethod, (recvlbl, recvcase) = self.genAsyncCtor(md)
             elif isctor:
                 sendmethod = self.genBlockingCtorMethod(md)
@@ -5180,31 +5178,24 @@ class _GenerateProtocolActorCode(ipdl.as
 
         stmts = [ StmtExpr(ExprCall(
             ExprSelect(var, '->', 'set_routing_id'),
             args=[ routingId ])) ]
 
         if md.decl.type.isSync():
             stmts.append(StmtExpr(ExprCall(
                 ExprSelect(var, '->', 'set_sync'))))
-        elif md.decl.type.isRpc():
-            # We use urgent messages from the parent to the child and
-            # RPC messages from the child to the parent. However,
-            # replies should always be sent using the same semantics
-            # as the original message, so we need to flip.
-            if (self.side == 'parent') ^ reply:
-                stmts.append(StmtExpr(ExprCall(
-                    ExprSelect(var, '->', 'set_urgent'))))
-            else:
-                stmts.append(StmtExpr(ExprCall(
-                    ExprSelect(var, '->', 'set_rpc'))))
         elif md.decl.type.isInterrupt():
             stmts.append(StmtExpr(ExprCall(
                 ExprSelect(var, '->', 'set_interrupt'))))
 
+        stmts.append(StmtExpr(ExprCall(
+            ExprSelect(var, '->', 'set_priority'),
+            args=[ ExprLiteral.Int(md.decl.type.priority) ])))
+
         if reply:
             stmts.append(StmtExpr(ExprCall(
                 ExprSelect(var, '->', 'set_reply'))))
 
         return stmts + [ Whitespace.NL ]
 
 
     def deserializeMessage(self, md, side, errfn):
--- a/ipc/ipdl/ipdl/parser.py
+++ b/ipc/ipdl/ipdl/parser.py
@@ -122,39 +122,43 @@ reserved = set((
         'call',
         'child',
         'class',
         'compress',
         '__delete__',
         'delete',                       # reserve 'delete' to prevent its use
         'from',
         'goto',
+        'high',
         'include',
         'intr',
         'manager',
         'manages',
         'namespace',
+        'normal',
         'nullable',
         'opens',
         'or',
         'parent',
+        'prio',
         'protocol',
         'recv',
         'returns',
-        'rpc',
         'send',
         'spawns',
         'start',
         'state',
         'struct',
         'sync',
         'union',
+        'upto',
+        'urgent',
         'using'))
 tokens = [
-    'COLONCOLON', 'ID', 'STRING'
+    'COLONCOLON', 'ID', 'STRING',
 ] + [ r.upper() for r in reserved ]
 
 t_COLONCOLON = '::'
 
 literals = '(){}[]<>;:,~'
 t_ignore = ' \f\t\v'
 
 def t_linecomment(t):
@@ -344,21 +348,22 @@ def p_ComponentTypes(p):
                       | Type ';'"""
     if 3 == len(p):
         p[0] = [ p[1] ]
     else:
         p[1].append(p[2])
         p[0] = p[1]
 
 def p_ProtocolDefn(p):
-    """ProtocolDefn : OptionalSendSemanticsQual PROTOCOL ID '{' ProtocolBody '}' ';'"""
+    """ProtocolDefn : OptionalProtocolSendSemanticsQual PROTOCOL ID '{' ProtocolBody '}' ';'"""
     protocol = p[5]
     protocol.loc = locFromTok(p, 2)
     protocol.name = p[3]
-    protocol.sendSemantics = p[1]
+    protocol.priorityRange = p[1][0]
+    protocol.sendSemantics = p[1][1]
     p[0] = protocol
 
     if Parser.current.type == 'header':
         _error(protocol.loc, 'can\'t define a protocol in a header.  Do it in a protocol spec instead.')
 
 
 def p_ProtocolBody(p):
     """ProtocolBody : SpawnsStmtsOpt"""
@@ -490,17 +495,18 @@ def p_MessageDirectionLabel(p):
     elif p[1] == 'both':
         Parser.current.direction = INOUT
     else:
         assert 0
 
 def p_MessageDecl(p):
     """MessageDecl : OptionalSendSemanticsQual MessageBody"""
     msg = p[2]
-    msg.sendSemantics = p[1]
+    msg.priority = p[1][0]
+    msg.sendSemantics = p[1][1]
 
     if Parser.current.direction is None:
         _error(msg.loc, 'missing message direction')
     msg.direction = Parser.current.direction
 
     p[0] = msg
 
 def p_MessageBody(p):
@@ -610,34 +616,77 @@ def p_StateList(p):
         p[0] = p[1]
 
 def p_State(p):
     """State : ID"""
     p[0] = State(locFromTok(p, 1), p[1])
 
 ##--------------------
 ## Minor stuff
+def p_Priority(p):
+    """Priority : NORMAL
+                | HIGH
+                | URGENT"""
+    prios = {'normal': 1,
+             'high': 2,
+             'urgent': 3}
+    p[0] = prios[p[1]]
+
 def p_OptionalSendSemanticsQual(p):
     """OptionalSendSemanticsQual : SendSemanticsQual
                                  | """
     if 2 == len(p): p[0] = p[1]
-    else:           p[0] = ASYNC
+    else:           p[0] = [ NORMAL_PRIORITY, ASYNC ]
 
 def p_SendSemanticsQual(p):
     """SendSemanticsQual : ASYNC
-                         | INTR
-                         | RPC
-                         | SYNC"""
-    s = p[1]
-    if 'async' == s: p[0] =    ASYNC
-    elif 'intr' == s: p[0] =   INTR
-    elif 'sync' == s: p[0] =   SYNC
-    elif 'rpc' == s: p[0] =    RPC
+                         | SYNC
+                         | PRIO '(' Priority ')' ASYNC
+                         | PRIO '(' Priority ')' SYNC
+                         | INTR"""
+    if p[1] == 'prio':
+        mtype = p[5]
+        prio = p[3]
     else:
-        assert 0
+        mtype = p[1]
+        prio = NORMAL_PRIORITY
+
+    if mtype == 'async': mtype = ASYNC
+    elif mtype == 'sync': mtype = SYNC
+    elif mtype == 'intr': mtype = INTR
+    else: assert 0
+
+    p[0] = [ prio, mtype ]
+
+def p_OptionalProtocolSendSemanticsQual(p):
+    """OptionalProtocolSendSemanticsQual : ProtocolSendSemanticsQual
+                                         | """
+    if 2 == len(p): p[0] = p[1]
+    else:           p[0] = [ (NORMAL_PRIORITY, NORMAL_PRIORITY), ASYNC ]
+
+def p_ProtocolSendSemanticsQual(p):
+    """ProtocolSendSemanticsQual : ASYNC
+                                 | SYNC
+                                 | PRIO '(' Priority UPTO Priority ')' ASYNC
+                                 | PRIO '(' Priority UPTO Priority ')' SYNC
+                                 | PRIO '(' Priority UPTO Priority ')' INTR
+                                 | INTR"""
+    if p[1] == 'prio':
+        mtype = p[7]
+        prio = (p[3], p[5])
+    else:
+        mtype = p[1]
+        prio = (NORMAL_PRIORITY, NORMAL_PRIORITY)
+
+    if mtype == 'async': mtype = ASYNC
+    elif mtype == 'sync': mtype = SYNC
+    elif mtype == 'intr': mtype = INTR
+    else: assert 0
+
+    p[0] = [ prio, mtype ]
 
 def p_ParamList(p):
     """ParamList : ParamList ',' Param
                  | Param
                  | """
     if 1 == len(p):
         p[0] = [ ]
     elif 2 == len(p):
--- a/ipc/ipdl/ipdl/type.py
+++ b/ipc/ipdl/ipdl/type.py
@@ -1,18 +1,20 @@
 # vim: set ts=4 sw=4 tw=99 et:
 # 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/.
 
 import os, sys
 
 from ipdl.ast import CxxInclude, Decl, Loc, QualifiedId, State, StructDecl, TransitionStmt
-from ipdl.ast import TypeSpec, UnionDecl, UsingStmt, Visitor, ASYNC, SYNC, INTR
-from ipdl.ast import IN, OUT, INOUT, ANSWER, CALL, RECV, SEND, RPC
+from ipdl.ast import TypeSpec, UnionDecl, UsingStmt, Visitor
+from ipdl.ast import ASYNC, SYNC, INTR
+from ipdl.ast import IN, OUT, INOUT, ANSWER, CALL, RECV, SEND
+from ipdl.ast import NORMAL_PRIORITY, HIGH_PRIORITY, URGENT_PRIORITY
 import ipdl.builtin as builtin
 
 _DELETE_MSG = '__delete__'
 
 
 def _otherside(side):
     if side == 'parent':  return 'child'
     elif side == 'child': return 'parent'
@@ -199,52 +201,59 @@ class IPDLType(Type):
     def isUnion(self): return False
     def isArray(self): return False
     def isAtom(self):  return True
     def isCompound(self): return False
     def isShmem(self): return False
     def isChmod(self): return False
     def isFD(self): return False
 
-    def isAsync(self): return self.sendSemantics is ASYNC
-    def isSync(self): return self.sendSemantics is SYNC
+    def isAsync(self): return self.sendSemantics == ASYNC
+    def isSync(self): return self.sendSemantics == SYNC
     def isInterrupt(self): return self.sendSemantics is INTR
-    def isRpc(self): return self.sendSemantics is RPC
+
+    def hasReply(self):  return (self.isSync() or self.isInterrupt())
 
-    def talksAsync(self): return True
-    def talksSync(self): return self.isSync() or self.isRpc() or self.isInterrupt()
-    def talksRpc(self): return self.isRpc() or self.isInterrupt()
-    def talksInterrupt(self): return self.isInterrupt()
+    @classmethod
+    def convertsTo(cls, lesser, greater):
+        if (lesser.priorityRange[0] < greater.priorityRange[0] or
+            lesser.priorityRange[1] > greater.priorityRange[1]):
+            return False
 
-    def hasReply(self):  return (self.isSync()
-                                 or self.isInterrupt()
-                                 or self.isRpc())
+        if lesser.isAsync():
+            return True
+        elif lesser.isSync() and not greater.isAsync():
+            return True
+        elif greater.isInterrupt():
+            return True
+
+        return False
 
     def needsMoreJuiceThan(self, o):
-        return (o.isAsync() and not self.isAsync()
-                or o.isSync() and self.isRpc()
-                or o.isRpc() and self.isInterrupt())
+        return not IPDLType.convertsTo(self, o)
 
 class StateType(IPDLType):
     def __init__(self, protocol, name, start=False):
         self.protocol = protocol
         self.name = name
         self.start = start
     def isState(self): return True
     def name(self):
         return self.name
     def fullname(self):
         return self.name()
 
 class MessageType(IPDLType):
-    def __init__(self, sendSemantics, direction,
+    def __init__(self, priority, sendSemantics, direction,
                  ctor=False, dtor=False, cdtype=None, compress=False):
         assert not (ctor and dtor)
         assert not (ctor or dtor) or type is not None
 
+        self.priority = priority
+        self.priorityRange = (priority, priority)
         self.sendSemantics = sendSemantics
         self.direction = direction
         self.params = [ ]
         self.returns = [ ]
         self.ctor = ctor
         self.dtor = dtor
         self.cdtype = cdtype
         self.compress = compress
@@ -270,18 +279,19 @@ class Bridge:
     def __cmp__(self, o):
         return cmp(self.parent, o.parent) or cmp(self.child, o.child)
     def __eq__(self, o):
         return self.parent == o.parent and self.child == o.child
     def __hash__(self):
         return hash(self.parent) + hash(self.child)
 
 class ProtocolType(IPDLType):
-    def __init__(self, qname, sendSemantics, stateless=False):
+    def __init__(self, qname, priorityRange, sendSemantics, stateless=False):
         self.qname = qname
+        self.priorityRange = priorityRange
         self.sendSemantics = sendSemantics
         self.spawns = set()             # ProtocolType
         self.opens = set()              # ProtocolType
         self.managers = []           # ProtocolType
         self.manages = [ ]
         self.stateless = stateless
         self.hasDelete = False
         self.hasReentrantDelete = False
@@ -679,17 +689,17 @@ class GatherDecls(TcheckVisitor):
             # types?
             qname = p.qname()
             if 0 == len(qname.quals):
                 fullname = None
             else:
                 fullname = str(qname)
             p.decl = self.declare(
                 loc=p.loc,
-                type=ProtocolType(qname, p.sendSemantics,
+                type=ProtocolType(qname, p.priorityRange, p.sendSemantics,
                                   stateless=(0 == len(p.transitionStmts))),
                 shortname=p.name,
                 fullname=fullname)
 
             # XXX ugh, this sucks.  but we need this information to compute
             # what friend decls we need in generated C++
             p.decl.type._ast = p
 
@@ -1078,17 +1088,17 @@ class GatherDecls(TcheckVisitor):
         if _DELETE_MSG == msgname:
             isdtor = True
             cdtype = self.currentProtocolDecl.type
 
 
         # enter message scope
         self.symtab.enterScope(md)
 
-        msgtype = MessageType(md.sendSemantics, md.direction,
+        msgtype = MessageType(md.priority, md.sendSemantics, md.direction,
                               ctor=isctor, dtor=isdtor, cdtype=cdtype,
                               compress=(md.compress == 'compress'))
 
         # replace inparam Param nodes with proper Decls
         def paramToDecl(param):
             ptname = param.typespec.basename()
             ploc = param.typespec.loc
 
@@ -1452,17 +1462,32 @@ class CheckTypes(TcheckVisitor):
 
 
     def visitMessageDecl(self, md):
         mtype, mname = md.decl.type, md.decl.progname
         ptype, pname = md.protocolDecl.type, md.protocolDecl.shortname
 
         loc = md.decl.loc
 
-        if mtype.isSync() and (mtype.isOut() or mtype.isInout()):
+        if mtype.priority == HIGH_PRIORITY and not mtype.isSync():
+            self.error(
+                loc,
+                "high priority messages must be sync (here, message `%s' in protocol `%s')",
+                mname, pname)
+
+        if mtype.priority == URGENT_PRIORITY and (mtype.isOut() or mtype.isInout()):
+            self.error(
+                loc,
+                "urgent parent-to-child messages are verboten (here, message `%s' in protocol `%s')",
+                mname, pname)
+
+        # We allow high priority sync messages to be sent from the
+        # parent. Normal and urgent sync messages can only come from
+        # the child.
+        if mtype.isSync() and mtype.priority == NORMAL_PRIORITY and (mtype.isOut() or mtype.isInout()):
             self.error(
                 loc,
                 "sync parent-to-child messages are verboten (here, message `%s' in protocol `%s')",
                 mname, pname)
 
         if mtype.needsMoreJuiceThan(ptype):
             self.error(
                 loc,
--- a/ipc/ipdl/test/cxx/Makefile.in
+++ b/ipc/ipdl/test/cxx/Makefile.in
@@ -14,17 +14,17 @@ IPDLTESTHDRS = $(addprefix $(srcdir)/,$(
 TESTER_TEMPLATE := $(srcdir)/IPDLUnitTests.template.cpp
 GENTESTER := $(srcdir)/genIPDLUnitTests.py
 
 include $(topsrcdir)/config/rules.mk
 
 
 IPDLUNITTEST_BIN = $(DEPTH)/dist/bin/ipdlunittest$(BIN_SUFFIX)
 
-IPDLUnitTests.cpp : Makefile.in $(GENTESTER) $(TESTER_TEMPLATE) $(IPDLTESTHDRS)
+IPDLUnitTests.cpp : Makefile.in moz.build $(GENTESTER) $(TESTER_TEMPLATE) $(IPDLTESTHDRS)
 	$(PYTHON) $(GENTESTER) $(TESTER_TEMPLATE) -t $(IPDLTESTS) -e $(EXTRA_PROTOCOLS) > $@
 
 check-proc::
 	@$(EXIT_ON_ERROR)  \
 	for test in $(IPDLTESTS); do  \
 		 $(RUN_TEST_PROGRAM) $(IPDLUNITTEST_BIN) $$test ;  \
 	done
 
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestHighestPrio.ipdl
@@ -0,0 +1,18 @@
+namespace mozilla {
+namespace _ipdltest {
+
+prio(normal upto urgent) sync protocol PTestHighestPrio
+{
+parent:
+  prio(urgent) async Msg1();
+  sync Msg2();
+  prio(urgent) async Msg3();
+  prio(urgent) sync Msg4();
+
+child:
+  async Start();
+  prio(high) sync StartInner();
+};
+
+}
+}
--- a/ipc/ipdl/test/cxx/PTestRPC.ipdl
+++ b/ipc/ipdl/test/cxx/PTestRPC.ipdl
@@ -1,27 +1,26 @@
 namespace mozilla {
 namespace _ipdltest {
 
-intr protocol PTestRPC
+prio(normal upto high) sync protocol PTestRPC
 {
 parent:
-    rpc Test1_Start() returns (uint32_t result);
-    rpc Test1_InnerEvent() returns (uint32_t result);
+    prio(high) sync Test1_Start() returns (uint32_t result);
+    prio(high) sync Test1_InnerEvent() returns (uint32_t result);
     async Test2_Start();
-    rpc Test2_OutOfOrder();
+    prio(high) sync Test2_Msg2();
+    prio(high) sync Test2_FirstUrgent();
+    prio(high) sync Test2_SecondUrgent();
     sync Test3_Start() returns (uint32_t result);
-    rpc Test3_InnerEvent() returns (uint32_t result);
-    intr Test4_Start() returns (uint32_t result);
-    rpc Test4_Inner() returns (uint32_t result);
+    prio(high) sync Test3_InnerEvent() returns (uint32_t result);
 
 child:
     async Start();
-    rpc Test1_InnerQuery() returns (uint32_t result);
-    rpc Test1_NoReenter() returns (uint32_t result);
-    rpc Test2_FirstUrgent();
-    rpc Test2_SecondUrgent();
-    rpc Test3_WakeUp() returns (uint32_t result);
-    rpc Test4_WakeUp() returns (uint32_t result);
+    prio(high) sync Test1_InnerQuery() returns (uint32_t result);
+    prio(high) sync Test1_NoReenter() returns (uint32_t result);
+    prio(high) sync Test2_Msg1();
+    prio(high) sync Test2_Msg3();
+    prio(high) sync Test3_WakeUp() returns (uint32_t result);
 };
 
 } // namespace _ipdltest
 } // namespace mozilla
--- a/ipc/ipdl/test/cxx/PTestUrgency.ipdl
+++ b/ipc/ipdl/test/cxx/PTestUrgency.ipdl
@@ -1,19 +1,19 @@
 namespace mozilla {
 namespace _ipdltest {
 
-intr protocol PTestUrgency
+prio(normal upto high) sync protocol PTestUrgency
 {
 parent:
     sync Test1() returns (uint32_t result);
     async Test2();
     sync Test3() returns (uint32_t result);
     sync FinalTest_Begin();
 
 child:
     async Start();
-    rpc Reply1() returns (uint32_t result);
-    rpc Reply2() returns (uint32_t result);
+    prio(high) sync Reply1() returns (uint32_t result);
+    prio(high) sync Reply2() returns (uint32_t result);
 };
 
 } // namespace _ipdltest
 } // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestHighestPrio.cpp
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "TestHighestPrio.h"
+
+#include "IPDLUnitTests.h"      // fail etc.
+#if defined(OS_POSIX)
+#include <unistd.h>
+#else
+#include <windows.h>
+#endif
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+
+TestHighestPrioParent::TestHighestPrioParent()
+  : msg_num_(0)
+{
+    MOZ_COUNT_CTOR(TestHighestPrioParent);
+}
+
+TestHighestPrioParent::~TestHighestPrioParent()
+{
+    MOZ_COUNT_DTOR(TestHighestPrioParent);
+}
+
+void
+TestHighestPrioParent::Main()
+{
+    if (!SendStart())
+        fail("sending Start");
+}
+
+bool
+TestHighestPrioParent::RecvMsg1()
+{
+    MOZ_ASSERT(msg_num_ == 0);
+    msg_num_ = 1;
+    return true;
+}
+
+bool
+TestHighestPrioParent::RecvMsg2()
+{
+
+    MOZ_ASSERT(msg_num_ == 1);
+    msg_num_ = 2;
+
+    if (!SendStartInner())
+        fail("sending StartInner");
+
+    return true;
+}
+
+bool
+TestHighestPrioParent::RecvMsg3()
+{
+    MOZ_ASSERT(msg_num_ == 2);
+    msg_num_ = 3;
+    return true;
+}
+
+bool
+TestHighestPrioParent::RecvMsg4()
+{
+    MOZ_ASSERT(msg_num_ == 3);
+    msg_num_ = 4;
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+
+TestHighestPrioChild::TestHighestPrioChild()
+{
+    MOZ_COUNT_CTOR(TestHighestPrioChild);
+}
+
+TestHighestPrioChild::~TestHighestPrioChild()
+{
+    MOZ_COUNT_DTOR(TestHighestPrioChild);
+}
+
+bool
+TestHighestPrioChild::RecvStart()
+{
+    if (!SendMsg1())
+        fail("sending Msg1");
+
+    if (!SendMsg2())
+        fail("sending Msg2");
+
+    Close();
+    return true;
+}
+
+bool
+TestHighestPrioChild::RecvStartInner()
+{
+    if (!SendMsg3())
+        fail("sending Msg3");
+
+    if (!SendMsg4())
+        fail("sending Msg4");
+
+    return true;
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestHighestPrio.h
@@ -0,0 +1,68 @@
+#ifndef mozilla__ipdltest_TestHighestPrio_h
+#define mozilla__ipdltest_TestHighestPrio_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestHighestPrioParent.h"
+#include "mozilla/_ipdltest/PTestHighestPrioChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+
+class TestHighestPrioParent :
+    public PTestHighestPrioParent
+{
+public:
+    TestHighestPrioParent();
+    virtual ~TestHighestPrioParent();
+
+    static bool RunTestInProcesses() { return true; }
+    static bool RunTestInThreads() { return false; }
+
+    void Main();
+
+    bool RecvMsg1() MOZ_OVERRIDE;
+    bool RecvMsg2() MOZ_OVERRIDE;
+    bool RecvMsg3() MOZ_OVERRIDE;
+    bool RecvMsg4() MOZ_OVERRIDE;
+
+    virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE
+    {
+        if (NormalShutdown != why)
+            fail("unexpected destruction!");
+        if (msg_num_ != 4)
+            fail("missed IPC call");
+        passed("ok");
+        QuitParent();
+    }
+
+private:
+    int msg_num_;
+};
+
+
+class TestHighestPrioChild :
+    public PTestHighestPrioChild
+{
+public:
+    TestHighestPrioChild();
+    virtual ~TestHighestPrioChild();
+
+    bool RecvStart() MOZ_OVERRIDE;
+    bool RecvStartInner() MOZ_OVERRIDE;
+
+    virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE
+    {
+        if (NormalShutdown != why)
+            fail("unexpected destruction!");
+        QuitChild();
+    }
+};
+
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+
+#endif // ifndef mozilla__ipdltest_TestHighestPrio_h
--- a/ipc/ipdl/test/cxx/TestRPC.cpp
+++ b/ipc/ipdl/test/cxx/TestRPC.cpp
@@ -9,18 +9,16 @@
 
 namespace mozilla {
 namespace _ipdltest {
 
 //-----------------------------------------------------------------------------
 // parent
 
 TestRPCParent::TestRPCParent()
- : reentered_(false),
-   resolved_first_cpow_(false)
 {
   MOZ_COUNT_CTOR(TestRPCParent);
 }
 
 TestRPCParent::~TestRPCParent()
 {
   MOZ_COUNT_DTOR(TestRPCParent);
 }
@@ -28,187 +26,177 @@ TestRPCParent::~TestRPCParent()
 void
 TestRPCParent::Main()
 {
   if (!SendStart())
     fail("sending Start");
 }
 
 bool
-TestRPCParent::AnswerTest1_Start(uint32_t* aResult)
+TestRPCParent::RecvTest1_Start(uint32_t* aResult)
 {
   uint32_t result;
-  if (!CallTest1_InnerQuery(&result))
-    fail("CallTest1_InnerQuery");
+  if (!SendTest1_InnerQuery(&result))
+    fail("SendTest1_InnerQuery");
   if (result != 300)
     fail("Wrong result (expected 300)");
 
   *aResult = 100;
   return true;
 }
 
 bool
-TestRPCParent::AnswerTest1_InnerEvent(uint32_t* aResult)
+TestRPCParent::RecvTest1_InnerEvent(uint32_t* aResult)
 {
   uint32_t result;
-  if (!CallTest1_NoReenter(&result))
-    fail("CallTest1_NoReenter");
+  if (!SendTest1_NoReenter(&result))
+    fail("SendTest1_NoReenter");
   if (result != 400)
     fail("Wrong result (expected 400)");
 
   *aResult = 200;
   return true;
 }
 
 bool
 TestRPCParent::RecvTest2_Start()
 {
-  // Send a CPOW. During this time, we must NOT process the RPC message, as
-  // we could start receiving CPOW replies out-of-order.
-  if (!CallTest2_FirstUrgent())
-    fail("CallTest2_FirstUrgent");
+  if (!SendTest2_Msg1())
+    fail("SendTest2_Msg1");
 
-  MOZ_ASSERT(!reentered_);
-  resolved_first_cpow_ = true;
   return true;
 }
 
 bool
-TestRPCParent::AnswerTest2_OutOfOrder()
+TestRPCParent::RecvTest2_Msg2()
 {
-  // Send a CPOW. If this RPC call was initiated while waiting for the first
-  // CPOW to resolve, replies will be processed out of order, and we'll crash.
-  if (!CallTest2_SecondUrgent())
-    fail("CallTest2_SecondUrgent");
+  if (!SendTest2_Msg3())
+    fail("SendTest2_Msg3");
+
+  return true;
+}
 
-  reentered_ = true;
+bool
+TestRPCParent::RecvTest2_FirstUrgent()
+{
+  return true;
+}
+
+bool
+TestRPCParent::RecvTest2_SecondUrgent()
+{
   return true;
 }
 
 bool
 TestRPCParent::RecvTest3_Start(uint32_t* aResult)
 {
-  if (!CallTest3_WakeUp(aResult))
-    fail("CallTest3_WakeUp");
+  if (!SendTest3_WakeUp(aResult))
+    fail("SendTest3_WakeUp");
 
   return true;
 }
 
 bool
-TestRPCParent::AnswerTest3_InnerEvent(uint32_t* aResult)
+TestRPCParent::RecvTest3_InnerEvent(uint32_t* aResult)
 {
   *aResult = 200;
   return true;
 }
 
-bool
-TestRPCParent::AnswerTest4_Start(uint32_t* aResult)
-{
-  if (!CallTest4_WakeUp(aResult))
-    fail("CallTest4_WakeUp");
-
-  return true;
-}
-
-bool
-TestRPCParent::AnswerTest4_Inner(uint32_t* aResult)
-{
-  *aResult = 700;
-  return true;
-}
-
 //-----------------------------------------------------------------------------
 // child
 
 
 TestRPCChild::TestRPCChild()
+ : reentered_(false),
+   resolved_first_cpow_(false)
 {
     MOZ_COUNT_CTOR(TestRPCChild);
 }
 
 TestRPCChild::~TestRPCChild()
 {
     MOZ_COUNT_DTOR(TestRPCChild);
 }
 
 bool
 TestRPCChild::RecvStart()
 {
   uint32_t result;
-  if (!CallTest1_Start(&result))
-    fail("CallTest1_Start");
+  if (!SendTest1_Start(&result))
+    fail("SendTest1_Start");
   if (result != 100)
     fail("Wrong result (expected 100)");
 
   if (!SendTest2_Start())
     fail("SendTest2_Start");
 
-  if (!CallTest2_OutOfOrder())
-    fail("CallTest2_OutOfOrder");
+  if (!SendTest2_Msg2())
+    fail("SendTest2_Msg2");
 
   result = 0;
   if (!SendTest3_Start(&result))
     fail("SendTest3_Start");
   if (result != 200)
     fail("Wrong result (expected 200)");
 
-  // See bug 937216 (RPC calls within interrupts).
-  if (!CallTest4_Start(&result))
-    fail("SendTest4_Start");
-  if (result != 700)
-    fail("Wrong result (expected 700)");
-
   Close();
   return true;
 }
 
 bool
-TestRPCChild::AnswerTest1_InnerQuery(uint32_t* aResult)
+TestRPCChild::RecvTest1_InnerQuery(uint32_t* aResult)
 {
   uint32_t result;
-  if (!CallTest1_InnerEvent(&result))
-    fail("CallTest1_InnerEvent");
+  if (!SendTest1_InnerEvent(&result))
+    fail("SendTest1_InnerEvent");
   if (result != 200)
     fail("Wrong result (expected 200)");
 
   *aResult = 300;
   return true;
 }
 
 bool
-TestRPCChild::AnswerTest1_NoReenter(uint32_t* aResult)
+TestRPCChild::RecvTest1_NoReenter(uint32_t* aResult)
 {
   *aResult = 400;
   return true;
 }
 
-bool
-TestRPCChild::AnswerTest2_FirstUrgent()
+bool TestRPCChild::RecvTest2_Msg1()
 {
-  return true;
-}
+  MOZ_ASSERT(resolved_first_cpow_);
 
-bool
-TestRPCChild::AnswerTest2_SecondUrgent()
-{
+  // Send a CPOW. If this RPC call was initiated while waiting for the first
+  // CPOW to resolve, replies will be processed out of order, and we'll crash.
+  if (!SendTest2_SecondUrgent())
+    fail("SendTest2_SecondUrgent");
+
+  reentered_ = true;
   return true;
 }
 
 bool
-TestRPCChild::AnswerTest3_WakeUp(uint32_t* aResult)
+TestRPCChild::RecvTest2_Msg3()
 {
-  if (!CallTest3_InnerEvent(aResult))
-    fail("CallTest3_InnerEvent");
+  // Send a CPOW. During this time, we must NOT process the RPC message, as
+  // we could start receiving CPOW replies out-of-order.
+  if (!SendTest2_FirstUrgent())
+    fail("SendTest2_FirstUrgent");
 
+  MOZ_ASSERT(!reentered_);
+  resolved_first_cpow_ = true;
   return true;
 }
 
 bool
-TestRPCChild::AnswerTest4_WakeUp(uint32_t* aResult)
+TestRPCChild::RecvTest3_WakeUp(uint32_t* aResult)
 {
-  if (!CallTest4_Inner(aResult))
-    fail("CallTest4_Inner");
+  if (!SendTest3_InnerEvent(aResult))
+    fail("SendTest3_InnerEvent");
 
   return true;
 }
 
 } // namespace _ipdltest
 } // namespace mozilla
--- a/ipc/ipdl/test/cxx/TestRPC.h
+++ b/ipc/ipdl/test/cxx/TestRPC.h
@@ -17,64 +17,59 @@ public:
     TestRPCParent();
     virtual ~TestRPCParent();
 
     static bool RunTestInProcesses() { return true; }
     static bool RunTestInThreads() { return false; }
 
     void Main();
 
-    bool AnswerTest1_Start(uint32_t* aResult) MOZ_OVERRIDE;
-    bool AnswerTest1_InnerEvent(uint32_t* aResult) MOZ_OVERRIDE;
+    bool RecvTest1_Start(uint32_t* aResult) MOZ_OVERRIDE;
+    bool RecvTest1_InnerEvent(uint32_t* aResult) MOZ_OVERRIDE;
     bool RecvTest2_Start() MOZ_OVERRIDE;
-    bool AnswerTest2_OutOfOrder() MOZ_OVERRIDE;
+    bool RecvTest2_Msg2() MOZ_OVERRIDE;
+    bool RecvTest2_FirstUrgent() MOZ_OVERRIDE;
+    bool RecvTest2_SecondUrgent() MOZ_OVERRIDE;
     bool RecvTest3_Start(uint32_t* aResult) MOZ_OVERRIDE;
-    bool AnswerTest3_InnerEvent(uint32_t* aResult) MOZ_OVERRIDE;
-    bool AnswerTest4_Start(uint32_t* aResult) MOZ_OVERRIDE;
-    bool AnswerTest4_Inner(uint32_t* aResult) MOZ_OVERRIDE;
+    bool RecvTest3_InnerEvent(uint32_t* aResult) MOZ_OVERRIDE;
 
     virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE
     {
         if (NormalShutdown != why)
             fail("unexpected destruction!");  
-        if (!reentered_)
-            fail("never processed raced RPC call!");
-        if (!resolved_first_cpow_)
-            fail("never resolved first CPOW!");
         passed("ok");
         QuitParent();
     }
-
-private:
-    bool reentered_;
-    bool resolved_first_cpow_;
 };
 
 
 class TestRPCChild :
     public PTestRPCChild
 {
 public:
     TestRPCChild();
     virtual ~TestRPCChild();
 
     bool RecvStart() MOZ_OVERRIDE;
-    bool AnswerTest1_InnerQuery(uint32_t* aResult) MOZ_OVERRIDE;
-    bool AnswerTest1_NoReenter(uint32_t* aResult) MOZ_OVERRIDE;
-    bool AnswerTest2_FirstUrgent() MOZ_OVERRIDE;
-    bool AnswerTest2_SecondUrgent() MOZ_OVERRIDE;
-    bool AnswerTest3_WakeUp(uint32_t* aResult) MOZ_OVERRIDE;
-    bool AnswerTest4_WakeUp(uint32_t* aResult) MOZ_OVERRIDE;
+    bool RecvTest1_InnerQuery(uint32_t* aResult) MOZ_OVERRIDE;
+    bool RecvTest1_NoReenter(uint32_t* aResult) MOZ_OVERRIDE;
+    bool RecvTest2_Msg1() MOZ_OVERRIDE;
+    bool RecvTest2_Msg3() MOZ_OVERRIDE;
+    bool RecvTest3_WakeUp(uint32_t* aResult) MOZ_OVERRIDE;
 
     virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE
     {
         if (NormalShutdown != why)
             fail("unexpected destruction!");
         QuitChild();
     }
+
+private:
+    bool reentered_;
+    bool resolved_first_cpow_;
 };
 
 
 } // namespace _ipdltest
 } // namespace mozilla
 
 
 #endif // ifndef mozilla__ipdltest_TestRPC_h
--- a/ipc/ipdl/test/cxx/TestUrgency.cpp
+++ b/ipc/ipdl/test/cxx/TestUrgency.cpp
@@ -43,29 +43,29 @@ TestUrgencyParent::Main()
 {
   if (!SendStart())
     fail("sending Start");
 }
 
 bool
 TestUrgencyParent::RecvTest1(uint32_t *value)
 {
-  if (!CallReply1(value))
+  if (!SendReply1(value))
     fail("sending Reply1");
   if (*value != 99)
     fail("bad value");
   return true;
 }
 
 bool
 TestUrgencyParent::RecvTest2()
 {
   uint32_t value;
   inreply_ = true;
-  if (!CallReply2(&value))
+  if (!SendReply2(&value))
     fail("sending Reply2");
   inreply_ = false;
   if (value != 500)
     fail("bad value");
   return true;
 }
 
 bool
@@ -125,31 +125,31 @@ TestUrgencyChild::RecvStart()
     fail("Final test should have succeeded");
 
   Close();
 
   return true;
 }
 
 bool
-TestUrgencyChild::AnswerReply1(uint32_t *reply)
+TestUrgencyChild::RecvReply1(uint32_t *reply)
 {
   if (test_ != kFirstTestBegin)
-    fail("wrong test # in AnswerReply1");
+    fail("wrong test # in RecvReply1");
 
   *reply = 99;
   test_ = kFirstTestGotReply;
   return true;
 }
 
 bool
-TestUrgencyChild::AnswerReply2(uint32_t *reply)
+TestUrgencyChild::RecvReply2(uint32_t *reply)
 {
   if (test_ != kSecondTestBegin)
-    fail("wrong test # in AnswerReply2");
+    fail("wrong test # in RecvReply2");
 
   // sleep for 5 seconds so the parent process tries to deliver more messages.
   Sleep(5000);
 
   *reply = 500;
   test_ = kSecondTestGotReply;
   return true;
 }
--- a/ipc/ipdl/test/cxx/TestUrgency.h
+++ b/ipc/ipdl/test/cxx/TestUrgency.h
@@ -47,20 +47,18 @@ private:
 class TestUrgencyChild :
     public PTestUrgencyChild
 {
 public:
     TestUrgencyChild();
     virtual ~TestUrgencyChild();
 
     bool RecvStart();
-    bool AnswerReply1(uint32_t *reply);
-    bool AnswerReply2(uint32_t *reply);
-    bool AnswerTest4_Reenter();
-    bool AnswerFinalTest_Hang();
+    bool RecvReply1(uint32_t *reply);
+    bool RecvReply2(uint32_t *reply);
 
     virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE
     {
         QuitChild();
     }
 
 private:
     uint32_t test_;
--- a/ipc/ipdl/test/cxx/moz.build
+++ b/ipc/ipdl/test/cxx/moz.build
@@ -17,16 +17,17 @@ SOURCES += [
     'TestActorPunning.cpp',
     'TestBadActor.cpp',
     'TestBridgeMain.cpp',
     'TestCrashCleanup.cpp',
     'TestDataStructures.cpp',
     'TestDesc.cpp',
     'TestFailedCtor.cpp',
     'TestHangs.cpp',
+    'TestHighestPrio.cpp',
     'TestInterruptErrorCleanup.cpp',
     'TestInterruptRaces.cpp',
     'TestInterruptShutdownRace.cpp',
     'TestJSON.cpp',
     'TestLatency.cpp',
     'TestManyChildAllocs.cpp',
     'TestMultiMgrs.cpp',
     'TestNestedLoops.cpp',
@@ -77,16 +78,17 @@ IPDL_SOURCES += [
     'PTestDesc.ipdl',
     'PTestDescSub.ipdl',
     'PTestDescSubsub.ipdl',
     'PTestFailedCtor.ipdl',
     'PTestFailedCtorSub.ipdl',
     'PTestFailedCtorSubsub.ipdl',
     'PTestHandle.ipdl',
     'PTestHangs.ipdl',
+    'PTestHighestPrio.ipdl',
     'PTestIndirectProtocolParam.ipdlh',
     'PTestIndirectProtocolParamFirst.ipdl',
     'PTestIndirectProtocolParamManage.ipdl',
     'PTestIndirectProtocolParamSecond.ipdl',
     'PTestInterruptErrorCleanup.ipdl',
     'PTestInterruptRaces.ipdl',
     'PTestInterruptShutdownRace.ipdl',
     'PTestJSON.ipdl',
--- a/ipc/testshell/PTestShell.ipdl
+++ b/ipc/testshell/PTestShell.ipdl
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PContent;
 include protocol PTestShellCommand;
 
 namespace mozilla {
 namespace ipc {
 
-intr protocol PTestShell
+async protocol PTestShell
 {
   manager PContent;
 
   manages PTestShellCommand;
 
 child:
   __delete__();
 
--- a/ipc/testshell/tests/xpcshell.ini
+++ b/ipc/testshell/tests/xpcshell.ini
@@ -1,10 +1,11 @@
 [DEFAULT]
 head = 
 tail = 
+skip-if = toolkit == 'android'
 
 [test_ipcshell.js]
 # Bug 676963: test fails consistently on Android
 fail-if = os == "android"
 skip-if = toolkit == "gonk"
 reason = bug 820380
 [test_ipcshell_child.js]
--- a/js/ductwork/debugger/tests/xpcshell.ini
+++ b/js/ductwork/debugger/tests/xpcshell.ini
@@ -1,7 +1,8 @@
 [DEFAULT]
 head = head_dbg.js
 tail =
+skip-if = toolkit == 'android' || toolkit == 'gonk'
 
 [test_nativewrappers.js]
 # Bug 685068
 fail-if = os == "android"
--- a/js/ipc/JavaScriptBase.h
+++ b/js/ipc/JavaScriptBase.h
@@ -30,199 +30,199 @@ class JavaScriptBase : public WrapperOwn
     virtual ~JavaScriptBase() {}
 
     virtual void ActorDestroy(WrapperOwner::ActorDestroyReason why) {
         WrapperOwner::ActorDestroy(why);
     }
 
     /*** IPC handlers ***/
 
-    bool AnswerPreventExtensions(const uint64_t &objId, ReturnStatus *rs) {
-        return Answer::AnswerPreventExtensions(ObjectId::deserialize(objId), rs);
+    bool RecvPreventExtensions(const uint64_t &objId, ReturnStatus *rs) {
+        return Answer::RecvPreventExtensions(ObjectId::deserialize(objId), rs);
     }
-    bool AnswerGetPropertyDescriptor(const uint64_t &objId, const JSIDVariant &id,
+    bool RecvGetPropertyDescriptor(const uint64_t &objId, const JSIDVariant &id,
                                      ReturnStatus *rs,
                                      PPropertyDescriptor *out) {
-        return Answer::AnswerGetPropertyDescriptor(ObjectId::deserialize(objId), id, rs, out);
+        return Answer::RecvGetPropertyDescriptor(ObjectId::deserialize(objId), id, rs, out);
     }
-    bool AnswerGetOwnPropertyDescriptor(const uint64_t &objId,
+    bool RecvGetOwnPropertyDescriptor(const uint64_t &objId,
                                         const JSIDVariant &id,
                                         ReturnStatus *rs,
                                         PPropertyDescriptor *out) {
-        return Answer::AnswerGetOwnPropertyDescriptor(ObjectId::deserialize(objId), id, rs, out);
+        return Answer::RecvGetOwnPropertyDescriptor(ObjectId::deserialize(objId), id, rs, out);
     }
-    bool AnswerDefineProperty(const uint64_t &objId, const JSIDVariant &id,
+    bool RecvDefineProperty(const uint64_t &objId, const JSIDVariant &id,
                               const PPropertyDescriptor &flags,
                               ReturnStatus *rs) {
-        return Answer::AnswerDefineProperty(ObjectId::deserialize(objId), id, flags, rs);
+        return Answer::RecvDefineProperty(ObjectId::deserialize(objId), id, flags, rs);
     }
-    bool AnswerDelete(const uint64_t &objId, const JSIDVariant &id,
+    bool RecvDelete(const uint64_t &objId, const JSIDVariant &id,
                       ReturnStatus *rs, bool *success) {
-        return Answer::AnswerDelete(ObjectId::deserialize(objId), id, rs, success);
+        return Answer::RecvDelete(ObjectId::deserialize(objId), id, rs, success);
     }
 
-    bool AnswerHas(const uint64_t &objId, const JSIDVariant &id,
+    bool RecvHas(const uint64_t &objId, const JSIDVariant &id,
                    ReturnStatus *rs, bool *bp) {
-        return Answer::AnswerHas(ObjectId::deserialize(objId), id, rs, bp);
+        return Answer::RecvHas(ObjectId::deserialize(objId), id, rs, bp);
     }
-    bool AnswerHasOwn(const uint64_t &objId, const JSIDVariant &id,
+    bool RecvHasOwn(const uint64_t &objId, const JSIDVariant &id,
                       ReturnStatus *rs, bool *bp) {
-        return Answer::AnswerHasOwn(ObjectId::deserialize(objId), id, rs, bp);
+        return Answer::RecvHasOwn(ObjectId::deserialize(objId), id, rs, bp);
     }
-    bool AnswerGet(const uint64_t &objId, const ObjectVariant &receiverVar,
+    bool RecvGet(const uint64_t &objId, const ObjectVariant &receiverVar,
                    const JSIDVariant &id,
                    ReturnStatus *rs, JSVariant *result) {
-        return Answer::AnswerGet(ObjectId::deserialize(objId), receiverVar, id, rs, result);
+        return Answer::RecvGet(ObjectId::deserialize(objId), receiverVar, id, rs, result);
     }
-    bool AnswerSet(const uint64_t &objId, const ObjectVariant &receiverVar,
+    bool RecvSet(const uint64_t &objId, const ObjectVariant &receiverVar,
                    const JSIDVariant &id, const bool &strict,
                    const JSVariant &value, ReturnStatus *rs, JSVariant *result) {
-        return Answer::AnswerSet(ObjectId::deserialize(objId), receiverVar, id, strict, value, rs, result);
+        return Answer::RecvSet(ObjectId::deserialize(objId), receiverVar, id, strict, value, rs, result);
     }
 
-    bool AnswerIsExtensible(const uint64_t &objId, ReturnStatus *rs,
+    bool RecvIsExtensible(const uint64_t &objId, ReturnStatus *rs,
                             bool *result) {
-        return Answer::AnswerIsExtensible(ObjectId::deserialize(objId), rs, result);
+        return Answer::RecvIsExtensible(ObjectId::deserialize(objId), rs, result);
     }
-    bool AnswerCallOrConstruct(const uint64_t &objId, const nsTArray<JSParam> &argv,
+    bool RecvCallOrConstruct(const uint64_t &objId, const nsTArray<JSParam> &argv,
                                const bool &construct, ReturnStatus *rs, JSVariant *result,
                                nsTArray<JSParam> *outparams) {
-        return Answer::AnswerCallOrConstruct(ObjectId::deserialize(objId), argv, construct, rs, result, outparams);
+        return Answer::RecvCallOrConstruct(ObjectId::deserialize(objId), argv, construct, rs, result, outparams);
     }
-    bool AnswerHasInstance(const uint64_t &objId, const JSVariant &v, ReturnStatus *rs, bool *bp) {
-        return Answer::AnswerHasInstance(ObjectId::deserialize(objId), v, rs, bp);
+    bool RecvHasInstance(const uint64_t &objId, const JSVariant &v, ReturnStatus *rs, bool *bp) {
+        return Answer::RecvHasInstance(ObjectId::deserialize(objId), v, rs, bp);
     }
-    bool AnswerObjectClassIs(const uint64_t &objId, const uint32_t &classValue,
+    bool RecvObjectClassIs(const uint64_t &objId, const uint32_t &classValue,
                              bool *result) {
-        return Answer::AnswerObjectClassIs(ObjectId::deserialize(objId), classValue, result);
+        return Answer::RecvObjectClassIs(ObjectId::deserialize(objId), classValue, result);
     }
-    bool AnswerClassName(const uint64_t &objId, nsString *result) {
-        return Answer::AnswerClassName(ObjectId::deserialize(objId), result);
+    bool RecvClassName(const uint64_t &objId, nsString *result) {
+        return Answer::RecvClassName(ObjectId::deserialize(objId), result);
     }
-    bool AnswerRegExpToShared(const uint64_t &objId, ReturnStatus *rs, nsString *source, uint32_t *flags) {
-        return Answer::AnswerRegExpToShared(ObjectId::deserialize(objId), rs, source, flags);
+    bool RecvRegExpToShared(const uint64_t &objId, ReturnStatus *rs, nsString *source, uint32_t *flags) {
+        return Answer::RecvRegExpToShared(ObjectId::deserialize(objId), rs, source, flags);
     }
 
-    bool AnswerGetPropertyNames(const uint64_t &objId, const uint32_t &flags,
+    bool RecvGetPropertyNames(const uint64_t &objId, const uint32_t &flags,
                                 ReturnStatus *rs, nsTArray<nsString> *names) {
-        return Answer::AnswerGetPropertyNames(ObjectId::deserialize(objId), flags, rs, names);
+        return Answer::RecvGetPropertyNames(ObjectId::deserialize(objId), flags, rs, names);
     }
-    bool AnswerInstanceOf(const uint64_t &objId, const JSIID &iid,
+    bool RecvInstanceOf(const uint64_t &objId, const JSIID &iid,
                           ReturnStatus *rs, bool *instanceof) {
-        return Answer::AnswerInstanceOf(ObjectId::deserialize(objId), iid, rs, instanceof);
+        return Answer::RecvInstanceOf(ObjectId::deserialize(objId), iid, rs, instanceof);
     }
-    bool AnswerDOMInstanceOf(const uint64_t &objId, const int &prototypeID, const int &depth,
+    bool RecvDOMInstanceOf(const uint64_t &objId, const int &prototypeID, const int &depth,
                              ReturnStatus *rs, bool *instanceof) {
-        return Answer::AnswerDOMInstanceOf(ObjectId::deserialize(objId), prototypeID, depth, rs, instanceof);
+        return Answer::RecvDOMInstanceOf(ObjectId::deserialize(objId), prototypeID, depth, rs, instanceof);
     }
 
-    bool AnswerIsCallable(const uint64_t &objId, bool *result) {
-        return Answer::AnswerIsCallable(ObjectId::deserialize(objId), result);
+    bool RecvIsCallable(const uint64_t &objId, bool *result) {
+        return Answer::RecvIsCallable(ObjectId::deserialize(objId), result);
     }
 
-    bool AnswerIsConstructor(const uint64_t &objId, bool *result) {
-        return Answer::AnswerIsConstructor(ObjectId::deserialize(objId), result);
+    bool RecvIsConstructor(const uint64_t &objId, bool *result) {
+        return Answer::RecvIsConstructor(ObjectId::deserialize(objId), result);
     }
 
     bool RecvDropObject(const uint64_t &objId) {
         return Answer::RecvDropObject(ObjectId::deserialize(objId));
     }
 
     /*** Dummy call handlers ***/
 
     bool SendDropObject(const ObjectId &objId) {
         return Base::SendDropObject(objId.serialize());
     }
-    bool CallPreventExtensions(const ObjectId &objId, ReturnStatus *rs) {
-        return Base::CallPreventExtensions(objId.serialize(), rs);
+    bool SendPreventExtensions(const ObjectId &objId, ReturnStatus *rs) {
+        return Base::SendPreventExtensions(objId.serialize(), rs);
     }
-    bool CallGetPropertyDescriptor(const ObjectId &objId, const JSIDVariant &id,
+    bool SendGetPropertyDescriptor(const ObjectId &objId, const JSIDVariant &id,
                                      ReturnStatus *rs,
                                      PPropertyDescriptor *out) {
-        return Base::CallGetPropertyDescriptor(objId.serialize(), id, rs, out);
+        return Base::SendGetPropertyDescriptor(objId.serialize(), id, rs, out);
     }
-    bool CallGetOwnPropertyDescriptor(const ObjectId &objId,
+    bool SendGetOwnPropertyDescriptor(const ObjectId &objId,
                                       const JSIDVariant &id,
                                       ReturnStatus *rs,
                                       PPropertyDescriptor *out) {
-        return Base::CallGetOwnPropertyDescriptor(objId.serialize(), id, rs, out);
+        return Base::SendGetOwnPropertyDescriptor(objId.serialize(), id, rs, out);
     }
-    bool CallDefineProperty(const ObjectId &objId, const JSIDVariant &id,
+    bool SendDefineProperty(const ObjectId &objId, const JSIDVariant &id,
                             const PPropertyDescriptor &flags,
                               ReturnStatus *rs) {
-        return Base::CallDefineProperty(objId.serialize(), id, flags, rs);
+        return Base::SendDefineProperty(objId.serialize(), id, flags, rs);
     }
-    bool CallDelete(const ObjectId &objId, const JSIDVariant &id,
+    bool SendDelete(const ObjectId &objId, const JSIDVariant &id,
                     ReturnStatus *rs, bool *success) {
-        return Base::CallDelete(objId.serialize(), id, rs, success);
+        return Base::SendDelete(objId.serialize(), id, rs, success);
     }
 
-    bool CallHas(const ObjectId &objId, const JSIDVariant &id,
+    bool SendHas(const ObjectId &objId, const JSIDVariant &id,
                    ReturnStatus *rs, bool *bp) {
-        return Base::CallHas(objId.serialize(), id, rs, bp);
+        return Base::SendHas(objId.serialize(), id, rs, bp);
     }
-    bool CallHasOwn(const ObjectId &objId, const JSIDVariant &id,
+    bool SendHasOwn(const ObjectId &objId, const JSIDVariant &id,
                     ReturnStatus *rs, bool *bp) {
-        return Base::CallHasOwn(objId.serialize(), id, rs, bp);
+        return Base::SendHasOwn(objId.serialize(), id, rs, bp);
     }
-    bool CallGet(const ObjectId &objId, const ObjectVariant &receiverVar,
+    bool SendGet(const ObjectId &objId, const ObjectVariant &receiverVar,
                  const JSIDVariant &id,
                  ReturnStatus *rs, JSVariant *result) {
-        return Base::CallGet(objId.serialize(), receiverVar, id, rs, result);
+        return Base::SendGet(objId.serialize(), receiverVar, id, rs, result);
     }
-    bool CallSet(const ObjectId &objId, const ObjectVariant &receiverVar,
+    bool SendSet(const ObjectId &objId, const ObjectVariant &receiverVar,
                  const JSIDVariant &id, const bool &strict,
                  const JSVariant &value, ReturnStatus *rs, JSVariant *result) {
-        return Base::CallSet(objId.serialize(), receiverVar, id, strict, value, rs, result);
+        return Base::SendSet(objId.serialize(), receiverVar, id, strict, value, rs, result);
     }
 
-    bool CallIsExtensible(const ObjectId &objId, ReturnStatus *rs,
+    bool SendIsExtensible(const ObjectId &objId, ReturnStatus *rs,
                           bool *result) {
-        return Base::CallIsExtensible(objId.serialize(), rs, result);
+        return Base::SendIsExtensible(objId.serialize(), rs, result);
     }
-    bool CallCallOrConstruct(const ObjectId &objId, const nsTArray<JSParam> &argv,
+    bool SendCallOrConstruct(const ObjectId &objId, const nsTArray<JSParam> &argv,
                              const bool &construct, ReturnStatus *rs, JSVariant *result,
                              nsTArray<JSParam> *outparams) {
-        return Base::CallCallOrConstruct(objId.serialize(), argv, construct, rs, result, outparams);
+        return Base::SendCallOrConstruct(objId.serialize(), argv, construct, rs, result, outparams);
     }
-    bool CallHasInstance(const ObjectId &objId, const JSVariant &v, ReturnStatus *rs, bool *bp) {
-        return Base::CallHasInstance(objId.serialize(), v, rs, bp);
+    bool SendHasInstance(const ObjectId &objId, const JSVariant &v, ReturnStatus *rs, bool *bp) {
+        return Base::SendHasInstance(objId.serialize(), v, rs, bp);
     }
-    bool CallObjectClassIs(const ObjectId &objId, const uint32_t &classValue,
+    bool SendObjectClassIs(const ObjectId &objId, const uint32_t &classValue,
                            bool *result) {
-        return Base::CallObjectClassIs(objId.serialize(), classValue, result);
+        return Base::SendObjectClassIs(objId.serialize(), classValue, result);
     }
-    bool CallClassName(const ObjectId &objId, nsString *result) {
-        return Base::CallClassName(objId.serialize(), result);
+    bool SendClassName(const ObjectId &objId, nsString *result) {
+        return Base::SendClassName(objId.serialize(), result);
     }
 
-    bool CallRegExpToShared(const ObjectId &objId, ReturnStatus *rs,
+    bool SendRegExpToShared(const ObjectId &objId, ReturnStatus *rs,
                             nsString *source, uint32_t *flags) {
-        return Base::CallRegExpToShared(objId.serialize(), rs, source, flags);
+        return Base::SendRegExpToShared(objId.serialize(), rs, source, flags);
     }
 
-    bool CallGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
+    bool SendGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
                               ReturnStatus *rs, nsTArray<nsString> *names) {
-        return Base::CallGetPropertyNames(objId.serialize(), flags, rs, names);
+        return Base::SendGetPropertyNames(objId.serialize(), flags, rs, names);
     }
-    bool CallInstanceOf(const ObjectId &objId, const JSIID &iid,
+    bool SendInstanceOf(const ObjectId &objId, const JSIID &iid,
                         ReturnStatus *rs, bool *instanceof) {
-        return Base::CallInstanceOf(objId.serialize(), iid, rs, instanceof);
+        return Base::SendInstanceOf(objId.serialize(), iid, rs, instanceof);
     }
-    bool CallDOMInstanceOf(const ObjectId &objId, const int &prototypeID, const int &depth,
+    bool SendDOMInstanceOf(const ObjectId &objId, const int &prototypeID, const int &depth,
                            ReturnStatus *rs, bool *instanceof) {
-        return Base::CallDOMInstanceOf(objId.serialize(), prototypeID, depth, rs, instanceof);
+        return Base::SendDOMInstanceOf(objId.serialize(), prototypeID, depth, rs, instanceof);
     }
 
-    bool CallIsCallable(const ObjectId &objId, bool *result) {
-        return Base::CallIsCallable(objId.serialize(), result);
+    bool SendIsCallable(const ObjectId &objId, bool *result) {
+        return Base::SendIsCallable(objId.serialize(), result);
     }
 
-    bool CallIsConstructor(const ObjectId &objId, bool *result) {
-        return Base::CallIsConstructor(objId.serialize(), result);
+    bool SendIsConstructor(const ObjectId &objId, bool *result) {
+        return Base::SendIsConstructor(objId.serialize(), result);
     }
 
     /* The following code is needed to suppress a bogus MSVC warning (C4250). */
 
     virtual bool toObjectVariant(JSContext *cx, JSObject *obj, ObjectVariant *objVarp) {
         return WrapperOwner::toObjectVariant(cx, obj, objVarp);
     }
     virtual JSObject *fromObjectVariant(JSContext *cx, ObjectVariant objVar) {
--- a/js/ipc/PJavaScript.ipdl
+++ b/js/ipc/PJavaScript.ipdl
@@ -10,48 +10,48 @@ include protocol PContentBridge;
 include DOMTypes;
 include JavaScriptTypes;
 
 using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 
 namespace mozilla {
 namespace jsipc {
 
-intr protocol PJavaScript
+prio(normal upto high) sync protocol PJavaScript
 {
     manager PContent or PContentBridge;
 
 both:
     // Sent when a CPOW has been finalized and table entries can be freed up.
     async DropObject(uint64_t objId);
 
     // These roughly map to the ProxyHandler hooks that CPOWs need.
-    rpc PreventExtensions(uint64_t objId) returns (ReturnStatus rs);
-    rpc GetPropertyDescriptor(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, PPropertyDescriptor result);
-    rpc GetOwnPropertyDescriptor(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, PPropertyDescriptor result);
-    rpc DefineProperty(uint64_t objId, JSIDVariant id, PPropertyDescriptor descriptor) returns (ReturnStatus rs);
-    rpc Delete(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool successful);
+    prio(high) sync PreventExtensions(uint64_t objId) returns (ReturnStatus rs);
+    prio(high) sync GetPropertyDescriptor(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, PPropertyDescriptor result);
+    prio(high) sync GetOwnPropertyDescriptor(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, PPropertyDescriptor result);
+    prio(high) sync DefineProperty(uint64_t objId, JSIDVariant id, PPropertyDescriptor descriptor) returns (ReturnStatus rs);
+    prio(high) sync Delete(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool successful);
 
-    rpc Has(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool has);
-    rpc HasOwn(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool has);
-    rpc Get(uint64_t objId, ObjectVariant receiver, JSIDVariant id) returns (ReturnStatus rs, JSVariant result);
-    rpc Set(uint64_t objId, ObjectVariant receiver, JSIDVariant id, bool strict, JSVariant value) returns (ReturnStatus rs, JSVariant result);
+    prio(high) sync Has(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool has);
+    prio(high) sync HasOwn(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool has);
+    prio(high) sync Get(uint64_t objId, ObjectVariant receiver, JSIDVariant id) returns (ReturnStatus rs, JSVariant result);
+    prio(high) sync Set(uint64_t objId, ObjectVariant receiver, JSIDVariant id, bool strict, JSVariant value) returns (ReturnStatus rs, JSVariant result);
 
-    rpc IsExtensible(uint64_t objId) returns (ReturnStatus rs, bool result);
-    rpc CallOrConstruct(uint64_t objId, JSParam[] argv, bool construct) returns (ReturnStatus rs, JSVariant result, JSParam[] outparams);
-    rpc HasInstance(uint64_t objId, JSVariant v) returns (ReturnStatus rs, bool has);
-    rpc ObjectClassIs(uint64_t objId, uint32_t classValue) returns (bool result);
-    rpc ClassName(uint64_t objId) returns (nsString name);
-    rpc RegExpToShared(uint64_t objId) returns (ReturnStatus rs, nsString source, uint32_t flags);
+    prio(high) sync IsExtensible(uint64_t objId) returns (ReturnStatus rs, bool result);
+    prio(high) sync CallOrConstruct(uint64_t objId, JSParam[] argv, bool construct) returns (ReturnStatus rs, JSVariant result, JSParam[] outparams);
+    prio(high) sync HasInstance(uint64_t objId, JSVariant v) returns (ReturnStatus rs, bool has);
+    prio(high) sync ObjectClassIs(uint64_t objId, uint32_t classValue) returns (bool result);
+    prio(high) sync ClassName(uint64_t objId) returns (nsString name);
+    prio(high) sync RegExpToShared(uint64_t objId) returns (ReturnStatus rs, nsString source, uint32_t flags);
 
-    rpc GetPropertyNames(uint64_t objId, uint32_t flags) returns (ReturnStatus rs, nsString[] names);
-    rpc InstanceOf(uint64_t objId, JSIID iid) returns (ReturnStatus rs, bool instanceof);
-    rpc DOMInstanceOf(uint64_t objId, int prototypeID, int depth) returns (ReturnStatus rs, bool instanceof);
+    prio(high) sync GetPropertyNames(uint64_t objId, uint32_t flags) returns (ReturnStatus rs, nsString[] names);
+    prio(high) sync InstanceOf(uint64_t objId, JSIID iid) returns (ReturnStatus rs, bool instanceof);
+    prio(high) sync DOMInstanceOf(uint64_t objId, int prototypeID, int depth) returns (ReturnStatus rs, bool instanceof);
 
-    rpc IsCallable(uint64_t objId) returns (bool result);
-    rpc IsConstructor(uint64_t objId) returns (bool result);
+    prio(high) sync IsCallable(uint64_t objId) returns (bool result);
+    prio(high) sync IsConstructor(uint64_t objId) returns (bool result);
 
 parent:
     async __delete__();
 };
 
 }
 }
--- a/js/ipc/WrapperAnswer.cpp
+++ b/js/ipc/WrapperAnswer.cpp
@@ -53,17 +53,17 @@ WrapperAnswer::fail(JSContext *cx, Retur
 bool
 WrapperAnswer::ok(ReturnStatus *rs)
 {
     *rs = ReturnStatus(ReturnSuccess());
     return true;
 }
 
 bool
-WrapperAnswer::AnswerPreventExtensions(const ObjectId &objId, ReturnStatus *rs)
+WrapperAnswer::RecvPreventExtensions(const ObjectId &objId, ReturnStatus *rs)
 {
     AutoSafeJSContext cx;
     JSAutoRequest request(cx);
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
         return fail(cx, rs);
 
@@ -82,18 +82,18 @@ EmptyDesc(PPropertyDescriptor *desc)
     desc->obj() = LocalObject(0);
     desc->attrs() = 0;
     desc->value() = UndefinedVariant();
     desc->getter() = 0;
     desc->setter() = 0;
 }
 
 bool
-WrapperAnswer::AnswerGetPropertyDescriptor(const ObjectId &objId, const JSIDVariant &idVar,
-                                           ReturnStatus *rs, PPropertyDescriptor *out)
+WrapperAnswer::RecvGetPropertyDescriptor(const ObjectId &objId, const JSIDVariant &idVar,
+                                         ReturnStatus *rs, PPropertyDescriptor *out)
 {
     AutoSafeJSContext cx;
     JSAutoRequest request(cx);
 
     EmptyDesc(out);
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
@@ -116,18 +116,18 @@ WrapperAnswer::AnswerGetPropertyDescript
 
     if (!fromDescriptor(cx, desc, out))
         return fail(cx, rs);
 
     return ok(rs);
 }
 
 bool
-WrapperAnswer::AnswerGetOwnPropertyDescriptor(const ObjectId &objId, const JSIDVariant &idVar,
-                                              ReturnStatus *rs, PPropertyDescriptor *out)
+WrapperAnswer::RecvGetOwnPropertyDescriptor(const ObjectId &objId, const JSIDVariant &idVar,
+                                            ReturnStatus *rs, PPropertyDescriptor *out)
 {
     AutoSafeJSContext cx;
     JSAutoRequest request(cx);
 
     EmptyDesc(out);
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
@@ -150,18 +150,18 @@ WrapperAnswer::AnswerGetOwnPropertyDescr
 
     if (!fromDescriptor(cx, desc, out))
         return fail(cx, rs);
 
     return ok(rs);
 }
 
 bool
-WrapperAnswer::AnswerDefineProperty(const ObjectId &objId, const JSIDVariant &idVar,
-                                    const PPropertyDescriptor &descriptor, ReturnStatus *rs)
+WrapperAnswer::RecvDefineProperty(const ObjectId &objId, const JSIDVariant &idVar,
+                                  const PPropertyDescriptor &descriptor, ReturnStatus *rs)
 {
     AutoSafeJSContext cx;
     JSAutoRequest request(cx);
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
         return fail(cx, rs);
 
@@ -188,18 +188,18 @@ WrapperAnswer::AnswerDefineProperty(cons
     {
         return fail(cx, rs);
     }
 
     return ok(rs);
 }
 
 bool
-WrapperAnswer::AnswerDelete(const ObjectId &objId, const JSIDVariant &idVar, ReturnStatus *rs,
-                            bool *success)
+WrapperAnswer::RecvDelete(const ObjectId &objId, const JSIDVariant &idVar, ReturnStatus *rs,
+                          bool *success)
 {
     AutoSafeJSContext cx;
     JSAutoRequest request(cx);
 
     *success = false;
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
@@ -215,17 +215,17 @@ WrapperAnswer::AnswerDelete(const Object
 
     if (!JS_DeletePropertyById2(cx, obj, id, success))
         return fail(cx, rs);
 
     return ok(rs);
 }
 
 bool
-WrapperAnswer::AnswerHas(const ObjectId &objId, const JSIDVariant &idVar, ReturnStatus *rs, bool *bp)
+WrapperAnswer::RecvHas(const ObjectId &objId, const JSIDVariant &idVar, ReturnStatus *rs, bool *bp)
 {
     AutoSafeJSContext cx;
     JSAutoRequest request(cx);
 
     *bp = false;
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
@@ -243,18 +243,18 @@ WrapperAnswer::AnswerHas(const ObjectId 
     if (!JS_HasPropertyById(cx, obj, id, &found))
         return fail(cx, rs);
     *bp = !!found;
 
     return ok(rs);
 }
 
 bool
-WrapperAnswer::AnswerHasOwn(const ObjectId &objId, const JSIDVariant &idVar, ReturnStatus *rs,
-                            bool *bp)
+WrapperAnswer::RecvHasOwn(const ObjectId &objId, const JSIDVariant &idVar, ReturnStatus *rs,
+                          bool *bp)
 {
     AutoSafeJSContext cx;
     JSAutoRequest request(cx);
 
     *bp = false;
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
@@ -272,18 +272,18 @@ WrapperAnswer::AnswerHasOwn(const Object
     if (!JS_GetPropertyDescriptorById(cx, obj, id, &desc))
         return fail(cx, rs);
     *bp = (desc.object() == obj);
 
     return ok(rs);
 }
 
 bool
-WrapperAnswer::AnswerGet(const ObjectId &objId, const ObjectVariant &receiverVar,
-                         const JSIDVariant &idVar, ReturnStatus *rs, JSVariant *result)
+WrapperAnswer::RecvGet(const ObjectId &objId, const ObjectVariant &receiverVar,
+                       const JSIDVariant &idVar, ReturnStatus *rs, JSVariant *result)
 {
     AutoSafeJSContext cx;
     JSAutoRequest request(cx);
 
     // The outparam will be written to the buffer, so it must be set even if
     // the parent won't read it.
     *result = UndefinedVariant();
 
@@ -309,19 +309,19 @@ WrapperAnswer::AnswerGet(const ObjectId 
         return fail(cx, rs);
 
     LOG("get %s.%s = %s", ReceiverObj(objId), Identifier(idVar), OutVariant(*result));
 
     return ok(rs);
 }
 
 bool
-WrapperAnswer::AnswerSet(const ObjectId &objId, const ObjectVariant &receiverVar,
-                         const JSIDVariant &idVar, const bool &strict, const JSVariant &value,
-                         ReturnStatus *rs, JSVariant *result)
+WrapperAnswer::RecvSet(const ObjectId &objId, const ObjectVariant &receiverVar,
+                       const JSIDVariant &idVar, const bool &strict, const JSVariant &value,
+                       ReturnStatus *rs, JSVariant *result)
 {
     AutoSafeJSContext cx;
     JSAutoRequest request(cx);
 
     // The outparam will be written to the buffer, so it must be set even if
     // the parent won't read it.
     *result = UndefinedVariant();
 
@@ -352,17 +352,17 @@ WrapperAnswer::AnswerSet(const ObjectId 
 
     if (!toVariant(cx, val, result))
         return fail(cx, rs);
 
     return ok(rs);
 }
 
 bool
-WrapperAnswer::AnswerIsExtensible(const ObjectId &objId, ReturnStatus *rs, bool *result)
+WrapperAnswer::RecvIsExtensible(const ObjectId &objId, ReturnStatus *rs, bool *result)
 {
     AutoSafeJSContext cx;
     JSAutoRequest request(cx);
 
     *result = false;
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
@@ -376,22 +376,22 @@ WrapperAnswer::AnswerIsExtensible(const 
     if (!JS_IsExtensible(cx, obj, &extensible))
         return fail(cx, rs);
 
     *result = !!extensible;
     return ok(rs);
 }
 
 bool
-WrapperAnswer::AnswerCallOrConstruct(const ObjectId &objId,
-                                     const nsTArray<JSParam> &argv,
-                                     const bool &construct,
-                                     ReturnStatus *rs,
-                                     JSVariant *result,
-                                     nsTArray<JSParam> *outparams)
+WrapperAnswer::RecvCallOrConstruct(const ObjectId &objId,
+                                   const nsTArray<JSParam> &argv,
+                                   const bool &construct,
+                                   ReturnStatus *rs,
+                                   JSVariant *result,
+                                   nsTArray<JSParam> *outparams)
 {
     AutoSafeJSContext cx;
     JSAutoRequest request(cx);
 
     // The outparam will be written to the buffer, so it must be set even if
     // the parent won't read it.
     *result = UndefinedVariant();
 
@@ -483,17 +483,17 @@ WrapperAnswer::AnswerCallOrConstruct(con
     }
 
     LOG("%s.call(%s) = %s", ReceiverObj(objId), argv, OutVariant(*result));
 
     return ok(rs);
 }
 
 bool
-WrapperAnswer::AnswerHasInstance(const ObjectId &objId, const JSVariant &vVar, ReturnStatus *rs, bool *bp)
+WrapperAnswer::RecvHasInstance(const ObjectId &objId, const JSVariant &vVar, ReturnStatus *rs, bool *bp)
 {
     AutoSafeJSContext cx;
     JSAutoRequest request(cx);
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
         return fail(cx, rs);
 
@@ -507,18 +507,18 @@ WrapperAnswer::AnswerHasInstance(const O
 
     if (!JS_HasInstance(cx, obj, val, bp))
         return fail(cx, rs);
 
     return ok(rs);
 }
 
 bool
-WrapperAnswer::AnswerObjectClassIs(const ObjectId &objId, const uint32_t &classValue,
-                                   bool *result)
+WrapperAnswer::RecvObjectClassIs(const ObjectId &objId, const uint32_t &classValue,
+                                 bool *result)
 {
     AutoSafeJSContext cx;
     JSAutoRequest request(cx);
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj) {
         // This is very unfortunate, but we have no choice.
         *result = false;
@@ -529,17 +529,17 @@ WrapperAnswer::AnswerObjectClassIs(const
 
     LOG("%s.objectClassIs()", ReceiverObj(objId));
 
     *result = js_ObjectClassIs(cx, obj, (js::ESClassValue)classValue);
     return true;
 }
 
 bool
-WrapperAnswer::AnswerClassName(const ObjectId &objId, nsString *name)
+WrapperAnswer::RecvClassName(const ObjectId &objId, nsString *name)
 {
     AutoSafeJSContext cx;
     JSAutoRequest request(cx);
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj) {
         // This is very unfortunate, but we have no choice.
         return "<dead CPOW>";
@@ -549,18 +549,18 @@ WrapperAnswer::AnswerClassName(const Obj
 
     LOG("%s.className()", ReceiverObj(objId));
 
     *name = NS_ConvertASCIItoUTF16(js_ObjectClassName(cx, obj));
     return true;
 }
 
 bool
-WrapperAnswer::AnswerRegExpToShared(const ObjectId &objId, ReturnStatus *rs,
-                                    nsString *source, uint32_t *flags)
+WrapperAnswer::RecvRegExpToShared(const ObjectId &objId, ReturnStatus *rs,
+                                  nsString *source, uint32_t *flags)
 {
     AutoSafeJSContext cx;
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
         return fail(cx, rs);
 
     JSAutoCompartment ac(cx, obj);
     MOZ_RELEASE_ASSERT(JS_ObjectIsRegExp(cx, obj));
@@ -574,18 +574,18 @@ WrapperAnswer::AnswerRegExpToShared(cons
     source->Assign(sourceStr);
 
     *flags = JS_GetRegExpFlags(cx, obj);
 
     return ok(rs);
 }
 
 bool
-WrapperAnswer::AnswerGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
-                                      ReturnStatus *rs, nsTArray<nsString> *names)
+WrapperAnswer::RecvGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
+                                    ReturnStatus *rs, nsTArray<nsString> *names)
 {
     AutoSafeJSContext cx;
     JSAutoRequest request(cx);
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
         return fail(cx, rs);
 
@@ -604,18 +604,18 @@ WrapperAnswer::AnswerGetPropertyNames(co
 
         names->AppendElement(name);
     }
 
     return ok(rs);
 }
 
 bool
-WrapperAnswer::AnswerInstanceOf(const ObjectId &objId, const JSIID &iid, ReturnStatus *rs,
-                                bool *instanceof)
+WrapperAnswer::RecvInstanceOf(const ObjectId &objId, const JSIID &iid, ReturnStatus *rs,
+                              bool *instanceof)
 {
     AutoSafeJSContext cx;
     JSAutoRequest request(cx);
 
     *instanceof = false;
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
@@ -631,18 +631,18 @@ WrapperAnswer::AnswerInstanceOf(const Ob
     nsresult rv = xpc::HasInstance(cx, obj, &nsiid, instanceof);
     if (rv != NS_OK)
         return fail(cx, rs);
 
     return ok(rs);
 }
 
 bool
-WrapperAnswer::AnswerDOMInstanceOf(const ObjectId &objId, const int &prototypeID,
-                                   const int &depth, ReturnStatus *rs, bool *instanceof)
+WrapperAnswer::RecvDOMInstanceOf(const ObjectId &objId, const int &prototypeID,
+                                 const int &depth, ReturnStatus *rs, bool *instanceof)
 {
     AutoSafeJSContext cx;
     JSAutoRequest request(cx);
 
     *instanceof = false;
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
@@ -656,17 +656,17 @@ WrapperAnswer::AnswerDOMInstanceOf(const
     if (!mozilla::dom::InterfaceHasInstance(cx, prototypeID, depth, obj, &tmp))
         return fail(cx, rs);
     *instanceof = tmp;
 
     return ok(rs);
 }
 
 bool
-WrapperAnswer::AnswerIsCallable(const ObjectId &objId, bool *result)
+WrapperAnswer::RecvIsCallable(const ObjectId &objId, bool *result)
 {
     AutoSafeJSContext cx;
     JSAutoRequest request(cx);
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj) {
         // This is very unfortunate, but we have no choice.
         *result = false;
@@ -676,17 +676,17 @@ WrapperAnswer::AnswerIsCallable(const Ob
 
     LOG("%s.isCallable()", ReceiverObj(objId));
 
     *result = JS::IsCallable(obj);
     return true;
 }
 
 bool
-WrapperAnswer::AnswerIsConstructor(const ObjectId &objId, bool *result)
+WrapperAnswer::RecvIsConstructor(const ObjectId &objId, bool *result)
 {
     AutoSafeJSContext cx;
     JSAutoRequest request(cx);
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj) {
         // This is very unfortunate, but we have no choice.
         *result = false;
--- a/js/ipc/WrapperAnswer.h
+++ b/js/ipc/WrapperAnswer.h
@@ -13,61 +13,61 @@
 namespace mozilla {
 namespace jsipc {
 
 class WrapperAnswer : public virtual JavaScriptShared
 {
   public:
     explicit WrapperAnswer(JSRuntime *rt) : JavaScriptShared(rt) {}
 
-    bool AnswerPreventExtensions(const ObjectId &objId, ReturnStatus *rs);
-    bool AnswerGetPropertyDescriptor(const ObjectId &objId, const JSIDVariant &id,
-                                     ReturnStatus *rs,
-                                     PPropertyDescriptor *out);
-    bool AnswerGetOwnPropertyDescriptor(const ObjectId &objId,
-                                        const JSIDVariant &id,
-                                        ReturnStatus *rs,
-                                        PPropertyDescriptor *out);
-    bool AnswerDefineProperty(const ObjectId &objId, const JSIDVariant &id,
-                              const PPropertyDescriptor &flags,
-                              ReturnStatus *rs);
-    bool AnswerDelete(const ObjectId &objId, const JSIDVariant &id,
-                      ReturnStatus *rs, bool *success);
+    bool RecvPreventExtensions(const ObjectId &objId, ReturnStatus *rs);
+    bool RecvGetPropertyDescriptor(const ObjectId &objId, const JSIDVariant &id,
+                                   ReturnStatus *rs,
+                                   PPropertyDescriptor *out);
+    bool RecvGetOwnPropertyDescriptor(const ObjectId &objId,
+                                      const JSIDVariant &id,
+                                      ReturnStatus *rs,
+                                      PPropertyDescriptor *out);
+    bool RecvDefineProperty(const ObjectId &objId, const JSIDVariant &id,
+                            const PPropertyDescriptor &flags,
+                            ReturnStatus *rs);
+    bool RecvDelete(const ObjectId &a