Merge the last PGO-green inbound changeset to m-c.
authorWes Kocher <wkocher@mozilla.com>
Mon, 22 Apr 2013 18:47:53 -0700
changeset 140442 acf388eaf9e91f948ac95131c8860fdb8aecd68d
parent 140415 f59811fe0fb3d303fd20abc4e10432488c3d3db5 (current diff)
parent 140441 dfc1cd702c6e7acb25e5f38af7f0c54ae9ffe2c3 (diff)
child 140494 1d7335eac2a743264cf7472957682ab875b7fa9c
child 140519 1071ca655e43ab8be7da42762200857f50e0cf1e
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone23.0a1
first release with
nightly linux32
acf388eaf9e9 / 23.0a1 / 20130423030935 / files
nightly linux64
acf388eaf9e9 / 23.0a1 / 20130423030935 / files
nightly mac
acf388eaf9e9 / 23.0a1 / 20130423030935 / files
nightly win32
acf388eaf9e9 / 23.0a1 / 20130423030935 / files
nightly win64
acf388eaf9e9 / 23.0a1 / 20130423030935 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge the last PGO-green inbound changeset to m-c.
gfx/layers/ipc/PLayers.ipdl
gfx/layers/ipc/ShadowLayersChild.cpp
gfx/layers/ipc/ShadowLayersChild.h
gfx/layers/ipc/ShadowLayersParent.cpp
gfx/layers/ipc/ShadowLayersParent.h
--- a/accessible/src/generic/HyperTextAccessible.cpp
+++ b/accessible/src/generic/HyperTextAccessible.cpp
@@ -1824,18 +1824,20 @@ HyperTextAccessible::FrameSelection()
   nsIFrame* frame = GetFrame();
   return frame ? frame->GetFrameSelection() : nullptr;
 }
 
 void
 HyperTextAccessible::GetSelectionDOMRanges(int16_t aType,
                                            nsTArray<nsRange*>* aRanges)
 {
+  // Ignore selection if it is not visible.
   nsRefPtr<nsFrameSelection> frameSelection = FrameSelection();
-  if (!frameSelection)
+  if (!frameSelection ||
+      frameSelection->GetDisplaySelection() <= nsISelectionController::SELECTION_HIDDEN)
     return;
 
   Selection* domSel = frameSelection->GetSelection(aType);
   if (!domSel)
     return;
 
   nsCOMPtr<nsINode> startNode = GetNode();
 
--- a/accessible/tests/mochitest/textselection/Makefile.in
+++ b/accessible/tests/mochitest/textselection/Makefile.in
@@ -8,11 +8,12 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir	= @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_A11Y_FILES = \
 		test_general.html \
+		test_userinput.html \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/textselection/test_userinput.html
@@ -0,0 +1,95 @@
+<html>
+
+<head>
+  <title>Text selection by user input</title>
+
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../role.js"></script>
+  <script type="application/javascript"
+          src="../states.js"></script>
+  <script type="application/javascript"
+          src="../events.js"></script>
+
+  <script type="application/javascript">
+    /**
+     * Invokers
+     */
+    function synthTabAndCheckPrevTabbed(aID, aPrevID)
+    {
+      this.__proto__ = new synthTab(aID, new focusChecker(aID));
+
+      this.finalCheck = function changeSelection_finalCheck()
+      {
+        var prevTabbed = getAccessible(aPrevID, [ nsIAccessibleText ]);
+        is(prevTabbed.selectionCount, 0,
+           "Wrong selection count for " + aPrevID);
+
+        var exceptionCaught = false;
+        try {
+          var startOffsetObj = {}, endOffsetObj = {};
+          prevTabbed.getSelectionBounds(0, startOffsetObj, endOffsetObj);
+        } catch (e) {
+          exceptionCaught = true;
+        }
+
+        ok(exceptionCaught, "No selection was expected for " + aPrevID);
+      }
+
+      this.getID = function changeSelection_getID()
+      {
+        return "Hidden selection check for " + aPrevID;
+      }
+    }
+
+    /**
+     * Do tests
+     */
+
+    //gA11yEventDumpToConsole = true; // debug stuff
+
+    var gQueue = null;
+    function doTests()
+    {
+      gQueue = new eventQueue();
+
+      // Tab to 't2' and then tab out it: it must has no selection.
+      gQueue.push(new synthFocus("t1"));
+      gQueue.push(new synthTab("t2", new focusChecker("t2")));
+      gQueue.push(new synthTabAndCheckPrevTabbed("t3", "t2"));
+
+      gQueue.invoke(); // Will call SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTests);
+  </script>
+</head>
+
+<body>
+
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=440590"
+     title="Text selection information is not updated when HTML and XUL entries lose focus">
+    Bug 440590
+  </a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <input type="text" id="t1" maxlength="3" size="3" value="1">
+  <input type="text" id="t2" maxlength="3" size="3" value="1">
+  <input type="text" id="t3" maxlength="3" size="3" value="1">
+
+</body>
+</html>
--- a/content/media/webaudio/AnalyserNode.cpp
+++ b/content/media/webaudio/AnalyserNode.cpp
@@ -72,21 +72,16 @@ AnalyserNode::AnalyserNode(AudioContext*
   , mSmoothingTimeConstant(.8)
   , mWriteIndex(0)
 {
   mStream = aContext->Graph()->CreateAudioNodeStream(new AnalyserNodeEngine(this),
                                                      MediaStreamGraph::INTERNAL_STREAM);
   AllocateBuffer();
 }
 
-AnalyserNode::~AnalyserNode()
-{
-  DestroyMediaStream();
-}
-
 JSObject*
 AnalyserNode::WrapObject(JSContext* aCx, JSObject* aScope)
 {
   return AnalyserNodeBinding::Wrap(aCx, aScope, this);
 }
 
 void
 AnalyserNode::SetFftSize(uint32_t aValue, ErrorResult& aRv)
@@ -238,22 +233,16 @@ AnalyserNode::ApplyBlackmanWindow(float*
 
   for (uint32_t i = 0; i < aSize; ++i) {
     double x = double(i) / aSize;
     double window = a0 - a1 * cos(2 * M_PI * x) + a2 * cos(4 * M_PI * x);
     aBuffer[i] *= window;
   }
 }
 
-void
-AnalyserNode::DestroyMediaStream()
-{
-  AudioNode::DestroyMediaStream();
-}
-
 bool
 AnalyserNode::AllocateBuffer()
 {
   bool result = true;
   if (mBuffer.Length() != mFFTSize) {
     result = mBuffer.SetLength(mFFTSize);
     if (result) {
       memset(mBuffer.Elements(), 0, sizeof(float) * mFFTSize);
--- a/content/media/webaudio/AnalyserNode.h
+++ b/content/media/webaudio/AnalyserNode.h
@@ -13,29 +13,26 @@ namespace mozilla {
 namespace dom {
 
 class AudioContext;
 
 class AnalyserNode : public AudioNode
 {
 public:
   explicit AnalyserNode(AudioContext* aContext);
-  virtual ~AnalyserNode();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope);
 
   virtual bool SupportsMediaStreams() const MOZ_OVERRIDE
   {
     return true;
   }
 
-  virtual void DestroyMediaStream() MOZ_OVERRIDE;
-
   void GetFloatFrequencyData(Float32Array& aArray);
   void GetByteFrequencyData(Uint8Array& aArray);
   void GetByteTimeDomainData(Uint8Array& aArray);
   uint32_t FftSize() const
   {
     return mFFTSize;
   }
   void SetFftSize(uint32_t aValue, ErrorResult& aRv);
--- a/content/media/webaudio/AudioBuffer.cpp
+++ b/content/media/webaudio/AudioBuffer.cpp
@@ -160,24 +160,21 @@ StealJSArrayDataIntoThreadSharedFloatArr
       result->Clear();
       return result.forget();
     }
   }
   return result.forget();
 }
 
 ThreadSharedFloatArrayBufferList*
-AudioBuffer::GetThreadSharedChannelsForRate(JSContext* aJSContext, uint32_t* aRate,
-                                            uint32_t* aLength)
+AudioBuffer::GetThreadSharedChannelsForRate(JSContext* aJSContext)
 {
   if (!mSharedChannels) {
     // Steal JS data
     mSharedChannels =
       StealJSArrayDataIntoThreadSharedFloatArrayBufferList(aJSContext, mJSChannels);
   }
 
-  *aLength = mLength;
-  *aRate = mSampleRate;
   return mSharedChannels;
 }
 
 }
 }
--- a/content/media/webaudio/AudioBuffer.h
+++ b/content/media/webaudio/AudioBuffer.h
@@ -84,22 +84,19 @@ public:
 
   JSObject* GetChannelData(uint32_t aChannel) const {
     // Doesn't perform bounds checking
     MOZ_ASSERT(aChannel < mJSChannels.Length());
     return mJSChannels[aChannel];
   }
 
   /**
-   * Returns a ThreadSharedFloatArrayBufferList containing the sample data
-   * at aRate. Sets *aLength to the number of samples per channel.
+   * Returns a ThreadSharedFloatArrayBufferList containing the sample data.
    */
-  ThreadSharedFloatArrayBufferList* GetThreadSharedChannelsForRate(JSContext* aContext,
-                                                                   uint32_t* aRate,
-                                                                   uint32_t* aLength);
+  ThreadSharedFloatArrayBufferList* GetThreadSharedChannelsForRate(JSContext* aContext);
 
   // aContents should either come from JS_AllocateArrayBufferContents or
   // JS_StealArrayBufferContents.
   void SetChannelDataFromArrayBufferContents(JSContext* aJSContext,
                                              uint32_t aChannel,
                                              void* aContents);
 
   // This replaces the contents of the JS array for the given channel.
--- a/content/media/webaudio/AudioBufferSourceNode.cpp
+++ b/content/media/webaudio/AudioBufferSourceNode.cpp
@@ -423,21 +423,19 @@ AudioBufferSourceNode::AudioBufferSource
   mStream = aContext->Graph()->CreateAudioNodeStream(
       new AudioBufferSourceNodeEngine(this, aContext->Destination()),
       MediaStreamGraph::INTERNAL_STREAM);
   mStream->AddMainThreadListener(this);
 }
 
 AudioBufferSourceNode::~AudioBufferSourceNode()
 {
-  // 
   if (Context()) {
     Context()->UnregisterAudioBufferSourceNode(this);
   }
-  DestroyMediaStream();
 }
 
 JSObject*
 AudioBufferSourceNode::WrapObject(JSContext* aCx, JSObject* aScope)
 {
   return AudioBufferSourceNodeBinding::Wrap(aCx, aScope, this);
 }
 
@@ -452,20 +450,20 @@ AudioBufferSourceNode::Start(JSContext* 
   mStartCalled = true;
 
   AudioNodeStream* ns = static_cast<AudioNodeStream*>(mStream.get());
   if (!mBuffer || !ns) {
     // Nothing to play, or we're already dead for some reason
     return;
   }
 
-  uint32_t rate;
-  uint32_t lengthSamples;
+  float rate = mBuffer->SampleRate();
+  int32_t lengthSamples = mBuffer->Length();
   nsRefPtr<ThreadSharedFloatArrayBufferList> data =
-    mBuffer->GetThreadSharedChannelsForRate(aCx, &rate, &lengthSamples);
+    mBuffer->GetThreadSharedChannelsForRate(aCx);
   double length = double(lengthSamples) / rate;
   double offset = std::max(0.0, aOffset);
   double endOffset = aDuration.WasPassed() ?
       std::min(aOffset + aDuration.Value(), length) : length;
 
   if (offset >= endOffset) {
     return;
   }
--- a/content/media/webaudio/AudioNode.h
+++ b/content/media/webaudio/AudioNode.h
@@ -73,18 +73,16 @@ private:
 class AudioNode : public nsDOMEventTargetHelper,
                   public EnableWebAudioCheck
 {
 public:
   explicit AudioNode(AudioContext* aContext);
   virtual ~AudioNode();
 
   // This should be idempotent (safe to call multiple times).
-  // This should be called in the destructor of every class that overrides
-  // this method.
   virtual void DestroyMediaStream()
   {
     if (mStream) {
       UnbindFromEngine();
       mStream->Destroy();
       mStream = nullptr;
     }
   }
--- a/content/media/webaudio/BiquadFilterNode.cpp
+++ b/content/media/webaudio/BiquadFilterNode.cpp
@@ -104,21 +104,16 @@ BiquadFilterNode::BiquadFilterNode(Audio
   , mQ(new AudioParam(this, SendQToStream, 1.f))
   , mGain(new AudioParam(this, SendGainToStream, 0.f))
 {
   BiquadFilterNodeEngine* engine = new BiquadFilterNodeEngine(this, aContext->Destination());
   mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM);
   engine->SetSourceStream(static_cast<AudioNodeStream*> (mStream.get()));
 }
 
-BiquadFilterNode::~BiquadFilterNode()
-{
-  DestroyMediaStream();
-}
-
 JSObject*
 BiquadFilterNode::WrapObject(JSContext* aCx, JSObject* aScope)
 {
   return BiquadFilterNodeBinding::Wrap(aCx, aScope, this);
 }
 
 void
 BiquadFilterNode::SetType(uint16_t aType, ErrorResult& aRv)
--- a/content/media/webaudio/BiquadFilterNode.h
+++ b/content/media/webaudio/BiquadFilterNode.h
@@ -28,17 +28,16 @@ MOZ_BEGIN_ENUM_CLASS(BiquadTypeEnum, uin
   ALLPASS = 7,
   Max = 7
 MOZ_END_ENUM_CLASS(BiquadTypeEnum)
 
 class BiquadFilterNode : public AudioNode
 {
 public:
   explicit BiquadFilterNode(AudioContext* aContext);
-  ~BiquadFilterNode();
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BiquadFilterNode, AudioNode)
 
   virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope);
 
   virtual bool SupportsMediaStreams() const MOZ_OVERRIDE
   {
--- a/content/media/webaudio/DynamicsCompressorNode.cpp
+++ b/content/media/webaudio/DynamicsCompressorNode.cpp
@@ -122,21 +122,16 @@ DynamicsCompressorNode::DynamicsCompress
   , mAttack(new AudioParam(this, SendAttackToStream, 0.003f))
   , mRelease(new AudioParam(this, SendReleaseToStream, 0.25f))
 {
   DynamicsCompressorNodeEngine* engine = new DynamicsCompressorNodeEngine(this, aContext->Destination());
   mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM);
   engine->SetSourceStream(static_cast<AudioNodeStream*> (mStream.get()));
 }
 
-DynamicsCompressorNode::~DynamicsCompressorNode()
-{
-  DestroyMediaStream();
-}
-
 JSObject*
 DynamicsCompressorNode::WrapObject(JSContext* aCx, JSObject* aScope)
 {
   return DynamicsCompressorNodeBinding::Wrap(aCx, aScope, this);
 }
 
 void
 DynamicsCompressorNode::SendThresholdToStream(AudioNode* aNode)
--- a/content/media/webaudio/DynamicsCompressorNode.h
+++ b/content/media/webaudio/DynamicsCompressorNode.h
@@ -14,17 +14,16 @@ namespace mozilla {
 namespace dom {
 
 class AudioContext;
 
 class DynamicsCompressorNode : public AudioNode
 {
 public:
   explicit DynamicsCompressorNode(AudioContext* aContext);
-  ~DynamicsCompressorNode();
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DynamicsCompressorNode, AudioNode)
 
   virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope);
 
   virtual bool SupportsMediaStreams() const MOZ_OVERRIDE
   {
--- a/content/media/webaudio/GainNode.cpp
+++ b/content/media/webaudio/GainNode.cpp
@@ -98,21 +98,16 @@ GainNode::GainNode(AudioContext* aContex
   : AudioNode(aContext)
   , mGain(new AudioParam(this, SendGainToStream, 1.0f))
 {
   GainNodeEngine* engine = new GainNodeEngine(this, aContext->Destination());
   mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM);
   engine->SetSourceStream(static_cast<AudioNodeStream*> (mStream.get()));
 }
 
-GainNode::~GainNode()
-{
-  DestroyMediaStream();
-}
-
 JSObject*
 GainNode::WrapObject(JSContext* aCx, JSObject* aScope)
 {
   return GainNodeBinding::Wrap(aCx, aScope, this);
 }
 
 void
 GainNode::SendGainToStream(AudioNode* aNode)
--- a/content/media/webaudio/GainNode.h
+++ b/content/media/webaudio/GainNode.h
@@ -14,17 +14,16 @@ namespace mozilla {
 namespace dom {
 
 class AudioContext;
 
 class GainNode : public AudioNode
 {
 public:
   explicit GainNode(AudioContext* aContext);
-  virtual ~GainNode();
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(GainNode, AudioNode)
 
   virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope);
 
   AudioParam* Gain() const
   {
--- a/content/media/webaudio/PannerNode.cpp
+++ b/content/media/webaudio/PannerNode.cpp
@@ -179,17 +179,16 @@ PannerNode::PannerNode(AudioContext* aCo
   Context()->Listener()->RegisterPannerNode(this);
 }
 
 PannerNode::~PannerNode()
 {
   if (Context()) {
     Context()->UnregisterPannerNode(this);
   }
-  DestroyMediaStream();
 }
 
 JSObject*
 PannerNode::WrapObject(JSContext* aCx, JSObject* aScope)
 {
   return PannerNodeBinding::Wrap(aCx, aScope, this);
 }
 
--- a/content/media/webaudio/ScriptProcessorNode.cpp
+++ b/content/media/webaudio/ScriptProcessorNode.cpp
@@ -8,17 +8,16 @@
 #include "mozilla/dom/ScriptProcessorNodeBinding.h"
 #include "AudioBuffer.h"
 #include "AudioDestinationNode.h"
 #include "AudioNodeEngine.h"
 #include "AudioNodeStream.h"
 #include "AudioProcessingEvent.h"
 #include "WebAudioUtils.h"
 #include "mozilla/Mutex.h"
-#include "mozilla/unused.h"
 #include "mozilla/PodOperations.h"
 #include <deque>
 
 namespace mozilla {
 namespace dom {
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ScriptProcessorNode)
 NS_INTERFACE_MAP_END_INHERITING(AudioNode)
@@ -299,20 +298,17 @@ private:
           event->InitEvent(inputBuffer,
                            mInputChannels.Length(),
                            mPlaybackTime);
           node->DispatchTrustedEvent(event);
 
           // Steal the output buffers
           nsRefPtr<ThreadSharedFloatArrayBufferList> output;
           if (event->HasOutputBuffer()) {
-            uint32_t rate, length;
-            output = event->OutputBuffer()->GetThreadSharedChannelsForRate(cx, &rate, &length);
-            unused << rate;
-            unused << length;
+            output = event->OutputBuffer()->GetThreadSharedChannelsForRate(cx);
           }
 
           // Append it to our output buffer queue
           node->GetSharedBuffers()->FinishProducingOutputBuffer(output, node->BufferSize());
         }
         return NS_OK;
       }
     private:
@@ -356,21 +352,16 @@ ScriptProcessorNode::ScriptProcessorNode
                                   aContext->Destination(),
                                   BufferSize(),
                                   aNumberOfInputChannels);
   mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM,
                                                      aNumberOfInputChannels);
   engine->SetSourceStream(static_cast<AudioNodeStream*> (mStream.get()));
 }
 
-ScriptProcessorNode::~ScriptProcessorNode()
-{
-  DestroyMediaStream();
-}
-
 JSObject*
 ScriptProcessorNode::WrapObject(JSContext* aCx, JSObject* aScope)
 {
   return ScriptProcessorNodeBinding::Wrap(aCx, aScope, this);
 }
 
 }
 }
--- a/content/media/webaudio/ScriptProcessorNode.h
+++ b/content/media/webaudio/ScriptProcessorNode.h
@@ -22,17 +22,16 @@ class SharedBuffers;
 
 class ScriptProcessorNode : public AudioNode
 {
 public:
   ScriptProcessorNode(AudioContext* aContext,
                       uint32_t aBufferSize,
                       uint32_t aNumberOfInputChannels,
                       uint32_t aNumberOfOutputChannels);
-  virtual ~ScriptProcessorNode();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   IMPL_EVENT_HANDLER(audioprocess)
 
   virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope);
 
   virtual bool SupportsMediaStreams() const MOZ_OVERRIDE
--- a/dom/mobilemessage/src/ril/MobileMessageDatabaseService.js
+++ b/dom/mobilemessage/src/ril/MobileMessageDatabaseService.js
@@ -849,17 +849,18 @@ MobileMessageDatabaseService.prototype =
                 + JSON.stringify(threadRecord));
         }
         aCallback(threadRecord, participantIds);
       };
     });
   },
 
   saveRecord: function saveRecord(aMessageRecord, aAddresses, aCallback) {
-    if (aMessageRecord.id === undefined) {
+    let isOverriding = (aMessageRecord.id !== undefined);
+    if (!isOverriding) {
       // Assign a new id.
       this.lastMessageId += 1;
       aMessageRecord.id = this.lastMessageId;
     }
     if (DEBUG) debug("Going to store " + JSON.stringify(aMessageRecord));
 
     let self = this;
     function notifyResult(rv) {
@@ -892,16 +893,28 @@ MobileMessageDatabaseService.prototype =
                                           aAddresses, true,
                                           function (threadRecord,
                                                     participantIds) {
         if (!participantIds) {
           notifyResult(Cr.NS_ERROR_FAILURE);
           return;
         }
 
+        // If the overriding message is going to be saved into another
+        // thread which is different from the original one containing the
+        // overrided message, we need to update the original thread info.
+        if (isOverriding &&
+            (!threadRecord || threadRecord.id != aMessageRecord.threadId)) {
+          self.updateThreadByMessageChange(messageStore,
+                                           threadStore,
+                                           aMessageRecord.threadId,
+                                           aMessageRecord.id,
+                                           aMessageRecord.read);
+        }
+
         let insertMessageRecord = function (threadId) {
           // Setup threadId & threadIdIndex.
           aMessageRecord.threadId = threadId;
           aMessageRecord.threadIdIndex = [threadId, timestamp];
           // Setup participantIdsIndex.
           aMessageRecord.participantIdsIndex = [];
           for each (let id in participantIds) {
             aMessageRecord.participantIdsIndex.push([id, timestamp]);
@@ -1278,16 +1291,67 @@ MobileMessageDatabaseService.prototype =
           return;
         }
         aRequest.notifyGetMessageFailed(aRv, null);
       }
     };
     this.getMessageRecordById(aMessageId, notifyCallback);
   },
 
+  updateThreadByMessageChange: function updateThreadByMessageChange(messageStore,
+                                                                    threadStore,
+                                                                    threadId,
+                                                                    messageId,
+                                                                    messageRead) {
+    threadStore.get(threadId).onsuccess = function(event) {
+      // This must exist.
+      let threadRecord = event.target.result;
+      if (DEBUG) debug("Updating thread record " + JSON.stringify(threadRecord));
+
+      if (!messageRead) {
+        threadRecord.unreadCount--;
+      }
+
+      if (threadRecord.lastMessageId == messageId) {
+        // Check most recent sender/receiver.
+        let range = IDBKeyRange.bound([threadId, 0], [threadId, ""]);
+        let request = messageStore.index("threadId")
+                                  .openCursor(range, PREV);
+        request.onsuccess = function(event) {
+          let cursor = event.target.result;
+          if (!cursor) {
+            if (DEBUG) {
+              debug("Deleting mru entry for thread id " + threadId);
+            }
+            threadStore.delete(threadId);
+            return;
+          }
+
+          let nextMsg = cursor.value;
+          threadRecord.lastMessageId = nextMsg.id;
+          threadRecord.lastTimestamp = nextMsg.timestamp;
+          threadRecord.subject = nextMsg.body;
+          if (DEBUG) {
+            debug("Updating mru entry: " +
+                  JSON.stringify(threadRecord));
+          }
+          threadStore.put(threadRecord);
+        };
+      } else if (!messageRead) {
+        // Shortcut, just update the unread count.
+        if (DEBUG) {
+          debug("Updating unread count for thread id " + threadId + ": " +
+                (threadRecord.unreadCount + 1) + " -> " +
+                threadRecord.unreadCount);
+        }
+        threadStore.put(threadRecord);
+      }
+    };
+  },
+
   deleteMessage: function deleteMessage(messageId, aRequest) {
     if (DEBUG) debug("deleteMessage: message id " + messageId);
     let deleted = false;
     let self = this;
     this.newTxn(READ_WRITE, function (error, txn, stores) {
       if (error) {
         if (DEBUG) debug("deleteMessage: failed to open transaction");
         aRequest.notifyDeleteMessageFailed(Ci.nsIMobileMessageCallback.INTERNAL_ERROR);
@@ -1315,62 +1379,21 @@ MobileMessageDatabaseService.prototype =
           if (DEBUG) debug("Deleting message id " + messageId);
 
           // First actually delete the message.
           messageStore.delete(messageId).onsuccess = function(event) {
             if (DEBUG) debug("Message id " + messageId + " deleted");
             deleted = true;
 
             // Then update unread count and most recent message.
-            let threadId = messageRecord.threadId;
-
-            threadStore.get(threadId).onsuccess = function(event) {
-              // This must exist.
-              let threadRecord = event.target.result;
-              if (DEBUG) debug("Updating thread record " + JSON.stringify(threadRecord));
-
-              if (!messageRecord.read) {
-                threadRecord.unreadCount--;
-              }
-
-              if (threadRecord.lastMessageId == messageId) {
-                // Check most recent sender/receiver.
-                let range = IDBKeyRange.bound([threadId, 0], [threadId, ""]);
-                let request = messageStore.index("threadId")
-                                          .openCursor(range, PREV);
-                request.onsuccess = function(event) {
-                  let cursor = event.target.result;
-                  if (!cursor) {
-                    if (DEBUG) {
-                      debug("Deleting mru entry for thread id " + threadId);
-                    }
-                    threadStore.delete(threadId);
-                    return;
-                  }
-
-                  let nextMsg = cursor.value;
-                  threadRecord.lastMessageId = nextMsg.id;
-                  threadRecord.lastTimestamp = nextMsg.timestamp;
-                  threadRecord.subject = nextMsg.body;
-                  if (DEBUG) {
-                    debug("Updating mru entry: " +
-                          JSON.stringify(threadRecord));
-                  }
-                  threadStore.put(threadRecord);
-                };
-              } else if (!messageRecord.read) {
-                // Shortcut, just update the unread count.
-                if (DEBUG) {
-                  debug("Updating unread count for thread id " + threadId + ": " +
-                        (threadRecord.unreadCount + 1) + " -> " +
-                        threadRecord.unreadCount);
-                }
-                threadStore.put(threadRecord);
-              }
-            };
+            self.updateThreadByMessageChange(messageStore,
+                                             threadStore,
+                                             messageRecord.threadId,
+                                             messageId,
+                                             messageRecord.read);
           };
         } else if (DEBUG) {
           debug("Message id " + messageId + " does not exist");
         }
       };
     }, [MESSAGE_STORE_NAME, THREAD_STORE_NAME]);
   },
 
--- a/dom/push/src/PushService.js
+++ b/dom/push/src/PushService.js
@@ -1290,36 +1290,32 @@ PushService.prototype = {
 
   /**
    * Get mobile network information to decide if the client is capable of being woken
    * up by UDP (which currently just means having an mcc and mnc along with an
    * IP).
    */
   _getNetworkState: function() {
     debug("getNetworkState()");
-
-    var networkManager = Cc["@mozilla.org/network/manager;1"]
-                           .getService(Ci.nsINetworkManager);
-    if (networkManager.active &&
-        networkManager.active.type ==
-                      Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE) {
-      debug("Running on mobile data");
-      var mcp = Cc["@mozilla.org/ril/content-helper;1"]
-                  .getService(Ci.nsIMobileConnectionProvider);
-      if (mcp.iccInfo) {
-        return {
-          mcc: mcp.iccInfo.mcc,
-          mnc: mcp.iccInfo.mnc,
-          ip: networkManager.active.ip
+    try {
+      var nm = Cc["@mozilla.org/network/manager;1"].getService(Ci.nsINetworkManager);
+      if (nm.active && nm.active.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE) {
+        var mcp = Cc["@mozilla.org/ril/content-helper;1"].getService(Ci.nsIMobileConnectionProvider);
+        if (mcp.iccInfo) {
+          debug("Running on mobile data");
+          return {
+            mcc: mcp.iccInfo.mcc,
+            mnc: mcp.iccInfo.mnc,
+            ip:  nm.active.ip
+          }
         }
       }
-    }
-    else {
-      debug("Running on wifi");
-    }
+    } catch (e) {}
+
+    debug("Running on wifi");
 
     return {
       mcc: 0,
       mnc: 0,
       ip: undefined
     };
   }
 }
--- a/extensions/spellcheck/hunspell/src/mozHunspell.cpp
+++ b/extensions/spellcheck/hunspell/src/mozHunspell.cpp
@@ -70,16 +70,18 @@
 #include "nsICharsetConverterManager.h"
 #include "nsUnicharUtilCIID.h"
 #include "nsUnicharUtils.h"
 #include "nsCRT.h"
 #include "mozInlineSpellChecker.h"
 #include "mozilla/Services.h"
 #include <stdlib.h>
 #include "nsIMemoryReporter.h"
+#include "nsIPrefService.h"
+#include "nsIPrefBranch.h"
 
 static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
 static NS_DEFINE_CID(kUnicharUtilCID, NS_UNICHARUTIL_CID);
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(mozHunspell)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(mozHunspell)
 
 NS_INTERFACE_MAP_BEGIN(mozHunspell)
@@ -367,21 +369,36 @@ mozHunspell::LoadDictionaryList()
 
   nsresult rv;
 
   nsCOMPtr<nsIProperties> dirSvc =
     do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
   if (!dirSvc)
     return;
 
-  // find built in dictionaries
+  // find built in dictionaries, or dictionaries specified in
+  // spellchecker.dictionary_path in prefs
   nsCOMPtr<nsIFile> dictDir;
-  rv = dirSvc->Get(DICTIONARY_SEARCH_DIRECTORY,
-                   NS_GET_IID(nsIFile), getter_AddRefs(dictDir));
-  if (NS_SUCCEEDED(rv)) {
+
+  // check preferences first
+  nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
+  if (prefs) {
+    nsCString extDictPath;
+    rv = prefs->GetCharPref("spellchecker.dictionary_path", getter_Copies(extDictPath));
+    if (NS_SUCCEEDED(rv)) {
+      // set the spellchecker.dictionary_path
+      rv = NS_NewNativeLocalFile(extDictPath, true, getter_AddRefs(dictDir));
+    }
+  }
+  if (!dictDir) {
+    // spellcheck.dictionary_path not found, set internal path
+    rv = dirSvc->Get(DICTIONARY_SEARCH_DIRECTORY,
+                     NS_GET_IID(nsIFile), getter_AddRefs(dictDir));
+  }
+  if (dictDir) {
     LoadDictionariesFromDir(dictDir);
   }
   else {
     // try to load gredir/dictionaries
     nsCOMPtr<nsIFile> greDir;
     rv = dirSvc->Get(NS_GRE_DIR,
                      NS_GET_IID(nsIFile), getter_AddRefs(greDir));
     if (NS_SUCCEEDED(rv)) {
--- a/image/decoders/nsPNGDecoder.cpp
+++ b/image/decoders/nsPNGDecoder.cpp
@@ -49,71 +49,64 @@ GetPNGDecoderAccountingLog()
 /* limit image dimensions (bug #251381) */
 #define MOZ_PNG_MAX_DIMENSION 1000000L
 
 // For size decodes
 #define WIDTH_OFFSET 16
 #define HEIGHT_OFFSET (WIDTH_OFFSET + 4)
 #define BYTES_NEEDED_FOR_DIMENSIONS (HEIGHT_OFFSET + 4)
 
-struct AnimFrameInfo
-{
-  AnimFrameInfo()
-   : mDispose(RasterImage::kDisposeKeep)
-   , mBlend(RasterImage::kBlendOver)
-   , mTimeout(0)
-  {}
+nsPNGDecoder::AnimFrameInfo::AnimFrameInfo()
+ : mDispose(RasterImage::kDisposeKeep)
+ , mBlend(RasterImage::kBlendOver)
+ , mTimeout(0)
+{}
 
 #ifdef PNG_APNG_SUPPORTED
-  AnimFrameInfo(png_structp aPNG, png_infop aInfo)
-   : mDispose(RasterImage::kDisposeKeep)
-   , mBlend(RasterImage::kBlendOver)
-   , mTimeout(0)
-  {
-    png_uint_16 delay_num, delay_den;
-    /* delay, in seconds is delay_num/delay_den */
-    png_byte dispose_op;
-    png_byte blend_op;
-    delay_num = png_get_next_frame_delay_num(aPNG, aInfo);
-    delay_den = png_get_next_frame_delay_den(aPNG, aInfo);
-    dispose_op = png_get_next_frame_dispose_op(aPNG, aInfo);
-    blend_op = png_get_next_frame_blend_op(aPNG, aInfo);
+nsPNGDecoder::AnimFrameInfo::AnimFrameInfo(png_structp aPNG, png_infop aInfo)
+ : mDispose(RasterImage::kDisposeKeep)
+ , mBlend(RasterImage::kBlendOver)
+ , mTimeout(0)
+{
+  png_uint_16 delay_num, delay_den;
+  /* delay, in seconds is delay_num/delay_den */
+  png_byte dispose_op;
+  png_byte blend_op;
+  delay_num = png_get_next_frame_delay_num(aPNG, aInfo);
+  delay_den = png_get_next_frame_delay_den(aPNG, aInfo);
+  dispose_op = png_get_next_frame_dispose_op(aPNG, aInfo);
+  blend_op = png_get_next_frame_blend_op(aPNG, aInfo);
 
-    if (delay_num == 0) {
-      mTimeout = 0; // SetFrameTimeout() will set to a minimum
-    } else {
-      if (delay_den == 0)
-        delay_den = 100; // so says the APNG spec
+  if (delay_num == 0) {
+    mTimeout = 0; // SetFrameTimeout() will set to a minimum
+  } else {
+    if (delay_den == 0)
+      delay_den = 100; // so says the APNG spec
 
-      // Need to cast delay_num to float to have a proper division and
-      // the result to int to avoid compiler warning
-      mTimeout = static_cast<int32_t>(static_cast<double>(delay_num) * 1000 / delay_den);
-    }
-
-    if (dispose_op == PNG_DISPOSE_OP_PREVIOUS) {
-      mDispose = RasterImage::kDisposeRestorePrevious;
-    } else if (dispose_op == PNG_DISPOSE_OP_BACKGROUND) {
-      mDispose = RasterImage::kDisposeClear;
-    } else {
-      mDispose = RasterImage::kDisposeKeep;
-    }
+    // Need to cast delay_num to float to have a proper division and
+    // the result to int to avoid compiler warning
+    mTimeout = static_cast<int32_t>(static_cast<double>(delay_num) * 1000 / delay_den);
+  }
 
-    if (blend_op == PNG_BLEND_OP_SOURCE) {
-      mBlend = RasterImage::kBlendSource;
-    } else {
-      mBlend = RasterImage::kBlendOver;
-    }
+  if (dispose_op == PNG_DISPOSE_OP_PREVIOUS) {
+    mDispose = RasterImage::kDisposeRestorePrevious;
+  } else if (dispose_op == PNG_DISPOSE_OP_BACKGROUND) {
+    mDispose = RasterImage::kDisposeClear;
+  } else {
+    mDispose = RasterImage::kDisposeKeep;
   }
+
+  if (blend_op == PNG_BLEND_OP_SOURCE) {
+    mBlend = RasterImage::kBlendSource;
+  } else {
+    mBlend = RasterImage::kBlendOver;
+  }
+}
 #endif
 
-  RasterImage::FrameDisposalMethod mDispose;
-  RasterImage::FrameBlendMethod mBlend;
-  int32_t mTimeout;
-};
-
 // First 8 bytes of a PNG file
 const uint8_t 
 nsPNGDecoder::pngSignatureBytes[] = { 137, 80, 78, 71, 13, 10, 26, 10 };
 
 nsPNGDecoder::nsPNGDecoder(RasterImage &aImage)
  : Decoder(aImage),
    mPNG(nullptr), mInfo(nullptr),
    mCMSLine(nullptr), interlacebuf(nullptr),
@@ -158,48 +151,48 @@ void nsPNGDecoder::CreateFrame(png_uint_
 
   PR_LOG(GetPNGDecoderAccountingLog(), PR_LOG_DEBUG,
          ("PNGDecoderAccounting: nsPNGDecoder::CreateFrame -- created "
           "image frame with %dx%d pixels in container %p",
           width, height,
           &mImage));
 
   mFrameHasNoAlpha = true;
+
+#ifdef PNG_APNG_SUPPORTED
+  if (png_get_valid(mPNG, mInfo, PNG_INFO_acTL)) {
+    mAnimInfo = AnimFrameInfo(mPNG, mInfo);
+  }
+#endif
 }
 
 // set timeout and frame disposal method for the current frame
 void nsPNGDecoder::EndImageFrame()
 {
   if (mFrameIsHidden)
     return;
 
   mNumFrames++;
 
   RasterImage::FrameAlpha alpha;
   if (mFrameHasNoAlpha)
     alpha = RasterImage::kFrameOpaque;
   else
     alpha = RasterImage::kFrameHasAlpha;
 
-  AnimFrameInfo animInfo;
-
 #ifdef PNG_APNG_SUPPORTED
   uint32_t numFrames = GetFrameCount();
 
   // We can't use mPNG->num_frames_read as it may be one ahead.
   if (numFrames > 1) {
     PostInvalidation(mFrameRect);
   }
-
-  if (png_get_valid(mPNG, mInfo, PNG_INFO_acTL)) {
-    animInfo = AnimFrameInfo(mPNG, mInfo);
-  }
 #endif
 
-  PostFrameStop(alpha, animInfo.mDispose, animInfo.mTimeout, animInfo.mBlend);
+  PostFrameStop(alpha, mAnimInfo.mDispose, mAnimInfo.mTimeout, mAnimInfo.mBlend);
 }
 
 void
 nsPNGDecoder::InitInternal()
 {
   mCMSMode = gfxPlatform::GetCMSMode();
   if ((mDecodeFlags & DECODER_NO_COLORSPACE_CONVERSION) != 0)
     mCMSMode = eCMSMode_Off;
--- a/image/decoders/nsPNGDecoder.h
+++ b/image/decoders/nsPNGDecoder.h
@@ -85,16 +85,30 @@ public:
   uint8_t mChannels;
   bool mFrameHasNoAlpha;
   bool mFrameIsHidden;
 
   // whether CMS or premultiplied alpha are forced off
   uint32_t mCMSMode;
   bool mDisablePremultipliedAlpha;
 
+  struct AnimFrameInfo
+  {
+    AnimFrameInfo();
+#ifdef PNG_APNG_SUPPORTED
+    AnimFrameInfo(png_structp aPNG, png_infop aInfo);
+#endif
+
+    RasterImage::FrameDisposalMethod mDispose;
+    RasterImage::FrameBlendMethod mBlend;
+    int32_t mTimeout;
+  };
+
+  AnimFrameInfo mAnimInfo;
+
   // The number of frames we've finished.
   uint32_t mNumFrames;
   
   /*
    * libpng callbacks
    *
    * We put these in the class so that they can access protected members.
    */
--- a/intl/uconv/tools/umaptable.c
+++ b/intl/uconv/tools/umaptable.c
@@ -1,15 +1,17 @@
 /* -*- Mode: C; tab-width: 4; 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
 #include "mozilla/StandardInteger.h"
 
 #define NOMAPPING 0xfffd
 
 typedef struct {
 		uint16_t srcBegin;		/* 2 byte	*/
 		uint16_t srcEnd;		/* 2 byte	*/
 		uint16_t destBegin;		/* 2 byte	*/
@@ -350,17 +352,17 @@ void writetable()
 }
 
 void usage()
 {
   fprintf(stderr, "please indicate what kind of mapping mapping table you want to generate:\n");
   fprintf(stderr, "\t-uf : generate *.uf (from unicode) table, or\n");
   fprintf(stderr, "\t-ut : generate *.ut (to unicode) table\n");
 }
-parsearg(int argc, char* argv[])
+void parsearg(int argc, char* argv[])
 {
 	int i;
 	for(i=0;i<argc;i++)
 	{
 		if(strncmp("-uf", argv[i],3) == 0) {
                         if(! bInitFromOrTo) {
                            bGenerateFromUnicodeTable = 1;
                            bInitFromOrTo = 1;
@@ -422,28 +424,29 @@ parsearg(int argc, char* argv[])
 	fprintf(stderr, "format 1 cnst = %d\n", FORMAT1CNST);
         fprintf(stderr, "generate u%c table\n", 
                         bGenerateFromUnicodeTable ? 'f' : 't');
 }
 void getinput()
 {
   char buf[256];
   short c,u;
-  for (; gets(buf);)
+  for (; fgets(buf,sizeof(buf),stdin);)
   {
      if(buf[0]=='0' && buf[1] == 'x')
         {
           sscanf(buf,"%hx %hx",&c,&u);
           if(bGenerateFromUnicodeTable)
             SetMapValue(u, c);
           else
             SetMapValue(c, u);
         }
   }
 }
-main(int argc, char* argv[])
+int main(int argc, char* argv[])
 {
   parsearg(argc, argv);
   initmaps();
   getinput();
   gentable();
-  writetable();	
+  writetable();
+  return 0;
 }
--- a/js/src/ion/BaselineBailouts.cpp
+++ b/js/src/ion/BaselineBailouts.cpp
@@ -1159,16 +1159,23 @@ ion::FinishBailoutToBaseline(BaselineBai
 {
     // The caller pushes R0 and R1 on the stack without rooting them.
     // Since GC here is very unlikely just suppress it.
     JSContext *cx = GetIonContext()->cx;
     js::gc::AutoSuppressGC suppressGC(cx);
 
     IonSpew(IonSpew_BaselineBailouts, "  Done restoring frames");
 
+    // Check that we can get the current script's PC.
+#ifdef DEBUG
+    jsbytecode *pc;
+    cx->stack.currentScript(&pc);
+    IonSpew(IonSpew_BaselineBailouts, "  Got pc=%p", pc);
+#endif
+
     uint32_t numFrames = bailoutInfo->numFrames;
     JS_ASSERT(numFrames > 0);
     BailoutKind bailoutKind = bailoutInfo->bailoutKind;
 
     // Free the bailout buffer.
     js_free(bailoutInfo);
     bailoutInfo = NULL;
 
--- a/js/src/ion/BaselineJIT.cpp
+++ b/js/src/ion/BaselineJIT.cpp
@@ -382,32 +382,45 @@ BaselineScript::pcMappingReader(size_t i
     uint8_t *dataStart = pcMappingData() + entry.bufferOffset;
     uint8_t *dataEnd = (indexEntry == numPCMappingIndexEntries() - 1)
         ? pcMappingData() + pcMappingSize_
         : pcMappingData() + pcMappingIndexEntry(indexEntry + 1).bufferOffset;
 
     return CompactBufferReader(dataStart, dataEnd);
 }
 
-ICEntry &
-BaselineScript::icEntryFromReturnOffset(CodeOffsetLabel returnOffset)
+ICEntry *
+BaselineScript::maybeICEntryFromReturnOffset(CodeOffsetLabel returnOffset)
 {
     size_t bottom = 0;
     size_t top = numICEntries();
     size_t mid = (bottom + top) / 2;
     while (mid < top) {
         ICEntry &midEntry = icEntry(mid);
         if (midEntry.returnOffset().offset() < returnOffset.offset())
             bottom = mid + 1;
         else // if (midEntry.returnOffset().offset() >= returnOffset.offset())
             top = mid;
         mid = (bottom + top) / 2;
     }
-    JS_ASSERT(icEntry(mid).returnOffset().offset() == returnOffset.offset());
-    return icEntry(mid);
+    if (mid >= numICEntries())
+        return NULL;
+
+    if (icEntry(mid).returnOffset().offset() != returnOffset.offset())
+        return NULL;
+
+    return &icEntry(mid);
+}
+
+ICEntry &
+BaselineScript::icEntryFromReturnOffset(CodeOffsetLabel returnOffset)
+{
+    ICEntry *result = maybeICEntryFromReturnOffset(returnOffset);
+    JS_ASSERT(result);
+    return *result;
 }
 
 uint8_t *
 BaselineScript::returnAddressForIC(const ICEntry &ent)
 {
     return method()->raw() + ent.returnOffset().offset();
 }
 
@@ -462,20 +475,30 @@ BaselineScript::icEntryFromPCOffset(uint
         }
         JS_ASSERT(curEntry->pcOffset() == pcOffset && curEntry->isForOp());
         return *curEntry;
     }
 
     return icEntryFromPCOffset(pcOffset);
 }
 
+ICEntry *
+BaselineScript::maybeICEntryFromReturnAddress(uint8_t *returnAddr)
+{
+    JS_ASSERT(returnAddr > method_->raw());
+    JS_ASSERT(returnAddr < method_->raw() + method_->instructionsSize());
+    CodeOffsetLabel offset(returnAddr - method_->raw());
+    return maybeICEntryFromReturnOffset(offset);
+}
+
 ICEntry &
 BaselineScript::icEntryFromReturnAddress(uint8_t *returnAddr)
 {
     JS_ASSERT(returnAddr > method_->raw());
+    JS_ASSERT(returnAddr < method_->raw() + method_->instructionsSize());
     CodeOffsetLabel offset(returnAddr - method_->raw());
     return icEntryFromReturnOffset(offset);
 }
 
 void
 BaselineScript::copyICEntries(HandleScript script, const ICEntry *entries, MacroAssembler &masm)
 {
     // Fix up the return offset in the IC entries and copy them in.
@@ -575,16 +598,70 @@ BaselineScript::nativeCodeForPC(JSScript
 
         curPC += GetBytecodeLength(curPC);
     }
 
     JS_NOT_REACHED("Invalid pc");
     return NULL;
 }
 
+jsbytecode *
+BaselineScript::pcForReturnOffset(JSScript *script, uint32_t nativeOffset)
+{
+    JS_ASSERT(script->baselineScript() == this);
+    JS_ASSERT(nativeOffset < method_->instructionsSize());
+
+    // Look for the first PCMappingIndexEntry with native offset > the native offset we are
+    // interested in.
+    uint32_t i = 1;
+    for (; i < numPCMappingIndexEntries(); i++) {
+        if (pcMappingIndexEntry(i).nativeOffset > nativeOffset)
+            break;
+    }
+
+    // Go back an entry to search forward from.
+    JS_ASSERT(i > 0);
+    i--;
+
+    PCMappingIndexEntry &entry = pcMappingIndexEntry(i);
+    JS_ASSERT(nativeOffset >= entry.nativeOffset);
+
+    CompactBufferReader reader(pcMappingReader(i));
+    jsbytecode *curPC = script->code + entry.pcOffset;
+    uint32_t curNativeOffset = entry.nativeOffset;
+
+    JS_ASSERT(curPC >= script->code);
+    JS_ASSERT(curNativeOffset <= nativeOffset);
+
+    while (true) {
+        // If the high bit is set, the native offset relative to the
+        // previous pc != 0 and comes next.
+        uint8_t b = reader.readByte();
+        if (b & 0x80)
+            curNativeOffset += reader.readUnsigned();
+
+        if (curNativeOffset == nativeOffset)
+            return curPC;
+
+        curPC += GetBytecodeLength(curPC);
+    }
+
+    JS_NOT_REACHED("Invalid pc");
+    return NULL;
+}
+
+jsbytecode *
+BaselineScript::pcForReturnAddress(JSScript *script, uint8_t *nativeAddress)
+{
+    JS_ASSERT(script->baselineScript() == this);
+    JS_ASSERT(nativeAddress >= method_->raw());
+    JS_ASSERT(nativeAddress < method_->raw() + method_->instructionsSize());
+    return pcForReturnOffset(script, uint32_t(nativeAddress - method_->raw()));
+}
+
 void
 BaselineScript::toggleDebugTraps(RawScript script, jsbytecode *pc)
 {
     JS_ASSERT(script->baselineScript() == this);
 
     SrcNoteLineScanner scanner(script->notes(), script->lineno);
 
     IonContext ictx(script->compartment(), NULL);
--- a/js/src/ion/BaselineJIT.h
+++ b/js/src/ion/BaselineJIT.h
@@ -206,19 +206,21 @@ struct BaselineScript
         method_ = code;
     }
 
     void toggleBarriers(bool enabled) {
         method()->togglePreBarriers(enabled);
     }
 
     ICEntry &icEntry(size_t index);
+    ICEntry *maybeICEntryFromReturnOffset(CodeOffsetLabel returnOffset);
     ICEntry &icEntryFromReturnOffset(CodeOffsetLabel returnOffset);
     ICEntry &icEntryFromPCOffset(uint32_t pcOffset);
     ICEntry &icEntryFromPCOffset(uint32_t pcOffset, ICEntry *prevLookedUpEntry);
+    ICEntry *maybeICEntryFromReturnAddress(uint8_t *returnAddr);
     ICEntry &icEntryFromReturnAddress(uint8_t *returnAddr);
     uint8_t *returnAddressForIC(const ICEntry &ent);
 
     size_t numICEntries() const {
         return icEntries_;
     }
 
     void copyICEntries(HandleScript script, const ICEntry *entries, MacroAssembler &masm);
@@ -230,16 +232,18 @@ struct BaselineScript
     size_t numPCMappingIndexEntries() const {
         return pcMappingIndexEntries_;
     }
 
     void copyPCMappingIndexEntries(const PCMappingIndexEntry *entries);
 
     void copyPCMappingEntries(const CompactBufferWriter &entries);
     uint8_t *nativeCodeForPC(JSScript *script, jsbytecode *pc, PCMappingSlotInfo *slotInfo = NULL);
+    jsbytecode *pcForReturnOffset(JSScript *script, uint32_t nativeOffset);
+    jsbytecode *pcForReturnAddress(JSScript *script, uint8_t *nativeAddress);
 
     // Toggle debug traps (used for breakpoints and step mode) in the script.
     // If |pc| is NULL, toggle traps for all ops in the script. Else, only
     // toggle traps at |pc|.
     void toggleDebugTraps(RawScript script, jsbytecode *pc);
 
     void toggleSPS(bool enable);
 
--- a/js/src/ion/IonCaches.cpp
+++ b/js/src/ion/IonCaches.cpp
@@ -571,17 +571,17 @@ IsOptimizableArgumentsObjectForGetElem(J
 
     if (argsObj.isAnyElementDeleted())
         return false;
 
     if (!idval.isInt32())
         return false;
 
     int32_t idint = idval.toInt32();
-    if (idint < 0 || idint >= argsObj.initialLength())
+    if (idint < 0 || static_cast<uint32_t>(idint) >= argsObj.initialLength())
         return false;
 
     return true;
 }
 
 static bool
 IsCacheableGetPropCallNative(JSObject *obj, JSObject *holder, RawShape shape)
 {
--- a/js/src/ion/IonFrames.cpp
+++ b/js/src/ion/IonFrames.cpp
@@ -188,18 +188,35 @@ IonFrameIterator::script() const
 void
 IonFrameIterator::baselineScriptAndPc(JSScript **scriptRes, jsbytecode **pcRes) const
 {
     JS_ASSERT(isBaselineJS());
     RawScript script = this->script();
     if (scriptRes)
         *scriptRes = script;
     uint8_t *retAddr = returnAddressToFp();
-    if (pcRes)
-        *pcRes = script->baselineScript()->icEntryFromReturnAddress(retAddr).pc(script);
+    if (pcRes) {
+        // If the return address is into the prologue entry addr, then assume PC 0.
+        if (retAddr == script->baselineScript()->prologueEntryAddr()) {
+            *pcRes = 0;
+            return;
+        }
+
+        // The return address _may_ be a return from a callVM or IC chain call done for
+        // some op.
+        ICEntry *icEntry = script->baselineScript()->maybeICEntryFromReturnAddress(retAddr);
+        if (icEntry) {
+            *pcRes = icEntry->pc(script);
+            return;
+        }
+
+        // If not, the return address _must_ be the start address of an op, which can
+        // be computed from the pc mapping table.
+        *pcRes = script->baselineScript()->pcForReturnAddress(script, retAddr);
+    }
 }
 
 Value *
 IonFrameIterator::nativeVp() const
 {
     JS_ASSERT(isNative());
     return exitFrame()->nativeExit()->vp();
 }
--- a/js/src/ion/IonMacroAssembler.cpp
+++ b/js/src/ion/IonMacroAssembler.cpp
@@ -842,17 +842,18 @@ MacroAssembler::generateBailoutTail(Regi
             bind(&endOfCopy);
         }
 
         // Enter exit frame for the FinishBailoutToBaseline call.
         loadPtr(Address(bailoutInfo, offsetof(BaselineBailoutInfo, resumeFramePtr)), temp);
         load32(Address(temp, BaselineFrame::reverseOffsetOfFrameSize()), temp);
         makeFrameDescriptor(temp, IonFrame_BaselineJS);
         push(temp);
-        push(Imm32(0)); // Fake return address.
+        loadPtr(Address(bailoutInfo, offsetof(BaselineBailoutInfo, resumeAddr)), temp);
+        push(temp);
         enterFakeExitFrame();
 
         // If monitorStub is non-null, handle resumeAddr appropriately.
         Label noMonitor;
         Label done;
         branchPtr(Assembler::Equal,
                   Address(bailoutInfo, offsetof(BaselineBailoutInfo, monitorStub)),
                   ImmWord((void*) 0),
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -465,16 +465,23 @@ js::powi(double x, int y)
 // Disable PGO for Math.pow() and related functions (see bug 791214).
 #if defined(_MSC_VER)
 # pragma optimize("g", off)
 #endif
 double
 js::ecmaPow(double x, double y)
 {
     /*
+     * Use powi if the exponent is an integer-valued double. We don't have to
+     * check for NaN since a comparison with NaN is always false.
+     */
+    if (int32_t(y) == y)
+        return powi(x, int32_t(y));
+
+    /*
      * Because C99 and ECMA specify different behavior for pow(),
      * we need to wrap the libm call to make it ECMA compliant.
      */
     if (!MOZ_DOUBLE_IS_FINITE(y) && (x == 1.0 || x == -1.0))
         return js_NaN;
     /* pow(x, +-0) is always 1, even for x = NaN (MSVC gets this wrong). */
     if (y == 0)
         return 1;
@@ -486,17 +493,17 @@ js::ecmaPow(double x, double y)
 
 // Disable PGO for Math.pow() and related functions (see bug 791214).
 #if defined(_MSC_VER)
 # pragma optimize("g", off)
 #endif
 JSBool
 js_math_pow(JSContext *cx, unsigned argc, Value *vp)
 {
-    double x, y, z;
+    double x, y;
 
     if (argc <= 1) {
         vp->setDouble(js_NaN);
         return JS_TRUE;
     }
     if (!ToNumber(cx, vp[2], &x) || !ToNumber(cx, vp[3], &y))
         return JS_FALSE;
     /*
@@ -514,25 +521,17 @@ js_math_pow(JSContext *cx, unsigned argc
         }
     }
     /* pow(x, +-0) is always 1, even for x = NaN. */
     if (y == 0) {
         vp->setInt32(1);
         return JS_TRUE;
     }
 
-    /*
-     * Use powi if the exponent is an integer or an integer-valued double.
-     * We don't have to check for NaN since a comparison with NaN is always
-     * false.
-     */
-    if (int32_t(y) == y)
-        z = powi(x, int32_t(y));
-    else
-        z = ecmaPow(x, y);
+    double z = ecmaPow(x, y);
 
     vp->setNumber(z);
     return JS_TRUE;
 }
 #if defined(_MSC_VER)
 # pragma optimize("", on)
 #endif
 
--- a/netwerk/base/src/nsSocketTransportService2.cpp
+++ b/netwerk/base/src/nsSocketTransportService2.cpp
@@ -681,40 +681,40 @@ nsSocketTransportService::Run()
 
     psm::StopSSLServerCertVerificationThreads();
 
     SOCKET_LOG(("STS thread exit\n"));
     return NS_OK;
 }
 
 void
+nsSocketTransportService::DetachSocketWithGuard(bool aGuardLocals,
+                                                SocketContext *socketList,
+                                                int32_t index)
+{
+    bool isGuarded = false;
+    if (aGuardLocals) {
+        socketList[index].mHandler->IsLocal(&isGuarded);
+        if (!isGuarded)
+            socketList[index].mHandler->KeepWhenOffline(&isGuarded);
+    }
+    if (!isGuarded)
+        DetachSocket(socketList, &socketList[index]);
+}
+
+void
 nsSocketTransportService::Reset(bool aGuardLocals)
 {
     // detach any sockets
     int32_t i;
-    bool isGuarded;
     for (i = mActiveCount - 1; i >= 0; --i) {
-        isGuarded = false;
-        if (aGuardLocals) {
-            mActiveList[i].mHandler->IsLocal(&isGuarded);
-            if (!isGuarded)
-                mActiveList[i].mHandler->KeepWhenOffline(&isGuarded);
-        }
-        if (!isGuarded)
-            DetachSocket(mActiveList, &mActiveList[i]);
+        DetachSocketWithGuard(aGuardLocals, mActiveList, i);
     }
     for (i = mIdleCount - 1; i >= 0; --i) {
-        isGuarded = false;
-        if (aGuardLocals) {
-            mIdleList[i].mHandler->IsLocal(&isGuarded);
-            if (!isGuarded)
-                mIdleList[i].mHandler->KeepWhenOffline(&isGuarded);
-        }
-        if (!isGuarded)
-            DetachSocket(mIdleList, &mIdleList[i]);
+        DetachSocketWithGuard(aGuardLocals, mIdleList, i);
     }
 }
 
 nsresult
 nsSocketTransportService::DoPollIteration(bool wait)
 {
     SOCKET_LOG(("STS poll iter [%d]\n", wait));
 
--- a/netwerk/base/src/nsSocketTransportService2.h
+++ b/netwerk/base/src/nsSocketTransportService2.h
@@ -187,14 +187,17 @@ private:
     void ProbeMaxCount();
 #endif
     bool mProbedMaxCount;
 
     void AnalyzeConnection(nsTArray<mozilla::net::SocketInfo> *data,
                            SocketContext *context, bool aActive);
 
     void ClosePrivateConnections();
+    void DetachSocketWithGuard(bool aGuardLocals,
+                               SocketContext *socketList,
+                               int32_t index);
 };
 
 extern nsSocketTransportService *gSocketTransportService;
 extern PRThread                 *gSocketThread;
 
 #endif // !nsSocketTransportService_h__
--- a/toolkit/crashreporter/google-breakpad/src/client/mac/handler/exception_handler.cc
+++ b/toolkit/crashreporter/google-breakpad/src/client/mac/handler/exception_handler.cc
@@ -276,19 +276,23 @@ bool ExceptionHandler::WriteMinidump(boo
 
   use_minidump_write_mutex_ = true;
   last_minidump_write_result_ = false;
 
   // Lock the mutex.  Since we just created it, this will return immediately.
   if (pthread_mutex_lock(&minidump_write_mutex_) == 0) {
     // Send an empty message to the handle port so that a minidump will
     // be written
-    SendMessageToHandlerThread(write_exception_stream ?
-                                   kWriteDumpWithExceptionMessage :
-                                   kWriteDumpMessage);
+    bool result = SendMessageToHandlerThread(write_exception_stream ?
+                                             kWriteDumpWithExceptionMessage :
+                                             kWriteDumpMessage);
+    if (!result) {
+      pthread_mutex_unlock(&minidump_write_mutex_);
+      return false;
+    }
 
     // Wait for the minidump writer to complete its writing.  It will unlock
     // the mutex when completed
     pthread_mutex_lock(&minidump_write_mutex_);
   }
 
   use_minidump_write_mutex_ = false;
   UpdateNextID();
--- a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/stackwalker.h
+++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/stackwalker.h
@@ -83,17 +83,20 @@ class Stackwalker {
   // argument.  If no suitable concrete subclass exists, returns NULL.
   static Stackwalker* StackwalkerForCPU(
      const SystemInfo* system_info,
      MinidumpContext* context,
      MemoryRegion* memory,
      const CodeModules* modules,
      StackFrameSymbolizer* resolver_helper);
 
-  static void set_max_frames(uint32_t max_frames) { max_frames_ = max_frames; }
+  static void set_max_frames(uint32_t max_frames) {
+    max_frames_ = max_frames;
+    max_frames_set_ = true;
+  }
   static uint32_t max_frames() { return max_frames_; }
 
  protected:
   // system_info identifies the operating system, NULL or empty if unknown.
   // memory identifies a MemoryRegion that provides the stack memory
   // for the stack to walk.  modules, if non-NULL, is a CodeModules
   // object that is used to look up which code module each stack frame is
   // associated with.  frame_symbolizer is a StackFrameSymbolizer object that
@@ -191,14 +194,19 @@ class Stackwalker {
   // the end of the stack has been reached).  GetCallerFrame allocates a new
   // StackFrame (or StackFrame subclass), ownership of which is taken by
   // the caller.
   virtual StackFrame* GetCallerFrame(const CallStack* stack) = 0;
 
   // The maximum number of frames Stackwalker will walk through.
   // This defaults to 1024 to prevent infinite loops.
   static uint32_t max_frames_;
+
+  // Keep track of whether max_frames_ has been set by the user, since
+  // it affects whether or not an error message is printed in the case
+  // where an unwind got stopped by the limit.
+  static bool max_frames_set_;
 };
 
 }  // namespace google_breakpad
 
 
 #endif  // GOOGLE_BREAKPAD_PROCESSOR_STACKWALKER_H__
--- a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker.cc
+++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker.cc
@@ -52,16 +52,17 @@
 #include "processor/stackwalker_x86.h"
 #include "processor/stackwalker_amd64.h"
 #include "processor/stackwalker_arm.h"
 
 namespace google_breakpad {
 
 const int Stackwalker::kRASearchWords = 30;
 uint32_t Stackwalker::max_frames_ = 1024;
+bool Stackwalker::max_frames_set_ = false;
 
 Stackwalker::Stackwalker(const SystemInfo* system_info,
                          MemoryRegion* memory,
                          const CodeModules* modules,
                          StackFrameSymbolizer* frame_symbolizer)
     : system_info_(system_info),
       memory_(memory),
       modules_(modules),
@@ -120,17 +121,20 @@ bool Stackwalker::Walk(CallStack* stack,
         modules_without_symbols->push_back(frame->module);
       }
     }
 
     // Add the frame to the call stack.  Relinquish the ownership claim
     // over the frame, because the stack now owns it.
     stack->frames_.push_back(frame.release());
     if (stack->frames_.size() > max_frames_) {
-      BPLOG(ERROR) << "The stack is over " << max_frames_ << " frames.";
+      // Only emit an error message in the case where the limit that we
+      // reached is the default limit, not set by the user.
+      if (!max_frames_set_)
+        BPLOG(ERROR) << "The stack is over " << max_frames_ << " frames.";
       break;
     }
 
     // Get the next frame and take ownership.
     frame.reset(GetCallerFrame(stack));
   }
 
   return true;
--- a/toolkit/devtools/debugger/tests/unit/test_dbgsocket.js
+++ b/toolkit/devtools/debugger/tests/unit/test_dbgsocket.js
@@ -3,16 +3,17 @@
 
 Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
 Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
 
 let port = 2929;
 
 function run_test()
 {
+  do_print("Starting test at " + new Date().toTimeString());
   // Allow incoming connections.
   DebuggerServer.init(function () true);
   DebuggerServer.addActors("resource://test/testactors.js");
 
   add_test(test_socket_conn);
   add_test(test_socket_shutdown);
   add_test(test_pipe_conn);
 
@@ -32,16 +33,17 @@ function test_socket_conn()
   do_check_eq(DebuggerServer._socketConnections, 0);
   try_open_listener();
   do_print("Debugger server port is " + port);
   do_check_eq(DebuggerServer._socketConnections, 1);
   // Make sure opening the listener twice does nothing.
   do_check_true(DebuggerServer.openListener(port));
   do_check_eq(DebuggerServer._socketConnections, 1);
 
+  do_print("Starting long and unicode tests at " + new Date().toTimeString());
   let unicodeString = "(╯°□°)╯︵ ┻━┻";
   let transport = debuggerSocketConnect("127.0.0.1", port);
   transport.hooks = {
     onPacket: function(aPacket) {
       this.onPacket = function(aPacket) {
         do_check_eq(aPacket.unicode, unicodeString);
         transport.close();
       }
@@ -64,29 +66,32 @@ function test_socket_shutdown()
 {
   do_check_eq(DebuggerServer._socketConnections, 1);
   do_check_true(DebuggerServer.closeListener());
   do_check_eq(DebuggerServer._socketConnections, 0);
   // Make sure closing the listener twice does nothing.
   do_check_false(DebuggerServer.closeListener());
   do_check_eq(DebuggerServer._socketConnections, 0);
 
+  do_print("Connecting to a server socket at " + new Date().toTimeString());
   let transport = debuggerSocketConnect("127.0.0.1", port);
   transport.hooks = {
     onPacket: function(aPacket) {
       // Shouldn't reach this, should never connect.
       do_check_true(false);
     },
 
     onClosed: function(aStatus) {
-      do_check_eq(aStatus, Components.results.NS_ERROR_CONNECTION_REFUSED);
+      do_print("test_socket_shutdown onClosed called at " + new Date().toTimeString());
+      do_check_eq(aStatus, Cr.NS_ERROR_CONNECTION_REFUSED);
       run_next_test();
     }
   };
 
+  do_print("Initializing input stream at " + new Date().toTimeString());
   transport.ready();
 }
 
 function test_pipe_conn()
 {
   let transport = DebuggerServer.connectPipe();
   transport.hooks = {
     onPacket: function(aPacket) {
--- a/tools/profiler/UnwinderThread2.cpp
+++ b/tools/profiler/UnwinderThread2.cpp
@@ -1641,16 +1641,22 @@ void do_breakpad_unwind_Buffer(/*OUT*/PC
 # else
 #   error "Unknown plat"
 # endif
 
   google_breakpad::CallStack* stack = new google_breakpad::CallStack();
 
   std::vector<const google_breakpad::CodeModule*>* modules_without_symbols
     = new std::vector<const google_breakpad::CodeModule*>();
+
+  // Set the max number of frames to a reasonably low level.  By
+  // default Breakpad's limit is 1024, which means it can wind up
+  // spending a lot of time looping on corrupted stacks.
+  sw->set_max_frames(256);
+
   bool b = sw->Walk(stack, modules_without_symbols);
   (void)b;
   delete modules_without_symbols;
 
   unsigned int n_frames = stack->frames()->size();
   unsigned int n_frames_good = 0;
   unsigned int n_frames_dubious = 0;