Merge mozilla-central and inbound
authorEd Morley <emorley@mozilla.com>
Wed, 31 Jul 2013 14:25:28 +0100
changeset 153029 c4dd1430498add735cd0f1b76eaf0b548b288f73
parent 153015 ffd57aa81b5f370a67ae0c0bbd539d6d228154ed (current diff)
parent 153028 d2e6989ff928abb6a79248457cc0f17df59b0b8a (diff)
child 153045 95870d5337eb479fa93898adc925fa60242e2858
child 153054 0021058a0c88640f04a4717a520d8071265c4bf9
child 153059 710c7f7c8e4c204876ba23083417b61c2333a1af
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone25.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central and inbound
--- a/dom/bindings/ErrorResult.h
+++ b/dom/bindings/ErrorResult.h
@@ -10,16 +10,17 @@
 
 #ifndef mozilla_ErrorResult_h
 #define mozilla_ErrorResult_h
 
 #include <stdarg.h>
 
 #include "js/Value.h"
 #include "nscore.h"
+#include "nsStringGlue.h"
 #include "mozilla/Assertions.h"
 
 namespace mozilla {
 
 namespace dom {
 
 enum ErrNum {
 #define MSG_DEF(_name, _argc, _str) \
@@ -140,11 +141,37 @@ private:
   bool mMightHaveUnreportedJSException;
 #endif
 
   // Not to be implemented, to make sure people always pass this by
   // reference, not by value.
   ErrorResult(const ErrorResult&) MOZ_DELETE;
 };
 
+/******************************************************************************
+ ** Macros for checking results
+ ******************************************************************************/
+
+#define ENSURE_SUCCESS(res, ret)                                          \
+  do {                                                                    \
+    if (res.Failed()) {                                                   \
+      nsCString msg;                                                      \
+      msg.AppendPrintf("ENSURE_SUCCESS(%s, %s) failed with "              \
+                       "result 0x%X", #res, #ret, res.ErrorCode());       \
+      NS_WARNING(msg.get());                                              \
+      return ret;                                                         \
+    }                                                                     \
+  } while(0)
+
+#define ENSURE_SUCCESS_VOID(res)                                          \
+  do {                                                                    \
+    if (res.Failed()) {                                                   \
+      nsCString msg;                                                      \
+      msg.AppendPrintf("ENSURE_SUCCESS_VOID(%s) failed with "             \
+                       "result 0x%X", #res, res.ErrorCode());             \
+      NS_WARNING(msg.get());                                              \
+      return;                                                             \
+    }                                                                     \
+  } while(0)
+
 } // namespace mozilla
 
 #endif /* mozilla_ErrorResult_h */
--- a/dom/src/storage/DOMStorageManager.cpp
+++ b/dom/src/storage/DOMStorageManager.cpp
@@ -141,28 +141,19 @@ CreateScopeKey(nsIPrincipal* aPrincipal,
     return NS_ERROR_UNEXPECTED;
   }
 
   nsAutoCString domainScope;
   rv = uri->GetAsciiHost(domainScope);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (domainScope.IsEmpty()) {
-    // About pages have an empty host but a valid path.  Since they are handled
-    // internally by our own redirector, we can trust them and use path as key.
-    // if file:/// protocol, let's make the exact directory the domain
+    // For the file:/// protocol use the exact directory as domain.
     bool isScheme = false;
-    if ((NS_SUCCEEDED(uri->SchemeIs("about", &isScheme)) && isScheme) ||
-        (NS_SUCCEEDED(uri->SchemeIs("moz-safe-about", &isScheme)) && isScheme)) {
-      rv = uri->GetPath(domainScope);
-      NS_ENSURE_SUCCESS(rv, rv);
-      // While the host is always canonicalized to lowercase, the path is not,
-      // thus need to force the casing.
-      ToLowerCase(domainScope);
-    } else if (NS_SUCCEEDED(uri->SchemeIs("file", &isScheme)) && isScheme) {
+    if (NS_SUCCEEDED(uri->SchemeIs("file", &isScheme)) && isScheme) {
       nsCOMPtr<nsIURL> url = do_QueryInterface(uri, &rv);
       NS_ENSURE_SUCCESS(rv, rv);
       rv = url->GetDirectory(domainScope);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   nsAutoCString key;
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -164,23 +164,23 @@ AsyncPanZoomController::InitializeGlobal
 
 AsyncPanZoomController::AsyncPanZoomController(uint64_t aLayersId,
                                                GeckoContentController* aGeckoContentController,
                                                GestureBehavior aGestures)
   :  mLayersId(aLayersId),
      mPaintThrottler(GetFrameTime()),
      mGeckoContentController(aGeckoContentController),
      mRefPtrMonitor("RefPtrMonitor"),
+     mMonitor("AsyncPanZoomController"),
      mTouchListenerTimeoutTask(nullptr),
      mX(this),
      mY(this),
      mAllowZoom(true),
      mMinZoom(MIN_ZOOM),
      mMaxZoom(MAX_ZOOM),
-     mMonitor("AsyncPanZoomController"),
      mLastSampleTime(GetFrameTime()),
      mState(NOTHING),
      mLastAsyncScrollTime(GetFrameTime()),
      mLastAsyncScrollOffset(0, 0),
      mCurrentAsyncScrollOffset(0, 0),
      mAsyncScrollTimeoutTask(nullptr),
      mDPI(72),
      mDisableNextTouchBatch(false),
@@ -248,17 +248,17 @@ WidgetSpaceToCompensatedViewportSpace(co
 }
 
 nsEventStatus
 AsyncPanZoomController::ReceiveInputEvent(const nsInputEvent& aEvent,
                                           nsInputEvent* aOutEvent)
 {
   CSSToScreenScale currentResolution;
   {
-    MonitorAutoLock monitor(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
     currentResolution = mFrameMetrics.CalculateResolution();
   }
 
   nsEventStatus status;
   switch (aEvent.eventStructType) {
   case NS_TOUCH_EVENT: {
     MultiTouchInput event(static_cast<const nsTouchEvent&>(aEvent));
     status = ReceiveInputEvent(event);
@@ -411,17 +411,17 @@ nsEventStatus AsyncPanZoomController::On
 
   ScreenIntPoint point = touch.mScreenPoint;
 
   switch (mState) {
     case ANIMATING_ZOOM:
       // We just interrupted a double-tap animation, so force a redraw in case
       // this touchstart is just a tap that doesn't end up triggering a redraw.
       {
-        MonitorAutoLock monitor(mMonitor);
+        ReentrantMonitorAutoEnter lock(mMonitor);
         // Bring the resolution back in sync with the zoom.
         SetZoomAndResolution(mFrameMetrics.mZoom);
         RequestContentRepaint();
         ScheduleComposite();
       }
       // Fall through.
     case FLING:
       CancelAnimation();
@@ -490,17 +490,17 @@ nsEventStatus AsyncPanZoomController::On
 
 nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent) {
   if (mDisableNextTouchBatch) {
     mDisableNextTouchBatch = false;
     return nsEventStatus_eIgnore;
   }
 
   {
-    MonitorAutoLock monitor(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
     SendAsyncScrollEvent();
   }
 
   switch (mState) {
   case FLING:
     // Should never happen.
     NS_WARNING("Received impossible touch end in OnTouchEnd.");
     // Fall through.
@@ -511,17 +511,17 @@ nsEventStatus AsyncPanZoomController::On
     return nsEventStatus_eIgnore;
 
   case TOUCHING:
     SetState(NOTHING);
     return nsEventStatus_eIgnore;
 
   case PANNING:
     {
-      MonitorAutoLock monitor(mMonitor);
+      ReentrantMonitorAutoEnter lock(mMonitor);
       ScheduleComposite();
       RequestContentRepaint();
     }
     mX.EndTouch();
     mY.EndTouch();
     SetState(FLING);
     return nsEventStatus_eConsumeNoDefault;
 
@@ -564,17 +564,17 @@ nsEventStatus AsyncPanZoomController::On
   if (fabsf(prevSpan) <= EPSILON || fabsf(aEvent.mCurrentSpan) <= EPSILON) {
     // We're still handling it; we've just decided to throw this event away.
     return nsEventStatus_eConsumeNoDefault;
   }
 
   float spanRatio = aEvent.mCurrentSpan / aEvent.mPreviousSpan;
 
   {
-    MonitorAutoLock monitor(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
 
     CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
     gfxFloat userZoom = mFrameMetrics.mZoom.scale;
     ScreenPoint focusPoint = aEvent.mFocusPoint;
 
     CSSPoint focusChange = (mLastZoomFocus - focusPoint) / resolution;
     // If displacing by the change in focus point will take us off page bounds,
     // then reduce the displacement such that it doesn't.
@@ -655,58 +655,58 @@ nsEventStatus AsyncPanZoomController::On
   return nsEventStatus_eConsumeNoDefault;
 }
 
 nsEventStatus AsyncPanZoomController::OnScaleEnd(const PinchGestureInput& aEvent) {
   SetState(PANNING);
   mX.StartTouch(aEvent.mFocusPoint.x);
   mY.StartTouch(aEvent.mFocusPoint.y);
   {
-    MonitorAutoLock monitor(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
     ScheduleComposite();
     RequestContentRepaint();
   }
 
   return nsEventStatus_eConsumeNoDefault;
 }
 
 nsEventStatus AsyncPanZoomController::OnLongPress(const TapGestureInput& aEvent) {
   nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
   if (controller) {
-    MonitorAutoLock monitor(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
 
     CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
     CSSPoint point = WidgetSpaceToCompensatedViewportSpace(aEvent.mPoint, resolution);
     controller->HandleLongTap(gfx::RoundedToInt(point));
     return nsEventStatus_eConsumeNoDefault;
   }
   return nsEventStatus_eIgnore;
 }
 
 nsEventStatus AsyncPanZoomController::OnSingleTapUp(const TapGestureInput& aEvent) {
   return nsEventStatus_eIgnore;
 }
 
 nsEventStatus AsyncPanZoomController::OnSingleTapConfirmed(const TapGestureInput& aEvent) {
   nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
   if (controller) {
-    MonitorAutoLock monitor(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
 
     CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
     CSSPoint point = WidgetSpaceToCompensatedViewportSpace(aEvent.mPoint, resolution);
     controller->HandleSingleTap(gfx::RoundedToInt(point));
     return nsEventStatus_eConsumeNoDefault;
   }
   return nsEventStatus_eIgnore;
 }
 
 nsEventStatus AsyncPanZoomController::OnDoubleTap(const TapGestureInput& aEvent) {
   nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
   if (controller) {
-    MonitorAutoLock monitor(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
 
     if (mAllowZoom) {
       CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
       CSSPoint point = WidgetSpaceToCompensatedViewportSpace(aEvent.mPoint, resolution);
       controller->HandleDoubleTap(gfx::RoundedToInt(point));
     }
 
     return nsEventStatus_eConsumeNoDefault;
@@ -715,17 +715,17 @@ nsEventStatus AsyncPanZoomController::On
 }
 
 nsEventStatus AsyncPanZoomController::OnCancelTap(const TapGestureInput& aEvent) {
   // XXX: Implement this.
   return nsEventStatus_eIgnore;
 }
 
 float AsyncPanZoomController::PanDistance() {
-  MonitorAutoLock monitor(mMonitor);
+  ReentrantMonitorAutoEnter lock(mMonitor);
   return NS_hypot(mX.PanDistance(), mY.PanDistance());
 }
 
 const gfx::Point AsyncPanZoomController::GetVelocityVector() {
   return gfx::Point(mX.GetVelocity(), mY.GetVelocity());
 }
 
 const gfx::Point AsyncPanZoomController::GetAccelerationVector() {
@@ -762,17 +762,17 @@ void AsyncPanZoomController::TrackTouch(
   // Probably a duplicate event, just throw it away.
   if (timeDelta.ToMilliseconds() <= EPSILON) {
     return;
   }
 
   UpdateWithTouchAtDevicePoint(aEvent);
 
   {
-    MonitorAutoLock monitor(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
 
     // We want to inversely scale it because when you're zoomed further in, a
     // larger swipe should move you a shorter distance.
     ScreenToCSSScale inverseResolution = mFrameMetrics.CalculateResolution().Inverse();
 
     gfx::Point displacement(mX.GetDisplacementForDuration(inverseResolution.scale,
                                                           timeDelta),
                             mY.GetDisplacementForDuration(inverseResolution.scale,
@@ -825,17 +825,17 @@ bool AsyncPanZoomController::DoFling(con
   if (timePaintDelta.ToMilliseconds() > gFlingRepaintInterval) {
     RequestContentRepaint();
   }
 
   return true;
 }
 
 void AsyncPanZoomController::CancelAnimation() {
-  MonitorAutoLock monitor(mMonitor);
+  ReentrantMonitorAutoEnter lock(mMonitor);
   mState = NOTHING;
 }
 
 void AsyncPanZoomController::SetCompositorParent(CompositorParent* aCompositorParent) {
   mCompositorParent = aCompositorParent;
 }
 
 void AsyncPanZoomController::ScrollBy(const CSSPoint& aOffset) {
@@ -1047,34 +1047,34 @@ void AsyncPanZoomController::RequestCont
   // Set the zoom back to what it was for the purpose of logic control.
   mFrameMetrics.mZoom = actualZoom;
 }
 
 void
 AsyncPanZoomController::FireAsyncScrollOnTimeout()
 {
   if (mCurrentAsyncScrollOffset != mLastAsyncScrollOffset) {
-    MonitorAutoLock monitor(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
     SendAsyncScrollEvent();
   }
   mAsyncScrollTimeoutTask = nullptr;
 }
 
 bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSampleTime,
                                                             ViewTransform* aNewTransform,
                                                             ScreenPoint& aScrollOffset) {
   // The eventual return value of this function. The compositor needs to know
   // whether or not to advance by a frame as soon as it can. For example, if a
   // fling is happening, it has to keep compositing so that the animation is
   // smooth. If an animation frame is requested, it is the compositor's
   // responsibility to schedule a composite.
   bool requestAnimationFrame = false;
 
   {
-    MonitorAutoLock mon(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
 
     switch (mState) {
     case FLING:
       // If a fling is currently happening, apply it now. We can pull
       // the updated metrics afterwards.
       requestAnimationFrame |= DoFling(aSampleTime - mLastSampleTime);
       break;
     case ANIMATING_ZOOM: {
@@ -1110,17 +1110,17 @@ bool AsyncPanZoomController::SampleConte
 
       break;
     }
     default:
       break;
     }
 
     aScrollOffset = mFrameMetrics.mScrollOffset * mFrameMetrics.CalculateResolution();
-    *aNewTransform = GetCurrentAsyncTransformInternal();
+    *aNewTransform = GetCurrentAsyncTransform();
 
     mCurrentAsyncScrollOffset = mFrameMetrics.mScrollOffset;
   }
 
   // Cancel the mAsyncScrollTimeoutTask because we will fire a
   // mozbrowserasyncscroll event or renew the mAsyncScrollTimeoutTask again.
   if (mAsyncScrollTimeoutTask) {
     mAsyncScrollTimeoutTask->Cancel();
@@ -1129,17 +1129,17 @@ bool AsyncPanZoomController::SampleConte
   // Fire the mozbrowserasyncscroll event immediately if it's been
   // sAsyncScrollThrottleTime ms since the last time we fired the event and the
   // current scroll offset is different than the mLastAsyncScrollOffset we sent
   // with the last event.
   // Otherwise, start a timer to fire the event sAsyncScrollTimeout ms from now.
   TimeDuration delta = aSampleTime - mLastAsyncScrollTime;
   if (delta.ToMilliseconds() > gAsyncScrollThrottleTime &&
       mCurrentAsyncScrollOffset != mLastAsyncScrollOffset) {
-    MonitorAutoLock monitor(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
     mLastAsyncScrollTime = aSampleTime;
     mLastAsyncScrollOffset = mCurrentAsyncScrollOffset;
     SendAsyncScrollEvent();
   }
   else {
     mAsyncScrollTimeoutTask =
       NewRunnableMethod(this, &AsyncPanZoomController::FireAsyncScrollOnTimeout);
     MessageLoop::current()->PostDelayedTask(FROM_HERE,
@@ -1148,32 +1148,29 @@ bool AsyncPanZoomController::SampleConte
   }
 
   mLastSampleTime = aSampleTime;
 
   return requestAnimationFrame;
 }
 
 ViewTransform AsyncPanZoomController::GetCurrentAsyncTransform() {
-  MonitorAutoLock mon(mMonitor);
-  return GetCurrentAsyncTransformInternal();
-}
+  ReentrantMonitorAutoEnter lock(mMonitor);
 
-ViewTransform AsyncPanZoomController::GetCurrentAsyncTransformInternal() {
   LayerPoint metricsScrollOffset;
   if (mLastContentPaintMetrics.IsScrollable()) {
     metricsScrollOffset = mLastContentPaintMetrics.GetScrollOffsetInLayerPixels();
   }
   CSSToScreenScale localScale = mFrameMetrics.CalculateResolution();
   LayerPoint translation = mFrameMetrics.GetScrollOffsetInLayerPixels() - metricsScrollOffset;
   return ViewTransform(-translation, localScale / mLastContentPaintMetrics.mDevPixelsPerCSSPixel);
 }
 
 void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetrics, bool aIsFirstPaint) {
-  MonitorAutoLock monitor(mMonitor);
+  ReentrantMonitorAutoEnter lock(mMonitor);
 
   mLastContentPaintMetrics = aLayerMetrics;
 
   mFrameMetrics.mMayHaveTouchListeners = aLayerMetrics.mMayHaveTouchListeners;
 
   // TODO: Once a mechanism for calling UpdateScrollOffset() when content does
   //       a scrollTo() is implemented for B2G (bug 895905), this block can be removed.
 #ifndef MOZ_WIDGET_ANDROID
@@ -1229,22 +1226,22 @@ void AsyncPanZoomController::NotifyLayer
   }
 
   if (needContentRepaint) {
     RequestContentRepaint();
   }
 }
 
 const FrameMetrics& AsyncPanZoomController::GetFrameMetrics() {
-  mMonitor.AssertCurrentThreadOwns();
+  mMonitor.AssertCurrentThreadIn();
   return mFrameMetrics;
 }
 
 void AsyncPanZoomController::UpdateCompositionBounds(const ScreenIntRect& aCompositionBounds) {
-  MonitorAutoLock mon(mMonitor);
+  ReentrantMonitorAutoEnter lock(mMonitor);
 
   ScreenIntRect oldCompositionBounds = mFrameMetrics.mCompositionBounds;
   mFrameMetrics.mCompositionBounds = aCompositionBounds;
 
   // If the window had 0 dimensions before, or does now, we don't want to
   // repaint or update the zoom since we'll run into rendering issues and/or
   // divide-by-zero. This manifests itself as the screen flashing. If the page
   // has gone out of view, the buffer will be cleared elsewhere anyways.
@@ -1268,17 +1265,17 @@ void AsyncPanZoomController::CancelDefau
 void AsyncPanZoomController::DetectScrollableSubframe() {
   mDelayPanning = true;
 }
 
 void AsyncPanZoomController::ZoomToRect(CSSRect aRect) {
   SetState(ANIMATING_ZOOM);
 
   {
-    MonitorAutoLock mon(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
 
     ScreenIntRect compositionBounds = mFrameMetrics.mCompositionBounds;
     CSSRect cssPageRect = mFrameMetrics.mScrollableRect;
     CSSPoint scrollOffset = mFrameMetrics.mScrollOffset;
     float currentZoom = mFrameMetrics.mZoom.scale;
     float targetZoom;
     float intrinsicScale = mFrameMetrics.CalculateIntrinsicScale().scale;
 
@@ -1399,17 +1396,17 @@ void AsyncPanZoomController::ContentRece
 }
 
 void AsyncPanZoomController::SetState(PanZoomState aNewState) {
 
   PanZoomState oldState;
 
   // Intentional scoping for mutex
   {
-    MonitorAutoLock monitor(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
     oldState = mState;
     mState = aNewState;
   }
 
   if (mGeckoContentController) {
     if (oldState == PANNING && aNewState != PANNING) {
       mGeckoContentController->HandlePanEnd();
     } else if (oldState != PANNING && aNewState == PANNING) {
@@ -1419,17 +1416,17 @@ void AsyncPanZoomController::SetState(Pa
 }
 
 void AsyncPanZoomController::TimeoutTouchListeners() {
   mTouchListenerTimeoutTask = nullptr;
   ContentReceivedTouch(false);
 }
 
 void AsyncPanZoomController::SetZoomAndResolution(const ScreenToScreenScale& aZoom) {
-  mMonitor.AssertCurrentThreadOwns();
+  mMonitor.AssertCurrentThreadIn();
   mFrameMetrics.mZoom = aZoom;
   CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
   // We use ScreenToLayerScale(1) below in order to ask gecko to render
   // what's currently visible on the screen. This is effectively turning
   // the async zoom amount into the gecko zoom amount.
   mFrameMetrics.mResolution = resolution / mFrameMetrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
 }
 
@@ -1453,29 +1450,30 @@ void AsyncPanZoomController::SendAsyncSc
   if (!controller) {
     return;
   }
 
   FrameMetrics::ViewID scrollId;
   CSSRect contentRect;
   CSSSize scrollableSize;
   {
-    // XXX bug 890932 - there should be a lock here. but it causes a deadlock.
+    ReentrantMonitorAutoEnter lock(mMonitor);
+
     scrollId = mFrameMetrics.mScrollId;
     scrollableSize = mFrameMetrics.mScrollableRect.Size();
     contentRect = mFrameMetrics.CalculateCompositedRectInCssPixels();
     contentRect.MoveTo(mCurrentAsyncScrollOffset);
   }
 
   controller->SendAsyncScrollDOMEvent(scrollId, contentRect, scrollableSize);
 }
 
 void AsyncPanZoomController::UpdateScrollOffset(const CSSPoint& aScrollOffset)
 {
-  MonitorAutoLock monitor(mMonitor);
+  ReentrantMonitorAutoEnter lock(mMonitor);
   mFrameMetrics.mScrollOffset = aScrollOffset;
 }
 
 bool AsyncPanZoomController::Matches(const ScrollableLayerGuid& aGuid)
 {
   // TODO: also check the presShellId and mScrollId, once those are
   // fully propagated everywhere in RenderFrameParent and AndroidJNI.
   return aGuid.mLayersId == mLayersId;
--- a/gfx/layers/ipc/AsyncPanZoomController.h
+++ b/gfx/layers/ipc/AsyncPanZoomController.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_layers_AsyncPanZoomController_h
 #define mozilla_layers_AsyncPanZoomController_h
 
 #include "GeckoContentController.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Monitor.h"
+#include "mozilla/ReentrantMonitor.h"
 #include "mozilla/RefPtr.h"
 #include "InputData.h"
 #include "Axis.h"
 #include "TaskThrottler.h"
 #include "mozilla/layers/APZCTreeManager.h"
 
 #include "base/message_loop.h"
 
@@ -212,20 +213,16 @@ public:
 
   /**
    * Returns the incremental transformation corresponding to the async pan/zoom
    * in progress. That is, when this transform is multiplied with the layer's
    * existing transform, it will make the layer appear with the desired pan/zoom
    * amount.
    */
   ViewTransform GetCurrentAsyncTransform();
-private:
-  /* Internal method of above. Callers to this MUST hold the monitor. */
-  ViewTransform GetCurrentAsyncTransformInternal();
-public:
 
   /**
    * Sets the DPI of the device for use within panning and zooming logic. It is
    * a platform responsibility to set this on initialization of this class and
    * whenever it changes.
    */
   void SetDPI(int aDPI);
 
@@ -530,17 +527,17 @@ protected:
   // Both |mFrameMetrics| and |mLastContentPaintMetrics| are protected by the
   // monitor. Do not read from or modify either of them without locking.
   FrameMetrics mFrameMetrics;
 
   // Protects |mFrameMetrics|, |mLastContentPaintMetrics|, and |mState|.
   // Before manipulating |mFrameMetrics| or |mLastContentPaintMetrics|, the
   // monitor should be held. When setting |mState|, either the SetState()
   // function can be used, or the monitor can be held and then |mState| updated.
-  Monitor mMonitor;
+  ReentrantMonitor mMonitor;
 
 private:
   // Metrics of the container layer corresponding to this APZC. This is
   // stored here so that it is accessible from the UI/controller thread.
   // These are the metrics at last content paint, the most recent
   // values we were notified of in NotifyLayersUpdate(). Since it represents
   // the Gecko state, it should be used as a basis for untransformation when
   // sending messages back to Gecko.
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -43,17 +43,17 @@ class TestAPZCContainerLayer : public Co
 
 class TestAsyncPanZoomController : public AsyncPanZoomController {
 public:
   TestAsyncPanZoomController(uint64_t aLayersId, MockContentController* mcc)
     : AsyncPanZoomController(aLayersId, mcc)
   {}
 
   void SetFrameMetrics(const FrameMetrics& metrics) {
-    MonitorAutoLock lock(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
     mFrameMetrics = metrics;
   }
 };
 
 class TestAPZCTreeManager : public APZCTreeManager {
 protected:
   void AssertOnCompositorThread() MOZ_OVERRIDE { /* no-op */ }
 };
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -980,16 +980,24 @@ GetObjectMetadata(JSContext *cx, unsigne
         JS_ReportError(cx, "Argument must be an object");
         return false;
     }
 
     args.rval().setObjectOrNull(GetObjectMetadata(&args[0].toObject()));
     return true;
 }
 
+JSBool
+js::testingFunc_bailout(JSContext *cx, unsigned argc, jsval *vp)
+{
+    // NOP when not in IonMonkey
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    return true;
+}
+
 static JSFunctionSpecWithHelp TestingFunctions[] = {
     JS_FN_HELP("gc", ::GC, 0, 0,
 "gc([obj] | 'compartment')",
 "  Run the garbage collector. When obj is given, GC only its compartment.\n"
 "  If 'compartment' is given, GC any compartments that were scheduled for\n"
 "  GC via schedulegc."),
 
     JS_FN_HELP("minorgc", ::MinorGC, 0, 0,
@@ -1158,16 +1166,20 @@ static JSFunctionSpecWithHelp TestingFun
     JS_FN_HELP("setObjectMetadata", SetObjectMetadata, 2, 0,
 "setObjectMetadata(obj, metadataObj)",
 "  Change the metadata for an object."),
 
     JS_FN_HELP("getObjectMetadata", GetObjectMetadata, 1, 0,
 "getObjectMetadata(obj)",
 "  Get the metadata for an object."),
 
+    JS_FN_HELP("bailout", testingFunc_bailout, 0, 0,
+"bailout()",
+"  Force a bailout out of ionmonkey (if running in ionmonkey)."),
+
     JS_FS_HELP_END
 };
 
 bool
 js::DefineTestingFunctions(JSContext *cx, HandleObject obj)
 {
     return JS_DefineFunctionsWithHelp(cx, obj, TestingFunctions);
 }
--- a/js/src/builtin/TestingFunctions.h
+++ b/js/src/builtin/TestingFunctions.h
@@ -12,11 +12,14 @@
 namespace js {
 
 bool
 DefineTestingFunctions(JSContext *cx, HandleObject obj);
 
 JSBool
 testingFunc_inParallelSection(JSContext *cx, unsigned argc, jsval *vp);
 
+JSBool
+testingFunc_bailout(JSContext *cx, unsigned argc, jsval *vp);
+
 } /* namespace js */
 
 #endif /* builtin_TestingFunctions_h */
--- a/js/src/ion/AsmJS.cpp
+++ b/js/src/ion/AsmJS.cpp
@@ -31,16 +31,17 @@
 using namespace js;
 using namespace js::frontend;
 using namespace js::ion;
 
 using mozilla::AddToHash;
 using mozilla::ArrayLength;
 using mozilla::DebugOnly;
 using mozilla::HashGeneric;
+using mozilla::IsNaN;
 using mozilla::IsNegativeZero;
 using mozilla::Maybe;
 using mozilla::Move;
 using mozilla::MoveRef;
 
 static const size_t LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 1 << 12;
 
 /*****************************************************************************/
@@ -750,42 +751,58 @@ IsNumericLiteral(ParseNode *pn)
 {
     return pn->isKind(PNK_NUMBER) ||
            (pn->isKind(PNK_NEG) && UnaryKid(pn)->isKind(PNK_NUMBER));
 }
 
 static NumLit
 ExtractNumericLiteral(ParseNode *pn)
 {
+    // The JS grammar treats -42 as -(42) (i.e., with separate grammar
+    // productions) for the unary - and literal 42). However, the asm.js spec
+    // recognizes -42 (modulo parens, so -(42) and -((42))) as a single literal
+    // so fold the two potential parse nodes into a single double value.
     JS_ASSERT(IsNumericLiteral(pn));
     ParseNode *numberNode;
     double d;
     if (pn->isKind(PNK_NEG)) {
         numberNode = UnaryKid(pn);
         d = -NumberNodeValue(numberNode);
     } else {
         numberNode = pn;
         d = NumberNodeValue(numberNode);
     }
 
+    // The asm.js spec syntactically distinguishes any literal containing a
+    // decimal point or the literal -0 as having double type.
     if (NumberNodeHasFrac(numberNode) || IsNegativeZero(d))
         return NumLit(NumLit::Double, DoubleValue(d));
 
+    // The syntactic checks above rule out these double values.
+    JS_ASSERT(!IsNegativeZero(d));
+    JS_ASSERT(!IsNaN(d));
+
+    // Although doubles can only *precisely* represent 53-bit integers, they
+    // can *imprecisely* represent integers much bigger than an int64_t.
+    // Furthermore, d may be inf or -inf. In both cases, casting to an int64_t
+    // is undefined, so test against the integer bounds using doubles.
+    if (d < double(INT32_MIN) || d > double(UINT32_MAX))
+        return NumLit(NumLit::OutOfRangeInt, UndefinedValue());
+
+    // With the above syntactic and range limitations, d is definitely an
+    // integer in the range [INT32_MIN, UINT32_MAX] range.
     int64_t i64 = int64_t(d);
-
     if (i64 >= 0) {
         if (i64 <= INT32_MAX)
             return NumLit(NumLit::Fixnum, Int32Value(i64));
-        if (i64 <= UINT32_MAX)
-            return NumLit(NumLit::BigUnsigned, Int32Value(uint32_t(i64)));
-        return NumLit(NumLit::OutOfRangeInt, UndefinedValue());
-    }
-    if (i64 >= INT32_MIN)
-        return NumLit(NumLit::NegativeInt, Int32Value(i64));
-    return NumLit(NumLit::OutOfRangeInt, UndefinedValue());
+        JS_ASSERT(i64 <= UINT32_MAX);
+        return NumLit(NumLit::BigUnsigned, Int32Value(uint32_t(i64)));
+    }
+    JS_ASSERT(i64 >= INT32_MIN);
+    return NumLit(NumLit::NegativeInt, Int32Value(i64));
 }
 
 static inline bool
 IsLiteralUint32(ParseNode *pn, uint32_t *u32)
 {
     if (!IsNumericLiteral(pn))
         return false;
 
@@ -1431,23 +1448,18 @@ class MOZ_STACK_CLASS ModuleCompiler
             return false;
         return exits_.add(p, Move(exitDescriptor), *exitIndex);
     }
     bool addGlobalAccess(AsmJSGlobalAccess access) {
         return globalAccesses_.append(access);
     }
 
     bool collectAccesses(MIRGenerator &gen) {
-#ifdef JS_CPU_ARM
-        if (!module_->addBoundsChecks(gen.asmBoundsChecks()))
-            return false;
-#else
         if (!module_->addHeapAccesses(gen.heapAccesses()))
             return false;
-#endif
         if (!globalAccesses_.appendAll(gen.globalAccesses()))
             return false;
         return true;
     }
 
 #ifdef MOZ_VTUNE
     bool trackProfiledFunction(const Func &func, unsigned endCodeOffset) {
         unsigned startCodeOffset = func.code()->offset();
@@ -1584,36 +1596,31 @@ class MOZ_STACK_CLASS ModuleCompiler
         // Function-pointer table entries
         for (unsigned i = 0; i < funcPtrTables_.length(); i++) {
             FuncPtrTable &table = funcPtrTables_[i];
             uint8_t **data = module_->globalDataOffsetToFuncPtrTable(table.globalDataOffset());
             for (unsigned j = 0; j < table.numElems(); j++)
                 data[j] = code + masm_.actualOffset(table.elem(j).code()->offset());
         }
 
-        // Global accesses in function bodies
+        // Fix up heap/global accesses now that compilation has finished
 #ifdef JS_CPU_ARM
-        JS_ASSERT(globalAccesses_.length() == 0);
         // The AsmJSHeapAccess offsets need to be updated to reflect the
         // "actualOffset" (an ARM distinction).
-        module_->convertBoundsChecksToActualOffset(masm_);
-
+        for (unsigned i = 0; i < module_->numHeapAccesses(); i++) {
+            AsmJSHeapAccess &access = module_->heapAccess(i);
+            access.setOffset(masm_.actualOffset(access.offset()));
+        }
+        JS_ASSERT(globalAccesses_.length() == 0);
 #else
-
         for (unsigned i = 0; i < globalAccesses_.length(); i++) {
             AsmJSGlobalAccess access = globalAccesses_[i];
             masm_.patchAsmJSGlobalAccess(access.offset, code, codeBytes, access.globalDataOffset);
         }
 #endif
-        // The AsmJSHeapAccess offsets need to be updated to reflect the
-        // "actualOffset" (an ARM distinction).
-        for (unsigned i = 0; i < module_->numHeapAccesses(); i++) {
-            AsmJSHeapAccess &access = module_->heapAccess(i);
-            access.updateOffset(masm_.actualOffset(access.offset()));
-        }
 
         *module = module_.forget();
 
         buildCompilationTimeReport(report);
         return true;
     }
 };
 
--- a/js/src/ion/AsmJSLink.cpp
+++ b/js/src/ion/AsmJSLink.cpp
@@ -215,32 +215,17 @@ DynamicallyLinkModule(JSContext *cx, Cal
         heap = &bufferVal.toObject().as<ArrayBufferObject>();
 
         if (!IsPowerOfTwo(heap->byteLength()) || heap->byteLength() < AsmJSAllocationGranularity)
             return LinkFail(cx, "ArrayBuffer byteLength must be a power of two greater than or equal to 4096");
 
         if (!ArrayBufferObject::prepareForAsmJS(cx, heap))
             return LinkFail(cx, "Unable to prepare ArrayBuffer for asm.js use");
 
-#if defined(JS_CPU_X86)
-        void *heapOffset = (void*)heap->dataPointer();
-        void *heapLength = (void*)heap->byteLength();
-        uint8_t *code = module.functionCode();
-        for (unsigned i = 0; i < module.numHeapAccesses(); i++) {
-            const AsmJSHeapAccess &access = module.heapAccess(i);
-            JSC::X86Assembler::setPointer(access.patchLengthAt(code), heapLength);
-            JSC::X86Assembler::setPointer(access.patchOffsetAt(code), heapOffset);
-        }
-#elif defined(JS_CPU_ARM)
-        // Now the length of the array is know, patch all of the bounds check sites
-        // with the new length.
-        ion::IonContext ic(cx, NULL);
-        module.patchBoundsChecks(heap->byteLength());
-
-#endif
+        module.patchHeapAccesses(heap, cx);
     }
 
     AutoObjectVector ffis(cx);
     if (!ffis.resize(module.numFFIs()))
         return false;
 
     for (unsigned i = 0; i < module.numGlobals(); i++) {
         AsmJSModule::Global &global = module.global(i);
--- a/js/src/ion/AsmJSModule.cpp
+++ b/js/src/ion/AsmJSModule.cpp
@@ -67,16 +67,36 @@ js::NewAsmJSModuleObject(JSContext *cx, 
     JSObject *obj = NewObjectWithGivenProto(cx, &AsmJSModuleClass, NULL, NULL);
     if (!obj)
         return NULL;
 
     obj->setReservedSlot(ASM_CODE_RESERVED_SLOT, PrivateValue(module->forget()));
     return obj;
 }
 
+void
+AsmJSModule::patchHeapAccesses(ArrayBufferObject *heap, JSContext *cx)
+{
+    JS_ASSERT(IsPowerOfTwo(heap->byteLength()));
+#if defined(JS_CPU_X86)
+    void *heapOffset = (void*)heap->dataPointer();
+    void *heapLength = (void*)heap->byteLength();
+    for (unsigned i = 0; i < heapAccesses_.length(); i++) {
+        JSC::X86Assembler::setPointer(heapAccesses_[i].patchLengthAt(code_), heapLength);
+        JSC::X86Assembler::setPointer(heapAccesses_[i].patchOffsetAt(code_), heapOffset);
+    }
+#elif defined(JS_CPU_ARM)
+    ion::IonContext ic(cx, NULL);
+    ion::AutoFlushCache afc("patchBoundsCheck");
+    uint32_t bits = mozilla::CeilingLog2(heap->byteLength());
+    for (unsigned i = 0; i < heapAccesses_.length(); i++)
+        ion::Assembler::updateBoundsCheck(bits, (ion::Instruction*)(heapAccesses_[i].offset() + code_));
+#endif
+}
+
 AsmJSModule::~AsmJSModule()
 {
     if (code_) {
         for (unsigned i = 0; i < numExits(); i++) {
             AsmJSModule::ExitDatum &exitDatum = exitIndexToGlobalDatum(i);
             if (!exitDatum.fun)
                 continue;
 
--- a/js/src/ion/AsmJSModule.h
+++ b/js/src/ion/AsmJSModule.h
@@ -355,31 +355,25 @@ class AsmJSModule
         }
     };
 
   private:
     typedef Vector<ExportedFunction, 0, SystemAllocPolicy> ExportedFunctionVector;
     typedef Vector<Global, 0, SystemAllocPolicy> GlobalVector;
     typedef Vector<Exit, 0, SystemAllocPolicy> ExitVector;
     typedef Vector<ion::AsmJSHeapAccess, 0, SystemAllocPolicy> HeapAccessVector;
-#if defined(JS_CPU_ARM)
-    typedef Vector<ion::AsmJSBoundsCheck, 0, SystemAllocPolicy> BoundsCheckVector;
-#endif
     typedef Vector<ion::IonScriptCounts *, 0, SystemAllocPolicy> FunctionCountsVector;
 #if defined(MOZ_VTUNE) or defined(JS_ION_PERF)
     typedef Vector<ProfiledFunction, 0, SystemAllocPolicy> ProfiledFunctionVector;
 #endif
 
     GlobalVector                          globals_;
     ExitVector                            exits_;
     ExportedFunctionVector                exports_;
     HeapAccessVector                      heapAccesses_;
-#if defined(JS_CPU_ARM)
-    BoundsCheckVector                     boundsChecks_;
-#endif
 #if defined(MOZ_VTUNE)
     ProfiledFunctionVector                profiledFunctions_;
 #endif
 #if defined(JS_ION_PERF)
     ProfiledFunctionVector                perfProfiledFunctions_;
     Vector<ProfiledBlocksFunction, 0, SystemAllocPolicy> perfProfiledBlocksFunctions_;
 #endif
 
@@ -671,43 +665,17 @@ class AsmJSModule
         return heapAccesses_.length();
     }
     ion::AsmJSHeapAccess &heapAccess(unsigned i) {
         return heapAccesses_[i];
     }
     const ion::AsmJSHeapAccess &heapAccess(unsigned i) const {
         return heapAccesses_[i];
     }
-#if defined(JS_CPU_ARM)
-    bool addBoundsChecks(const ion::AsmJSBoundsCheckVector &checks) {
-        return boundsChecks_.appendAll(checks);
-    }
-    void convertBoundsChecksToActualOffset(ion::MacroAssembler &masm) {
-        for (unsigned i = 0; i < boundsChecks_.length(); i++)
-            boundsChecks_[i].setOffset(masm.actualOffset(boundsChecks_[i].offset()));
-    }
-
-    void patchBoundsChecks(unsigned heapSize) {
-        if (heapSize == 0)
-            return;
-
-        ion::AutoFlushCache afc("patchBoundsCheck");
-        uint32_t bits = mozilla::CeilingLog2(heapSize);
-
-        for (unsigned i = 0; i < boundsChecks_.length(); i++)
-            ion::Assembler::updateBoundsCheck(bits, (ion::Instruction*)(boundsChecks_[i].offset() + code_));
-
-    }
-    unsigned numBoundsChecks() const {
-        return boundsChecks_.length();
-    }
-    const ion::AsmJSBoundsCheck &boundsCheck(unsigned i) const {
-        return boundsChecks_[i];
-    }
-#endif
+    void patchHeapAccesses(ArrayBufferObject *heap, JSContext *cx);
 
     void takeOwnership(JSC::ExecutablePool *pool, uint8_t *code, size_t codeBytes, size_t totalBytes) {
         JS_ASSERT(uintptr_t(code) % AsmJSPageSize == 0);
         codePool_ = pool;
         code_ = code;
         codeBytes_ = codeBytes;
         totalBytes_ = totalBytes;
     }
--- a/js/src/ion/BaselineBailouts.cpp
+++ b/js/src/ion/BaselineBailouts.cpp
@@ -1152,17 +1152,17 @@ InitFromBailout(JSContext *cx, HandleScr
         return false;
 
     // Push rectifier frame descriptor
     if (!builder.writeWord(rectifierFrameDescr, "Descriptor"))
         return false;
 
     // Push return address into the ArgumentsRectifier code, immediately after the ioncode
     // call.
-    void *rectReturnAddr = cx->compartment()->ionCompartment()->getArgumentsRectifierReturnAddr();
+    void *rectReturnAddr = cx->runtime()->ionRuntime()->getArgumentsRectifierReturnAddr();
     JS_ASSERT(rectReturnAddr);
     if (!builder.writePtr(rectReturnAddr, "ReturnAddr"))
         return false;
 
     return true;
 }
 
 uint32_t
--- a/js/src/ion/BaselineCompiler.cpp
+++ b/js/src/ion/BaselineCompiler.cpp
@@ -513,17 +513,17 @@ bool
 BaselineCompiler::emitDebugTrap()
 {
     JS_ASSERT(debugMode_);
     JS_ASSERT(frame.numUnsyncedSlots() == 0);
 
     bool enabled = script->stepModeEnabled() || script->hasBreakpointsAt(pc);
 
     // Emit patchable call to debug trap handler.
-    IonCode *handler = cx->compartment()->ionCompartment()->debugTrapHandler(cx);
+    IonCode *handler = cx->runtime()->ionRuntime()->debugTrapHandler(cx);
     mozilla::DebugOnly<CodeOffsetLabel> offset = masm.toggledCall(handler, enabled);
 
 #ifdef DEBUG
     // Patchable call offset has to match the pc mapping offset.
     PCMappingEntry &entry = pcMappingEntries_[pcMappingEntries_.length() - 1];
     JS_ASSERT((&offset)->offset() == entry.nativeOffset);
 #endif
 
--- a/js/src/ion/BaselineIC.cpp
+++ b/js/src/ion/BaselineIC.cpp
@@ -557,43 +557,40 @@ ICStubCompiler::getStubCode()
     JS_ASSERT(entersStubFrame_ == ICStub::CanMakeCalls(kind));
 
     return newStubCode;
 }
 
 bool
 ICStubCompiler::tailCallVM(const VMFunction &fun, MacroAssembler &masm)
 {
-    IonCompartment *ion = cx->compartment()->ionCompartment();
-    IonCode *code = ion->getVMWrapper(fun);
+    IonCode *code = cx->runtime()->ionRuntime()->getVMWrapper(fun);
     if (!code)
         return false;
 
     uint32_t argSize = fun.explicitStackSlots() * sizeof(void *);
     EmitTailCallVM(code, masm, argSize);
     return true;
 }
 
 bool
 ICStubCompiler::callVM(const VMFunction &fun, MacroAssembler &masm)
 {
-    IonCompartment *ion = cx->compartment()->ionCompartment();
-    IonCode *code = ion->getVMWrapper(fun);
+    IonCode *code = cx->runtime()->ionRuntime()->getVMWrapper(fun);
     if (!code)
         return false;
 
     EmitCallVM(code, masm);
     return true;
 }
 
 bool
 ICStubCompiler::callTypeUpdateIC(MacroAssembler &masm, uint32_t objectOffset)
 {
-    IonCompartment *ion = cx->compartment()->ionCompartment();
-    IonCode *code = ion->getVMWrapper(DoTypeUpdateFallbackInfo);
+    IonCode *code = cx->runtime()->ionRuntime()->getVMWrapper(DoTypeUpdateFallbackInfo);
     if (!code)
         return false;
 
     EmitCallTypeUpdateIC(masm, code, objectOffset);
     return true;
 }
 
 void
@@ -5746,17 +5743,17 @@ ICGetProp_CallScripted::Compiler::genera
     Label noUnderflow;
     masm.load16ZeroExtend(Address(callee, offsetof(JSFunction, nargs)), scratch);
     masm.branch32(Assembler::Equal, scratch, Imm32(0), &noUnderflow);
     {
         // Call the arguments rectifier.
         JS_ASSERT(ArgumentsRectifierReg != code);
 
         IonCode *argumentsRectifier =
-            cx->compartment()->ionCompartment()->getArgumentsRectifier(SequentialExecution);
+            cx->runtime()->ionRuntime()->getArgumentsRectifier(SequentialExecution);
 
         masm.movePtr(ImmGCPtr(argumentsRectifier), code);
         masm.loadPtr(Address(code, IonCode::offsetOfCode()), code);
         masm.mov(Imm32(0), ArgumentsRectifierReg);
     }
 
     masm.bind(&noUnderflow);
 
@@ -6672,17 +6669,17 @@ ICSetProp_CallScripted::Compiler::genera
     Label noUnderflow;
     masm.load16ZeroExtend(Address(callee, offsetof(JSFunction, nargs)), scratch);
     masm.branch32(Assembler::BelowOrEqual, scratch, Imm32(1), &noUnderflow);
     {
         // Call the arguments rectifier.
         JS_ASSERT(ArgumentsRectifierReg != code);
 
         IonCode *argumentsRectifier =
-            cx->compartment()->ionCompartment()->getArgumentsRectifier(SequentialExecution);
+            cx->runtime()->ionRuntime()->getArgumentsRectifier(SequentialExecution);
 
         masm.movePtr(ImmGCPtr(argumentsRectifier), code);
         masm.loadPtr(Address(code, IonCode::offsetOfCode()), code);
         masm.mov(Imm32(1), ArgumentsRectifierReg);
     }
 
     masm.bind(&noUnderflow);
 
@@ -7430,17 +7427,17 @@ ICCallScriptedCompiler::generateStubCode
     masm.load16ZeroExtend(Address(callee, offsetof(JSFunction, nargs)), callee);
     masm.branch32(Assembler::AboveOrEqual, argcReg, callee, &noUnderflow);
     {
         // Call the arguments rectifier.
         JS_ASSERT(ArgumentsRectifierReg != code);
         JS_ASSERT(ArgumentsRectifierReg != argcReg);
 
         IonCode *argumentsRectifier =
-            cx->compartment()->ionCompartment()->getArgumentsRectifier(SequentialExecution);
+            cx->runtime()->ionRuntime()->getArgumentsRectifier(SequentialExecution);
 
         masm.movePtr(ImmGCPtr(argumentsRectifier), code);
         masm.loadPtr(Address(code, IonCode::offsetOfCode()), code);
         masm.mov(argcReg, ArgumentsRectifierReg);
     }
 
     masm.bind(&noUnderflow);
 
@@ -7689,17 +7686,17 @@ ICCall_ScriptedApplyArguments::Compiler:
     Label noUnderflow;
     masm.branch32(Assembler::AboveOrEqual, argcReg, scratch, &noUnderflow);
     {
         // Call the arguments rectifier.
         JS_ASSERT(ArgumentsRectifierReg != target);
         JS_ASSERT(ArgumentsRectifierReg != argcReg);
 
         IonCode *argumentsRectifier =
-            cx->compartment()->ionCompartment()->getArgumentsRectifier(SequentialExecution);
+            cx->runtime()->ionRuntime()->getArgumentsRectifier(SequentialExecution);
 
         masm.movePtr(ImmGCPtr(argumentsRectifier), target);
         masm.loadPtr(Address(target, IonCode::offsetOfCode()), target);
         masm.mov(argcReg, ArgumentsRectifierReg);
     }
     masm.bind(&noUnderflow);
     regs.add(argcReg);
 
--- a/js/src/ion/BaselineJIT.cpp
+++ b/js/src/ion/BaselineJIT.cpp
@@ -80,17 +80,17 @@ IsJSDEnabled(JSContext *cx)
 
 static IonExecStatus
 EnterBaseline(JSContext *cx, EnterJitData &data)
 {
     JS_CHECK_RECURSION(cx, return IonExec_Aborted);
     JS_ASSERT(ion::IsBaselineEnabled(cx));
     JS_ASSERT_IF(data.osrFrame, CheckFrame(data.osrFrame));
 
-    EnterIonCode enter = cx->compartment()->ionCompartment()->enterBaselineJIT();
+    EnterIonCode enter = cx->runtime()->ionRuntime()->enterBaseline();
 
     // Caller must construct |this| before invoking the Ion function.
     JS_ASSERT_IF(data.constructing, data.maxArgv[0].isObject());
 
     data.result.setInt32(data.numActualArgs);
     {
         AssertCompartmentUnchanged pcc(cx);
         IonContext ictx(cx, NULL);
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -1294,17 +1294,17 @@ CodeGenerator::visitOutOfLineCallPostWri
         objreg = regs.takeAny();
         masm.movePtr(ImmGCPtr(&obj->toConstant()->toObject()), objreg);
     } else {
         objreg = ToRegister(obj);
         regs.takeUnchecked(objreg);
     }
 
     Register runtimereg = regs.takeAny();
-    masm.mov(ImmWord(GetIonContext()->compartment->rt), runtimereg);
+    masm.mov(ImmWord(gen->compartment->rt), runtimereg);
 
     masm.setupUnalignedABICall(2, regs.takeAny());
     masm.passABIArg(runtimereg);
     masm.passABIArg(objreg);
     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, PostWriteBarrier));
 
     restoreLive(ool->lir());
 
@@ -1316,17 +1316,17 @@ CodeGenerator::visitOutOfLineCallPostWri
 bool
 CodeGenerator::visitPostWriteBarrierO(LPostWriteBarrierO *lir)
 {
 #ifdef JSGC_GENERATIONAL
     OutOfLineCallPostWriteBarrier *ool = new OutOfLineCallPostWriteBarrier(lir, lir->object());
     if (!addOutOfLineCode(ool))
         return false;
 
-    Nursery &nursery = GetIonContext()->compartment->rt->gcNursery;
+    Nursery &nursery = gen->compartment->rt->gcNursery;
 
     if (lir->object()->isConstant()) {
         JS_ASSERT(!nursery.isInside(&lir->object()->toConstant()->toObject()));
     } else {
         Label tenured;
         Register objreg = ToRegister(lir->object());
         masm.branchPtr(Assembler::Below, objreg, ImmWord(nursery.start()), &tenured);
         masm.branchPtr(Assembler::Below, objreg, ImmWord(nursery.heapEnd()), ool->rejoin());
@@ -1348,17 +1348,17 @@ CodeGenerator::visitPostWriteBarrierV(LP
 #ifdef JSGC_GENERATIONAL
     OutOfLineCallPostWriteBarrier *ool = new OutOfLineCallPostWriteBarrier(lir, lir->object());
     if (!addOutOfLineCode(ool))
         return false;
 
     ValueOperand value = ToValue(lir, LPostWriteBarrierV::Input);
     masm.branchTestObject(Assembler::NotEqual, value, ool->rejoin());
 
-    Nursery &nursery = GetIonContext()->compartment->rt->gcNursery;
+    Nursery &nursery = gen->compartment->rt->gcNursery;
 
     if (lir->object()->isConstant()) {
         JS_ASSERT(!nursery.isInside(&lir->object()->toConstant()->toObject()));
     } else {
         Label tenured;
         Register objreg = ToRegister(lir->object());
         masm.branchPtr(Assembler::Below, objreg, ImmWord(nursery.start()), &tenured);
         masm.branchPtr(Assembler::Below, objreg, ImmWord(nursery.heapEnd()), ool->rejoin());
@@ -1640,18 +1640,17 @@ CodeGenerator::visitCallGeneric(LCallGen
     uint32_t unusedStack = StackOffsetOfPassedArg(call->argslot());
     ExecutionMode executionMode = gen->info().executionMode();
     Label uncompiled, thunk, makeCall, end;
 
     // Known-target case is handled by LCallKnown.
     JS_ASSERT(!call->hasSingleTarget());
 
     // Generate an ArgumentsRectifier.
-    IonCompartment *ion = gen->ionCompartment();
-    IonCode *argumentsRectifier = ion->getArgumentsRectifier(executionMode);
+    IonCode *argumentsRectifier = gen->ionRuntime()->getArgumentsRectifier(executionMode);
 
     masm.checkStackAlignment();
 
     // Guard that calleereg is actually a function object.
     masm.loadObjClass(calleereg, nargsreg);
     masm.cmpPtr(nargsreg, ImmWord(&JSFunction::class_));
     if (!bailoutIf(Assembler::NotEqual, call->snapshot()))
         return false;
@@ -2035,18 +2034,17 @@ CodeGenerator::visitApplyArgsGeneric(LAp
         // underflow.
         masm.jump(&rejoin);
 
         // Argument fixup needed. Get ready to call the argumentsRectifier.
         {
             masm.bind(&underflow);
 
             // Hardcode the address of the argumentsRectifier code.
-            IonCompartment *ion = gen->ionCompartment();
-            IonCode *argumentsRectifier = ion->getArgumentsRectifier(executionMode);
+            IonCode *argumentsRectifier = gen->ionRuntime()->getArgumentsRectifier(executionMode);
 
             JS_ASSERT(ArgumentsRectifierReg != objreg);
             masm.movePtr(ImmGCPtr(argumentsRectifier), objreg); // Necessary for GC marking.
             masm.loadPtr(Address(objreg, IonCode::offsetOfCode()), objreg);
             masm.movePtr(argcreg, ArgumentsRectifierReg);
         }
 
         masm.bind(&rejoin);
@@ -2078,16 +2076,22 @@ CodeGenerator::visitApplyArgsGeneric(LAp
     // Pop arguments and continue.
     masm.bind(&end);
     emitPopArguments(apply, copyreg);
 
     return true;
 }
 
 bool
+CodeGenerator::visitBail(LBail *lir)
+{
+    return bailout(lir->snapshot());
+}
+
+bool
 CodeGenerator::visitGetDynamicName(LGetDynamicName *lir)
 {
     Register scopeChain = ToRegister(lir->getScopeChain());
     Register name = ToRegister(lir->getName());
     Register temp1 = ToRegister(lir->temp1());
     Register temp2 = ToRegister(lir->temp2());
     Register temp3 = ToRegister(lir->temp3());
 
@@ -5053,17 +5057,17 @@ CodeGenerator::visitIteratorStart(LItera
 #endif // !JSGC_GENERATIONAL
     }
 
     // Mark iterator as active.
     masm.storePtr(obj, Address(niTemp, offsetof(NativeIterator, obj)));
     masm.or32(Imm32(JSITER_ACTIVE), Address(niTemp, offsetof(NativeIterator, flags)));
 
     // Chain onto the active iterator stack.
-    masm.movePtr(ImmWord(GetIonContext()->compartment), temp1);
+    masm.movePtr(ImmWord(gen->compartment), temp1);
     masm.loadPtr(Address(temp1, offsetof(JSCompartment, enumerators)), temp1);
 
     // ni->next = list
     masm.storePtr(temp1, Address(niTemp, NativeIterator::offsetOfNext()));
 
     // ni->prev = list->prev
     masm.loadPtr(Address(temp1, NativeIterator::offsetOfPrev()), temp2);
     masm.storePtr(temp2, Address(niTemp, NativeIterator::offsetOfPrev()));
@@ -5364,17 +5368,17 @@ CodeGenerator::generate()
 
     // Before generating any code, we generate type checks for all parameters.
     // This comes before deoptTable_, because we can't use deopt tables without
     // creating the actual frame.
     if (!generateArgumentsChecks())
         return false;
 
     if (frameClass_ != FrameSizeClass::None()) {
-        deoptTable_ = GetIonContext()->compartment->ionCompartment()->getBailoutTable(frameClass_);
+        deoptTable_ = gen->ionRuntime()->getBailoutTable(frameClass_);
         if (!deoptTable_)
             return false;
     }
 
 #if JS_TRACE_LOGGING
     Label skip;
     masm.jump(&skip);
 #endif
--- a/js/src/ion/CodeGenerator.h
+++ b/js/src/ion/CodeGenerator.h
@@ -100,16 +100,17 @@ class CodeGenerator : public CodeGenerat
     bool emitCallInvokeFunction(LInstruction *call, Register callereg,
                                 uint32_t argc, uint32_t unusedStack);
     bool visitCallGeneric(LCallGeneric *call);
     bool visitCallKnown(LCallKnown *call);
     bool emitCallInvokeFunction(LApplyArgsGeneric *apply, Register extraStackSize);
     void emitPushArguments(LApplyArgsGeneric *apply, Register extraStackSpace);
     void emitPopArguments(LApplyArgsGeneric *apply, Register extraStackSize);
     bool visitApplyArgsGeneric(LApplyArgsGeneric *apply);
+    bool visitBail(LBail *lir);
     bool visitGetDynamicName(LGetDynamicName *lir);
     bool visitFilterArguments(LFilterArguments *lir);
     bool visitCallDirectEval(LCallDirectEval *lir);
     bool visitDoubleToInt32(LDoubleToInt32 *lir);
     bool visitNewSlots(LNewSlots *lir);
     bool visitNewParallelArrayVMCall(LNewParallelArray *lir);
     bool visitNewParallelArray(LNewParallelArray *lir);
     bool visitOutOfLineNewParallelArray(OutOfLineNewParallelArray *ool);
--- a/js/src/ion/Ion.cpp
+++ b/js/src/ion/Ion.cpp
@@ -424,28 +424,28 @@ IonCompartment::sweep(FreeOp *fop)
     if (stringConcatStub_ && !IsIonCodeMarked(stringConcatStub_.unsafeGet()))
         stringConcatStub_ = NULL;
 
     if (parallelStringConcatStub_ && !IsIonCodeMarked(parallelStringConcatStub_.unsafeGet()))
         parallelStringConcatStub_ = NULL;
 }
 
 IonCode *
-IonCompartment::getBailoutTable(const FrameSizeClass &frameClass)
+IonRuntime::getBailoutTable(const FrameSizeClass &frameClass)
 {
     JS_ASSERT(frameClass != FrameSizeClass::None());
-    return rt->bailoutTables_[frameClass.classId()];
+    return bailoutTables_[frameClass.classId()];
 }
 
 IonCode *
-IonCompartment::getVMWrapper(const VMFunction &f)
+IonRuntime::getVMWrapper(const VMFunction &f)
 {
-    JS_ASSERT(rt->functionWrappers_);
-    JS_ASSERT(rt->functionWrappers_->initialized());
-    IonRuntime::VMWrapperMap::Ptr p = rt->functionWrappers_->readonlyThreadsafeLookup(&f);
+    JS_ASSERT(functionWrappers_);
+    JS_ASSERT(functionWrappers_->initialized());
+    IonRuntime::VMWrapperMap::Ptr p = functionWrappers_->readonlyThreadsafeLookup(&f);
     JS_ASSERT(p);
 
     return p->value;
 }
 
 IonCode *
 IonCode::New(JSContext *cx, uint8_t *code, uint32_t bufferSize, JSC::ExecutablePool *pool)
 {
@@ -1785,17 +1785,17 @@ ion::CanEnterInParallel(JSContext *cx, H
     if (status != Method_Compiled) {
         if (status == Method_CantCompile)
             ForbidCompilation(cx, script, ParallelExecution);
         return status;
     }
 
     // This can GC, so afterward, script->parallelIon is
     // not guaranteed to be valid.
-    if (!cx->compartment()->ionCompartment()->enterJIT())
+    if (!cx->runtime()->ionRuntime()->enterIon())
         return Method_Error;
 
     // Subtle: it is possible for GC to occur during
     // compilation of one of the invoked functions, which
     // would cause the earlier functions (such as the
     // kernel itself) to be collected.  In this event, we
     // give up and fallback to sequential for now.
     if (!script->hasParallelIonScript()) {
@@ -1822,33 +1822,33 @@ ion::CanEnterUsingFastInvoke(JSContext *
     // missing arguments with |undefined|.
     if (numActualArgs < script->function()->nargs)
         return Method_Skipped;
 
     if (!cx->compartment()->ensureIonCompartmentExists(cx))
         return Method_Error;
 
     // This can GC, so afterward, script->ion is not guaranteed to be valid.
-    if (!cx->compartment()->ionCompartment()->enterJIT())
+    if (!cx->runtime()->ionRuntime()->enterIon())
         return Method_Error;
 
     if (!script->hasIonScript())
         return Method_Skipped;
 
     return Method_Compiled;
 }
 
 static IonExecStatus
 EnterIon(JSContext *cx, EnterJitData &data)
 {
     JS_CHECK_RECURSION(cx, return IonExec_Aborted);
     JS_ASSERT(ion::IsEnabled(cx));
     JS_ASSERT(!data.osrFrame);
 
-    EnterIonCode enter = cx->compartment()->ionCompartment()->enterJIT();
+    EnterIonCode enter = cx->runtime()->ionRuntime()->enterIon();
 
     // Caller must construct |this| before invoking the Ion function.
     JS_ASSERT_IF(data.constructing, data.maxArgv[0].isObject());
 
     data.result.setInt32(data.numActualArgs);
     {
         AssertCompartmentUnchanged pcc(cx);
         IonContext ictx(cx, NULL);
@@ -1955,17 +1955,17 @@ ion::FastInvoke(JSContext *cx, HandleFun
     IonCode *code = ion->method();
     void *jitcode = code->raw();
 
     JS_ASSERT(ion::IsEnabled(cx));
     JS_ASSERT(!ion->bailoutExpected());
 
     JitActivation activation(cx, /* firstFrameIsConstructing = */false);
 
-    EnterIonCode enter = cx->compartment()->ionCompartment()->enterJIT();
+    EnterIonCode enter = cx->runtime()->ionRuntime()->enterIon();
     void *calleeToken = CalleeToToken(fun);
 
     RootedValue result(cx, Int32Value(args.length()));
     JS_ASSERT(args.length() >= fun->nargs);
 
     JSAutoResolveFlags rf(cx, RESOLVE_INFER);
     enter(jitcode, args.length() + 1, args.array() - 1, NULL, calleeToken,
           /* scopeChain = */ NULL, 0, result.address());
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -6791,16 +6791,21 @@ IonBuilder::jsop_setelem()
 
             // If AmbiguousDoubleConversion, only handle int32 values for now.
             if (conversion == types::StackTypeSet::AmbiguousDoubleConversion &&
                 value->type() != MIRType_Int32)
             {
                 break;
             }
 
+            // Don't generate a fast path if there have been bounds check failures
+            // and this access might be on a sparse property.
+            if (ElementAccessHasExtraIndexedProperty(cx, object) && failedBoundsCheck_)
+                break;
+
             return jsop_setelem_dense(conversion, SetElem_Normal, object, index, value);
         } while(false);
     }
 
     if (object->type() == MIRType_Magic)
         return jsop_arguments_setelem(object, index, value);
 
     if (script()->argumentsHasVarBinding() && object->mightBeType(MIRType_Magic))
--- a/js/src/ion/IonBuilder.h
+++ b/js/src/ion/IonBuilder.h
@@ -494,32 +494,35 @@ class IonBuilder : public MIRGenerator
     InliningStatus inlineNewDenseArrayForSequentialExecution(CallInfo &callInfo);
     InliningStatus inlineNewDenseArrayForParallelExecution(CallInfo &callInfo);
 
     // Slot intrinsics.
     InliningStatus inlineUnsafeSetReservedSlot(CallInfo &callInfo);
     InliningStatus inlineUnsafeGetReservedSlot(CallInfo &callInfo);
 
     // Parallel intrinsics.
-    InliningStatus inlineForceSequentialOrInParallelSection(CallInfo &callInfo);
     InliningStatus inlineNewParallelArray(CallInfo &callInfo);
     InliningStatus inlineParallelArray(CallInfo &callInfo);
     InliningStatus inlineParallelArrayTail(CallInfo &callInfo,
                                            HandleFunction target,
                                            MDefinition *ctor,
                                            types::StackTypeSet *ctorTypes,
                                            uint32_t discards);
 
     // Utility intrinsics.
     InliningStatus inlineIsCallable(CallInfo &callInfo);
     InliningStatus inlineNewObjectWithClassPrototype(CallInfo &callInfo);
     InliningStatus inlineHaveSameClass(CallInfo &callInfo);
     InliningStatus inlineToObject(CallInfo &callInfo);
     InliningStatus inlineDump(CallInfo &callInfo);
 
+    // Testing functions.
+    InliningStatus inlineForceSequentialOrInParallelSection(CallInfo &callInfo);
+    InliningStatus inlineBailout(CallInfo &callInfo);
+
     // Main inlining functions
     InliningStatus inlineNativeCall(CallInfo &callInfo, JSNative native);
     bool inlineScriptedCall(CallInfo &callInfo, JSFunction *target);
     InliningStatus inlineSingleCall(CallInfo &callInfo, JSFunction *target);
 
     // Call functions
     InliningStatus inlineCallsite(AutoObjectVector &targets, AutoObjectVector &originals,
                                   bool lambda, CallInfo &callInfo);
--- a/js/src/ion/IonCaches.cpp
+++ b/js/src/ion/IonCaches.cpp
@@ -2650,16 +2650,33 @@ IsElementSetInlineable(HandleObject obj,
         return false;
 
     if (obj->watched())
         return false;
 
     if (!index.isInt32())
         return false;
 
+    // The object may have a setter definition,
+    // either directly, or via a prototype, or via the target object for a prototype
+    // which is a proxy, that handles a particular integer write.
+    // Scan the prototype and shape chain to make sure that this is not the case.
+    JSObject *curObj = obj;
+    while (curObj) {
+        // Ensure object is native.
+        if (!curObj->isNative())
+            return false;
+
+        // Ensure all indexed properties are stored in dense elements.
+        if (curObj->isIndexed())
+            return false;
+
+        curObj = curObj->getProto();
+    }
+
     return true;
 }
 
 bool
 SetElementIC::attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval)
 {
     JS_ASSERT(obj->isNative());
     JS_ASSERT(idval.isInt32());
--- a/js/src/ion/IonCompartment.h
+++ b/js/src/ion/IonCompartment.h
@@ -182,18 +182,16 @@ class IonRuntime
     IonCode *generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void **returnAddrOut);
     IonCode *generateBailoutTable(JSContext *cx, uint32_t frameClass);
     IonCode *generateBailoutHandler(JSContext *cx);
     IonCode *generateInvalidator(JSContext *cx);
     IonCode *generatePreBarrier(JSContext *cx, MIRType type);
     IonCode *generateDebugTrapHandler(JSContext *cx);
     IonCode *generateVMWrapper(JSContext *cx, const VMFunction &f);
 
-    IonCode *debugTrapHandler(JSContext *cx);
-
   public:
     IonRuntime();
     ~IonRuntime();
     bool initialize(JSContext *cx);
 
     uint8_t *allocateOsrTempData(size_t size);
     void freeOsrTempData();
 
@@ -201,16 +199,65 @@ class IonRuntime
 
     AutoFlushCache *flusher() {
         return flusher_;
     }
     void setFlusher(AutoFlushCache *fl) {
         if (!flusher_ || !fl)
             flusher_ = fl;
     }
+
+    IonCode *getVMWrapper(const VMFunction &f);
+    IonCode *debugTrapHandler(JSContext *cx);
+
+    IonCode *getGenericBailoutHandler() const {
+        return bailoutHandler_;
+    }
+
+    IonCode *getExceptionTail() const {
+        return exceptionTail_;
+    }
+
+    IonCode *getBailoutTail() const {
+        return bailoutTail_;
+    }
+
+    IonCode *getBailoutTable(const FrameSizeClass &frameClass);
+
+    IonCode *getArgumentsRectifier(ExecutionMode mode) const {
+        switch (mode) {
+          case SequentialExecution: return argumentsRectifier_;
+          case ParallelExecution:   return parallelArgumentsRectifier_;
+          default:                  MOZ_ASSUME_UNREACHABLE("No such execution mode");
+        }
+    }
+
+    void *getArgumentsRectifierReturnAddr() const {
+        return argumentsRectifierReturnAddr_;
+    }
+
+    IonCode *getInvalidationThunk() const {
+        return invalidator_;
+    }
+
+    EnterIonCode enterIon() const {
+        return enterJIT_->as<EnterIonCode>();
+    }
+
+    EnterIonCode enterBaseline() const {
+        return enterBaselineJIT_->as<EnterIonCode>();
+    }
+
+    IonCode *valuePreBarrier() const {
+        return valuePreBarrier_;
+    }
+
+    IonCode *shapePreBarrier() const {
+        return shapePreBarrier_;
+    }
 };
 
 class IonCompartment
 {
     friend class JitActivation;
 
     // Ion state for the compartment's runtime.
     IonRuntime *rt;
@@ -239,18 +286,16 @@ class IonCompartment
     // pointers. This has to be a weak pointer to avoid keeping the whole
     // compartment alive.
     ReadBarriered<IonCode> stringConcatStub_;
     ReadBarriered<IonCode> parallelStringConcatStub_;
 
     IonCode *generateStringConcatStub(JSContext *cx, ExecutionMode mode);
 
   public:
-    IonCode *getVMWrapper(const VMFunction &f);
-
     OffThreadCompilationVector &finishedOffThreadCompilations() {
         return finishedOffThreadCompilations_;
     }
 
     IonCode *getStubCode(uint32_t key) {
         ICStubCodeMap::AddPtr p = stubCodes_->lookupForAdd(key);
         if (p)
             return p->value;
@@ -302,66 +347,16 @@ class IonCompartment
 
     void mark(JSTracer *trc, JSCompartment *compartment);
     void sweep(FreeOp *fop);
 
     JSC::ExecutableAllocator *execAlloc() {
         return rt->execAlloc_;
     }
 
-    IonCode *getGenericBailoutHandler() {
-        return rt->bailoutHandler_;
-    }
-
-    IonCode *getExceptionTail() {
-        return rt->exceptionTail_;
-    }
-
-    IonCode *getBailoutTail() {
-        return rt->bailoutTail_;
-    }
-
-    IonCode *getBailoutTable(const FrameSizeClass &frameClass);
-
-    IonCode *getArgumentsRectifier(ExecutionMode mode) {
-        switch (mode) {
-          case SequentialExecution: return rt->argumentsRectifier_;
-          case ParallelExecution:   return rt->parallelArgumentsRectifier_;
-          default:                  MOZ_ASSUME_UNREACHABLE("No such execution mode");
-        }
-    }
-
-    void *getArgumentsRectifierReturnAddr() {
-        return rt->argumentsRectifierReturnAddr_;
-    }
-
-    IonCode *getInvalidationThunk() {
-        return rt->invalidator_;
-    }
-
-    EnterIonCode enterJIT() {
-        return rt->enterJIT_->as<EnterIonCode>();
-    }
-
-    EnterIonCode enterBaselineJIT() {
-        return rt->enterBaselineJIT_->as<EnterIonCode>();
-    }
-
-    IonCode *valuePreBarrier() {
-        return rt->valuePreBarrier_;
-    }
-
-    IonCode *shapePreBarrier() {
-        return rt->shapePreBarrier_;
-    }
-
-    IonCode *debugTrapHandler(JSContext *cx) {
-        return rt->debugTrapHandler(cx);
-    }
-
     IonCode *stringConcatStub(ExecutionMode mode) {
         switch (mode) {
           case SequentialExecution: return stringConcatStub_;
           case ParallelExecution:   return parallelStringConcatStub_;
           default:                  MOZ_ASSUME_UNREACHABLE("No such execution mode");
         }
     }
 
--- a/js/src/ion/IonMacroAssembler.h
+++ b/js/src/ion/IonMacroAssembler.h
@@ -493,20 +493,20 @@ class MacroAssembler : public MacroAssem
         Label done;
 
         if (type == MIRType_Value)
             branchTestGCThing(Assembler::NotEqual, address, &done);
 
         Push(PreBarrierReg);
         computeEffectiveAddress(address, PreBarrierReg);
 
-        JSCompartment *compartment = GetIonContext()->compartment;
+        JSRuntime *runtime = GetIonContext()->runtime;
         IonCode *preBarrier = (type == MIRType_Shape)
-                              ? compartment->ionCompartment()->shapePreBarrier()
-                              : compartment->ionCompartment()->valuePreBarrier();
+                              ? runtime->ionRuntime()->shapePreBarrier()
+                              : runtime->ionRuntime()->valuePreBarrier();
 
         call(preBarrier);
         Pop(PreBarrierReg);
 
         bind(&done);
     }
 
     template <typename T>
--- a/js/src/ion/LIR-Common.h
+++ b/js/src/ion/LIR-Common.h
@@ -1057,16 +1057,22 @@ class LCallDOMNative : public LJSCallIns
     const LAllocation *getArgPrivate() {
         return getTemp(2)->output();
     }
     const LAllocation *getArgArgs() {
         return getTemp(3)->output();
     }
 };
 
+class LBail : public LInstructionHelper<0, 0, 0>
+{
+  public:
+    LIR_HEADER(Bail)
+};
+
 template <size_t defs, size_t ops>
 class LDOMPropertyInstructionHelper : public LCallInstructionHelper<defs, 1 + ops, 3>
 {
   protected:
     LDOMPropertyInstructionHelper(const LDefinition &JSContextReg, const LAllocation &ObjectReg,
                                   const LDefinition &PrivReg, const LDefinition &ValueReg)
     {
         this->setOperand(0, ObjectReg);
--- a/js/src/ion/LOpcodes.h
+++ b/js/src/ion/LOpcodes.h
@@ -39,16 +39,17 @@
     _(CheckOverRecursed)            \
     _(CheckOverRecursedPar)         \
     _(DefVar)                       \
     _(DefFun)                       \
     _(CallKnown)                    \
     _(CallGeneric)                  \
     _(CallNative)                   \
     _(ApplyArgsGeneric)             \
+    _(Bail)                         \
     _(GetDynamicName)               \
     _(FilterArguments)              \
     _(CallDirectEval)               \
     _(StackArgT)                    \
     _(StackArgV)                    \
     _(CreateThis)                   \
     _(CreateThisWithProto)          \
     _(CreateThisWithTemplate)       \
--- a/js/src/ion/Lowering.cpp
+++ b/js/src/ion/Lowering.cpp
@@ -472,16 +472,23 @@ LIRGenerator::visitApplyArgs(MApplyArgs 
     if (!defineReturn(lir, apply))
         return false;
     if (!assignSafepoint(lir, apply))
         return false;
     return true;
 }
 
 bool
+LIRGenerator::visitBail(MBail *bail)
+{
+    LBail *lir = new LBail();
+    return assignSnapshot(lir) && add(lir, bail);
+}
+
+bool
 LIRGenerator::visitGetDynamicName(MGetDynamicName *ins)
 {
     MDefinition *scopeChain = ins->getScopeChain();
     JS_ASSERT(scopeChain->type() == MIRType_Object);
 
     MDefinition *name = ins->getName();
     JS_ASSERT(name->type() == MIRType_String);
 
--- a/js/src/ion/Lowering.h
+++ b/js/src/ion/Lowering.h
@@ -107,16 +107,17 @@ class LIRGenerator : public LIRGenerator
     bool visitCreateThisWithProto(MCreateThisWithProto *ins);
     bool visitCreateThis(MCreateThis *ins);
     bool visitCreateArgumentsObject(MCreateArgumentsObject *ins);
     bool visitGetArgumentsObjectArg(MGetArgumentsObjectArg *ins);
     bool visitSetArgumentsObjectArg(MSetArgumentsObjectArg *ins);
     bool visitReturnFromCtor(MReturnFromCtor *ins);
     bool visitCall(MCall *call);
     bool visitApplyArgs(MApplyArgs *apply);
+    bool visitBail(MBail *bail);
     bool visitGetDynamicName(MGetDynamicName *ins);
     bool visitFilterArguments(MFilterArguments *ins);
     bool visitCallDirectEval(MCallDirectEval *ins);
     bool visitTest(MTest *test);
     bool visitFunctionDispatch(MFunctionDispatch *ins);
     bool visitTypeObjectDispatch(MTypeObjectDispatch *ins);
     bool visitPolyInlineDispatch(MPolyInlineDispatch *ins);
     bool visitCompare(MCompare *comp);
--- a/js/src/ion/MCallOptimize.cpp
+++ b/js/src/ion/MCallOptimize.cpp
@@ -125,33 +125,37 @@ IonBuilder::inlineNativeCall(CallInfo &c
     if (native == intrinsic_UnsafeSetReservedSlot)
         return inlineUnsafeSetReservedSlot(callInfo);
     if (native == intrinsic_UnsafeGetReservedSlot)
         return inlineUnsafeGetReservedSlot(callInfo);
 
     // Parallel intrinsics.
     if (native == intrinsic_ShouldForceSequential)
         return inlineForceSequentialOrInParallelSection(callInfo);
-    if (native == testingFunc_inParallelSection)
-        return inlineForceSequentialOrInParallelSection(callInfo);
     if (native == intrinsic_NewParallelArray)
         return inlineNewParallelArray(callInfo);
     if (native == ParallelArrayObject::construct)
         return inlineParallelArray(callInfo);
 
     // Utility intrinsics.
     if (native == intrinsic_IsCallable)
         return inlineIsCallable(callInfo);
     if (native == intrinsic_NewObjectWithClassPrototype)
         return inlineNewObjectWithClassPrototype(callInfo);
     if (native == intrinsic_HaveSameClass)
         return inlineHaveSameClass(callInfo);
     if (native == intrinsic_ToObject)
         return inlineToObject(callInfo);
 
+    // Testing Functions
+    if (native == testingFunc_inParallelSection)
+        return inlineForceSequentialOrInParallelSection(callInfo);
+    if (native == testingFunc_bailout)
+        return inlineBailout(callInfo);
+
     return InliningStatus_NotInlined;
 }
 
 types::StackTypeSet *
 IonBuilder::getInlineReturnTypeSet()
 {
     return types::TypeScript::BytecodeTypes(script(), pc);
 }
@@ -1493,10 +1497,22 @@ IonBuilder::inlineToObject(CallInfo &cal
 
     callInfo.unwrapArgs();
     MDefinition *object = callInfo.getArg(0);
 
     current->push(object);
     return InliningStatus_Inlined;
 }
 
+IonBuilder::InliningStatus
+IonBuilder::inlineBailout(CallInfo &callInfo)
+{
+    callInfo.unwrapArgs();
+
+    current->add(MBail::New());
+
+    MConstant *undefined = MConstant::New(UndefinedValue());
+    current->push(undefined);
+    return InliningStatus_Inlined;
+}
+
 } // namespace ion
 } // namespace js
--- a/js/src/ion/MIR.h
+++ b/js/src/ion/MIR.h
@@ -1791,16 +1791,34 @@ class MApplyArgs
     TypePolicy *typePolicy() {
         return this;
     }
     bool possiblyCalls() const {
         return true;
     }
 };
 
+class MBail : public MNullaryInstruction
+{
+  protected:
+    MBail()
+    {
+        setGuard();
+    }
+
+  public:
+    INSTRUCTION_HEADER(Bail)
+
+    static MBail *
+    New() {
+        return new MBail();
+    }
+
+};
+
 class MGetDynamicName
   : public MAryInstruction<2>,
     public MixPolicy<ObjectPolicy<0>, StringPolicy<1> >
 {
   protected:
     MGetDynamicName(MDefinition *scopeChain, MDefinition *name)
     {
         setOperand(0, scopeChain);
--- a/js/src/ion/MIRGenerator.h
+++ b/js/src/ion/MIRGenerator.h
@@ -54,16 +54,19 @@ class MIRGenerator
         return *graph_;
     }
     bool ensureBallast() {
         return temp().ensureBallast();
     }
     IonCompartment *ionCompartment() const {
         return compartment->ionCompartment();
     }
+    IonRuntime *ionRuntime() const {
+        return compartment->rt->ionRuntime();
+    }
     CompileInfo &info() {
         return *info_;
     }
 
     template <typename T>
     T * allocate(size_t count = 1) {
         return reinterpret_cast<T *>(temp().allocate(sizeof(T) * count));
     }
@@ -110,31 +113,22 @@ class MIRGenerator
     void setPerformsAsmJSCall() {
         JS_ASSERT(compilingAsmJS());
         performsAsmJSCall_ = true;
     }
     bool performsAsmJSCall() const {
         JS_ASSERT(compilingAsmJS());
         return performsAsmJSCall_;
     }
-#ifndef JS_CPU_ARM
     bool noteHeapAccess(AsmJSHeapAccess heapAccess) {
         return asmJSHeapAccesses_.append(heapAccess);
     }
     const Vector<AsmJSHeapAccess, 0, IonAllocPolicy> &heapAccesses() const {
         return asmJSHeapAccesses_;
     }
-#else
-    bool noteBoundsCheck(uint32_t offsetBefore) {
-        return asmJSBoundsChecks_.append(AsmJSBoundsCheck(offsetBefore));
-    }
-    const Vector<AsmJSBoundsCheck, 0, IonAllocPolicy> &asmBoundsChecks() const {
-        return asmJSBoundsChecks_;
-    }
-#endif
     bool noteGlobalAccess(unsigned offset, unsigned globalDataOffset) {
         return asmJSGlobalAccesses_.append(AsmJSGlobalAccess(offset, globalDataOffset));
     }
     const Vector<AsmJSGlobalAccess, 0, IonAllocPolicy> &globalAccesses() const {
         return asmJSGlobalAccesses_;
     }
 
   public:
@@ -146,21 +140,17 @@ class MIRGenerator
     JSFunction *fun_;
     uint32_t nslots_;
     MIRGraph *graph_;
     bool error_;
     size_t cancelBuild_;
 
     uint32_t maxAsmJSStackArgBytes_;
     bool performsAsmJSCall_;
-#ifdef JS_CPU_ARM
-    AsmJSBoundsCheckVector asmJSBoundsChecks_;
-#else
     AsmJSHeapAccessVector asmJSHeapAccesses_;
-#endif
     AsmJSGlobalAccessVector asmJSGlobalAccesses_;
 
 #if defined(JS_ION_PERF)
     AsmJSPerfSpewer asmJSPerfSpewer_;
 
   public:
     AsmJSPerfSpewer &perfSpewer() { return asmJSPerfSpewer_; }
 #endif
--- a/js/src/ion/MOpcodes.h
+++ b/js/src/ion/MOpcodes.h
@@ -34,16 +34,17 @@ namespace ion {
     _(CreateThisWithTemplate)                                               \
     _(CreateArgumentsObject)                                                \
     _(GetArgumentsObjectArg)                                                \
     _(SetArgumentsObjectArg)                                                \
     _(PrepareCall)                                                          \
     _(PassArg)                                                              \
     _(Call)                                                                 \
     _(ApplyArgs)                                                            \
+    _(Bail)                                                                 \
     _(GetDynamicName)                                                       \
     _(FilterArguments)                                                      \
     _(CallDirectEval)                                                       \
     _(BitNot)                                                               \
     _(TypeOf)                                                               \
     _(ToId)                                                                 \
     _(BitAnd)                                                               \
     _(BitOr)                                                                \
--- a/js/src/ion/ParallelSafetyAnalysis.cpp
+++ b/js/src/ion/ParallelSafetyAnalysis.cpp
@@ -128,16 +128,17 @@ class ParallelSafetyVisitor : public MIn
     UNSAFE_OP(CreateThisWithProto)
     UNSAFE_OP(CreateArgumentsObject)
     UNSAFE_OP(GetArgumentsObjectArg)
     UNSAFE_OP(SetArgumentsObjectArg)
     SAFE_OP(PrepareCall)
     SAFE_OP(PassArg)
     CUSTOM_OP(Call)
     UNSAFE_OP(ApplyArgs)
+    UNSAFE_OP(Bail)
     UNSAFE_OP(GetDynamicName)
     UNSAFE_OP(FilterArguments)
     UNSAFE_OP(CallDirectEval)
     SPECIALIZED_OP(BitNot, PERMIT_INT32)
     UNSAFE_OP(TypeOf)
     SAFE_OP(ToId)
     SPECIALIZED_OP(BitAnd, PERMIT_INT32)
     SPECIALIZED_OP(BitOr, PERMIT_INT32)
--- a/js/src/ion/RegisterSets.h
+++ b/js/src/ion/RegisterSets.h
@@ -780,83 +780,66 @@ class ABIArg
 
     bool argInRegister() const { return kind() != Stack; }
     AnyRegister reg() const { return kind_ == GPR ? AnyRegister(gpr()) : AnyRegister(fpu()); }
 };
 
 class AsmJSHeapAccess
 {
     uint32_t offset_;
-    uint8_t opLength_;
 #if defined(JS_CPU_X86)
-    uint8_t cmpDelta_;
+    uint8_t cmpDelta_;  // the number of bytes from the cmp to the load/store instruction
 #endif
+#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
+    uint8_t opLength_;  // the length of the load/store instruction
     uint8_t isFloat32Load_;
     ion::AnyRegister::Code loadedReg_ : 8;
+#endif
 
     JS_STATIC_ASSERT(ion::AnyRegister::Total < UINT8_MAX);
 
   public:
-#if defined(JS_CPU_X86)
-    AsmJSHeapAccess(uint32_t cmp, uint32_t offset, uint32_t after, ArrayBufferView::ViewType vt,
-                    AnyRegister loadedReg)
+#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
+    AsmJSHeapAccess(uint32_t offset, uint32_t after, ArrayBufferView::ViewType vt,
+                    AnyRegister loadedReg, uint32_t cmp = UINT32_MAX)
       : offset_(offset),
-        opLength_(after - offset),
+# if defined(JS_CPU_X86)
         cmpDelta_(offset - cmp),
-        isFloat32Load_(vt == ArrayBufferView::TYPE_FLOAT32),
-        loadedReg_(loadedReg.code())
-    {}
-    AsmJSHeapAccess(uint32_t cmp, uint32_t offset, uint8_t after)
-      : offset_(offset),
-        opLength_(after - offset),
-        cmpDelta_(offset - cmp),
-        isFloat32Load_(false),
-        loadedReg_(UINT8_MAX)
-    {}
-#else
-    AsmJSHeapAccess(uint32_t offset, uint32_t after, ArrayBufferView::ViewType vt,
-                    AnyRegister loadedReg)
-      : offset_(offset),
+# endif
         opLength_(after - offset),
         isFloat32Load_(vt == ArrayBufferView::TYPE_FLOAT32),
         loadedReg_(loadedReg.code())
     {}
-    AsmJSHeapAccess(uint32_t offset, uint8_t after)
+    AsmJSHeapAccess(uint32_t offset, uint8_t after, uint32_t cmp = UINT32_MAX)
       : offset_(offset),
+# if defined(JS_CPU_X86)
+        cmpDelta_(offset - cmp),
+# endif
         opLength_(after - offset),
         isFloat32Load_(false),
         loadedReg_(UINT8_MAX)
     {}
+#elif defined(JS_CPU_ARM)
+    explicit AsmJSHeapAccess(uint32_t offset)
+      : offset_(offset)
+    {}
 #endif
 
     uint32_t offset() const { return offset_; }
-    unsigned opLength() const { return opLength_; }
-    bool isLoad() const { return loadedReg_ != UINT8_MAX; }
-    bool isFloat32Load() const { return isFloat32Load_; }
-    ion::AnyRegister loadedReg() const { return ion::AnyRegister::FromCode(loadedReg_); }
-
+    void setOffset(uint32_t offset) { offset_ = offset; }
 #if defined(JS_CPU_X86)
     void *patchLengthAt(uint8_t *code) const { return code + (offset_ - cmpDelta_); }
     void *patchOffsetAt(uint8_t *code) const { return code + (offset_ + opLength_); }
 #endif
-    void updateOffset(uint32_t offset) { offset_ = offset; }
+#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
+    unsigned opLength() const { return opLength_; }
+    bool isLoad() const { return loadedReg_ != UINT8_MAX; }
+    bool isFloat32Load() const { return isFloat32Load_; }
+    ion::AnyRegister loadedReg() const { return ion::AnyRegister::FromCode(loadedReg_); }
+#endif
 };
 
 typedef Vector<AsmJSHeapAccess, 0, IonAllocPolicy> AsmJSHeapAccessVector;
 
-#ifdef JS_CPU_ARM
-struct AsmJSBoundsCheck
-{
-    unsigned offset_;
-    AsmJSBoundsCheck(unsigned offset)
-    : offset_(offset)
-    {}
-    void setOffset(uint32_t offset) { offset_ = offset; }
-    unsigned offset() {return offset_;}
-};
-
-typedef Vector<AsmJSBoundsCheck, 0, IonAllocPolicy> AsmJSBoundsCheckVector;
-#endif
-
 } // namespace ion
 } // namespace js
 
 #endif /* ion_RegisterSets_h */
--- a/js/src/ion/arm/Bailouts-arm.cpp
+++ b/js/src/ion/arm/Bailouts-arm.cpp
@@ -127,19 +127,18 @@ IonBailoutIterator::IonBailoutIterator(c
 
     if (bailout->frameClass() == FrameSizeClass::None()) {
         snapshotOffset_ = bailout->snapshotOffset();
         return;
     }
 
     // Compute the snapshot offset from the bailout ID.
     JitActivation *activation = activations.activation()->asJit();
-    JSCompartment *jsCompartment = activation->compartment();
-    IonCompartment *ionCompartment = jsCompartment->ionCompartment();
-    IonCode *code = ionCompartment->getBailoutTable(bailout->frameClass());
+    JSRuntime *rt = activation->compartment()->rt;
+    IonCode *code = rt->ionRuntime()->getBailoutTable(bailout->frameClass());
     uintptr_t tableOffset = bailout->tableOffset();
     uintptr_t tableStart = reinterpret_cast<uintptr_t>(code->raw());
 
     JS_ASSERT(tableOffset >= tableStart &&
               tableOffset < tableStart + code->instructionsSize());
     JS_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0);
 
     uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1;
--- a/js/src/ion/arm/CodeGenerator-arm.cpp
+++ b/js/src/ion/arm/CodeGenerator-arm.cpp
@@ -156,19 +156,17 @@ CodeGeneratorARM::generateOutOfLineCode(
 
     if (deoptLabel_.used()) {
         // All non-table-based bailouts will go here.
         masm.bind(&deoptLabel_);
 
         // Push the frame size, so the handler can recover the IonScript.
         masm.ma_mov(Imm32(frameSize()), lr);
 
-        IonCompartment *ion = GetIonContext()->compartment->ionCompartment();
-        IonCode *handler = ion->getGenericBailoutHandler();
-
+        IonCode *handler = gen->ionRuntime()->getGenericBailoutHandler();
         masm.branch(handler);
     }
 
     return true;
 }
 
 bool
 CodeGeneratorARM::bailoutIf(Assembler::Condition condition, LSnapshot *snapshot)
@@ -1726,17 +1724,17 @@ CodeGeneratorARM::generateInvalidateEpil
 
     masm.bind(&invalidate_);
 
     // Push the return address of the point that we bailed out at onto the stack
     masm.Push(lr);
 
     // Push the Ion script onto the stack (when we determine what that pointer is).
     invalidateEpilogueData_ = masm.pushWithPatch(ImmWord(uintptr_t(-1)));
-    IonCode *thunk = GetIonContext()->compartment->ionCompartment()->getInvalidationThunk();
+    IonCode *thunk = gen->ionRuntime()->getInvalidationThunk();
 
     masm.branch(thunk);
 
     // We should never reach this point in JIT code -- the invalidation thunk should
     // pop the invalidated JS frame and return directly to its caller.
     masm.breakpoint();
     return true;
 }
@@ -1803,17 +1801,17 @@ CodeGeneratorARM::visitAsmJSLoadHeap(LAs
             masm.ma_vldr(vd, HeapReg, index, 0, Assembler::Zero);
         }
         masm.ma_vmov(NANReg, ToFloatRegister(ins->output()), Assembler::NonZero);
     }  else {
         masm.ma_dataTransferN(IsLoad, size, isSigned, HeapReg, index,
                               ToRegister(ins->output()), Offset, Assembler::Zero);
         masm.ma_mov(Imm32(0), ToRegister(ins->output()), NoSetCond, Assembler::NonZero);
     }
-    return gen->noteBoundsCheck(bo.getOffset());
+    return gen->noteHeapAccess(AsmJSHeapAccess(bo.getOffset()));
 }
 
 bool
 CodeGeneratorARM::visitAsmJSStoreHeap(LAsmJSStoreHeap *ins)
 {
     const MAsmJSStoreHeap *mir = ins->mir();
     bool isSigned;
     int size;
@@ -1841,17 +1839,17 @@ CodeGeneratorARM::visitAsmJSStoreHeap(LA
             masm.storeFloat(vd, HeapReg, index, Assembler::Zero);
         } else {
             masm.ma_vstr(vd, HeapReg, index, 0, Assembler::Zero);
         }
     }  else {
         masm.ma_dataTransferN(IsStore, size, isSigned, HeapReg, index,
                               ToRegister(ins->value()), Offset, Assembler::Zero);
     }
-    return gen->noteBoundsCheck(bo.getOffset());
+    return gen->noteHeapAccess(AsmJSHeapAccess(bo.getOffset()));
 }
 
 bool
 CodeGeneratorARM::visitAsmJSPassStackArg(LAsmJSPassStackArg *ins)
 {
     const MAsmJSPassStackArg *mir = ins->mir();
     Operand dst(StackPointer, mir->spOffset());
     if (ins->arg()->isConstant()) {
--- a/js/src/ion/arm/MacroAssembler-arm.cpp
+++ b/js/src/ion/arm/MacroAssembler-arm.cpp
@@ -3299,17 +3299,17 @@ MacroAssemblerARMCompat::handleFailureWi
     ma_sub(Imm32(size), sp);
     ma_mov(sp, r0);
 
     // Ask for an exception handler.
     setupUnalignedABICall(1, r1);
     passABIArg(r0);
     callWithABI(handler);
 
-    IonCode *excTail = GetIonContext()->compartment->ionCompartment()->getExceptionTail();
+    IonCode *excTail = GetIonContext()->runtime->ionRuntime()->getExceptionTail();
     branch(excTail);
 }
 
 void
 MacroAssemblerARMCompat::handleFailureWithHandlerTail()
 {
     Label entryFrame;
     Label catch_;
--- a/js/src/ion/arm/Trampoline-arm.cpp
+++ b/js/src/ion/arm/Trampoline-arm.cpp
@@ -344,17 +344,17 @@ IonRuntime::generateInvalidator(JSContex
     // Remove the return address, the IonScript, the register state
     // (InvaliationBailoutStack) and the space that was allocated for the return value
     masm.ma_add(sp, Imm32(sizeof(InvalidationBailoutStack) + sizeOfRetval + sizeOfBailoutInfo), sp);
     // remove the space that this frame was using before the bailout
     // (computed by InvalidationBailout)
     masm.ma_add(sp, r1, sp);
 
     // Jump to shared bailout tail. The BailoutInfo pointer has to be in r2.
-    IonCode *bailoutTail = cx->compartment()->ionCompartment()->getBailoutTail();
+    IonCode *bailoutTail = cx->runtime()->ionRuntime()->getBailoutTail();
     masm.branch(bailoutTail);
 
     Linker linker(masm);
     IonCode *code = linker.newCode(cx, JSC::OTHER_CODE);
     IonSpew(IonSpew_Invalidate, "   invalidation thunk created at %p", (void *) code->raw());
     return code;
 }
 
@@ -548,17 +548,17 @@ GenerateBailoutThunk(JSContext *cx, Macr
         uint32_t frameSize = FrameSizeClass::FromClass(frameClass).frameSize();
         masm.ma_add(Imm32(frameSize // the frame that was added when we entered the most recent function
                           + sizeof(void*) // the size of the "return address" that was dumped on the stack
                           + bailoutFrameSize) // everything else that was pushed on the stack
                     , sp);
     }
 
     // Jump to shared bailout tail. The BailoutInfo pointer has to be in r2.
-    IonCode *bailoutTail = cx->compartment()->ionCompartment()->getBailoutTail();
+    IonCode *bailoutTail = cx->runtime()->ionRuntime()->getBailoutTail();
     masm.branch(bailoutTail);
 }
 
 IonCode *
 IonRuntime::generateBailoutTable(JSContext *cx, uint32_t frameClass)
 {
     MacroAssembler masm(cx);
 
@@ -801,18 +801,17 @@ IonRuntime::generateDebugTrapHandler(JSC
     masm.subPtr(Imm32(BaselineFrame::Size()), scratch1);
 
     // Enter a stub frame and call the HandleDebugTrap VM function. Ensure
     // the stub frame has a NULL ICStub pointer, since this pointer is marked
     // during GC.
     masm.movePtr(ImmWord((void *)NULL), BaselineStubReg);
     EmitEnterStubFrame(masm, scratch2);
 
-    IonCompartment *ion = cx->compartment()->ionCompartment();
-    IonCode *code = ion->getVMWrapper(HandleDebugTrapInfo);
+    IonCode *code = cx->runtime()->ionRuntime()->getVMWrapper(HandleDebugTrapInfo);
     if (!code)
         return NULL;
 
     masm.push(lr);
     masm.push(scratch1);
     EmitCallVM(code, masm);
 
     EmitLeaveStubFrame(masm);
--- a/js/src/ion/shared/BaselineCompiler-shared.cpp
+++ b/js/src/ion/shared/BaselineCompiler-shared.cpp
@@ -28,18 +28,17 @@ BaselineCompilerShared::BaselineCompiler
     pushedBeforeCall_(0),
     inCall_(false),
     spsPushToggleOffset_()
 { }
 
 bool
 BaselineCompilerShared::callVM(const VMFunction &fun)
 {
-    IonCompartment *ion = cx->compartment()->ionCompartment();
-    IonCode *code = ion->getVMWrapper(fun);
+    IonCode *code = cx->runtime()->ionRuntime()->getVMWrapper(fun);
     if (!code)
         return false;
 
 #ifdef DEBUG
     // Assert prepareVMCall() has been called.
     JS_ASSERT(inCall_);
     inCall_ = false;
 #endif
--- a/js/src/ion/shared/CodeGenerator-shared.cpp
+++ b/js/src/ion/shared/CodeGenerator-shared.cpp
@@ -440,18 +440,17 @@ CodeGeneratorShared::callVM(const VMFunc
     //    ... frame ...
     //    [args]
 #ifdef DEBUG
     JS_ASSERT(pushedArgs_ == fun.explicitArgs);
     pushedArgs_ = 0;
 #endif
 
     // Get the wrapper of the VM function.
-    IonCompartment *ion = GetIonContext()->compartment->ionCompartment();
-    IonCode *wrapper = ion->getVMWrapper(fun);
+    IonCode *wrapper = gen->ionRuntime()->getVMWrapper(fun);
     if (!wrapper)
         return false;
 
     // Call the wrapper function.  The wrapper is in charge to unwind the stack
     // when returning from the call.  Failures are handled with exceptions based
     // on the return value of the C functions.  To guard the outcome of the
     // returned value, use another LIR instruction.
     uint32_t callOffset;
--- a/js/src/ion/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/ion/shared/CodeGenerator-x86-shared.cpp
@@ -240,19 +240,17 @@ CodeGeneratorX86Shared::generateOutOfLin
 
     if (deoptLabel_.used()) {
         // All non-table-based bailouts will go here.
         masm.bind(&deoptLabel_);
 
         // Push the frame size, so the handler can recover the IonScript.
         masm.push(Imm32(frameSize()));
 
-        IonCompartment *ion = GetIonContext()->compartment->ionCompartment();
-        IonCode *handler = ion->getGenericBailoutHandler();
-
+        IonCode *handler = gen->ionRuntime()->getGenericBailoutHandler();
         masm.jmp(handler->raw(), Relocation::IONCODE);
     }
 
     return true;
 }
 
 class BailoutJump {
     Assembler::Condition cond_;
@@ -1471,17 +1469,17 @@ CodeGeneratorX86Shared::generateInvalida
     // epilogue.
     for (size_t i = 0; i < sizeof(void *); i+= Assembler::nopSize())
         masm.nop();
 
     masm.bind(&invalidate_);
 
     // Push the Ion script onto the stack (when we determine what that pointer is).
     invalidateEpilogueData_ = masm.pushWithPatch(ImmWord(uintptr_t(-1)));
-    IonCode *thunk = GetIonContext()->compartment->ionCompartment()->getInvalidationThunk();
+    IonCode *thunk = gen->ionRuntime()->getInvalidationThunk();
 
     masm.call(thunk);
 
     // We should never reach this point in JIT code -- the invalidation thunk should
     // pop the invalidated JS frame and return directly to its caller.
     masm.breakpoint();
     return true;
 }
--- a/js/src/ion/x64/MacroAssembler-x64.cpp
+++ b/js/src/ion/x64/MacroAssembler-x64.cpp
@@ -237,17 +237,17 @@ MacroAssemblerX64::handleFailureWithHand
     subq(Imm32(sizeof(ResumeFromException)), rsp);
     movq(rsp, rax);
 
     // Ask for an exception handler.
     setupUnalignedABICall(1, rcx);
     passABIArg(rax);
     callWithABI(handler);
 
-    IonCode *excTail = GetIonContext()->compartment->ionCompartment()->getExceptionTail();
+    IonCode *excTail = GetIonContext()->runtime->ionRuntime()->getExceptionTail();
     jmp(excTail);
 }
 
 void
 MacroAssemblerX64::handleFailureWithHandlerTail()
 {
     Label entryFrame;
     Label catch_;
--- a/js/src/ion/x64/Trampoline-x64.cpp
+++ b/js/src/ion/x64/Trampoline-x64.cpp
@@ -307,17 +307,17 @@ IonRuntime::generateInvalidator(JSContex
 
     masm.pop(r9); // Get the bailoutInfo outparam.
     masm.pop(rbx); // Get the frameSize outparam.
 
     // Pop the machine state and the dead frame.
     masm.lea(Operand(rsp, rbx, TimesOne, sizeof(InvalidationBailoutStack)), rsp);
 
     // Jump to shared bailout tail. The BailoutInfo pointer has to be in r9.
-    IonCode *bailoutTail = cx->compartment()->ionCompartment()->getBailoutTail();
+    IonCode *bailoutTail = cx->runtime()->ionRuntime()->getBailoutTail();
     masm.jmp(bailoutTail);
 
     Linker linker(masm);
     return linker.newCode(cx, JSC::OTHER_CODE);
 }
 
 IonCode *
 IonRuntime::generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void **returnAddrOut)
@@ -441,17 +441,17 @@ GenerateBailoutThunk(JSContext *cx, Macr
     // Remove both the bailout frame and the topmost Ion frame's stack.
     static const uint32_t BailoutDataSize = sizeof(void *) * Registers::Total +
                                           sizeof(double) * FloatRegisters::Total;
     masm.addq(Imm32(BailoutDataSize), rsp);
     masm.pop(rcx);
     masm.lea(Operand(rsp, rcx, TimesOne, sizeof(void *)), rsp);
 
     // Jump to shared bailout tail. The BailoutInfo pointer has to be in r9.
-    IonCode *bailoutTail = cx->compartment()->ionCompartment()->getBailoutTail();
+    IonCode *bailoutTail = cx->runtime()->ionRuntime()->getBailoutTail();
     masm.jmp(bailoutTail);
 }
 
 IonCode *
 IonRuntime::generateBailoutTable(JSContext *cx, uint32_t frameClass)
 {
     MOZ_ASSUME_UNREACHABLE("x64 does not use bailout tables");
 }
@@ -693,18 +693,17 @@ IonRuntime::generateDebugTrapHandler(JSC
     masm.subPtr(Imm32(BaselineFrame::Size()), scratch2);
 
     // Enter a stub frame and call the HandleDebugTrap VM function. Ensure
     // the stub frame has a NULL ICStub pointer, since this pointer is marked
     // during GC.
     masm.movePtr(ImmWord((void *)NULL), BaselineStubReg);
     EmitEnterStubFrame(masm, scratch3);
 
-    IonCompartment *ion = cx->compartment()->ionCompartment();
-    IonCode *code = ion->getVMWrapper(HandleDebugTrapInfo);
+    IonCode *code = cx->runtime()->ionRuntime()->getVMWrapper(HandleDebugTrapInfo);
     if (!code)
         return NULL;
 
     masm.push(scratch1);
     masm.push(scratch2);
     EmitCallVM(code, masm);
 
     EmitLeaveStubFrame(masm);
--- a/js/src/ion/x86/Bailouts-x86.cpp
+++ b/js/src/ion/x86/Bailouts-x86.cpp
@@ -80,19 +80,18 @@ IonBailoutIterator::IonBailoutIterator(c
 
     if (bailout->frameClass() == FrameSizeClass::None()) {
         snapshotOffset_ = bailout->snapshotOffset();
         return;
     }
 
     // Compute the snapshot offset from the bailout ID.
     JitActivation *activation = activations.activation()->asJit();
-    JSCompartment *jsCompartment = activation->compartment();
-    IonCompartment *ionCompartment = jsCompartment->ionCompartment();
-    IonCode *code = ionCompartment->getBailoutTable(bailout->frameClass());
+    JSRuntime *rt = activation->compartment()->rt;
+    IonCode *code = rt->ionRuntime()->getBailoutTable(bailout->frameClass());
     uintptr_t tableOffset = bailout->tableOffset();
     uintptr_t tableStart = reinterpret_cast<uintptr_t>(code->raw());
 
     JS_ASSERT(tableOffset >= tableStart &&
               tableOffset < tableStart + code->instructionsSize());
     JS_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0);
 
     uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1;
--- a/js/src/ion/x86/CodeGenerator-x86.cpp
+++ b/js/src/ion/x86/CodeGenerator-x86.cpp
@@ -491,23 +491,23 @@ CodeGeneratorX86::visitAsmJSLoadHeap(LAs
     Address srcAddr(ptr, 0);
     if (vt == ArrayBufferView::TYPE_FLOAT32) {
         FloatRegister dest = ToFloatRegister(out);
         uint32_t before = masm.size();
         masm.movssWithPatch(srcAddr, dest);
         uint32_t after = masm.size();
         masm.cvtss2sd(dest, dest);
         masm.bind(ool->rejoin());
-        return gen->noteHeapAccess(AsmJSHeapAccess(cmp.offset(), before, after, vt, AnyRegister(dest)));
+        return gen->noteHeapAccess(AsmJSHeapAccess(before, after, vt, AnyRegister(dest), cmp.offset()));
     }
     uint32_t before = masm.size();
     loadViewTypeElement(vt, srcAddr, out);
     uint32_t after = masm.size();
     masm.bind(ool->rejoin());
-    return gen->noteHeapAccess(AsmJSHeapAccess(cmp.offset(), before, after, vt, ToAnyRegister(out)));
+    return gen->noteHeapAccess(AsmJSHeapAccess(before, after, vt, ToAnyRegister(out), cmp.offset()));
 }
 
 bool
 CodeGeneratorX86::visitOutOfLineLoadTypedArrayOutOfBounds(OutOfLineLoadTypedArrayOutOfBounds *ool)
 {
     if (ool->dest().isFloat()) {
         masm.movsd(&js_NaN, ool->dest().fpu());
     } else {
@@ -578,23 +578,23 @@ CodeGeneratorX86::visitAsmJSStoreHeap(LA
 
     Address dstAddr(ptr, 0);
     if (vt == ArrayBufferView::TYPE_FLOAT32) {
         masm.convertDoubleToFloat(ToFloatRegister(value), ScratchFloatReg);
         uint32_t before = masm.size();
         masm.movssWithPatch(ScratchFloatReg, dstAddr);
         uint32_t after = masm.size();
         masm.bind(&rejoin);
-        return gen->noteHeapAccess(AsmJSHeapAccess(cmp.offset(), before, after));
+        return gen->noteHeapAccess(AsmJSHeapAccess(before, after, cmp.offset()));
     }
     uint32_t before = masm.size();
     storeViewTypeElement(vt, value, dstAddr);
     uint32_t after = masm.size();
     masm.bind(&rejoin);
-    return gen->noteHeapAccess(AsmJSHeapAccess(cmp.offset(), before, after));
+    return gen->noteHeapAccess(AsmJSHeapAccess(before, after, cmp.offset()));
 }
 
 bool
 CodeGeneratorX86::visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar *ins)
 {
     MAsmJSLoadGlobalVar *mir = ins->mir();
 
     CodeOffsetLabel label;
--- a/js/src/ion/x86/MacroAssembler-x86.cpp
+++ b/js/src/ion/x86/MacroAssembler-x86.cpp
@@ -209,17 +209,17 @@ MacroAssemblerX86::handleFailureWithHand
     subl(Imm32(sizeof(ResumeFromException)), esp);
     movl(esp, eax);
 
     // Ask for an exception handler.
     setupUnalignedABICall(1, ecx);
     passABIArg(eax);
     callWithABI(handler);
 
-    IonCode *excTail = GetIonContext()->compartment->ionCompartment()->getExceptionTail();
+    IonCode *excTail = GetIonContext()->runtime->ionRuntime()->getExceptionTail();
     jmp(excTail);
 }
 
 void
 MacroAssemblerX86::handleFailureWithHandlerTail()
 {
     Label entryFrame;
     Label catch_;
--- a/js/src/ion/x86/Trampoline-x86.cpp
+++ b/js/src/ion/x86/Trampoline-x86.cpp
@@ -293,17 +293,17 @@ IonRuntime::generateInvalidator(JSContex
 
     masm.pop(ecx); // Get bailoutInfo outparam.
     masm.pop(ebx); // Get the frameSize outparam.
 
     // Pop the machine state and the dead frame.
     masm.lea(Operand(esp, ebx, TimesOne, sizeof(InvalidationBailoutStack)), esp);
 
     // Jump to shared bailout tail. The BailoutInfo pointer has to be in ecx.
-    IonCode *bailoutTail = cx->compartment()->ionCompartment()->getBailoutTail();
+    IonCode *bailoutTail = cx->runtime()->ionRuntime()->getBailoutTail();
     masm.jmp(bailoutTail);
 
     Linker linker(masm);
     IonCode *code = linker.newCode(cx, JSC::OTHER_CODE);
     IonSpew(IonSpew_Invalidate, "   invalidation thunk created at %p", (void *) code->raw());
     return code;
 }
 
@@ -456,17 +456,17 @@ GenerateBailoutThunk(JSContext *cx, Macr
         //    ... frame ...
         //    bailoutId
         //    ... bailoutFrame ...
         uint32_t frameSize = FrameSizeClass::FromClass(frameClass).frameSize();
         masm.addl(Imm32(BailoutDataSize + sizeof(void *) + frameSize), esp);
     }
 
     // Jump to shared bailout tail. The BailoutInfo pointer has to be in ecx.
-    IonCode *bailoutTail = cx->compartment()->ionCompartment()->getBailoutTail();
+    IonCode *bailoutTail = cx->runtime()->ionRuntime()->getBailoutTail();
     masm.jmp(bailoutTail);
 }
 
 IonCode *
 IonRuntime::generateBailoutTable(JSContext *cx, uint32_t frameClass)
 {
     MacroAssembler masm;
 
@@ -719,18 +719,17 @@ IonRuntime::generateDebugTrapHandler(JSC
     masm.subPtr(Imm32(BaselineFrame::Size()), scratch2);
 
     // Enter a stub frame and call the HandleDebugTrap VM function. Ensure
     // the stub frame has a NULL ICStub pointer, since this pointer is marked
     // during GC.
     masm.movePtr(ImmWord((void *)NULL), BaselineStubReg);
     EmitEnterStubFrame(masm, scratch3);
 
-    IonCompartment *ion = cx->compartment()->ionCompartment();
-    IonCode *code = ion->getVMWrapper(HandleDebugTrapInfo);
+    IonCode *code = cx->runtime()->ionRuntime()->getVMWrapper(HandleDebugTrapInfo);
     if (!code)
         return NULL;
 
     masm.push(scratch1);
     masm.push(scratch2);
     EmitCallVM(code, masm);
 
     EmitLeaveStubFrame(masm);
--- a/js/src/jit-test/tests/asm.js/testLiterals.js
+++ b/js/src/jit-test/tests/asm.js/testLiterals.js
@@ -14,16 +14,22 @@ assertEq(asmLink(asmCompile(USE_ASM + 'f
 assertEq(asmLink(asmCompile(USE_ASM + 'function f(d) { d=+d; var e=1.0e0; e=d; return +e } return f'))(0.1), 0.1);
 assertEq(asmLink(asmCompile(USE_ASM + 'function f(d) { d=+d; var e=-1.0e0; e=d; return +e } return f'))(0.1), 0.1);
 assertEq(asmLink(asmCompile(USE_ASM + 'function f() { return 0.0 } function g() { var d=0.1; d=+f(); return +d } return g'))(), 0);
 assertEq(asmLink(asmCompile(USE_ASM + 'function f() { return -0.0 } function g() { var d=0.1; d=+f(); return +d } return g'))(), -0);
 assertEq(asmLink(asmCompile(USE_ASM + 'function f() { return 10.0 } function g() { var d=0.1; d=+f(); return +d } return g'))(), 10);
 assertEq(asmLink(asmCompile(USE_ASM + 'function f() { return -10.0 } function g() { var d=0.1; d=+f(); return +d } return g'))(), -10.0);
 
 assertAsmTypeFail(USE_ASM + "function f(i) { i=i|0; var j=1e10; j=i; return j|0 } return f");
+assertAsmTypeFail(USE_ASM + "function f(i) { i=i|0; var j=9007199254740991e0; j=i; return j|0 } return f");
+assertAsmTypeFail(USE_ASM + "function f(i) { i=i|0; var j=9007199254740992e0; j=i; return j|0 } return f");
+assertAsmTypeFail(USE_ASM + "function f(i) { i=i|0; var j=9007199254740993e0; j=i; return j|0 } return f");
+assertAsmTypeFail(USE_ASM + "function f(i) { i=i|0; var j=-9007199254740991e0; j=i; return j|0 } return f");
+assertAsmTypeFail(USE_ASM + "function f(i) { i=i|0; var j=-9007199254740992e0; j=i; return j|0 } return f");
+assertAsmTypeFail(USE_ASM + "function f(i) { i=i|0; var j=-9007199254740993e0; j=i; return j|0 } return f");
 assertAsmTypeFail(USE_ASM + "function f(i) { i=i|0; var j=1e100; j=i; return j|0 } return f");
 assertAsmTypeFail(USE_ASM + "function f(i) { i=i|0; var j=1e10000; j=i; return j|0 } return f");
 assertAsmTypeFail(USE_ASM + "function f(i) { i=i|0; var j=1000000000000000000; j=i; return j|0 } return f");
 assertEq(asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; var j=1e0; j=i; return j|0 } return f"))(42), 42);
 assertEq(asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; var j=1e9; j=i; return j|0 } return f"))(42), 42);
 
 assertAsmTypeFail(USE_ASM + 'function f() { var i=-2147483649; return i|0 } return f');
 assertAsmTypeFail(USE_ASM + 'function f() { var i=4294967296; return i|0 } return f');
--- a/js/src/jit-test/tests/ion/bug765454.js
+++ b/js/src/jit-test/tests/ion/bug765454.js
@@ -1,10 +1,8 @@
-var bailout = Proxy.createFunction({}, Math.sin);
-
 var seen = -1;
 
 // Test to make sure the jits get the number of calls, and return value
 // of setters correct. We should not be affected by whether the setter
 // modifies its argument or returns some value.
 function setter(x) {
     this.val = x;
     x = 255;
--- a/js/src/jit-test/tests/ion/bug813784.js
+++ b/js/src/jit-test/tests/ion/bug813784.js
@@ -117,17 +117,16 @@ var args = base2(10,11,12);
 assertEq(args, undefined);
 var args = base2(11,11,12);
 assertEq(args[0], undefined);
 assertEq(args[1], 5);
 assertEq(args[2], 6);
 
 //////////////////
 
-var bailout = Proxy.createFunction({}, Math.sin);
 function arg_len2() { assertEq(arguments.length, 4); }
 function bailing_arg_len(a) {
     if (a == 90) {
         bailout();
         arg_len.apply({}, arguments);
     }
     assertEq(arguments.length, 4);
     return arguments;
--- a/js/src/jit-test/tests/ion/entryOverflowBailout.js
+++ b/js/src/jit-test/tests/ion/entryOverflowBailout.js
@@ -1,12 +1,11 @@
 var o;
 var f1;
 var counter = 0;
-var bailout = Proxy.createFunction({}, Math.sin);
 
 function f2(a) {
     bailout();
     return f2.arguments;
 };
 
 var restartCode = "counter = 0; " + f2.toSource();
 
--- a/js/src/vm/ForkJoin.cpp
+++ b/js/src/vm/ForkJoin.cpp
@@ -1242,33 +1242,33 @@ class ParallelIonInvoke
     void *jitcode_;
     void *calleeToken_;
     Value argv_[maxArgc + 2];
     uint32_t argc_;
 
   public:
     Value *args;
 
-    ParallelIonInvoke(JSCompartment *compartment,
+    ParallelIonInvoke(JSRuntime *rt,
                       HandleFunction callee,
                       uint32_t argc)
       : argc_(argc),
         args(argv_ + 2)
     {
         JS_ASSERT(argc <= maxArgc + 2);
 
         // Set 'callee' and 'this'.
         argv_[0] = ObjectValue(*callee);
         argv_[1] = UndefinedValue();
 
         // Find JIT code pointer.
         IonScript *ion = callee->nonLazyScript()->parallelIonScript();
         IonCode *code = ion->method();
         jitcode_ = code->raw();
-        enter_ = compartment->ionCompartment()->enterJIT();
+        enter_ = rt->ionRuntime()->enterIon();
         calleeToken_ = CalleeToParallelToken(callee);
     }
 
     bool invoke(PerThreadData *perThread) {
         RootedValue result(perThread);
         enter_(jitcode_, argc_ + 1, argv_ + 1, NULL, calleeToken_, NULL, 0, result.address());
         return !result.isMagic();
     }
@@ -1465,17 +1465,17 @@ ForkJoinShared::executePortion(PerThread
         // script can be collected between starting the parallel
         // op and reaching this point.  In that case, we just fail
         // and fallback.
         Spew(SpewOps, "Down (Script no longer present)");
         slice.bailoutRecord->setCause(ParallelBailoutMainScriptNotPresent,
                                       NULL, NULL, NULL);
         setAbortFlag(false);
     } else {
-        ParallelIonInvoke<3> fii(cx_->compartment(), callee, 3);
+        ParallelIonInvoke<3> fii(cx_->runtime(), callee, 3);
 
         fii.args[0] = Int32Value(slice.sliceId);
         fii.args[1] = Int32Value(slice.numSlices);
         fii.args[2] = BooleanValue(false);
 
         bool ok = fii.invoke(perThread);
         JS_ASSERT(ok == !slice.bailoutRecord->topScript);
         if (!ok)
--- a/media/webrtc/signaling/src/callcontrol/debug-psipcc-types.cpp
+++ b/media/webrtc/signaling/src/callcontrol/debug-psipcc-types.cpp
@@ -378,64 +378,89 @@ DEFINE_CC_TYPE_NAME_FUNCTION   (lamp_sta
 	                            ENAME_DECL(CC_LAMP_NONE),
 	                            ENAME_DECL(CC_LAMP_ON),
 	                            ENAME_DECL(CC_LAMP_BLINK),
 	                            ENAME_DECL(CC_LAMP_FRESH)
                                 );
 
 //define cause_getname(cc_cause_t);
 DEFINE_CC_TYPE_NAME_FUNCTION   (cause, CC_TYPE,
-	                            ENAME_DECL(CC_CAUSE_MIN),
-	                            ENAME_DECL(CC_CAUSE_BASE),
-	                            ENAME_DECL(CC_CAUSE_OK),
-	                            ENAME_DECL(CC_CAUSE_ERROR),
-	                            ENAME_DECL(CC_CAUSE_UNASSIGNED_NUM),
-	                            ENAME_DECL(CC_CAUSE_NO_RESOURCE),
-	                            ENAME_DECL(CC_CAUSE_NO_ROUTE),
-	                            ENAME_DECL(CC_CAUSE_NORMAL),
-	                            ENAME_DECL(CC_CAUSE_BUSY),
-	                            ENAME_DECL(CC_CAUSE_NO_USER_RESP),
-	                            ENAME_DECL(CC_CAUSE_NO_USER_ANS),
-	                            ENAME_DECL(CC_CAUSE_REJECT),
-	                            ENAME_DECL(CC_CAUSE_INVALID_NUMBER),
-	                            ENAME_DECL(CC_CAUSE_FACILITY_REJECTED),
-	                            ENAME_DECL(CC_CAUSE_CALL_ID_IN_USE),
-	                            ENAME_DECL(CC_CAUSE_XFER_LOCAL),
-	                            ENAME_DECL(CC_CAUSE_XFER_REMOTE),
-	                            ENAME_DECL(CC_CAUSE_XFER_BY_REMOTE),
-	                            ENAME_DECL(CC_CAUSE_XFER_CNF),
-	                            ENAME_DECL(CC_CAUSE_CONGESTION),
-	                            ENAME_DECL(CC_CAUSE_ANONYMOUS),
-	                            ENAME_DECL(CC_CAUSE_REDIRECT),
-	                            ENAME_DECL(CC_CAUSE_PAYLOAD_MISMATCH),
-	                            ENAME_DECL(CC_CAUSE_CONF),
-	                            ENAME_DECL(CC_CAUSE_REPLACE),
-	                            ENAME_DECL(CC_CAUSE_NO_REPLACE_CALL),
-	                            ENAME_DECL(CC_CAUSE_NO_RESUME),
-	                            ENAME_DECL(CC_CAUSE_NO_MEDIA),
-	                            ENAME_DECL(CC_CAUSE_REQUEST_PENDING),
-	                            ENAME_DECL(CC_CAUSE_INVALID_PARTICIPANT),
-	                            ENAME_DECL(CC_CAUSE_NO_CNF_BRIDE),
-	                            ENAME_DECL(CC_MAXIMUM_PARTICIPANT),
-	                            ENAME_DECL(CC_KEY_NOT_ACTIVE),
-	                            ENAME_DECL(CC_TEMP_NOT_AVAILABLE),
-	                            ENAME_DECL(CC_CAUSE_REMOTE_SERVER_ERROR),
-	                            ENAME_DECL(CC_CAUSE_NOT_FOUND),
-	                            ENAME_DECL(CC_CAUSE_SECURITY_FAILURE),
-	                            ENAME_DECL(CC_CAUSE_MONITOR),
-	                            ENAME_DECL(CC_CAUSE_UI_STATE_BUSY),
-	                            ENAME_DECL(CC_SIP_CAUSE_ANSWERED_ELSEWHERE),
-	                            ENAME_DECL(CC_CAUSE_RETRIEVED),
-	                            ENAME_DECL(CC_CAUSE_FORWARDED),
-	                            ENAME_DECL(CC_CAUSE_ABANDONED),
-	                            ENAME_DECL(CC_CAUSE_XFER_LOCAL_WITH_DIALSTRING),
-	                            ENAME_DECL(CC_CAUSE_BW_OK),
-	                            ENAME_DECL(CC_CAUSE_XFER_COMPLETE),
-	                            ENAME_DECL(CC_CAUSE_RESP_TIMEOUT),
-	                            ENAME_DECL(CC_CAUSE_MAX)
+                                ENAME_DECL(CC_CAUSE_MIN),
+                                ENAME_DECL(CC_CAUSE_BASE),
+                                ENAME_DECL(CC_CAUSE_OK),
+                                ENAME_DECL(CC_CAUSE_ERROR),
+                                ENAME_DECL(CC_CAUSE_UNASSIGNED_NUM),
+                                ENAME_DECL(CC_CAUSE_NO_RESOURCE),
+                                ENAME_DECL(CC_CAUSE_NO_ROUTE),
+                                ENAME_DECL(CC_CAUSE_NORMAL),
+                                ENAME_DECL(CC_CAUSE_BUSY),
+                                ENAME_DECL(CC_CAUSE_NO_USER_RESP),
+                                ENAME_DECL(CC_CAUSE_NO_USER_ANS),
+                                ENAME_DECL(CC_CAUSE_REJECT),
+                                ENAME_DECL(CC_CAUSE_INVALID_NUMBER),
+                                ENAME_DECL(CC_CAUSE_FACILITY_REJECTED),
+                                ENAME_DECL(CC_CAUSE_CALL_ID_IN_USE),
+                                ENAME_DECL(CC_CAUSE_XFER_LOCAL),
+                                ENAME_DECL(CC_CAUSE_XFER_REMOTE),
+                                ENAME_DECL(CC_CAUSE_XFER_BY_REMOTE),
+                                ENAME_DECL(CC_CAUSE_XFER_CNF),
+                                ENAME_DECL(CC_CAUSE_CONGESTION),
+                                ENAME_DECL(CC_CAUSE_ANONYMOUS),
+                                ENAME_DECL(CC_CAUSE_REDIRECT),
+                                ENAME_DECL(CC_CAUSE_PAYLOAD_MISMATCH),
+                                ENAME_DECL(CC_CAUSE_CONF),
+                                ENAME_DECL(CC_CAUSE_REPLACE),
+                                ENAME_DECL(CC_CAUSE_NO_REPLACE_CALL),
+                                ENAME_DECL(CC_CAUSE_NO_RESUME),
+                                ENAME_DECL(CC_CAUSE_NO_MEDIA),
+                                ENAME_DECL(CC_CAUSE_REQUEST_PENDING),
+                                ENAME_DECL(CC_CAUSE_INVALID_PARTICIPANT),
+                                ENAME_DECL(CC_CAUSE_NO_CNF_BRIDE),
+                                ENAME_DECL(CC_MAXIMUM_PARTICIPANT),
+                                ENAME_DECL(CC_KEY_NOT_ACTIVE),
+                                ENAME_DECL(CC_TEMP_NOT_AVAILABLE),
+                                ENAME_DECL(CC_CAUSE_REMOTE_SERVER_ERROR),
+                                ENAME_DECL(CC_CAUSE_NOT_FOUND),
+                                ENAME_DECL(CC_CAUSE_SECURITY_FAILURE),
+                                ENAME_DECL(CC_CAUSE_MONITOR),
+                                ENAME_DECL(CC_CAUSE_UI_STATE_BUSY),
+                                ENAME_DECL(CC_SIP_CAUSE_ANSWERED_ELSEWHERE),
+                                ENAME_DECL(CC_CAUSE_RETRIEVED),
+                                ENAME_DECL(CC_CAUSE_FORWARDED),
+                                ENAME_DECL(CC_CAUSE_ABANDONED),
+                                ENAME_DECL(CC_CAUSE_XFER_LOCAL_WITH_DIALSTRING),
+                                ENAME_DECL(CC_CAUSE_BW_OK),
+                                ENAME_DECL(CC_CAUSE_XFER_COMPLETE),
+                                ENAME_DECL(CC_CAUSE_RESP_TIMEOUT),
+                                ENAME_DECL(CC_CAUSE_SERV_ERR_UNAVAIL),
+                                ENAME_DECL(CC_CAUSE_REMOTE_DISCONN_REQ_PLAYTONE),
+                                ENAME_DECL(CC_CAUSE_OUT_OF_MEM),
+                                ENAME_DECL(CC_CAUSE_VALUE_NOT_FOUND),
+                                ENAME_DECL(CC_CAUSE_BAD_ICE_ATTRIBUTE),
+                                ENAME_DECL(CC_CAUSE_DTLS_ATTRIBUTE_ERROR),
+                                ENAME_DECL(CC_CAUSE_DTLS_DIGEST_ALGORITHM_EMPTY),
+                                ENAME_DECL(CC_CAUSE_DTLS_DIGEST_ALGORITHM_TOO_LONG),
+                                ENAME_DECL(CC_CAUSE_DTLS_DIGEST_EMPTY),
+                                ENAME_DECL(CC_CAUSE_DTLS_DIGEST_TOO_LONG),
+                                ENAME_DECL(CC_CAUSE_DTLS_FINGERPRINT_PARSE_ERROR),
+                                ENAME_DECL(CC_CAUSE_DTLS_FINGERPRINT_TOO_LONG),
+                                ENAME_DECL(CC_CAUSE_INVALID_SDP_POINTER),
+                                ENAME_DECL(CC_CAUSE_NO_AUDIO),
+                                ENAME_DECL(CC_CAUSE_NO_DTLS_FINGERPRINT),
+                                ENAME_DECL(CC_CAUSE_MISSING_ICE_ATTRIBUTES),
+                                ENAME_DECL(CC_CAUSE_NO_MEDIA_CAPABILITY),
+                                ENAME_DECL(CC_CAUSE_NO_M_LINE),
+                                ENAME_DECL(CC_CAUSE_NO_PEERCONNECTION),
+                                ENAME_DECL(CC_CAUSE_NO_SDP),
+                                ENAME_DECL(CC_CAUSE_NULL_POINTER),
+                                ENAME_DECL(CC_CAUSE_SDP_CREATE_FAILED),
+                                ENAME_DECL(CC_CAUSE_SDP_ENCODE_FAILED),
+                                ENAME_DECL(CC_CAUSE_SDP_PARSE_FAILED),
+                                ENAME_DECL(CC_CAUSE_SETTING_ICE_SESSION_PARAMETERS_FAILED),
+                                ENAME_DECL(CC_CAUSE_MAX)
                                 );
 
 //define subscriptions_ext_getname(cc_subscriptions_ext_t);
 DEFINE_CC_TYPE_NAME_FUNCTION   (subscriptions_ext, CC_TYPE,
                                 ENAME_DECL(CC_SUBSCRIPTIONS_KPML_EXT),
                                 ENAME_DECL(CC_SUBSCRIPTIONS_PRESENCE_EXT),
                                 ENAME_DECL(CC_SUBSCRIPTIONS_REMOTECC_EXT),
                                 ENAME_DECL(CC_SUBSCRIPTIONS_REMOTECC_OPTIONSIND_EXT),
--- a/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c
+++ b/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c
@@ -1560,59 +1560,64 @@ gsmsdp_set_sdp_direction (fsmdef_media_t
  *
  * session         - true = session level attributes, false = media line attribs
  * level           - The media level of the SDP where the media attribute exists.
  * sdp_p           - Pointer to the SDP whose ice candidates are being searched.
  * ice_attribs     - return ice attribs at this level in an array
  * attributes_ctp  - count of array of media line attributes
  */
 
-static boolean
+static cc_causes_t
 gsmsdp_get_ice_attributes (sdp_attr_e sdp_attr, uint16_t level, void *sdp_p, char ***ice_attribs, int *attributes_ctp)
 {
     uint16_t        num_a_lines = 0;
     uint16_t        i;
     sdp_result_e    result;
     char*           ice_attrib;
 
     result = sdp_attr_num_instances(sdp_p, level, 0, sdp_attr, &num_a_lines);
     if (result != SDP_SUCCESS) {
         GSM_ERR_MSG("enumerating ICE attributes failed");
-        return FALSE;
+        return result;
     }
 
     if (num_a_lines < 1) {
-    	GSM_ERR_MSG("enumerating ICE attributes returned 0 attributes");
-    	return TRUE;
+        GSM_DEBUG("enumerating ICE attributes returned 0 attributes");
+        return CC_CAUSE_OK;
     }
 
     *ice_attribs = (char **)cpr_malloc(num_a_lines * sizeof(char *));
 
     if (!(*ice_attribs))
-      return FALSE;
+      return CC_CAUSE_OUT_OF_MEM;
 
     *attributes_ctp = 0;
 
     for (i = 0; i < num_a_lines; i++) {
         result = sdp_attr_get_ice_attribute (sdp_p, level, 0, sdp_attr, (uint16_t) (i + 1),
           &ice_attrib);
         if (result != SDP_SUCCESS) {
-    		GSM_ERR_MSG("Failed to retrieve ICE attribute");
-    		cpr_free(*ice_attribs);
-    		return FALSE;
-    	}
+            GSM_ERR_MSG("Failed to retrieve ICE attribute");
+            cpr_free(*ice_attribs);
+            return result == SDP_INVALID_SDP_PTR ?
+                             CC_CAUSE_INVALID_SDP_POINTER :
+                   result == SDP_INVALID_PARAMETER ?
+                             CC_CAUSE_BAD_ICE_ATTRIBUTE :
+                   /* otherwise */
+                             CC_CAUSE_ERROR;
+        }
         (*ice_attribs)[i] = (char *) cpr_calloc(1, strlen(ice_attrib) + 1);
         if(!(*ice_attribs)[i])
-        	return FALSE;
+            return CC_CAUSE_OUT_OF_MEM;
 
         sstrncpy((*ice_attribs)[i], ice_attrib, strlen(ice_attrib) + 1);
         (*attributes_ctp)++;
     }
 
-    return TRUE;
+    return CC_CAUSE_OK;
 }
 
 /*
  * gsmsdp_set_ice_attribute
  *
  * Description:
  *
  * Adds an ice attribute attributes to the specified SDP.
@@ -4992,34 +4997,37 @@ gsmsdp_get_offered_media_types (fsm_fcb_
  *
  * Parameters:
  *
  * peerconnection - handle to peerconnection object
  * sdp_pp     - Pointer to the local sdp
  *
  * returns    cc_causes_t
  *            CC_CAUSE_OK - indicates success
- *            CC_CAUSE_ERROR - indicates failure
+ *            Any other code - indicates failure
  */
 static cc_causes_t
 gsmsdp_init_local_sdp (const char *peerconnection, cc_sdp_t **sdp_pp)
 {
     char            addr_str[MAX_IPADDR_STR_LEN];
     cpr_ip_addr_t   ipaddr;
     unsigned long   session_id = 0;
     char            session_version_str[GSMSDP_VERSION_STR_LEN];
     void           *local_sdp_p = NULL;
     cc_sdp_t       *sdp_p = NULL;
     int             nat_enable = 0;
     char           *p_addr_str;
     cpr_ip_mode_e   ip_mode;
     char           *strtok_state;
 
-    if (!peerconnection || !sdp_pp) {
-        return CC_CAUSE_ERROR;
+    if (!peerconnection) {
+        return CC_CAUSE_NO_PEERCONNECTION;
+    }
+    if (!sdp_pp) {
+        return CC_CAUSE_NULL_POINTER;
     }
 
     ip_mode = platform_get_ip_address_mode();
     /*
      * Get device address. We will need this later.
      */
     config_get_value(CFGID_NAT_ENABLE, &nat_enable, sizeof(nat_enable));
     if (nat_enable == 0) {
@@ -5049,17 +5057,17 @@ gsmsdp_init_local_sdp (const char *peerc
             sipsdp_src_dest_free(CCSIP_SRC_SDP_BIT, sdp_pp);
         }
         sipsdp_src_dest_create(peerconnection,
             CCSIP_SRC_SDP_BIT, sdp_pp);
     }
     sdp_p = *sdp_pp;
 
     if ( sdp_p == NULL )
-       return CC_CAUSE_ERROR;
+       return CC_CAUSE_NO_SDP;
 
     local_sdp_p = sdp_p->src_sdp;
 
     /*
      * v= line
      */
     (void) sdp_set_version(local_sdp_p, SIPSDP_VERSION);
 
@@ -5300,48 +5308,50 @@ gsmsdp_add_media_line (fsmdef_dcb_t *dcb
  * Parameters:
  *
  * dcb_p - Pointer to the DCB whose local SDP is to be updated.
  * force_streams_enabled - temporarily generate SDP even when no
  *                         streams are added
  *
  * returns    cc_causes_t
  *            CC_CAUSE_OK - indicates success
- *            CC_CAUSE_ERROR - indicates failure
+ *            Any other code- indicates failure
  */
 cc_causes_t
 gsmsdp_create_local_sdp (fsmdef_dcb_t *dcb_p, boolean force_streams_enabled,
                          boolean audio, boolean video, boolean data, boolean offer)
 {
     static const char fname[] = "gsmsdp_create_local_sdp";
     uint16_t        level;
     const cc_media_cap_table_t *media_cap_tbl;
     const cc_media_cap_t       *media_cap;
     cpr_ip_mode_e   ip_mode;
     uint8_t         cap_index;
     fsmdef_media_t  *media;
     boolean         has_audio;
     int             sdpmode = 0;
     boolean         media_enabled;
-
-    if ( CC_CAUSE_OK != gsmsdp_init_local_sdp(dcb_p->peerconnection,
-        &(dcb_p->sdp)) )
-      return CC_CAUSE_ERROR;
+    cc_causes_t     cause;
+
+    cause = gsmsdp_init_local_sdp(dcb_p->peerconnection, &(dcb_p->sdp));
+    if ( cause != CC_CAUSE_OK) {
+      return cause;
+    }
 
     config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
 
     dcb_p->src_sdp_version = 0;
 
     media_cap_tbl = dcb_p->media_cap_tbl;
 
     if (media_cap_tbl == NULL) {
         /* should not happen */
         GSM_ERR_MSG(GSM_L_C_F_PREFIX"no media capbility available",
                     dcb_p->line, dcb_p->call_id, fname);
-        return (CC_CAUSE_ERROR);
+        return (CC_CAUSE_NO_MEDIA_CAPABILITY);
     }
 
     media_cap = &media_cap_tbl->cap[0];
     level = 0;
     for (cap_index = 0; cap_index < CC_MAX_MEDIA_CAP-1; cap_index++) {
 
         /* Build local m lines based on m lines that were in the offered SDP */
         media_enabled = TRUE;
@@ -5404,17 +5414,17 @@ gsmsdp_create_local_sdp (fsmdef_dcb_t *d
 
     if (level == 0) {
         /*
          * Did not find media line for the SDP and we do not
          * support SDP without any media line.
          */
         GSM_ERR_MSG(GSM_L_C_F_PREFIX"no media line for SDP",
                     dcb_p->line, dcb_p->call_id, fname);
-        return (CC_CAUSE_ERROR);
+        return (CC_CAUSE_NO_M_LINE);
     }
 
     /*
      *
      * This is a suitable place to add ice ufrag and pwd to the SDP
      */
 
     if (dcb_p->ice_ufrag)
@@ -5437,17 +5447,17 @@ gsmsdp_create_local_sdp (fsmdef_dcb_t *d
                 has_audio = TRUE; /* found one audio line, done */
                 break;
             }
         }
         if (!has_audio) {
             /* No audio, do not allow */
             GSM_ERR_MSG(GSM_L_C_F_PREFIX"no audio media line for SDP",
                     dcb_p->line, dcb_p->call_id, fname);
-            return (CC_CAUSE_ERROR);
+            return (CC_CAUSE_NO_AUDIO);
         }
     }
 
     return CC_CAUSE_OK;
 }
 
 /**
  * The function creates a SDP that contains phone's current
@@ -5459,17 +5469,17 @@ gsmsdp_create_local_sdp (fsmdef_dcb_t *d
  * @pre              (sdp_pp not_eq NULL)
  */
 void
 gsmsdp_create_options_sdp (cc_sdp_t ** sdp_pp)
 {
     cc_sdp_t *sdp_p;
 
     /* This empty string represents to associated peerconnection object */
-    if (gsmsdp_init_local_sdp("", sdp_pp) == CC_CAUSE_ERROR) {
+    if (gsmsdp_init_local_sdp("", sdp_pp) != CC_CAUSE_OK) {
         return;
     }
 
     sdp_p = *sdp_pp;
 
     /*
      * Insert media line at level 1.
      */
@@ -6158,27 +6168,27 @@ gsmsdp_set_local_resume_sdp (fsmdef_dcb_
 cc_causes_t
 gsmsdp_encode_sdp (cc_sdp_t *sdp_p, cc_msgbody_info_t *msg_body)
 {
     char           *sdp_body;
     cc_msgbody_t   *part;
     uint32_t        body_length;
 
     if (!msg_body || !sdp_p) {
-        return CC_CAUSE_ERROR;
+        return CC_CAUSE_NULL_POINTER;
     }
 
     /* Support single SDP encoding for now */
     sdp_body = sipsdp_write_to_buf(sdp_p->src_sdp, &body_length);
 
     if (sdp_body == NULL) {
-        return CC_CAUSE_ERROR;
+        return CC_CAUSE_SDP_ENCODE_FAILED;
     } else if (body_length == 0) {
         cpr_free(sdp_body);
-        return CC_CAUSE_ERROR;
+        return CC_CAUSE_SDP_ENCODE_FAILED;
     }
 
     /* Clear off the bodies info */
     cc_initialize_msg_body_parts_info(msg_body);
 
     /* Set up for one SDP entry */
     msg_body->num_parts = 1;
     msg_body->content_type = cc_content_type_SDP;
@@ -6206,31 +6216,30 @@ gsmsdp_encode_sdp (cc_sdp_t *sdp_p, cc_m
  *
  * Returns:
  * cc_causes_t to indicate failure or success.
  */
 cc_causes_t
 gsmsdp_encode_sdp_and_update_version (fsmdef_dcb_t *dcb_p, cc_msgbody_info_t *msg_body)
 {
     char version_str[GSMSDP_VERSION_STR_LEN];
+    cc_causes_t cause;
 
     snprintf(version_str, sizeof(version_str), "%d", dcb_p->src_sdp_version);
 
-    if ( dcb_p->sdp == NULL || dcb_p->sdp->src_sdp == NULL )
-    {
-    	if ( CC_CAUSE_OK != gsmsdp_init_local_sdp(dcb_p->peerconnection,
-            &(dcb_p->sdp)) )
-    	{
-    		return CC_CAUSE_ERROR;
-    	}
+    if ( dcb_p->sdp == NULL || dcb_p->sdp->src_sdp == NULL ) {
+        cause = gsmsdp_init_local_sdp(dcb_p->peerconnection, &(dcb_p->sdp));
+        if ( cause != CC_CAUSE_OK) {
+            return cause;
+        }
     }
     (void) sdp_set_owner_version(dcb_p->sdp->src_sdp, version_str);
 
     if (gsmsdp_encode_sdp(dcb_p->sdp, msg_body) != CC_CAUSE_OK) {
-        return CC_CAUSE_ERROR;
+        return CC_CAUSE_SDP_ENCODE_FAILED;
     }
 
     dcb_p->src_sdp_version++;
     return CC_CAUSE_OK;
 }
 
 /*
  * gsmsdp_get_sdp
@@ -6322,17 +6331,17 @@ gsmsdp_realloc_dest_sdp (fsmdef_dcb_t *d
         }
         sipsdp_src_dest_create(dcb_p->peerconnection,
             CCSIP_DEST_SDP_BIT, &dcb_p->sdp);
     }
 
     /* No SDP info block and parsed control block are available */
     if ((dcb_p->sdp == NULL) || (dcb_p->sdp->dest_sdp == NULL)) {
         /* Unable to create internal SDP structure to parse SDP. */
-        return CC_CAUSE_ERROR;
+        return CC_CAUSE_SDP_CREATE_FAILED;
     }
     return CC_CAUSE_OK;
 }
 
 /*
  * gsmsdp_negotiate_answer_sdp
  *
  * Description:
@@ -6358,30 +6367,31 @@ gsmsdp_negotiate_answer_sdp (fsm_fcb_t *
     /* Get just the SDP bodies */
     num_sdp_bodies = gsmsdp_get_sdp_body(msg_body, &sdp_bodies[0],
                                          CC_MAX_BODY_PARTS);
     GSM_DEBUG(DEB_F_PREFIX"",DEB_F_PREFIX_ARGS(GSM, fname));
     if (num_sdp_bodies == 0) {
         /*
          * Clear the call - we don't have any remote SDP info!
          */
-        return CC_CAUSE_ERROR;
+        return CC_CAUSE_NO_SDP;
     }
 
     /* There are SDPs to process, prepare for parsing the SDP */
-    if (gsmsdp_realloc_dest_sdp(dcb_p) != CC_CAUSE_OK) {
+    status = gsmsdp_realloc_dest_sdp(dcb_p);
+    if (status != CC_CAUSE_OK) {
         /* Unable to create internal SDP structure to parse SDP. */
-        return CC_CAUSE_ERROR;
+        return status;
     }
 
     /*
      * Parse the SDP into internal structure,
      * now just parse one
      */
-    status = CC_CAUSE_ERROR;
+    status = CC_CAUSE_SDP_PARSE_FAILED;
     for (i = 0; (i < num_sdp_bodies); i++) {
         if ((sdp_bodies[i]->body != NULL) && (sdp_bodies[i]->body_length > 0)) {
             /* Found a body */
             sdp_body = sdp_bodies[i]->body;
             if (sdp_parse(dcb_p->sdp->dest_sdp, &sdp_body,
                           (uint16_t)sdp_bodies[i]->body_length)
                     == SDP_SUCCESS) {
                 status = CC_CAUSE_OK;
@@ -6473,40 +6483,43 @@ gsmsdp_process_offer_sdp (fsm_fcb_t *fcb
         DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname), init);
     if (num_sdp_bodies == 0) {
         /*
          * No remote SDP. So we will offer in our response and receive far end
          * answer in the ack. Only need to create local sdp if this is first offer
          * of a session. Otherwise, we will send what we have.
          */
         if (init) {
-            if ( CC_CAUSE_OK != gsmsdp_create_local_sdp(dcb_p, FALSE, TRUE, TRUE, TRUE, TRUE)) {
-                return CC_CAUSE_ERROR;
+            status = gsmsdp_create_local_sdp(dcb_p, FALSE, TRUE,
+                                             TRUE, TRUE, TRUE);
+            if ( status != CC_CAUSE_OK) {
+                return status;
             }
         } else {
             /*
              * Reset all media entries that we have to offer all capabilities
              */
            (void)gsmsdp_update_local_sdp_media_capability(dcb_p, TRUE, FALSE);
         }
         dcb_p->remote_sdp_in_ack = TRUE;
         return CC_CAUSE_OK;
     }
 
     /* There are SDPs to process, prepare for parsing the SDP */
-    if (gsmsdp_realloc_dest_sdp(dcb_p) != CC_CAUSE_OK) {
+    status = gsmsdp_realloc_dest_sdp(dcb_p);
+    if (status != CC_CAUSE_OK) {
         /* Unable to create internal SDP structure to parse SDP. */
-        return CC_CAUSE_ERROR;
+        return status;
     }
 
     /*
      * Parse the SDP into internal structure,
      * now just parse one
      */
-    status = CC_CAUSE_ERROR;
+    status = CC_CAUSE_SDP_PARSE_FAILED;
     for (i = 0; (i < num_sdp_bodies); i++) {
         if ((sdp_bodies[i]->body != NULL) && (sdp_bodies[i]->body_length > 0)) {
             /* Found a body */
             sdp_body = sdp_bodies[i]->body;
             if (sdp_parse(dcb_p->sdp->dest_sdp, &sdp_body,
                           (uint16_t)sdp_bodies[i]->body_length)
                     == SDP_SUCCESS) {
                 status = CC_CAUSE_OK;
@@ -6575,28 +6588,28 @@ gsmsdp_check_ice_attributes_exist(fsm_fc
 
         if (!has_session_ufrag) {
             sdp_res = sdp_attr_get_ice_attribute(dcb_p->sdp->dest_sdp,
                 media->level, 0, SDP_ATTR_ICE_UFRAG, 1, &ufrag);
 
             if (sdp_res != SDP_SUCCESS || !ufrag) {
                 GSM_ERR_MSG(GSM_L_C_F_PREFIX"missing ICE ufrag parameter.",
                             dcb_p->line, dcb_p->call_id, __FUNCTION__);
-                return CC_CAUSE_ERROR;
+                return CC_CAUSE_MISSING_ICE_ATTRIBUTES;
             }
         }
 
         if (!has_session_pwd) {
             sdp_res = sdp_attr_get_ice_attribute(dcb_p->sdp->dest_sdp,
                 media->level, 0, SDP_ATTR_ICE_PWD, 1, &pwd);
 
             if (sdp_res != SDP_SUCCESS || !pwd) {
                 GSM_ERR_MSG(GSM_L_C_F_PREFIX"missing ICE pwd parameter.",
                             dcb_p->line, dcb_p->call_id, __FUNCTION__);
-                return CC_CAUSE_ERROR;
+                return CC_CAUSE_MISSING_ICE_ATTRIBUTES;
             }
         }
     }
 
     return CC_CAUSE_OK;
 }
 
 /*
@@ -6616,34 +6629,34 @@ gsmsdp_install_peer_ice_attributes(fsm_f
     char            **candidates;
     int             candidate_ct;
     sdp_result_e    sdp_res;
     short           vcm_res;
     fsmdef_dcb_t    *dcb_p = fcb_p->dcb;
     cc_sdp_t        *sdp_p = dcb_p->sdp;
     fsmdef_media_t  *media;
     int             level;
-    short           result;
+    cc_causes_t     result;
 
     /* Tolerate missing ufrag/pwd here at the session level
        because it might be at the media level */
     sdp_res = sdp_attr_get_ice_attribute(sdp_p->dest_sdp, SDP_SESSION_LEVEL, 0,
       SDP_ATTR_ICE_UFRAG, 1, &ufrag);
     if (sdp_res != SDP_SUCCESS)
       ufrag = NULL;
 
     sdp_res = sdp_attr_get_ice_attribute(sdp_p->dest_sdp, SDP_SESSION_LEVEL, 0,
       SDP_ATTR_ICE_PWD, 1, &pwd);
     if (sdp_res != SDP_SUCCESS)
       pwd = NULL;
 
     if (ufrag && pwd) {
         vcm_res = vcmSetIceSessionParams(dcb_p->peerconnection, ufrag, pwd);
         if (vcm_res)
-            return (CC_CAUSE_ERROR);
+            return (CC_CAUSE_SETTING_ICE_SESSION_PARAMETERS_FAILED);
     }
 
     /* Now process all the media lines */
     GSMSDP_FOR_ALL_MEDIA(media, dcb_p) {
       if (!GSMSDP_MEDIA_ENABLED(media))
         continue;
 
       sdp_res = sdp_attr_get_ice_attribute(sdp_p->dest_sdp, media->level, 0,
@@ -6655,18 +6668,18 @@ gsmsdp_install_peer_ice_attributes(fsm_f
         SDP_ATTR_ICE_PWD, 1, &pwd);
       if (sdp_res != SDP_SUCCESS)
         pwd = NULL;
 
       candidate_ct = 0;
       candidates = NULL;
       result = gsmsdp_get_ice_attributes (SDP_ATTR_ICE_CANDIDATE, media->level, sdp_p->dest_sdp,
                                           &candidates, &candidate_ct);
-      if(!result)
-        return (CC_CAUSE_ERROR);
+      if(result != CC_CAUSE_OK)
+        return (result);
 
       /* Set ICE parameters into ICE engine */
 
       vcm_res = vcmSetIceMediaParams(dcb_p->peerconnection, media->level, ufrag, pwd,
                                     candidates, candidate_ct);
 
       /* Clean up */
       if(candidates) {
@@ -6675,17 +6688,17 @@ gsmsdp_install_peer_ice_attributes(fsm_f
         for (i=0; i<candidate_ct; i++) {
           if (candidates[i])
             cpr_free(candidates[i]);
         }
         cpr_free(candidates);
       }
 
       if (vcm_res)
-        return (CC_CAUSE_ERROR);
+        return (CC_CAUSE_SETTING_ICE_SESSION_PARAMETERS_FAILED);
 
     }
 
     return CC_CAUSE_OK;
 }
 
 /*
  * gsmsdp_configure_dtls_data_attributes
@@ -6728,66 +6741,66 @@ gsmsdp_configure_dtls_data_attributes(fs
             continue;
 
         /* check for media level algorithm and key */
         sdp_res = sdp_attr_get_dtls_fingerprint_attribute (sdp_p->dest_sdp, media->level,
                                     0, SDP_ATTR_DTLS_FINGERPRINT, 1, &fingerprint);
 
         if (SDP_SUCCESS == sdp_res ) {
             if (strlen(fingerprint) >= sizeof(line_to_split))
-                return CC_CAUSE_ERROR;
+                return CC_CAUSE_DTLS_FINGERPRINT_TOO_LONG;
             sstrncpy(line_to_split, fingerprint, sizeof(line_to_split));
         } else if (SDP_SUCCESS == sdp_session_res) {
             if (strlen(session_fingerprint) >= sizeof(line_to_split))
-                return CC_CAUSE_ERROR;
+                return CC_CAUSE_DTLS_FINGERPRINT_TOO_LONG;
             sstrncpy(line_to_split, session_fingerprint, sizeof(line_to_split));
         } else {
-            cause = CC_CAUSE_ERROR;
+            cause = CC_CAUSE_NO_DTLS_FINGERPRINT;
             continue;
         }
 
         if (SDP_SUCCESS == sdp_res || SDP_SUCCESS == sdp_session_res) {
             if(!(token = PL_strtok_r(line_to_split, delim, &strtok_state)))
-                return CC_CAUSE_ERROR;
+                return CC_CAUSE_DTLS_FINGERPRINT_PARSE_ERROR;
 
             if (strlen(token) >= sizeof(digest_alg))
-                return CC_CAUSE_ERROR;
+                return CC_CAUSE_DTLS_DIGEST_ALGORITHM_TOO_LONG;
 
             sstrncpy(digest_alg, token, sizeof(digest_alg));
             if(!(token = PL_strtok_r(NULL, delim, &strtok_state)))
-                return CC_CAUSE_ERROR;
+                return CC_CAUSE_DTLS_FINGERPRINT_PARSE_ERROR;
 
             if (strlen(token) >= sizeof(digest))
-                return CC_CAUSE_ERROR;
+                return CC_CAUSE_DTLS_DIGEST_TOO_LONG;
 
             sstrncpy(digest, token, sizeof(digest));
 
             if (strlen(digest_alg) >= sizeof(media->negotiated_crypto.algorithm))
-                return CC_CAUSE_ERROR;
+                return CC_CAUSE_DTLS_DIGEST_ALGORITHM_TOO_LONG;
 
             sstrncpy(media->negotiated_crypto.algorithm, digest_alg, sizeof(media->negotiated_crypto.algorithm));
             if (strlen(media->negotiated_crypto.algorithm) == 0) {
-                return CC_CAUSE_ERROR;
+                return CC_CAUSE_DTLS_DIGEST_ALGORITHM_EMPTY;
             }
 
             if (strlen(digest) >= sizeof(media->negotiated_crypto.digest))
-                return CC_CAUSE_ERROR;
+                return CC_CAUSE_DTLS_DIGEST_TOO_LONG;
 
             sstrncpy(media->negotiated_crypto.digest, digest, sizeof(media->negotiated_crypto.digest));
             if (strlen(media->negotiated_crypto.digest) == 0) {
-                return CC_CAUSE_ERROR;
+                return CC_CAUSE_DTLS_DIGEST_EMPTY;
             }
 
             /* Here we have DTLS data */
             cause = CC_CAUSE_OK;
 
         } else {
             GSM_DEBUG(DEB_F_PREFIX"DTLS attribute error",
                                    DEB_F_PREFIX_ARGS(GSM, __FUNCTION__));
-            return CC_CAUSE_ERROR;
+            return CC_CAUSE_DTLS_ATTRIBUTE_ERROR;
         }
     }
 
     return cause;
 }
 
 /*
  * gsmsdp_free
--- a/media/webrtc/signaling/src/sipcc/core/gsm/subapi.c
+++ b/media/webrtc/signaling/src/sipcc/core/gsm/subapi.c
@@ -48,17 +48,17 @@ sub_print_msg (char *pData, int len)
 cc_rcs_t
 sub_send_msg (cprBuffer_t buf, uint32_t cmd, uint16_t len, cc_srcs_t dst_id)
 {
     cpr_status_e rc;
 
     /* This buffer is assumed to be at least of size int */
     MOZ_ASSERT(len >= sizeof(int));
     if (len < sizeof(int)) {
-        return CPR_FAILURE;
+        return CC_RC_ERROR;
     }
 
     CC_DEBUG_MSG sub_print_msg((char *)buf, len);
 
     switch (dst_id) {
     case CC_SRC_GSM:
         rc = gsm_send_msg(cmd, buf, len);
         if (rc == CPR_FAILURE) {
--- a/media/webrtc/signaling/src/sipcc/core/includes/sessionConstants.h
+++ b/media/webrtc/signaling/src/sipcc/core/includes/sessionConstants.h
@@ -338,16 +338,39 @@ static const char *cc_cause_names[] = {
     "FORWARDED",
     "ABANDONED",
     "XFER_LOCAL_WITH_DIALSTRING",
     "CAC_BW_OK",
     "ONHOOK_FEAT_COMP",
     "RESP_TIMEOUT",
     "SERV_ERR_UNAVAIL",
     "REMOTE_DISCONN_REQ_PLAYTONE",
+    "OUT_OF_MEM",
+    "VALUE_NOT_FOUND",
+    "BAD_ICE_ATTRIBUTE",
+    "DTLS_ATTRIBUTE_ERROR",
+    "DTLS_DIGEST_ALGORITHM_EMPTY",
+    "DTLS_DIGEST_ALGORITHM_TOO_LONG",
+    "DTLS_DIGEST_EMPTY",
+    "DTLS_DIGEST_TOO_LONG",
+    "DTLS_FINGERPRINT_PARSE_ERROR",
+    "DTLS_FINGERPRINT_TOO_LONG",
+    "INVALID_SDP_POINTER",
+    "NO_AUDIO",
+    "NO_DTLS_FINGERPRINT",
+    "MISSING_ICE_ATTRIBUTES",
+    "NO_MEDIA_CAPABILITY",
+    "NO_M_LINE",
+    "NO_PEERCONNECTION",
+    "NO_SDP",
+    "NULL_POINTER",
+    "SDP_CREATE_FAILED",
+    "SDP_ENCODE_FAILED",
+    "SDP_PARSE_FAILED",
+    "SETTING_ICE_SESSION_PARAMETERS_FAILED",
     "MAX_CAUSE"
 };
 #endif //__CC_CAUSE_STRINGS__
 
 #define MAX_SOFT_KEYS    16
 
 
 // eventually these should come from the Java side
--- a/media/webrtc/signaling/src/sipcc/include/cc_constants.h
+++ b/media/webrtc/signaling/src/sipcc/include/cc_constants.h
@@ -416,70 +416,91 @@ typedef enum {
 	CC_LAMP_FRESH
 } cc_lamp_state_t;
 
 /**
  * defines call cause
  * Important: when update this enum, please update the cc_cause_name accordingly.
  */
 typedef enum {
-	CC_CAUSE_MIN = -1,
-	CC_CAUSE_BASE = -1,
-	CC_CAUSE_OK,
-	CC_CAUSE_ERROR,
-	CC_CAUSE_UNASSIGNED_NUM,
-	CC_CAUSE_NO_RESOURCE,
-	CC_CAUSE_NO_ROUTE,
-	CC_CAUSE_NORMAL,
-	CC_CAUSE_BUSY,
-	CC_CAUSE_NO_USER_RESP,
-	CC_CAUSE_NO_USER_ANS,
-	CC_CAUSE_REJECT,
-	CC_CAUSE_INVALID_NUMBER,
-	CC_CAUSE_FACILITY_REJECTED,
-	CC_CAUSE_CALL_ID_IN_USE,
-	CC_CAUSE_XFER_LOCAL,
-	CC_CAUSE_XFER_REMOTE,
-	CC_CAUSE_XFER_BY_REMOTE,
-	CC_CAUSE_XFER_CNF,
-	CC_CAUSE_CONGESTION,
-	CC_CAUSE_ANONYMOUS,
-	CC_CAUSE_REDIRECT,
-	CC_CAUSE_PAYLOAD_MISMATCH,
-	CC_CAUSE_CONF,
-	CC_CAUSE_REPLACE,
-	CC_CAUSE_NO_REPLACE_CALL,
-	CC_CAUSE_NO_RESUME,
-	CC_CAUSE_NO_MEDIA,
-	CC_CAUSE_REQUEST_PENDING,
-	CC_CAUSE_INVALID_PARTICIPANT,
-	CC_CAUSE_NO_CNF_BRIDE,
-	CC_MAXIMUM_PARTICIPANT,
-	CC_KEY_NOT_ACTIVE,
-	CC_TEMP_NOT_AVAILABLE,
-	CC_CAUSE_REMOTE_SERVER_ERROR,
-	CC_CAUSE_BARGE,
-	CC_CAUSE_CBARGE,
-	CC_CAUSE_NOT_FOUND,
-	CC_CAUSE_SECURITY_FAILURE,
-	CC_CAUSE_MONITOR,
-	CC_CAUSE_UI_STATE_BUSY,
-	CC_SIP_CAUSE_ANSWERED_ELSEWHERE,
-	CC_CAUSE_RETRIEVED,
-	CC_CAUSE_FORWARDED,
-	CC_CAUSE_ABANDONED,
-	CC_CAUSE_XFER_LOCAL_WITH_DIALSTRING,
-	CC_CAUSE_BW_OK,
-	CC_CAUSE_XFER_COMPLETE,
-	CC_CAUSE_RESP_TIMEOUT,
-	CC_CAUSE_SERV_ERR_UNAVAIL,
+    CC_CAUSE_MIN = -1,
+    CC_CAUSE_BASE = -1,
+    CC_CAUSE_OK,
+    CC_CAUSE_ERROR,
+    CC_CAUSE_UNASSIGNED_NUM,
+    CC_CAUSE_NO_RESOURCE,
+    CC_CAUSE_NO_ROUTE,
+    CC_CAUSE_NORMAL,
+    CC_CAUSE_BUSY,
+    CC_CAUSE_NO_USER_RESP,
+    CC_CAUSE_NO_USER_ANS,
+    CC_CAUSE_REJECT,
+    CC_CAUSE_INVALID_NUMBER,
+    CC_CAUSE_FACILITY_REJECTED,
+    CC_CAUSE_CALL_ID_IN_USE,
+    CC_CAUSE_XFER_LOCAL,
+    CC_CAUSE_XFER_REMOTE,
+    CC_CAUSE_XFER_BY_REMOTE,
+    CC_CAUSE_XFER_CNF,
+    CC_CAUSE_CONGESTION,
+    CC_CAUSE_ANONYMOUS,
+    CC_CAUSE_REDIRECT,
+    CC_CAUSE_PAYLOAD_MISMATCH,
+    CC_CAUSE_CONF,
+    CC_CAUSE_REPLACE,
+    CC_CAUSE_NO_REPLACE_CALL,
+    CC_CAUSE_NO_RESUME,
+    CC_CAUSE_NO_MEDIA,
+    CC_CAUSE_REQUEST_PENDING,
+    CC_CAUSE_INVALID_PARTICIPANT,
+    CC_CAUSE_NO_CNF_BRIDE,
+    CC_MAXIMUM_PARTICIPANT,
+    CC_KEY_NOT_ACTIVE,
+    CC_TEMP_NOT_AVAILABLE,
+    CC_CAUSE_REMOTE_SERVER_ERROR,
+    CC_CAUSE_BARGE,
+    CC_CAUSE_CBARGE,
+    CC_CAUSE_NOT_FOUND,
+    CC_CAUSE_SECURITY_FAILURE,
+    CC_CAUSE_MONITOR,
+    CC_CAUSE_UI_STATE_BUSY,
+    CC_SIP_CAUSE_ANSWERED_ELSEWHERE,
+    CC_CAUSE_RETRIEVED,
+    CC_CAUSE_FORWARDED,
+    CC_CAUSE_ABANDONED,
+    CC_CAUSE_XFER_LOCAL_WITH_DIALSTRING,
+    CC_CAUSE_BW_OK,
+    CC_CAUSE_XFER_COMPLETE,
+    CC_CAUSE_RESP_TIMEOUT,
+    CC_CAUSE_SERV_ERR_UNAVAIL,
     CC_CAUSE_REMOTE_DISCONN_REQ_PLAYTONE,
     CC_CAUSE_OUT_OF_MEM,
     CC_CAUSE_VALUE_NOT_FOUND,
-	CC_CAUSE_MAX
+    CC_CAUSE_BAD_ICE_ATTRIBUTE,
+    CC_CAUSE_DTLS_ATTRIBUTE_ERROR,
+    CC_CAUSE_DTLS_DIGEST_ALGORITHM_EMPTY,
+    CC_CAUSE_DTLS_DIGEST_ALGORITHM_TOO_LONG,
+    CC_CAUSE_DTLS_DIGEST_EMPTY,
+    CC_CAUSE_DTLS_DIGEST_TOO_LONG,
+    CC_CAUSE_DTLS_FINGERPRINT_PARSE_ERROR,
+    CC_CAUSE_DTLS_FINGERPRINT_TOO_LONG,
+    CC_CAUSE_INVALID_SDP_POINTER,
+    CC_CAUSE_NO_AUDIO,
+    CC_CAUSE_NO_DTLS_FINGERPRINT,
+    CC_CAUSE_MISSING_ICE_ATTRIBUTES,
+    CC_CAUSE_NO_MEDIA_CAPABILITY,
+    CC_CAUSE_NO_M_LINE,
+    CC_CAUSE_NO_PEERCONNECTION,
+    CC_CAUSE_NO_SDP,
+    CC_CAUSE_NULL_POINTER,
+    CC_CAUSE_SDP_CREATE_FAILED,
+    CC_CAUSE_SDP_ENCODE_FAILED,
+    CC_CAUSE_SDP_PARSE_FAILED,
+    CC_CAUSE_SETTING_ICE_SESSION_PARAMETERS_FAILED,
+    CC_CAUSE_MAX
 } cc_cause_t;
 
 /**
  * defines subscription event type
  */
 typedef enum {
 	CC_SUBSCRIPTIONS_DIALOG_EXT = 2,
     CC_SUBSCRIPTIONS_KPML_EXT = 4,
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -484,19 +484,16 @@ abstract public class GeckoApp
 
         return super.onKeyDown(keyCode, event);
     }
 
     @Override
     protected void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
 
-        if (outState == null)
-            outState = new Bundle();
-
         outState.putBoolean(SAVED_STATE_IN_BACKGROUND, isApplicationInBackground());
         outState.putString(SAVED_STATE_PRIVATE_SESSION, mPrivateBrowsingSession);
 
         // Bug 896992 - Replace intent action with ACTION_MAIN on restart.
         if (mIntentHandled) {
             outState.putBoolean(SAVED_STATE_INTENT_HANDLED, true);
         }
     }