Merge m-c to f-t
authorPhil Ringnalda <philringnalda@gmail.com>
Sat, 07 Dec 2013 18:35:20 -0800
changeset 175085 095c03bb1d79bcb613383bc3d75ef20a7982b264
parent 175084 b44cec692a98840460937958e93fda54e11cf483 (current diff)
parent 175067 edac8cba9f78c0160edf79ff56041831ef44c2fa (diff)
child 175086 8b3ff10c5a525da953b16cfe0615dd2b503e1e0d
child 175134 550462c1dae0f6e8fd81357b2ece2b74fcd3831f
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone28.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 m-c to f-t
--- a/build/autoconf/icu.m4
+++ b/build/autoconf/icu.m4
@@ -17,15 +17,15 @@ AC_DEFUN([MOZ_CONFIG_ICU], [
     fi
 
     version=`sed -n 's/^[[:space:]]*#[[:space:]]*define[[:space:]][[:space:]]*U_ICU_VERSION_MAJOR_NUM[[:space:]][[:space:]]*\([0-9][0-9]*\)[[:space:]]*$/\1/p' "$icudir/common/unicode/uvernum.h"`
     if test x"$version" = x; then
        AC_MSG_ERROR([cannot determine icu version number from uvernum.h header file $lineno])
     fi
     MOZ_ICU_VERSION="$version"
 
-    if test -n "${JS_SHARED_LIBRARY}${MOZ_NATIVE_ICU}"; then
+    if test -z "${JS_STANDALONE}" -a -n "${JS_SHARED_LIBRARY}${MOZ_NATIVE_ICU}"; then
         MOZ_SHARED_ICU=1
     fi
 
     AC_SUBST(MOZ_ICU_VERSION)
     AC_SUBST(MOZ_SHARED_ICU)
 ])
--- a/content/canvas/src/WebGLFramebuffer.cpp
+++ b/content/canvas/src/WebGLFramebuffer.cpp
@@ -499,17 +499,17 @@ WebGLFramebuffer::CheckAndInitializeAtta
 
 bool WebGLFramebuffer::CheckColorAttachementNumber(GLenum attachment, const char * functionName) const
 {
     const char* const errorFormating = "%s: attachment: invalid enum value 0x%x";
 
     if (mContext->IsExtensionEnabled(WebGLContext::WEBGL_draw_buffers))
     {
         if (attachment < LOCAL_GL_COLOR_ATTACHMENT0 ||
-            attachment > GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + mContext->mGLMaxColorAttachments))
+            attachment >= GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + mContext->mGLMaxColorAttachments))
         {
             mContext->ErrorInvalidEnum(errorFormating, functionName, attachment);
             return false;
         }
     }
     else if (attachment != LOCAL_GL_COLOR_ATTACHMENT0)
     {
         if (attachment > LOCAL_GL_COLOR_ATTACHMENT0 &&
--- a/content/html/content/src/HTMLInputElement.cpp
+++ b/content/html/content/src/HTMLInputElement.cpp
@@ -609,16 +609,18 @@ private:
   // We'd prefer this member to be bool, but we don't support Atomic<bool>.
   mozilla::Atomic<uint32_t> mCanceled;
 };
 
 
 NS_IMETHODIMP
 HTMLInputElement::nsFilePickerShownCallback::Done(int16_t aResult)
 {
+  mInput->PickerClosed();
+
   if (aResult == nsIFilePicker::returnCancel) {
     return NS_OK;
   }
 
   mInput->CancelDirectoryPickerScanIfRunning();
 
   int16_t mode;
   mFilePicker->GetMode(&mode);
@@ -791,16 +793,18 @@ nsColorPickerShownCallback::Done(const n
    * When Done() is called, we might be at the end of a serie of Update() calls
    * in which case mValueChanged is set to true and a change event will have to
    * be fired but we might also be in a one shot Done() call situation in which
    * case we should fire a change event iif the value actually changed.
    * UpdateInternal(bool) is taking care of that logic for us.
    */
   nsresult rv = NS_OK;
 
+  mInput->PickerClosed();
+
   if (!aColor.IsEmpty()) {
     UpdateInternal(aColor, false);
   }
 
   if (mValueChanged) {
     rv = nsContentUtils::DispatchTrustedEvent(mInput->OwnerDoc(),
                                               static_cast<nsIDOMHTMLInputElement*>(mInput.get()),
                                               NS_LITERAL_STRING("change"), true,
@@ -834,16 +838,21 @@ HTMLInputElement::IsPopupBlocked() const
   uint32_t permission;
   pm->TestPermission(OwnerDoc()->NodePrincipal(), &permission);
   return permission == nsIPopupWindowManager::DENY_POPUP;
 }
 
 nsresult
 HTMLInputElement::InitColorPicker()
 {
+  if (mPickerRunning) {
+    NS_WARNING("Just one nsIColorPicker is allowed");
+    return NS_ERROR_FAILURE;
+  }
+
   nsCOMPtr<nsIDocument> doc = OwnerDoc();
 
   nsCOMPtr<nsPIDOMWindow> win = doc->GetWindow();
   if (!win) {
     return NS_ERROR_FAILURE;
   }
 
   if (IsPopupBlocked()) {
@@ -864,22 +873,32 @@ HTMLInputElement::InitColorPicker()
   nsAutoString initialValue;
   GetValueInternal(initialValue);
   nsresult rv = colorPicker->Init(win, title, initialValue);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIColorPickerShownCallback> callback =
     new nsColorPickerShownCallback(this, colorPicker);
 
-  return colorPicker->Open(callback);
+  rv = colorPicker->Open(callback);
+  if (NS_SUCCEEDED(rv)) {
+    mPickerRunning = true;
+  }
+
+  return rv;
 }
 
 nsresult
 HTMLInputElement::InitFilePicker(FilePickerType aType)
 {
+  if (mPickerRunning) {
+    NS_WARNING("Just one nsIFilePicker is allowed");
+    return NS_ERROR_FAILURE;
+  }
+
   // Get parent nsPIDOMWindow object.
   nsCOMPtr<nsIDocument> doc = OwnerDoc();
 
   nsCOMPtr<nsPIDOMWindow> win = doc->GetWindow();
   if (!win) {
     return NS_ERROR_FAILURE;
   }
 
@@ -950,20 +969,26 @@ HTMLInputElement::InitFilePicker(FilePic
     if (oldFiles.Length() == 1) {
       nsAutoString leafName;
       oldFiles[0]->GetName(leafName);
       if (!leafName.IsEmpty()) {
         filePicker->SetDefaultString(leafName);
       }
     }
 
-    return filePicker->Open(callback);
+    rv = filePicker->Open(callback);
+    if (NS_SUCCEEDED(rv)) {
+      mPickerRunning = true;
+    }
+
+    return rv;
   }
 
   HTMLInputElement::gUploadLastDir->FetchDirectoryAndDisplayPicker(doc, filePicker, callback);
+  mPickerRunning = true;
   return NS_OK;
 }
 
 #define CPS_PREF_NAME NS_LITERAL_STRING("browser.upload.lastDir")
 
 NS_IMPL_ISUPPORTS2(UploadLastDir, nsIObserver, nsISupportsWeakReference)
 
 void
@@ -1089,16 +1114,18 @@ HTMLInputElement::HTMLInputElement(alrea
   , mIndeterminate(false)
   , mInhibitRestoration(aFromParser & FROM_PARSER_FRAGMENT)
   , mCanShowValidUI(true)
   , mCanShowInvalidUI(true)
   , mHasRange(false)
   , mIsDraggingRange(false)
   , mProgressTimerIsActive(false)
   , mNumberControlSpinnerIsSpinning(false)
+  , mNumberControlSpinnerSpinsUp(false)
+  , mPickerRunning(false)
 {
   // We are in a type=text so we now we currenty need a nsTextEditorState.
   mInputData.mState = new nsTextEditorState(this);
 
   if (!gUploadLastDir)
     HTMLInputElement::InitUploadLastDir();
 
   // Set up our default state.  By default we're enabled (since we're
@@ -7173,16 +7200,22 @@ HTMLInputElement::UpdateHasRange()
 
   Decimal maximum = GetMaximum();
   if (!maximum.isNaN()) {
     mHasRange = true;
     return;
   }
 }
 
+void
+HTMLInputElement::PickerClosed()
+{
+  mPickerRunning = false;
+}
+
 JSObject*
 HTMLInputElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return HTMLInputElementBinding::Wrap(aCx, aScope, this);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/content/html/content/src/HTMLInputElement.h
+++ b/content/html/content/src/HTMLInputElement.h
@@ -198,16 +198,19 @@ public:
   const nsTArray<nsCOMPtr<nsIDOMFile> >& GetFilesInternal() const
   {
     return mFiles;
   }
 
   void SetFiles(const nsTArray<nsCOMPtr<nsIDOMFile> >& aFiles, bool aSetValueChanged);
   void SetFiles(nsIDOMFileList* aFiles, bool aSetValueChanged);
 
+  // Called when a nsIFilePicker or a nsIColorPicker terminate.
+  void PickerClosed();
+
   void SetCheckedChangedInternal(bool aCheckedChanged);
   bool GetCheckedChanged() const {
     return mCheckedChanged;
   }
   void AddedToRadioGroup();
   void WillRemoveFromRadioGroup();
 
  /**
@@ -1262,16 +1265,17 @@ protected:
   bool                     mInhibitRestoration  : 1;
   bool                     mCanShowValidUI      : 1;
   bool                     mCanShowInvalidUI    : 1;
   bool                     mHasRange            : 1;
   bool                     mIsDraggingRange     : 1;
   bool                     mProgressTimerIsActive : 1;
   bool                     mNumberControlSpinnerIsSpinning : 1;
   bool                     mNumberControlSpinnerSpinsUp : 1;
+  bool                     mPickerRunning : 1;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
                                     nsRuleData* aData);
 
   /**
    * Returns true if this input's type will fire a DOM "change" event when it
    * loses focus if its value has changed since it gained focus.
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -16,16 +16,17 @@
 #include "Layers.h"
 #include "TestLayers.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 using ::testing::_;
 using ::testing::NiceMock; 
+using ::testing::AtLeast;
 
 class MockContentController : public GeckoContentController {
 public:
   MOCK_METHOD1(RequestContentRepaint, void(const FrameMetrics&));
   MOCK_METHOD2(HandleDoubleTap, void(const CSSIntPoint&, int32_t));
   MOCK_METHOD2(HandleSingleTap, void(const CSSIntPoint&, int32_t));
   MOCK_METHOD2(HandleLongTap, void(const CSSIntPoint&, int32_t));
   MOCK_METHOD3(SendAsyncScrollDOMEvent, void(bool aIsRoot, const CSSRect &aContentRect, const CSSSize &aScrollableSize));
@@ -164,17 +165,17 @@ TEST(AsyncPanZoomController, Pinch) {
   fm.mViewport = CSSRect(0, 0, 980, 480);
   fm.mCompositionBounds = ScreenIntRect(200, 200, 100, 200);
   fm.mScrollableRect = CSSRect(0, 0, 980, 1000);
   fm.mScrollOffset = CSSPoint(300, 300);
   fm.mZoom = CSSToScreenScale(2.0);
   apzc->SetFrameMetrics(fm);
   // the visible area of the document in CSS pixels is x=300 y=300 w=50 h=100
 
-  EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(2);
+  EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
   EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
 
   ApzcPinch(apzc, 250, 300, 1.25);
 
   // the visible area of the document in CSS pixels is now x=305 y=310 w=40 h=80
   fm = apzc->GetFrameMetrics();
   EXPECT_EQ(fm.mZoom.scale, 2.5f);
   EXPECT_EQ(fm.mScrollOffset.x, 305);
@@ -204,17 +205,17 @@ TEST(AsyncPanZoomController, Overzoom) {
   fm.mViewport = CSSRect(0, 0, 100, 100);
   fm.mCompositionBounds = ScreenIntRect(0, 0, 100, 100);
   fm.mScrollableRect = CSSRect(0, 0, 125, 150);
   fm.mScrollOffset = CSSPoint(10, 0);
   fm.mZoom = CSSToScreenScale(1.0);
   apzc->SetFrameMetrics(fm);
   // the visible area of the document in CSS pixels is x=10 y=0 w=100 h=100
 
-  EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(1);
+  EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
   EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
 
   ApzcPinch(apzc, 50, 50, 0.5);
 
   fm = apzc->GetFrameMetrics();
   EXPECT_EQ(fm.mZoom.scale, 0.8f);
   // bug 936721 - PGO builds introduce rounding error so
   // use a fuzzy match instead
@@ -348,17 +349,17 @@ TEST(AsyncPanZoomController, Pan) {
 
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc, tm);
 
   apzc->SetFrameMetrics(TestFrameMetrics());
   apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
 
-  EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(4);
+  EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
   EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
 
   int time = 0;
   int touchStart = 50;
   int touchEnd = 10;
   ScreenPoint pointOut;
   ViewTransform viewTransformOut;
 
@@ -381,17 +382,17 @@ TEST(AsyncPanZoomController, Fling) {
 
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc, tm);
 
   apzc->SetFrameMetrics(TestFrameMetrics());
   apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
 
-  EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(2);
+  EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
   EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
 
   int time = 0;
   int touchStart = 50;
   int touchEnd = 10;
   ScreenPoint pointOut;
   ViewTransform viewTransformOut;
 
@@ -411,17 +412,17 @@ TEST(AsyncPanZoomController, OverScrollP
 
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc, tm);
 
   apzc->SetFrameMetrics(TestFrameMetrics());
   apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
 
-  EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(4);
+  EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
   EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
 
   // Pan sufficiently to hit overscroll behavior
   int time = 0;
   int touchStart = 500;
   int touchEnd = 10;
   ScreenPoint pointOut;
   ViewTransform viewTransformOut;
@@ -654,17 +655,17 @@ TEST(APZCTreeManager, HitTesting2) {
   EXPECT_EQ(gfxPoint(75, 75), transformToGecko.Transform(gfxPoint(37.5, 75)));
 
   // Pan the root layer upward by 50 pixels.
   // This causes layers[1] to scroll out of view, and an async transform
   // of -50 to be set on the root layer.
   int time = 0;
   // Silence GMock warnings about "uninteresting mock function calls".
   EXPECT_CALL(*mcc, PostDelayedTask(_,_)).Times(1);
-  EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(2);
+  EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
   EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
   ApzcPan(apzcroot, manager, time, 100, 50);
 
   // Hit where layers[3] used to be. It should now hit the root.
   hit = GetTargetAPZC(manager, ScreenPoint(75, 75), transformToApzc, transformToGecko);
   EXPECT_EQ(apzcroot, hit.get());
   // transformToApzc doesn't unapply the root's own async transform
   EXPECT_EQ(gfxPoint(75, 75), transformToApzc.Transform(gfxPoint(75, 75)));
--- a/js/public/HashTable.h
+++ b/js/public/HashTable.h
@@ -1518,16 +1518,17 @@ class HashTable : private AllocPolicy
     // Note: |l| may be a reference to a piece of |u|, so this function
     // must take care not to use |l| after moving |u|.
     template <class U>
     bool relookupOrAdd(AddPtr& p, const Lookup &l, U &&u)
     {
         p.mutationCount = mutationCount;
         {
             mozilla::ReentrancyGuard g(*this);
+            JS_ASSERT(prepareHash(l) == p.keyHash); // l has not been destroyed
             p.entry_ = &lookup(l, p.keyHash, sCollisionBit);
         }
         return p.found() || add(p, mozilla::Forward<U>(u));
     }
 
     void remove(Ptr p)
     {
         JS_ASSERT(table);
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -120,16 +120,17 @@ jsconfig_DEST = $(DIST)/include
 jsconfig_TARGET := export
 
 # Ensure that this happens before using $(MOZ_PSEUDO_DERECURSE)
 include $(topsrcdir)/config/config.mk
 
 # Ensure that this happens before including rules.mk
 ifdef ENABLE_INTL_API
 ifndef MOZ_NATIVE_ICU
+ifdef MOZ_SHARED_ICU
 ifeq ($(OS_ARCH),WINNT)
   # Library names: On Windows, ICU uses modified library names for static
   # and debug libraries.
   ifdef MOZ_DEBUG
     ICU_LIB_SUFFIX=d
   endif
   ifdef JS_SHARED_LIBRARY
     ICU_FILES := $(foreach libname,$(ICU_LIB_NAMES),intl/icu/target/lib/$(libname)$(ICU_LIB_SUFFIX)$(MOZ_ICU_VERSION).dll)
@@ -151,16 +152,17 @@ endif
 ifdef ICU_FILES
   ICU_DEST := $(DIST)/bin
   INSTALL_TARGETS += ICU
   $(ICU_FILES): buildicu
   ICU_TARGET := $(if $(MOZ_PSEUDO_DERECURSE),compile,export)
 endif
 endif
 endif
+endif
 
 include $(topsrcdir)/config/rules.mk
 
 .PHONY: buildffi buildicu
 buildffi buildicu:
 $(if $(MOZ_PSEUDO_DERECURSE),compile,export):: buildffi buildicu
 
 ifdef JS_HAS_CTYPES
--- a/js/src/build/autoconf/icu.m4
+++ b/js/src/build/autoconf/icu.m4
@@ -17,15 +17,15 @@ AC_DEFUN([MOZ_CONFIG_ICU], [
     fi
 
     version=`sed -n 's/^[[:space:]]*#[[:space:]]*define[[:space:]][[:space:]]*U_ICU_VERSION_MAJOR_NUM[[:space:]][[:space:]]*\([0-9][0-9]*\)[[:space:]]*$/\1/p' "$icudir/common/unicode/uvernum.h"`
     if test x"$version" = x; then
        AC_MSG_ERROR([cannot determine icu version number from uvernum.h header file $lineno])
     fi
     MOZ_ICU_VERSION="$version"
 
-    if test -n "${JS_SHARED_LIBRARY}${MOZ_NATIVE_ICU}"; then
+    if test -z "${JS_STANDALONE}" -a -n "${JS_SHARED_LIBRARY}${MOZ_NATIVE_ICU}"; then
         MOZ_SHARED_ICU=1
     fi
 
     AC_SUBST(MOZ_ICU_VERSION)
     AC_SUBST(MOZ_SHARED_ICU)
 ])
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -1114,21 +1114,21 @@ SetJitCompilerOption(JSContext *cx, unsi
 
     JS_SetGlobalJitCompilerOption(cx, opt, uint32_t(number));
 
     args.rval().setBoolean(true);
     return true;
 }
 
 static bool
-SetIonAssertGraphCoherency(JSContext *cx, unsigned argc, jsval *vp)
+SetIonCheckGraphCoherency(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 #ifdef JS_ION
-    jit::js_IonOptions.assertGraphConsistency = ToBoolean(args.get(0));
+    jit::js_IonOptions.checkGraphConsistency = ToBoolean(args.get(0));
 #endif
     args.rval().setUndefined();
     return true;
 }
 
 class CloneBufferObject : public JSObject {
     static const JSPropertySpec props_[2];
     static const size_t DATA_SLOT   = 0;
@@ -1572,18 +1572,18 @@ static const JSFunctionSpecWithHelp Test
     JS_FN_HELP("bailout", testingFunc_bailout, 0, 0,
 "bailout()",
 "  Force a bailout out of ionmonkey (if running in ionmonkey)."),
 
     JS_FN_HELP("setJitCompilerOption", SetJitCompilerOption, 2, 0,
 "setCompilerOption(<option>, <number>)",
 "  Set a compiler option indexed in JSCompileOption enum to a number.\n"),
 
-    JS_FN_HELP("setIonAssertGraphCoherency", SetIonAssertGraphCoherency, 1, 0,
-"setIonAssertGraphCoherency(bool)",
+    JS_FN_HELP("setIonCheckGraphCoherency", SetIonCheckGraphCoherency, 1, 0,
+"setIonCheckGraphCoherency(bool)",
 "  Set whether Ion should perform graph consistency (DEBUG-only) assertions. These assertions\n"
 "  are valuable and should be generally enabled, however they can be very expensive for large\n"
 "  (asm.js) programs."),
 
     JS_FN_HELP("serialize", Serialize, 1, 0,
 "serialize(data, [transferables])",
 "  Serialize 'data' using JS_WriteStructuredClone. Returns a structured\n"
 "  clone buffer object."),
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -1130,17 +1130,16 @@ if test "$GNU_CC"; then
     # -Wdeclaration-after-statement - MSVC doesn't like these
     # -Werror=return-type - catches missing returns, zero false positives
     # -Wtype-limits - catches overflow bugs, few false positives
     # -Wempty-body - catches bugs, e.g. "if (c); foo();", few false positives
     # -Wsign-compare - catches comparison of signed and unsigned types
     #
     _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wall -Wpointer-arith -Wdeclaration-after-statement"
     MOZ_C_SUPPORTS_WARNING(-W, error=return-type, ac_c_has_werror_return_type)
-    MOZ_C_SUPPORTS_WARNING(-W, type-limits, ac_c_has_wtype_limits)
     MOZ_C_SUPPORTS_WARNING(-W, empty-body, ac_c_has_wempty_body)
     MOZ_C_SUPPORTS_WARNING(-W, sign-compare, ac_c_has_sign_compare)
 
     # Turn off the following warnings that -Wall turns on:
     # -Wno-unused - lots of violations in third-party code
     #
     _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wno-unused"
 
@@ -4208,55 +4207,55 @@ if test -n "$ENABLE_INTL_API"; then
     AC_DEFINE(ENABLE_INTL_API)
 
     MOZ_CONFIG_ICU()
 
     if test -z "$MOZ_NATIVE_ICU"; then
         case "$OS_TARGET" in
             WINNT)
                 ICU_LIB_NAMES="icuin icuuc icudt"
-                if test "$DISABLE_SHARED_JS" != "1"; then
+                if test -n "$MOZ_SHARED_ICU"; then
                     DBG_SUFFIX=
                     if test -n "$MOZ_DEBUG"; then
                         DBG_SUFFIX=d
                     fi
                     MOZ_ICU_LIBS='$(foreach lib,$(ICU_LIB_NAMES),$(DEPTH)/intl/icu/target/lib/$(LIB_PREFIX)$(lib)$(DBG_SUFFIX).$(LIB_SUFFIX))'
                 fi
                 ;;
             Darwin)
                 ICU_LIB_NAMES="icui18n icuuc icudata"
-                if test "$DISABLE_SHARED_JS" != "1"; then
+                if test -n "$MOZ_SHARED_ICU"; then
                    MOZ_ICU_LIBS='$(foreach lib,$(ICU_LIB_NAMES),$(DEPTH)/intl/icu/target/lib/$(DLL_PREFIX)$(lib).$(MOZ_ICU_VERSION)$(DLL_SUFFIX))'
                 fi
                 ;;
             Linux|DragonFly|FreeBSD|NetBSD|OpenBSD)
                 ICU_LIB_NAMES="icui18n icuuc icudata"
-                if test "$DISABLE_SHARED_JS" != "1"; then
+                if test -n "$MOZ_SHARED_ICU"; then
                    MOZ_ICU_LIBS='$(foreach lib,$(ICU_LIB_NAMES),$(DEPTH)/intl/icu/target/lib/$(DLL_PREFIX)$(lib)$(DLL_SUFFIX).$(MOZ_ICU_VERSION))'
                 fi
                 ;;
             *)
                 AC_MSG_ERROR([ECMAScript Internationalization API is not yet supported on this platform])
         esac
-        if test "$DISABLE_SHARED_JS" = "1"; then
+        if test -z "$MOZ_SHARED_ICU"; then
             MOZ_ICU_LIBS='$(call EXPAND_LIBNAME_PATH,$(ICU_LIB_NAMES),$(DEPTH)/intl/icu/target/lib)'
         fi
     fi
 fi
 
 AC_SUBST(DBG_SUFFIX)
 AC_SUBST(ENABLE_INTL_API)
 AC_SUBST(ICU_LIB_NAMES)
 AC_SUBST(MOZ_ICU_LIBS)
 AC_SUBST(MOZ_NATIVE_ICU)
 
 dnl Settings for ICU
 if test -n "$ENABLE_INTL_API" -a -z "$MOZ_NATIVE_ICU"; then
     dnl We build ICU as a static library for non-shared js builds and as a shared library for shared js builds.
-    if test "$DISABLE_SHARED_JS" = "1"; then
+    if test -z "$MOZ_SHARED_ICU"; then
         AC_DEFINE(U_STATIC_IMPLEMENTATION)
     else
         AC_DEFINE(U_COMBINED_IMPLEMENTATION)
     fi
 
     dnl Source files that use ICU should have control over which parts of the ICU
     dnl namespace they want to use.
     AC_DEFINE(U_USING_ICU_NAMESPACE,0)
@@ -4342,17 +4341,17 @@ if test -n "$ENABLE_INTL_API" -a -z "$MO
         ICU_CROSS_BUILD_OPT="--with-cross-build=$ICU_HOST_PATH"
         ICU_TARGET_OPT="--build=$build --host=$target"
     else
         # CROSS_COMPILE isn't set build and target are i386 and x86-64.
         # So we must set target for --build and --host.
         ICU_TARGET_OPT="--build=$target --host=$target"
     fi
 
-    if test "$DISABLE_SHARED_JS" = "1"; then
+    if test -z "$MOZ_SHARED_ICU"; then
         # To reduce library size, use static linking
         ICU_LINK_OPTS="--enable-static --disable-shared"
     else
         ICU_LINK_OPTS="--disable-static --enable-shared"
     fi
     # Force the ICU static libraries to be position independent code
     ICU_CFLAGS="$DSO_PIC_CFLAGS $CFLAGS"
     ICU_CXXFLAGS="$DSO_PIC_CFLAGS $CXXFLAGS"
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -673,23 +673,30 @@ EnclosingStaticScope(BytecodeEmitter *bc
     return bce->sc->asFunctionBox()->function();
 }
 
 // Push a block scope statement and link blockObj into bce->blockChain.
 static bool
 PushBlockScopeBCE(BytecodeEmitter *bce, StmtInfoBCE *stmt, ObjectBox *objbox,
                   ptrdiff_t top)
 {
+    uint32_t parent = UINT32_MAX;
+    if (bce->blockChain) {
+        StmtInfoBCE *stmt = bce->topScopeStmt;
+        for (; stmt->blockObj != bce->blockChain; stmt = stmt->down) {}
+        parent = stmt->blockScopeIndex;
+    }
+
     StaticBlockObject &blockObj = objbox->object->as<StaticBlockObject>();
 
     PushStatementBCE(bce, stmt, STMT_BLOCK, top);
 
     unsigned scopeObjectIndex = bce->objectList.add(objbox);
     stmt->blockScopeIndex = bce->blockScopeList.length();
-    if (!bce->blockScopeList.append(scopeObjectIndex, bce->offset()))
+    if (!bce->blockScopeList.append(scopeObjectIndex, bce->offset(), parent))
         return false;
 
     blockObj.initEnclosingStaticScope(EnclosingStaticScope(bce));
     FinishPushBlockScope(bce, stmt, blockObj);
 
     return true;
 }
 
@@ -809,33 +816,28 @@ EmitUnaliasedVarOp(ExclusiveContext *cx,
     return true;
 }
 
 static bool
 EmitAliasedVarOp(ExclusiveContext *cx, JSOp op, ScopeCoordinate sc, BytecodeEmitter *bce)
 {
     JS_ASSERT(JOF_OPTYPE(op) == JOF_SCOPECOORD);
 
-    uint32_t maybeBlockIndex = UINT32_MAX;
-    if (bce->blockChain)
-        maybeBlockIndex = bce->objectList.indexOf(bce->blockChain);
-
-    unsigned n = 2 * sizeof(uint16_t) + sizeof(uint32_t);
+    unsigned n = 2 * sizeof(uint16_t);
     JS_ASSERT(int(n) + 1 /* op */ == js_CodeSpec[op].length);
 
     ptrdiff_t off = EmitN(cx, bce, op, n);
     if (off < 0)
         return false;
 
     jsbytecode *pc = bce->code(off);
     SET_UINT16(pc, sc.hops);
     pc += sizeof(uint16_t);
     SET_UINT16(pc, sc.slot);
     pc += sizeof(uint16_t);
-    SET_UINT32_INDEX(pc, maybeBlockIndex);
     CheckTypeSet(cx, bce, op);
     return true;
 }
 
 static unsigned
 ClonedBlockDepth(BytecodeEmitter *bce)
 {
     unsigned clonedBlockDepth = 0;
@@ -6874,23 +6876,24 @@ CGTryNoteList::finish(TryNoteArray *arra
 {
     JS_ASSERT(length() == array->length);
 
     for (unsigned i = 0; i < length(); i++)
         array->vector[i] = list[i];
 }
 
 bool
-CGBlockScopeList::append(uint32_t scopeObject, uint32_t offset)
+CGBlockScopeList::append(uint32_t scopeObject, uint32_t offset, uint32_t parent)
 {
     BlockScopeNote note;
     mozilla::PodZero(&note);
 
     note.index = scopeObject;
     note.start = offset;
+    note.parent = parent;
 
     return list.append(note);
 }
 
 void
 CGBlockScopeList::recordEnd(uint32_t index, uint32_t offset)
 {
     JS_ASSERT(index < length());
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -56,17 +56,17 @@ struct CGTryNoteList {
     size_t length() const { return list.length(); }
     void finish(TryNoteArray *array);
 };
 
 struct CGBlockScopeList {
     Vector<BlockScopeNote> list;
     CGBlockScopeList(ExclusiveContext *cx) : list(cx) {}
 
-    bool append(uint32_t scopeObject, uint32_t offset);
+    bool append(uint32_t scopeObject, uint32_t offset, uint32_t parent);
     void recordEnd(uint32_t index, uint32_t offset);
     size_t length() const { return list.length(); }
     void finish(BlockScopeArray *array);
 };
 
 struct StmtInfoBCE;
 
 // Use zero inline elements because these go on the stack and affect how many
--- a/js/src/jit-test/tests/asm.js/testBullet.js
+++ b/js/src/jit-test/tests/asm.js/testBullet.js
@@ -4,15 +4,15 @@
 
 if (!isAsmJSCompilationAvailable())
     quit();
 
 // Note: if you get some failure in this test, it probably has to do with
 // bullet.js and not the nestedShell() call, so try first commenting out
 // nestedShell() (and the loadedFromCache assertion) to see if the error
 // reproduces.
-var code = "setIonAssertGraphCoherency(false); load('" + libdir + "bullet.js'); runBullet()";
+var code = "setIonCheckGraphCoherency(false); load('" + libdir + "bullet.js'); runBullet()";
 nestedShell("--js-cache", "--execute=" + code);
-setIonAssertGraphCoherency(false);
+setIonCheckGraphCoherency(false);
 load(libdir + 'bullet.js');
 var results = runBullet();
 assertEq(results.asmJSValidated, true);
 assertEq(results.loadedFromCache, true);
--- a/js/src/jit-test/tests/asm.js/testZOOB.js
+++ b/js/src/jit-test/tests/asm.js/testZOOB.js
@@ -1,13 +1,13 @@
 load(libdir + "asm.js");
 
 // constants
 var buf = new ArrayBuffer(4096);
-setIonAssertGraphCoherency(false);
+setIonCheckGraphCoherency(false);
 
 // An unshifted literal constant byte index in the range 0 to 2^31-1 inclusive should give a link failure.
 assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + 'var arr=new glob.Int8Array(b);  function f() {return arr[0x7fffffff]|0 } return f'), this, null, buf);
 assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + 'var arr=new glob.Int32Array(b); function f() {return arr[0x1fffffff]|0 } return f'), this, null, buf);
 
 
 // An unshifted literal constant byte index outside the range 0 to 2^31-1 inclusive should cause an error compiling.
 assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + 'var arr=new glob.Int32Array(b); function f() {return arr[0x20000000]|0 } return f');
--- a/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js
+++ b/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js
@@ -1,14 +1,14 @@
 // |jit-test| debug
 setDebug(true);
 x = "notset";
 function main() {
   /* The JSOP_STOP in main. */
-  a = { valueOf: function () { trap(main, 95, "success()"); } };
+  a = { valueOf: function () { trap(main, 91, "success()"); } };
   b = "";
   eval();
   a + b;
   x = "failure";
 }
 function success() { x = "success"; }
 
 main();
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -5502,17 +5502,17 @@ LoadJSContextFromActivation(MacroAssembl
 static void
 AssertStackAlignment(MacroAssembler &masm)
 {
     JS_ASSERT((AlignmentAtPrologue + masm.framePushed()) % StackAlignment == 0);
 #ifdef DEBUG
     Label ok;
     JS_ASSERT(IsPowerOfTwo(StackAlignment));
     masm.branchTestPtr(Assembler::Zero, StackPointer, Imm32(StackAlignment - 1), &ok);
-    masm.breakpoint();
+    masm.assume_unreachable("Stack should be aligned.");
     masm.bind(&ok);
 #endif
 }
 
 template <class VectorT>
 static unsigned
 StackArgBytes(const VectorT &argTypes)
 {
@@ -5957,17 +5957,16 @@ GenerateOOLConvert(ModuleCompiler &m, Re
                             MIRType_Pointer }; // argv
     MIRTypeVector callArgTypes(m.cx());
     callArgTypes.infallibleAppend(typeArray, ArrayLength(typeArray));
 
     // Reserve space for a call to InvokeFromAsmJS_* and an array of values
     // passed to this FFI call.
     unsigned arraySize = sizeof(Value);
     unsigned stackDec = StackDecrementForCall(masm, callArgTypes, arraySize);
-    masm.setFramePushed(0);
     masm.reserveStack(stackDec);
 
     // Store value
     unsigned offsetToArgv = StackArgBytes(callArgTypes);
     masm.storeValue(JSReturnOperand, Address(StackPointer, offsetToArgv));
 
     // Store real arguments
     ABIArgMIRTypeIter i(callArgTypes);
@@ -5991,16 +5990,17 @@ GenerateOOLConvert(ModuleCompiler &m, Re
     } else {
         masm.computeEffectiveAddress(argv, scratch);
         masm.storePtr(scratch, Address(StackPointer, i->offsetFromArgBase()));
     }
     i++;
     JS_ASSERT(i.done());
 
     // Call
+    AssertStackAlignment(masm);
     switch (retType.which()) {
       case RetType::Signed:
           masm.call(AsmJSImm_CoerceInPlace_ToInt32);
           masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
           masm.unboxInt32(Address(StackPointer, offsetToArgv), ReturnReg);
           break;
       case RetType::Double:
           masm.call(AsmJSImm_CoerceInPlace_ToNumber);
@@ -6133,16 +6133,17 @@ GenerateFFIIonExit(ModuleCompiler &m, co
 
 #ifdef DEBUG
     masm.branchTestMagicValue(Assembler::Equal, JSReturnOperand, JS_ION_ERROR, throwLabel);
     masm.branchTestMagic(Assembler::Equal, JSReturnOperand, &ionFailed);
 #else
     masm.branchTestMagic(Assembler::Equal, JSReturnOperand, throwLabel);
 #endif
 
+    uint32_t oolConvertFramePushed = masm.framePushed();
     switch (exit.sig().retType().which()) {
       case RetType::Void:
         break;
       case RetType::Signed:
         masm.convertValueToInt32(JSReturnOperand, ReturnFloatReg, ReturnReg, &oolConvert,
                                  /* -0 check */ false);
         break;
       case RetType::Double:
@@ -6155,23 +6156,25 @@ GenerateFFIIonExit(ModuleCompiler &m, co
 
     masm.bind(&done);
     masm.PopRegsInMask(restoreSet);
     masm.ret();
 
     // oolConvert
     if (oolConvert.used()) {
         masm.bind(&oolConvert);
+        masm.setFramePushed(oolConvertFramePushed);
         GenerateOOLConvert(m, exit.sig().retType(), throwLabel);
+        masm.setFramePushed(0);
         masm.jump(&done);
     }
 
 #ifdef DEBUG
     masm.bind(&ionFailed);
-    masm.breakpoint();
+    masm.assume_unreachable("AsmJS to IonMonkey call failed.");
 #endif
 }
 
 // See "asm.js FFI calls" comment above.
 static void
 GenerateFFIExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit, unsigned exitIndex,
                 Label *throwLabel)
 {
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -2360,16 +2360,20 @@ bool
 BaselineCompiler::emit_JSOP_CALLARG()
 {
     return emit_JSOP_GETARG();
 }
 
 bool
 BaselineCompiler::emit_JSOP_SETARG()
 {
+    // Ionmonkey can't inline functions with SETARG with magic arguments.
+    if (!script->argsObjAliasesFormals() && script->argumentsAliasesFormals())
+        script->uninlineable = true;
+
     modifiesArguments_ = true;
 
     uint32_t arg = GET_SLOTNO(pc);
     return emitFormalArgAccess(arg, /* get = */ false);
 }
 
 bool
 BaselineCompiler::emitCall()
@@ -2499,16 +2503,18 @@ BaselineCompiler::emit_JSOP_THROW()
     pushArg(R0);
 
     return callVM(ThrowInfo);
 }
 
 bool
 BaselineCompiler::emit_JSOP_TRY()
 {
+    // Ionmonkey can't inline function with JSOP_TRY.
+    script->uninlineable = true;
     return true;
 }
 
 bool
 BaselineCompiler::emit_JSOP_FINALLY()
 {
     // JSOP_FINALLY has a def count of 2, but these values are already on the
     // stack (they're pushed by JSOP_GOSUB). Update the compiler's stack state.
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -1090,17 +1090,17 @@ ICProfiler_PushFunction::Compiler::gener
     Register scratch = R0.scratchReg();
     Register scratch2 = R1.scratchReg();
 
     // Profiling should be enabled if we ever reach here.
 #ifdef DEBUG
     Label spsEnabled;
     uint32_t *enabledAddr = cx->runtime()->spsProfiler.addressOfEnabled();
     masm.branch32(Assembler::NotEqual, AbsoluteAddress(enabledAddr), Imm32(0), &spsEnabled);
-    masm.breakpoint();
+    masm.assume_unreachable("Profiling should have been enabled.");
     masm.bind(&spsEnabled);
 #endif
 
     // Push SPS entry.
     masm.spsPushFrame(&cx->runtime()->spsProfiler,
                       Address(BaselineStubReg, ICProfiler_PushFunction::offsetOfStr()),
                       Address(BaselineStubReg, ICProfiler_PushFunction::offsetOfScript()),
                       scratch,
@@ -5128,17 +5128,17 @@ ICSetElem_Dense::Compiler::generateStubC
     masm.branchTest32(Assembler::Zero, elementsFlags,
                       Imm32(ObjectElements::CONVERT_DOUBLE_ELEMENTS),
                       &dontConvertDoubles);
     // Note that double arrays are only created by IonMonkey, so if we have no
     // floating-point support Ion is disabled and there should be no double arrays.
     if (cx->runtime()->jitSupportsFloatingPoint)
         masm.convertInt32ValueToDouble(valueAddr, regs.getAny(), &dontConvertDoubles);
     else
-        masm.breakpoint();
+        masm.assume_unreachable("There shouldn't be double arrays when there is no FP support.");
     masm.bind(&dontConvertDoubles);
 
     // Don't overwrite R0 becuase |obj| might overlap with it, and it's needed
     // for post-write barrier later.
     ValueOperand tmpVal = regs.takeAnyValue();
     masm.loadValue(valueAddr, tmpVal);
     EmitPreBarrier(masm, element, MIRType_Value);
     masm.storeValue(tmpVal, element);
@@ -5316,17 +5316,17 @@ ICSetElemDenseAddCompiler::generateStubC
     masm.branchTest32(Assembler::Zero, elementsFlags,
                       Imm32(ObjectElements::CONVERT_DOUBLE_ELEMENTS),
                       &dontConvertDoubles);
     // Note that double arrays are only created by IonMonkey, so if we have no
     // floating-point support Ion is disabled and there should be no double arrays.
     if (cx->runtime()->jitSupportsFloatingPoint)
         masm.convertInt32ValueToDouble(valueAddr, regs.getAny(), &dontConvertDoubles);
     else
-        masm.breakpoint();
+        masm.assume_unreachable("There shouldn't be double arrays when there is no FP support.");
     masm.bind(&dontConvertDoubles);
 
     // Write the value.  No need for pre-barrier since we're not overwriting an old value.
     ValueOperand tmpVal = regs.takeAnyValue();
     BaseIndex element(scratchReg, key, TimesEight);
     masm.loadValue(valueAddr, tmpVal);
     masm.storeValue(tmpVal, element);
     regs.add(key);
@@ -8279,17 +8279,17 @@ ICCall_Fallback::Compiler::generateStubC
     Label skipThisReplace;
     masm.load16ZeroExtend(Address(BaselineStubReg, ICStub::offsetOfExtra()), scratch);
     masm.branchTest32(Assembler::Zero, scratch, Imm32(ICCall_Fallback::CONSTRUCTING_FLAG),
                       &skipThisReplace);
     masm.branchTestObject(Assembler::Equal, JSReturnOperand, &skipThisReplace);
     masm.moveValue(R1, R0);
 #ifdef DEBUG
     masm.branchTestObject(Assembler::Equal, JSReturnOperand, &skipThisReplace);
-    masm.breakpoint();
+    masm.assume_unreachable("Failed to return object in constructing call.");
 #endif
     masm.bind(&skipThisReplace);
 
     // At this point, BaselineStubReg points to the ICCall_Fallback stub, which is NOT
     // a MonitoredStub, but rather a MonitoredFallbackStub.  To use EmitEnterTypeMonitorIC,
     // first load the ICTypeMonitor_Fallback stub into BaselineStubReg.  Then, use
     // EmitEnterTypeMonitorIC with a custom struct offset.
     masm.loadPtr(Address(BaselineStubReg, ICMonitoredFallbackStub::offsetOfFallbackMonitorStub()),
@@ -8388,17 +8388,17 @@ ICCallScriptedCompiler::generateStubCode
         masm.push(masm.extractObject(R1, ExtractTemp0));
         if (!callVM(CreateThisInfoBaseline, masm))
             return false;
 
         // Return of CreateThis must be an object.
 #ifdef DEBUG
         Label createdThisIsObject;
         masm.branchTestObject(Assembler::Equal, JSReturnOperand, &createdThisIsObject);
-        masm.breakpoint();
+        masm.assume_unreachable("The return of CreateThis must be an object.");
         masm.bind(&createdThisIsObject);
 #endif
 
         // Reset the register set from here on in.
         JS_ASSERT(JSReturnOperand == R0);
         regs = availableGeneralRegs(0);
         regs.take(R0);
         regs.take(ArgumentsRectifierReg);
@@ -8529,17 +8529,17 @@ ICCallScriptedCompiler::generateStubCode
         // STUB_FRAME_SIZE + sizeof(ThisVal) + sizeof(size_t) + sizeof(void *) + sizoef(size_t)
         // for: stub frame, this value, actual argc, callee, and descriptor
         masm.lshiftPtr(Imm32(1), scratchReg);
         BaseIndex reloadThisSlot(BaselineStackReg, scratchReg, TimesEight,
                                  STUB_FRAME_SIZE + sizeof(Value) + 3*sizeof(size_t));
         masm.loadValue(reloadThisSlot, JSReturnOperand);
 #ifdef DEBUG
         masm.branchTestObject(Assembler::Equal, JSReturnOperand, &skipThisReplace);
-        masm.breakpoint();
+        masm.assume_unreachable("Return of constructing call should be an object.");
 #endif
         masm.bind(&skipThisReplace);
     }
 
     leaveStubFrame(masm, true);
 
     // Enter type monitor IC to type-check result.
     EmitEnterTypeMonitorIC(masm);
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -2493,17 +2493,17 @@ CodeGenerator::generateArgumentsChecks(b
     if (miss.used()) {
         if (bailout) {
             if (!bailoutFrom(&miss, graph.entrySnapshot()))
                 return false;
         } else {
             Label success;
             masm.jump(&success);
             masm.bind(&miss);
-            masm.breakpoint();
+            masm.assume_unreachable("Argument check fail.");
             masm.bind(&success);
         }
     }
 
     masm.freeStack(frameSize());
 
     return true;
 }
@@ -3667,17 +3667,17 @@ CodeGenerator::visitGetArgumentsObjectAr
     ValueOperand out = ToOutValue(lir);
 
     masm.loadPrivate(Address(argsObj, ArgumentsObject::getDataSlotOffset()), temp);
     Address argAddr(temp, ArgumentsData::offsetOfArgs() + lir->mir()->argno() * sizeof(Value));
     masm.loadValue(argAddr, out);
 #ifdef DEBUG
     Label success;
     masm.branchTestMagic(Assembler::NotEqual, out, &success);
-    masm.breakpoint();
+    masm.assume_unreachable("Result from ArgumentObject shouldn't be MIRType_Magic.");
     masm.bind(&success);
 #endif
     return true;
 }
 
 bool
 CodeGenerator::visitSetArgumentsObjectArg(LSetArgumentsObjectArg *lir)
 {
@@ -3686,17 +3686,17 @@ CodeGenerator::visitSetArgumentsObjectAr
     ValueOperand value = ToValue(lir, LSetArgumentsObjectArg::ValueIndex);
 
     masm.loadPrivate(Address(argsObj, ArgumentsObject::getDataSlotOffset()), temp);
     Address argAddr(temp, ArgumentsData::offsetOfArgs() + lir->mir()->argno() * sizeof(Value));
     emitPreBarrier(argAddr, MIRType_Value);
 #ifdef DEBUG
     Label success;
     masm.branchTestMagic(Assembler::NotEqual, argAddr, &success);
-    masm.breakpoint();
+    masm.assume_unreachable("Result in ArgumentObject shouldn't be MIRType_Magic.");
     masm.bind(&success);
 #endif
     masm.storeValue(value, argAddr);
     return true;
 }
 
 bool
 CodeGenerator::visitReturnFromCtor(LReturnFromCtor *lir)
@@ -4515,17 +4515,17 @@ static void
 CopyStringChars(MacroAssembler &masm, Register to, Register from, Register len, Register scratch)
 {
     // Copy |len| jschars from |from| to |to|. Assumes len > 0 (checked below in
     // debug builds), and when done |to| must point to the next available char.
 
 #ifdef DEBUG
     Label ok;
     masm.branch32(Assembler::GreaterThan, len, Imm32(0), &ok);
-    masm.breakpoint();
+    masm.assume_unreachable("Length should be greater than 0.");
     masm.bind(&ok);
 #endif
 
     JS_STATIC_ASSERT(sizeof(jschar) == 2);
 
     Label start;
     masm.bind(&start);
     masm.load16ZeroExtend(Address(from, 0), scratch);
@@ -5913,16 +5913,30 @@ CodeGenerator::link(JSContext *cx, types
 
     ionScript->setMethod(code);
     ionScript->setSkipArgCheckEntryOffset(getSkipArgCheckEntryOffset());
 
     // If SPS is enabled, mark IonScript as having been instrumented with SPS
     if (sps_.enabled())
         ionScript->setHasSPSInstrumentation();
 
+    // We finished the new IonScript. Invalidate the current active IonScript,
+    // so we can replace it with this new (probably higher optimized) version.
+    if (HasIonScript(script, executionMode)) {
+        JS_ASSERT(GetIonScript(script, executionMode)->isRecompiling());
+        // Do a normal invalidate, except don't cancel offThread compilations,
+        // since that will cancel this compilation too.
+        if (!Invalidate(cx, script, SequentialExecution,
+                        /* resetUses */ false, /* cancelOffThread*/ false))
+        {
+            js_free(ionScript);
+            return false;
+        }
+    }
+
     SetIonScript(script, executionMode, ionScript);
 
     // In parallel execution mode, when we first compile a script, we
     // don't know that its potential callees are compiled, so set a
     // flag warning that the callees may not be fully compiled.
     if (callTargets.length() != 0)
         ionScript->setHasUncompiledCallTarget();
 
@@ -7683,17 +7697,17 @@ CodeGenerator::visitAsmJSCall(LAsmJSCall
         masm.freeStack(mir->spIncrement());
 
    JS_ASSERT((AlignmentAtPrologue +  masm.framePushed()) % StackAlignment == 0);
 
 #ifdef DEBUG
     Label ok;
     JS_ASSERT(IsPowerOfTwo(StackAlignment));
     masm.branchTestPtr(Assembler::Zero, StackPointer, Imm32(StackAlignment - 1), &ok);
-    masm.breakpoint();
+    masm.assume_unreachable("Stack should be aligned.");
     masm.bind(&ok);
 #endif
 
     MAsmJSCall::Callee callee = mir->callee();
     switch (callee.which()) {
       case MAsmJSCall::Callee::Internal:
         masm.call(callee.internal());
         break;
@@ -7762,25 +7776,25 @@ CodeGenerator::visitAsmJSCheckOverRecurs
 
 bool
 CodeGenerator::emitAssertRangeI(const Range *r, Register input)
 {
     // Check the lower bound.
     if (r->hasInt32LowerBound() && r->lower() > INT32_MIN) {
         Label success;
         masm.branch32(Assembler::GreaterThanOrEqual, input, Imm32(r->lower()), &success);
-        masm.breakpoint();
+        masm.assume_unreachable("Integer input should be equal or higher than Lowerbound.");
         masm.bind(&success);
     }
 
     // Check the upper bound.
     if (r->hasInt32UpperBound() && r->upper() < INT32_MAX) {
         Label success;
         masm.branch32(Assembler::LessThanOrEqual, input, Imm32(r->upper()), &success);
-        masm.breakpoint();
+        masm.assume_unreachable("Integer input should be lower or equal than Upperbound.");
         masm.bind(&success);
     }
 
     // For r->canHaveFractionalPart() and r->exponent(), there's nothing to check, because
     // if we ended up in the integer range checking code, the value is already
     // in an integer register in the integer range.
 
     return true;
@@ -7791,67 +7805,67 @@ CodeGenerator::emitAssertRangeD(const Ra
 {
     // Check the lower bound.
     if (r->hasInt32LowerBound()) {
         Label success;
         masm.loadConstantDouble(r->lower(), temp);
         if (r->canBeNaN())
             masm.branchDouble(Assembler::DoubleUnordered, input, input, &success);
         masm.branchDouble(Assembler::DoubleGreaterThanOrEqual, input, temp, &success);
-        masm.breakpoint();
+        masm.assume_unreachable("Double input should be equal or higher than Lowerbound.");
         masm.bind(&success);
     }
     // Check the upper bound.
     if (r->hasInt32UpperBound()) {
         Label success;
         masm.loadConstantDouble(r->upper(), temp);
         if (r->canBeNaN())
             masm.branchDouble(Assembler::DoubleUnordered, input, input, &success);
         masm.branchDouble(Assembler::DoubleLessThanOrEqual, input, temp, &success);
-        masm.breakpoint();
+        masm.assume_unreachable("Double input should be lower or equal than Upperbound.");
         masm.bind(&success);
     }
 
     // This code does not yet check r->canHaveFractionalPart(). This would require new
     // assembler interfaces to make rounding instructions available.
 
     if (!r->hasInt32Bounds() && !r->canBeInfiniteOrNaN() && r->exponent() < DoubleExponentBias) {
         // Check the bounds implied by the maximum exponent.
         Label exponentLoOk;
         masm.loadConstantDouble(pow(2.0, r->exponent() + 1), temp);
         masm.branchDouble(Assembler::DoubleUnordered, input, input, &exponentLoOk);
         masm.branchDouble(Assembler::DoubleLessThanOrEqual, input, temp, &exponentLoOk);
-        masm.breakpoint();
+        masm.assume_unreachable("Check for exponent failed.");
         masm.bind(&exponentLoOk);
 
         Label exponentHiOk;
         masm.loadConstantDouble(-pow(2.0, r->exponent() + 1), temp);
         masm.branchDouble(Assembler::DoubleUnordered, input, input, &exponentHiOk);
         masm.branchDouble(Assembler::DoubleGreaterThanOrEqual, input, temp, &exponentHiOk);
-        masm.breakpoint();
+        masm.assume_unreachable("Check for exponent failed.");
         masm.bind(&exponentHiOk);
     } else if (!r->hasInt32Bounds() && !r->canBeNaN()) {
         // If we think the value can't be NaN, check that it isn't.
         Label notnan;
         masm.branchDouble(Assembler::DoubleOrdered, input, input, &notnan);
-        masm.breakpoint();
+        masm.assume_unreachable("Input shouldn't be NaN.");
         masm.bind(&notnan);
 
         // If we think the value also can't be an infinity, check that it isn't.
         if (!r->canBeInfiniteOrNaN()) {
             Label notposinf;
             masm.loadConstantDouble(PositiveInfinity(), temp);
             masm.branchDouble(Assembler::DoubleLessThan, input, temp, &notposinf);
-            masm.breakpoint();
+            masm.assume_unreachable("Input shouldn't be +Inf.");
             masm.bind(&notposinf);
 
             Label notneginf;
             masm.loadConstantDouble(NegativeInfinity(), temp);
             masm.branchDouble(Assembler::DoubleGreaterThan, input, temp, &notneginf);
-            masm.breakpoint();
+            masm.assume_unreachable("Input shouldn't be -Inf.");
             masm.bind(&notneginf);
         }
     }
 
     return true;
 }
 
 bool
@@ -7910,15 +7924,15 @@ CodeGenerator::visitAssertRangeV(LAssert
         FloatRegister input = ToFloatRegister(ins->floatTemp1());
         FloatRegister temp = ToFloatRegister(ins->floatTemp2());
         masm.unboxDouble(value, input);
         emitAssertRangeD(r, input, temp);
         masm.jump(&done);
         masm.bind(&isNotDouble);
     }
 
-    masm.breakpoint();
+    masm.assume_unreachable("Incorrect range for Value.");
     masm.bind(&done);
     return true;
 }
 
 } // namespace jit
 } // namespace js
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -513,16 +513,20 @@ JitCompartment::ensureIonStubsExist(JSCo
     return true;
 }
 
 void
 jit::FinishOffThreadBuilder(IonBuilder *builder)
 {
     ExecutionMode executionMode = builder->info().executionMode();
 
+    // Clear the recompiling flag if it would have failed.
+    if (builder->script()->hasIonScript())
+        builder->script()->ionScript()->clearRecompiling();
+
     // Clean up if compilation did not succeed.
     if (CompilingOffThread(builder->script(), executionMode))
         SetIonScript(builder->script(), executionMode, nullptr);
 
     // The builder is allocated into its LifoAlloc, so destroying that will
     // destroy the builder and all other data accumulated during compilation,
     // except any final codegen (which includes an assembler and needs to be
     // explicitly destroyed).
@@ -717,16 +721,17 @@ IonScript::IonScript()
     osrPc_(nullptr),
     osrEntryOffset_(0),
     skipArgCheckEntryOffset_(0),
     invalidateEpilogueOffset_(0),
     invalidateEpilogueDataOffset_(0),
     numBailouts_(0),
     hasUncompiledCallTarget_(false),
     hasSPSInstrumentation_(false),
+    recompiling_(false),
     runtimeData_(0),
     runtimeSize_(0),
     cacheIndex_(0),
     cacheEntries_(0),
     safepointIndexOffset_(0),
     safepointIndexEntries_(0),
     safepointsStart_(0),
     safepointsSize_(0),
@@ -1595,25 +1600,24 @@ TrackPropertiesForSingletonScopes(JSCont
         if (scope->is<CallObject>() && scope->hasSingletonType())
             TrackAllProperties(cx, scope);
     }
 }
 
 static AbortReason
 IonCompile(JSContext *cx, JSScript *script,
            BaselineFrame *baselineFrame, jsbytecode *osrPc, bool constructing,
-           ExecutionMode executionMode)
+           ExecutionMode executionMode, bool recompile)
 {
 #if JS_TRACE_LOGGING
     AutoTraceLog logger(TraceLogging::defaultLogger(),
                         TraceLogging::ION_COMPILE_START,
                         TraceLogging::ION_COMPILE_STOP,
                         script);
 #endif
-
     TrackPropertiesForSingletonScopes(cx, script, baselineFrame);
 
     LifoAlloc *alloc = cx->new_<LifoAlloc>(BUILDER_LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
     if (!alloc)
         return AbortReason_Alloc;
 
     ScopedJSDeletePtr<LifoAlloc> autoDelete(alloc);
 
@@ -1658,17 +1662,17 @@ IonCompile(JSContext *cx, JSScript *scri
 
     IonBuilder *builder = alloc->new_<IonBuilder>((JSContext *) nullptr,
                                                   CompileCompartment::get(cx->compartment()),
                                                   temp, graph, constraints,
                                                   &inspector, info, baselineFrameInspector);
     if (!builder)
         return AbortReason_Alloc;
 
-    JS_ASSERT(!GetIonScript(builder->script(), executionMode));
+    JS_ASSERT(recompile == HasIonScript(builder->script(), executionMode));
     JS_ASSERT(CanIonCompile(builder->script(), executionMode));
 
     RootedScript builderScript(cx, builder->script());
     IonSpewNewFunction(graph, builderScript);
 
     mozilla::Maybe<AutoProtectHeapForCompilation> protect;
     if (js_IonOptions.checkThreadSafety &&
         cx->runtime()->gcIncrementalState == gc::NO_INCREMENTAL &&
@@ -1688,17 +1692,22 @@ IonCompile(JSContext *cx, JSScript *scri
         }
 
         IonSpew(IonSpew_Abort, "Builder failed to build.");
         return builder->abortReason();
     }
 
     // If possible, compile the script off thread.
     if (OffThreadCompilationAvailable(cx)) {
-        SetIonScript(builder->script(), executionMode, ION_COMPILING_SCRIPT);
+        if (recompile) {
+            JS_ASSERT(executionMode == SequentialExecution);
+            builderScript->ionScript()->setRecompiling();
+        } else {
+            SetIonScript(builder->script(), executionMode, ION_COMPILING_SCRIPT);
+        }
 
         if (!StartOffThreadIonCompile(cx, builder)) {
             IonSpew(IonSpew_Abort, "Unable to start off-thread ion compilation.");
             return AbortReason_Alloc;
         }
 
         // The allocator and associated data will be destroyed after being
         // processed in the finishedOffThreadCompilations list.
@@ -1857,31 +1866,34 @@ Compile(JSContext *cx, HandleScript scri
     }
 
     MethodStatus status = CheckScriptSize(cx, script);
     if (status != Method_Compiled) {
         IonSpew(IonSpew_Abort, "Aborted compilation of %s:%d", script->filename(), script->lineno);
         return status;
     }
 
+    bool recompile = false;
+
     IonScript *scriptIon = GetIonScript(script, executionMode);
     if (scriptIon) {
         if (!scriptIon->method())
             return Method_CantCompile;
         return Method_Compiled;
     }
 
     if (executionMode == SequentialExecution) {
         // Use getUseCount instead of incUseCount to avoid bumping the
         // use count twice.
         if (script->getUseCount() < UsesBeforeIonRecompile(script, osrPc ? osrPc : script->code()))
             return Method_Skipped;
     }
 
-    AbortReason reason = IonCompile(cx, script, osrFrame, osrPc, constructing, executionMode);
+    AbortReason reason = IonCompile(cx, script, osrFrame, osrPc, constructing, executionMode,
+                                    recompile);
     if (reason == AbortReason_Error)
         return Method_Error;
 
     if (reason == AbortReason_Disable)
         return Method_CantCompile;
 
     if (reason == AbortReason_Alloc) {
         js_ReportOutOfMemory(cx);
@@ -2053,16 +2065,35 @@ jit::CompileFunctionForBaseline(JSContex
             ForbidCompilation(cx, script);
         return status;
     }
 
     return Method_Compiled;
 }
 
 MethodStatus
+jit::Recompile(JSContext *cx, HandleScript script, BaselineFrame *osrFrame, jsbytecode *osrPc,
+               bool constructing)
+{
+    JS_ASSERT(script->hasIonScript());
+    if (script->ionScript()->isRecompiling())
+        return Method_Compiled;
+
+    MethodStatus status =
+        Compile(cx, script, osrFrame, osrPc, constructing, SequentialExecution);
+    if (status != Method_Compiled) {
+        if (status == Method_CantCompile)
+            ForbidCompilation(cx, script);
+        return status;
+    }
+
+    return Method_Compiled;
+}
+
+MethodStatus
 jit::CanEnterInParallel(JSContext *cx, HandleScript script)
 {
     // Skip if the script has been disabled.
     //
     // Note: We return Method_Skipped in this case because the other
     // CanEnter() methods do so. However, ForkJoin.cpp detects this
     // condition differently treats it more like an error.
     if (!script->canParallelIonCompile())
@@ -2423,30 +2454,32 @@ jit::InvalidateAll(FreeOp *fop, Zone *zo
             InvalidateActivation(fop, iter.jitTop(), true);
         }
     }
 }
 
 
 void
 jit::Invalidate(types::TypeCompartment &types, FreeOp *fop,
-                const Vector<types::RecompileInfo> &invalid, bool resetUses)
+                const Vector<types::RecompileInfo> &invalid, bool resetUses,
+                bool cancelOffThread)
 {
     IonSpew(IonSpew_Invalidate, "Start invalidation.");
     AutoFlushCache afc ("Invalidate", fop->runtime()->jitRuntime());
 
     // Add an invalidation reference to all invalidated IonScripts to indicate
     // to the traversal which frames have been invalidated.
     size_t numInvalidations = 0;
     for (size_t i = 0; i < invalid.length(); i++) {
         const types::CompilerOutput &co = *invalid[i].compilerOutput(types);
         if (!co.isValid())
             continue;
 
-        CancelOffThreadIonCompile(co.script()->compartment(), co.script());
+        if (cancelOffThread)
+            CancelOffThreadIonCompile(co.script()->compartment(), co.script());
 
         if (!co.ion())
             continue;
 
         IonSpew(IonSpew_Invalidate, " Invalidate %s:%u, IonScript %p",
                 co.script()->filename(), co.script()->lineno, co.ion());
 
         // Keep the ion script alive during the invalidation and flag this
@@ -2500,23 +2533,26 @@ jit::Invalidate(types::TypeCompartment &
     }
 
     // Make sure we didn't leak references by invalidating the same IonScript
     // multiple times in the above loop.
     JS_ASSERT(!numInvalidations);
 }
 
 void
-jit::Invalidate(JSContext *cx, const Vector<types::RecompileInfo> &invalid, bool resetUses)
+jit::Invalidate(JSContext *cx, const Vector<types::RecompileInfo> &invalid, bool resetUses,
+                bool cancelOffThread)
 {
-    jit::Invalidate(cx->compartment()->types, cx->runtime()->defaultFreeOp(), invalid, resetUses);
+    jit::Invalidate(cx->compartment()->types, cx->runtime()->defaultFreeOp(), invalid, resetUses,
+                    cancelOffThread);
 }
 
 bool
-jit::Invalidate(JSContext *cx, JSScript *script, ExecutionMode mode, bool resetUses)
+jit::Invalidate(JSContext *cx, JSScript *script, ExecutionMode mode, bool resetUses,
+                bool cancelOffThread)
 {
     JS_ASSERT(script->hasIonScript());
 
     Vector<types::RecompileInfo> scripts(cx);
 
     switch (mode) {
       case SequentialExecution:
         JS_ASSERT(script->hasIonScript());
@@ -2527,24 +2563,24 @@ jit::Invalidate(JSContext *cx, JSScript 
         JS_ASSERT(script->hasParallelIonScript());
         if (!scripts.append(script->parallelIonScript()->recompileInfo()))
             return false;
         break;
       default:
         MOZ_ASSUME_UNREACHABLE("No such execution mode");
     }
 
-    Invalidate(cx, scripts, resetUses);
+    Invalidate(cx, scripts, resetUses, cancelOffThread);
     return true;
 }
 
 bool
-jit::Invalidate(JSContext *cx, JSScript *script, bool resetUses)
+jit::Invalidate(JSContext *cx, JSScript *script, bool resetUses, bool cancelOffThread)
 {
-    return Invalidate(cx, script, SequentialExecution, resetUses);
+    return Invalidate(cx, script, SequentialExecution, resetUses, cancelOffThread);
 }
 
 static void
 FinishInvalidationOf(FreeOp *fop, JSScript *script, IonScript *ionScript, bool parallel)
 {
     // In all cases, nullptr out script->ion or script->parallelIon to avoid
     // re-entry.
     if (parallel)
--- a/js/src/jit/Ion.h
+++ b/js/src/jit/Ion.h
@@ -89,17 +89,17 @@ struct IonOptions
     // Default: false
     bool checkThreadSafety;
 
     // Whether to perform expensive graph-consistency DEBUG-only assertions.
     // It can be useful to disable this to reduce DEBUG-compile time of large
     // asm.js programs.
     //
     // Default: true
-    bool assertGraphConsistency;
+    bool checkGraphConsistency;
 
     // Toggles whether Unreachable Code Elimination is performed.
     //
     // Default: true
     bool uce;
 
     // Toggles whether Effective Address Analysis is performed.
     //
@@ -223,17 +223,17 @@ struct IonOptions
         osr(true),
         limitScriptSize(true),
         registerAllocator(RegisterAllocator_LSRA),
         inlining(true),
         edgeCaseAnalysis(true),
         rangeAnalysis(true),
         checkRangeAnalysis(false),
         checkThreadSafety(false),
-        assertGraphConsistency(true),
+        checkGraphConsistency(true),
         uce(true),
         eaa(true),
 #ifdef CHECK_OSIPOINT_REGISTERS
         checkOsiPointRegisters(false),
 #endif
         baselineUsesBeforeCompile(10),
         usesBeforeCompile(1000),
         usesBeforeInliningFactor(.125),
@@ -325,16 +325,20 @@ MethodStatus CanEnterAtBranch(JSContext 
                               BaselineFrame *frame, jsbytecode *pc, bool isConstructing);
 MethodStatus CanEnter(JSContext *cx, RunState &state);
 MethodStatus CompileFunctionForBaseline(JSContext *cx, HandleScript script, BaselineFrame *frame,
                                         bool isConstructing);
 MethodStatus CanEnterUsingFastInvoke(JSContext *cx, HandleScript script, uint32_t numActualArgs);
 
 MethodStatus CanEnterInParallel(JSContext *cx, HandleScript script);
 
+MethodStatus
+Recompile(JSContext *cx, HandleScript script, BaselineFrame *osrFrame, jsbytecode *osrPc,
+          bool constructing);
+
 enum IonExecStatus
 {
     // The method call had to be aborted due to a stack limit check. This
     // error indicates that Ion never attempted to clean up frames.
     IonExec_Aborted,
 
     // The method call resulted in an error, and IonMonkey has cleaned up
     // frames.
@@ -356,20 +360,24 @@ bool SetEnterJitData(JSContext *cx, Ente
 
 IonExecStatus IonCannon(JSContext *cx, RunState &state);
 
 // Used to enter Ion from C++ natives like Array.map. Called from FastInvokeGuard.
 IonExecStatus FastInvoke(JSContext *cx, HandleFunction fun, CallArgs &args);
 
 // Walk the stack and invalidate active Ion frames for the invalid scripts.
 void Invalidate(types::TypeCompartment &types, FreeOp *fop,
-                const Vector<types::RecompileInfo> &invalid, bool resetUses = true);
-void Invalidate(JSContext *cx, const Vector<types::RecompileInfo> &invalid, bool resetUses = true);
-bool Invalidate(JSContext *cx, JSScript *script, ExecutionMode mode, bool resetUses = true);
-bool Invalidate(JSContext *cx, JSScript *script, bool resetUses = true);
+                const Vector<types::RecompileInfo> &invalid, bool resetUses = true,
+                bool cancelOffThread = true);
+void Invalidate(JSContext *cx, const Vector<types::RecompileInfo> &invalid, bool resetUses = true,
+                bool cancelOffThread = true);
+bool Invalidate(JSContext *cx, JSScript *script, ExecutionMode mode, bool resetUses = true,
+                bool cancelOffThread = true);
+bool Invalidate(JSContext *cx, JSScript *script, bool resetUses = true,
+                bool cancelOffThread = true);
 
 void MarkValueFromIon(JSRuntime *rt, Value *vp);
 void MarkShapeFromIon(JSRuntime *rt, Shape **shapep);
 
 void ToggleBarriers(JS::Zone *zone, bool needs);
 
 class IonBuilder;
 class MIRGenerator;
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -1283,32 +1283,32 @@ AssertReversePostOrder(MIRGraph &graph)
     graph.unmarkBlocks();
 }
 #endif
 
 void
 jit::AssertGraphCoherency(MIRGraph &graph)
 {
 #ifdef DEBUG
-    if (!js_IonOptions.assertGraphConsistency)
+    if (!js_IonOptions.checkGraphConsistency)
         return;
     AssertBasicGraphCoherency(graph);
     AssertReversePostOrder(graph);
 #endif
 }
 
 void
 jit::AssertExtendedGraphCoherency(MIRGraph &graph)
 {
     // Checks the basic GraphCoherency but also other conditions that
     // do not hold immediately (such as the fact that critical edges
     // are split)
 
 #ifdef DEBUG
-    if (!js_IonOptions.assertGraphConsistency)
+    if (!js_IonOptions.checkGraphConsistency)
         return;
     AssertGraphCoherency(graph);
 
     uint32_t idx = 0;
     for (MBasicBlockIterator block(graph.begin()); block != graph.end(); block++) {
         JS_ASSERT(block->id() == idx++);
 
         // No critical edges:
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -3430,18 +3430,17 @@ IonBuilder::jsop_try()
     if (!js_IonOptions.compileTryCatch)
         return abort("Try-catch support disabled");
 
     // Try-finally is not yet supported.
     if (analysis().hasTryFinally())
         return abort("Has try-finally");
 
     // Try-catch within inline frames is not yet supported.
-    if (isInlineBuilder())
-        return abort("try-catch within inline frame");
+    JS_ASSERT(script()->uninlineable && !isInlineBuilder());
 
     graph().setHasTryBlock();
 
     jssrcnote *sn = info().getNote(gsn, pc);
     JS_ASSERT(SN_TYPE(sn) == SRC_TRY);
 
     // Get the pc of the last instruction in the try block. It's a JSOP_GOTO to
     // jump over the catch block.
@@ -9145,19 +9144,18 @@ IonBuilder::jsop_setarg(uint32_t arg)
     }
 
     // Otherwise, if a magic arguments is in use, and it aliases formals, and there exist
     // arguments[...] GETELEM expressions in the script, then SetFrameArgument must be used.
     // If no arguments[...] GETELEM expressions are in the script, and an argsobj is not
     // required, then it means that any aliased argument set can never be observed, and
     // the frame does not actually need to be updated with the new arg value.
     if (info().argumentsAliasesFormals()) {
-        // Try-catch within inline frames is not yet supported.
-        if (isInlineBuilder())
-            return abort("JSOP_SETARG with magic arguments in inlined function.");
+        // JSOP_SETARG with magic arguments within inline frames is not yet supported.
+        JS_ASSERT(script()->uninlineable && !isInlineBuilder());
 
         MSetFrameArgument *store = MSetFrameArgument::New(alloc(), arg, val);
         current->add(store);
         current->setArg(arg);
         return true;
     }
 
     // If this assignment is at the start of the function and is coercing
--- a/js/src/jit/IonCode.h
+++ b/js/src/jit/IonCode.h
@@ -194,16 +194,19 @@ struct IonScript
     // Flag set when it is likely that one of our (transitive) call
     // targets is not compiled.  Used in ForkJoin.cpp to decide when
     // we should add call targets to the worklist.
     bool hasUncompiledCallTarget_;
 
     // Flag set if IonScript was compiled with SPS profiling enabled.
     bool hasSPSInstrumentation_;
 
+    // Flag for if this script is getting recompiled.
+    bool recompiling_;
+
     // Any kind of data needed by the runtime, these can be either cache
     // information or profiling info.
     uint32_t runtimeData_;
     uint32_t runtimeSize_;
 
     // State for polymorphic caches in the compiled code. All caches are stored
     // in the runtimeData buffer and indexed by the cacheIndex which give a
     // relative offset in the runtimeData array.
@@ -525,16 +528,28 @@ struct IonScript
     }
     uint32_t incrOsrPcMismatchCounter() {
         return ++osrPcMismatchCounter_;
     }
     void resetOsrPcMismatchCounter() {
         osrPcMismatchCounter_ = 0;
     }
 
+    void setRecompiling() {
+        recompiling_ = true;
+    }
+
+    bool isRecompiling() const {
+        return recompiling_;
+    }
+
+    void clearRecompiling() {
+        recompiling_ = false;
+    }
+
     static void writeBarrierPre(Zone *zone, IonScript *ionScript);
 };
 
 // Execution information for a basic block which may persist after the
 // accompanying IonScript is destroyed, for use during profiling.
 struct IonBlockCounts
 {
   private:
--- a/js/src/jit/IonMacroAssembler.cpp
+++ b/js/src/jit/IonMacroAssembler.cpp
@@ -1200,16 +1200,53 @@ MacroAssembler::handleFailure(ExecutionM
     }
     MacroAssemblerSpecific::handleFailureWithHandler(handler);
 
     // Doesn't actually emit code, but balances the leave()
     if (sps_)
         sps_->reenter(*this, InvalidReg);
 }
 
+#ifdef DEBUG
+static inline bool
+IsCompilingAsmJS()
+{
+    // asm.js compilation pushes an IonContext with a null JSCompartment.
+    IonContext *ictx = MaybeGetIonContext();
+    return ictx && ictx->compartment == nullptr;
+}
+#endif
+
+static void assume_unreachable_(const char *output) {
+    MOZ_ReportAssertionFailure(output, __FILE__, __LINE__);
+}
+
+void
+MacroAssembler::assume_unreachable(const char *output)
+{
+#ifdef DEBUG
+    // AsmJS forbids use of ImmPtr.
+    if (!IsCompilingAsmJS()) {
+        RegisterSet regs = RegisterSet::Volatile();
+        PushRegsInMask(regs);
+
+        Register temp = regs.takeGeneral();
+
+        setupUnalignedABICall(1, temp);
+        movePtr(ImmPtr(output), temp);
+        passABIArg(temp);
+        callWithABI(JS_FUNC_TO_DATA_PTR(void *, assume_unreachable_));
+
+        PopRegsInMask(RegisterSet::Volatile());
+    }
+#endif
+
+    breakpoint();
+}
+
 static void printf0_(const char *output) {
     printf("%s", output);
 }
 
 void
 MacroAssembler::printf(const char *output)
 {
     RegisterSet regs = RegisterSet::Volatile();
--- a/js/src/jit/IonMacroAssembler.h
+++ b/js/src/jit/IonMacroAssembler.h
@@ -1089,16 +1089,17 @@ class MacroAssembler : public MacroAssem
           case SequentialExecution: return &sequentialFailureLabel_;
           case ParallelExecution: return &parallelFailureLabel_;
           default: MOZ_ASSUME_UNREACHABLE("Unexpected execution mode");
         }
     }
 
     void finish();
 
+    void assume_unreachable(const char *output);
     void printf(const char *output);
     void printf(const char *output, Register value);
 
 #if JS_TRACE_LOGGING
     void tracelogStart(JSScript *script);
     void tracelogStop();
     void tracelogLog(TraceLogging::Type type);
 #endif
--- a/js/src/jit/LinearScan.cpp
+++ b/js/src/jit/LinearScan.cpp
@@ -1123,17 +1123,17 @@ LinearScanAllocator::canCoexist(LiveInte
  * Ensure intervals appear in exactly the appropriate one of {active,inactive,
  * handled}, and that active and inactive intervals do not conflict. Handled
  * intervals are checked for conflicts in validateAllocations for performance
  * reasons.
  */
 void
 LinearScanAllocator::validateIntervals()
 {
-    if (!js_IonOptions.assertGraphConsistency)
+    if (!js_IonOptions.checkGraphConsistency)
         return;
 
     for (IntervalIterator i(active.begin()); i != active.end(); i++) {
         JS_ASSERT(i->numRanges() > 0);
         JS_ASSERT(i->covers(current->start()));
 
         for (IntervalIterator j(active.begin()); j != i; j++)
             JS_ASSERT(canCoexist(*i, *j));
@@ -1169,17 +1169,17 @@ LinearScanAllocator::validateIntervals()
 
 /*
  * This function performs a nice, expensive check that all intervals
  * in the function can coexist with every other interval.
  */
 void
 LinearScanAllocator::validateAllocations()
 {
-    if (!js_IonOptions.assertGraphConsistency)
+    if (!js_IonOptions.checkGraphConsistency)
         return;
 
     for (IntervalIterator i(handled.begin()); i != handled.end(); i++) {
         for (IntervalIterator j(handled.begin()); j != i; j++) {
             JS_ASSERT(*i != *j);
             JS_ASSERT(canCoexist(*i, *j));
         }
         LinearScanVirtualRegister *reg = &vregs[i->vreg()];
--- a/js/src/jit/LiveRangeAllocator.h
+++ b/js/src/jit/LiveRangeAllocator.h
@@ -595,17 +595,17 @@ class LiveRangeAllocator : protected Reg
         if (!fixedIntervals[reg.code()]->addRangeAtHead(from, to))
             return false;
         return fixedIntervalsUnion->addRangeAtHead(from, to);
     }
 
     void validateVirtualRegisters()
     {
 #ifdef DEBUG
-        if (!js_IonOptions.assertGraphConsistency)
+        if (!js_IonOptions.checkGraphConsistency)
             return;
 
         for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
             VirtualRegister *reg = &vregs[i];
 
             LiveInterval *prev = nullptr;
             for (size_t j = 0; j < reg->numIntervals(); j++) {
                 LiveInterval *interval = reg->getInterval(j);
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -590,22 +590,22 @@ LIRGenerator::visitCallDirectEval(MCallD
         lir = new(alloc()) LCallDirectEvalS(useRegisterAtStart(scopeChain),
                                             useRegisterAtStart(string));
     } else {
         lir = new(alloc()) LCallDirectEvalV(useRegisterAtStart(scopeChain));
         if (!useBoxAtStart(lir, LCallDirectEvalV::Argument, string))
             return false;
     }
 
-    if (!useBoxAtStart(lir, (string->type() == MIRType_String
-                             ? LCallDirectEvalS::ThisValue
-                             : LCallDirectEvalV::ThisValue),
-                       thisValue))
-    {
-        return false;
+    if (string->type() == MIRType_String) {
+        if (!useBoxAtStart(lir, LCallDirectEvalS::ThisValue, thisValue))
+            return false;
+    } else {
+        if (!useBoxAtStart(lir, LCallDirectEvalV::ThisValue, thisValue))
+            return false;
     }
 
     return defineReturn(lir, ins) && assignSafepoint(lir, ins);
 }
 
 static JSOp
 ReorderComparison(JSOp op, MDefinition **lhsp, MDefinition **rhsp)
 {
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -917,11 +917,33 @@ InitBaselineFrameForOsr(BaselineFrame *f
 }
 
 JSObject *CreateDerivedTypedObj(JSContext *cx, HandleObject type,
                                 HandleObject owner, int32_t offset)
 {
     return TypedObject::createDerived(cx, type, owner, offset);
 }
 
+bool
+Recompile(JSContext *cx)
+{
+    JS_ASSERT(cx->currentlyRunningInJit());
+    JitActivationIterator activations(cx->runtime());
+    IonFrameIterator iter(activations);
+
+    JS_ASSERT(iter.type() == IonFrame_Exit);
+    ++iter;
+
+    bool isConstructing = iter.isConstructing();
+    RootedScript script(cx, iter.script());
+    JS_ASSERT(script->hasIonScript());
+
+    MethodStatus status = Recompile(cx, script, nullptr, nullptr, isConstructing);
+    if (status == Method_Error)
+        return false;
+
+    JS_ASSERT(script->hasIonScript());
+
+    return true;
+}
 
 } // namespace jit
 } // namespace js
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -656,12 +656,13 @@ bool EnterBlock(JSContext *cx, BaselineF
 bool LeaveBlock(JSContext *cx, BaselineFrame *frame);
 
 bool InitBaselineFrameForOsr(BaselineFrame *frame, StackFrame *interpFrame,
                              uint32_t numStackValues);
 
 JSObject *CreateDerivedTypedObj(JSContext *cx, HandleObject type,
                                 HandleObject owner, int32_t offset);
 
+bool Recompile(JSContext *cx);
 } // namespace jit
 } // namespace js
 
 #endif /* jit_VMFunctions_h */
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -1903,17 +1903,17 @@ CodeGeneratorARM::generateInvalidateEpil
     // Push the Ion script onto the stack (when we determine what that pointer is).
     invalidateEpilogueData_ = masm.pushWithPatch(ImmWord(uintptr_t(-1)));
     IonCode *thunk = gen->jitRuntime()->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();
+    masm.assume_unreachable("Should have returned directly to its caller instead of here.");
     return true;
 }
 
 void
 DispatchIonCache::initializeAddCacheState(LInstruction *ins, AddCacheState *addState)
 {
     // Can always use the scratch register on ARM.
     addState->dispatchScratch = ScratchRegister;
--- a/js/src/jit/arm/Trampoline-arm.cpp
+++ b/js/src/jit/arm/Trampoline-arm.cpp
@@ -796,17 +796,17 @@ JitRuntime::generateVMWrapper(JSContext 
         masm.load8ZeroExtend(Address(sp, 0), ReturnReg);
         masm.freeStack(sizeof(int32_t));
         break;
 
       case Type_Double:
         if (cx->runtime()->jitSupportsFloatingPoint)
             masm.loadDouble(Address(sp, 0), ReturnFloatReg);
         else
-            masm.breakpoint();
+            masm.assume_unreachable("Unable to load into float reg, with no FP support.");
         masm.freeStack(sizeof(double));
         break;
 
       default:
         JS_ASSERT(f.outParam == Type_Void);
         break;
     }
     masm.leaveExitFrame();
--- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp
@@ -1766,17 +1766,17 @@ CodeGeneratorX86Shared::generateInvalida
     // Push the Ion script onto the stack (when we determine what that pointer is).
     invalidateEpilogueData_ = masm.pushWithPatch(ImmWord(uintptr_t(-1)));
     IonCode *thunk = gen->jitRuntime()->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();
+    masm.assume_unreachable("Should have returned directly to its caller instead of here.");
     return true;
 }
 
 bool
 CodeGeneratorX86Shared::visitNegI(LNegI *ins)
 {
     Register input = ToRegister(ins->input());
     JS_ASSERT(input == ToRegister(ins->output()));
--- a/js/src/jit/x86/Trampoline-x86.cpp
+++ b/js/src/jit/x86/Trampoline-x86.cpp
@@ -682,17 +682,17 @@ JitRuntime::generateVMWrapper(JSContext 
         masm.Pop(ReturnReg);
         masm.movzbl(ReturnReg, ReturnReg);
         break;
 
       case Type_Double:
         if (cx->runtime()->jitSupportsFloatingPoint)
             masm.Pop(ReturnFloatReg);
         else
-            masm.breakpoint();
+            masm.assume_unreachable("Unable to pop to float reg, with no FP support.");
         break;
 
       default:
         JS_ASSERT(f.outParam == Type_Void);
         break;
     }
     masm.leaveExitFrame();
     masm.retn(Imm32(sizeof(IonExitFrameLayout) +
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -1427,35 +1427,62 @@ js_QuoteString(ExclusiveContext *cx, JSS
     char *bytes = QuoteString(&sprinter, str, quote);
     if (!bytes)
         return nullptr;
     return js_NewStringCopyZ<CanGC>(cx, bytes);
 }
 
 /************************************************************************/
 
-static JSObject *
-GetBlockChainAtPC(JSContext *cx, JSScript *script, jsbytecode *pc)
+StaticBlockObject *
+js::GetBlockChainAtPC(JSScript *script, jsbytecode *pc)
 {
     JS_ASSERT(script->containsPC(pc));
-    JS_ASSERT(pc >= script->main());
-
-    ptrdiff_t offset = pc - script->main();
 
     if (!script->hasBlockScopes())
         return nullptr;
 
+    if (pc < script->main())
+        return nullptr;
+    ptrdiff_t offset = pc - script->main();
+
     BlockScopeArray *blockScopes = script->blockScopes();
-    JSObject *blockChain = nullptr;
-    for (uint32_t n = 0; n < blockScopes->length; n++) {
-        const BlockScopeNote *note = &blockScopes->vector[n];
-        if (note->start > offset)
-            break;
-        if (offset <= note->start + note->length)
-            blockChain = script->getObject(note->index);
+    StaticBlockObject *blockChain = nullptr;
+
+    // Find the innermost block chain using a binary search.
+    size_t bottom = 0;
+    size_t top = blockScopes->length;
+
+    while (bottom < top) {
+        size_t mid = bottom + (top - bottom) / 2;
+        const BlockScopeNote *note = &blockScopes->vector[mid];
+        if (note->start <= offset) {
+            // Block scopes are ordered in the list by their starting offset, and since
+            // blocks form a tree ones earlier in the list may cover the pc even if
+            // later blocks end before the pc. This only happens when the earlier block
+            // is a parent of the later block, so we need to check parents of |mid| in
+            // the searched range for coverage.
+            size_t check = mid;
+            while (check >= bottom) {
+                const BlockScopeNote *checkNote = &blockScopes->vector[check];
+                JS_ASSERT(checkNote->start <= offset);
+                if (offset <= checkNote->start + checkNote->length) {
+                    // We found a matching block chain but there may be inner ones
+                    // at a higher block chain index than mid. Continue the binary search.
+                    blockChain = &script->getObject(checkNote->index)->as<StaticBlockObject>();
+                    break;
+                }
+                if (checkNote->parent == UINT32_MAX)
+                    break;
+                check = checkNote->parent;
+            }
+            bottom = mid + 1;
+        } else {
+            top = mid;
+        }
     }
 
     return blockChain;
 }
 
 namespace {
 /*
  * The expression decompiler is invoked by error handling code to produce a
@@ -1711,17 +1738,17 @@ ExpressionDecompiler::loadAtom(jsbytecod
 {
     return script->getAtom(GET_UINT32_INDEX(pc));
 }
 
 JSAtom *
 ExpressionDecompiler::findLetVar(jsbytecode *pc, unsigned depth)
 {
     if (script->hasObjects()) {
-        JSObject *chain = GetBlockChainAtPC(cx, script, pc);
+        JSObject *chain = GetBlockChainAtPC(script, pc);
         if (!chain)
             return nullptr;
         JS_ASSERT(chain->is<BlockObject>());
         do {
             BlockObject &block = chain->as<BlockObject>();
             uint32_t blockDepth = block.stackDepth();
             uint32_t blockCount = block.slotCount();
             if (uint32_t(depth - blockDepth) < uint32_t(blockCount)) {
--- a/js/src/jsopcode.h
+++ b/js/src/jsopcode.h
@@ -772,16 +772,21 @@ class PCCounts
 JS_STATIC_ASSERT(sizeof(PCCounts) % sizeof(Value) == 0);
 
 static inline jsbytecode *
 GetNextPc(jsbytecode *pc)
 {
     return pc + GetBytecodeLength(pc);
 }
 
+class StaticBlockObject;
+
+StaticBlockObject *
+GetBlockChainAtPC(JSScript *script, jsbytecode *pc);
+
 } /* namespace js */
 
 #if defined(DEBUG)
 /*
  * Disassemblers, for debugging only.
  */
 bool
 js_Disassemble(JSContext *cx, JS::Handle<JSScript*> script, bool lines, js::Sprinter *sp);
--- a/js/src/jsopcode.tbl
+++ b/js/src/jsopcode.tbl
@@ -313,22 +313,20 @@ OPDEF(JSOP_FINALLY,     135,"finally",  
  * 'with', and 'arguments'. All of these cases require creating a CallObject to
  * own the aliased variable.
  *
  * An ALIASEDVAR opcode contains the following immediates:
  *  uint16 hops:  the number of scope objects to skip to find the ScopeObject
  *                containing the variable being accessed
  *  uint16 slot:  the slot containing the variable in the ScopeObject (this
  *                'slot' does not include RESERVED_SLOTS).
- *  uint32 block: the index (into the script object table) of the block chain
- *                at the point of the variable access.
  */
-OPDEF(JSOP_GETALIASEDVAR, 136,"getaliasedvar",NULL,   9,  0,  1, JOF_SCOPECOORD|JOF_NAME|JOF_TYPESET)
-OPDEF(JSOP_CALLALIASEDVAR,137,"callaliasedvar",NULL,  9,  0,  1, JOF_SCOPECOORD|JOF_NAME|JOF_TYPESET)
-OPDEF(JSOP_SETALIASEDVAR, 138,"setaliasedvar",NULL,   9,  1,  1, JOF_SCOPECOORD|JOF_NAME|JOF_SET|JOF_DETECTING)
+OPDEF(JSOP_GETALIASEDVAR, 136,"getaliasedvar",NULL,   5,  0,  1, JOF_SCOPECOORD|JOF_NAME|JOF_TYPESET)
+OPDEF(JSOP_CALLALIASEDVAR,137,"callaliasedvar",NULL,  5,  0,  1, JOF_SCOPECOORD|JOF_NAME|JOF_TYPESET)
+OPDEF(JSOP_SETALIASEDVAR, 138,"setaliasedvar",NULL,   5,  1,  1, JOF_SCOPECOORD|JOF_NAME|JOF_SET|JOF_DETECTING)
 
 OPDEF(JSOP_UNUSED139,  139, "unused139",   NULL,         1,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED140,  140, "unused140",   NULL,         1,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED141,  141, "unused141",   NULL,         1,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED142,  142, "unused142",   NULL,         1,  0,  0,  JOF_BYTE)
 
 /*
  * Intrinsic names are emitted instead of JSOP_*NAME ops when the
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -802,17 +802,18 @@ js::XDRScript(XDRState<mode> *xdr, Handl
             }
         } while (tn != tnfirst);
     }
 
     for (i = 0; i < nblockscopes; ++i) {
         BlockScopeNote *note = &script->blockScopes()->vector[i];
         if (!xdr->codeUint32(&note->index) ||
             !xdr->codeUint32(&note->start) ||
-            !xdr->codeUint32(&note->length))
+            !xdr->codeUint32(&note->length) ||
+            !xdr->codeUint32(&note->parent))
         {
             return false;
         }
     }
 
     if (mode == XDR_DECODE)
         scriptp.set(script);
 
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -80,17 +80,17 @@ struct JSTryNote {
 };
 
 namespace js {
 
 struct BlockScopeNote {
     uint32_t        index;      // Index of StaticScopeObject in the object array.
     uint32_t        start;      // Bytecode offset at which this scope starts.
     uint32_t        length;     // Bytecode length of scope.
-    uint32_t        padding;    // Pad to 64-bit boundary.
+    uint32_t        parent;     // Index of parent block scope in notes, or UINT32_MAX.
 };
 
 struct ConstArray {
     js::HeapValue   *vector;    /* array of indexed constant values */
     uint32_t        length;
 };
 
 struct ObjectArray {
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -33,21 +33,20 @@ typedef Rooted<ArgumentsObject *> Rooted
 /*****************************************************************************/
 
 static JSObject *
 InnermostStaticScope(JSScript *script, jsbytecode *pc)
 {
     JS_ASSERT(script->containsPC(pc));
     JS_ASSERT(JOF_OPTYPE(*pc) == JOF_SCOPECOORD);
 
-    uint32_t blockIndex = GET_UINT32_INDEX(pc + 2 * sizeof(uint16_t));
-
-    if (blockIndex == UINT32_MAX)
-        return script->function();
-    return &script->getObject(blockIndex)->as<StaticBlockObject>();
+    StaticBlockObject *block = GetBlockChainAtPC(script, pc);
+    if (block)
+        return block;
+    return script->function();
 }
 
 Shape *
 js::ScopeCoordinateToStaticScopeShape(JSScript *script, jsbytecode *pc)
 {
     StaticScopeIter<NoGC> ssi(InnermostStaticScope(script, pc));
     ScopeCoordinate sc(pc);
     while (true) {
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -17,17 +17,17 @@ namespace js {
  * Bytecode version number. Increment the subtrahend whenever JS bytecode
  * changes incompatibly.
  *
  * This version number is XDR'd near the front of xdr bytecode and
  * aborts deserialization if there is a mismatch between the current
  * and saved versions. If deserialization fails, the data should be
  * invalidated if possible.
  */
-static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 155);
+static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 156);
 
 class XDRBuffer {
   public:
     XDRBuffer(JSContext *cx)
       : context(cx), base(nullptr), cursor(nullptr), limit(nullptr) { }
 
     JSContext *cx() const {
         return context;
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -4201,20 +4201,21 @@ already_AddRefed<Layer> nsDisplayTransfo
   const gfx3DMatrix& newTransformMatrix =
     GetTransform(mFrame->PresContext()->AppUnitsPerDevPixel());
 
   if (mFrame->StyleDisplay()->mBackfaceVisibility == NS_STYLE_BACKFACE_VISIBILITY_HIDDEN &&
       newTransformMatrix.IsBackfaceVisible()) {
     return nullptr;
   }
 
+  uint32_t flags = ShouldPrerenderTransformedContent(aBuilder, mFrame, false) ?
+    FrameLayerBuilder::CONTAINER_NOT_CLIPPED_BY_ANCESTORS : 0;
   nsRefPtr<ContainerLayer> container = aManager->GetLayerBuilder()->
     BuildContainerLayerFor(aBuilder, aManager, mFrame, this, *mStoredList.GetChildren(),
-                           aContainerParameters, &newTransformMatrix,
-                           FrameLayerBuilder::CONTAINER_NOT_CLIPPED_BY_ANCESTORS);
+                           aContainerParameters, &newTransformMatrix, flags);
 
   if (!container) {
     return nullptr;
   }
 
   // Add the preserve-3d flag for this layer, BuildContainerLayerFor clears all flags,
   // so we never need to explicitely unset this flag.
   if (mFrame->Preserves3D() || mFrame->Preserves3DChildren()) {
--- a/layout/generic/nsVideoFrame.cpp
+++ b/layout/generic/nsVideoFrame.cpp
@@ -87,18 +87,17 @@ nsVideoFrame::CreateAnonymousContent(nsT
     // as the image is native anonymous, and so can't be reframed (currently).
     nsCOMPtr<nsIImageLoadingContent> imgContent = do_QueryInterface(mPosterImage);
     NS_ENSURE_TRUE(imgContent, NS_ERROR_FAILURE);
 
     imgContent->ForceImageState(true, 0);
     // And now have it update its internal state
     element->UpdateState(false);
 
-    nsresult res = UpdatePosterSource(false);
-    NS_ENSURE_SUCCESS(res,res);
+    UpdatePosterSource(false);
 
     if (!aElements.AppendElement(mPosterImage))
       return NS_ERROR_OUT_OF_MEMORY;
 
     // Set up the caption overlay div for showing any TextTrack data
     nodeInfo = nodeInfoManager->GetNodeInfo(nsGkAtoms::div,
                                             nullptr,
                                             kNameSpaceID_XHTML,
@@ -587,40 +586,41 @@ nsVideoFrame::GetVideoIntrinsicSize(nsRe
       return imgsize;
     }
   }
 
   return nsSize(nsPresContext::CSSPixelsToAppUnits(size.width),
                 nsPresContext::CSSPixelsToAppUnits(size.height));
 }
 
-nsresult
+void
 nsVideoFrame::UpdatePosterSource(bool aNotify)
 {
   NS_ASSERTION(HasVideoElement(), "Only call this on <video> elements.");
   HTMLVideoElement* element = static_cast<HTMLVideoElement*>(GetContent());
 
-  nsAutoString posterStr;
-  element->GetPoster(posterStr);
-  nsresult res = mPosterImage->SetAttr(kNameSpaceID_None,
-                                       nsGkAtoms::src,
-                                       posterStr,
-                                       aNotify);
-  NS_ENSURE_SUCCESS(res,res);
-  return NS_OK;
+  if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::poster)) {
+    nsAutoString posterStr;
+    element->GetPoster(posterStr);
+    mPosterImage->SetAttr(kNameSpaceID_None,
+                          nsGkAtoms::src,
+                          posterStr,
+                          aNotify);
+  } else {
+    mPosterImage->UnsetAttr(kNameSpaceID_None, nsGkAtoms::poster, aNotify);
+  }
 }
 
 NS_IMETHODIMP
 nsVideoFrame::AttributeChanged(int32_t aNameSpaceID,
                                nsIAtom* aAttribute,
                                int32_t aModType)
 {
   if (aAttribute == nsGkAtoms::poster && HasVideoElement()) {
-    nsresult res = UpdatePosterSource(true);
-    NS_ENSURE_SUCCESS(res,res);
+    UpdatePosterSource(true);
   }
   return nsContainerFrame::AttributeChanged(aNameSpaceID,
                                             aAttribute,
                                             aModType);
 }
 
 bool nsVideoFrame::HasVideoElement() {
   nsCOMPtr<nsIDOMHTMLVideoElement> videoDomElement = do_QueryInterface(mContent);
--- a/layout/generic/nsVideoFrame.h
+++ b/layout/generic/nsVideoFrame.h
@@ -107,17 +107,17 @@ protected:
   // Returns true if there is video data to render. Can return false
   // when we're the frame for an audio element, or we've created a video
   // element for a media which is audio-only.
   bool HasVideoData();
 
   // Sets the mPosterImage's src attribute to be the video's poster attribute,
   // if we're the frame for a video element. Only call on frames for video
   // elements, not for frames for audio elements.
-  nsresult UpdatePosterSource(bool aNotify);
+  void UpdatePosterSource(bool aNotify);
 
   virtual ~nsVideoFrame();
 
   nsMargin mBorderPadding;
 
   // Anonymous child which is bound via XBL to the video controls.
   nsCOMPtr<nsIContent> mVideoControls;
 
--- a/layout/generic/test/mochitest.ini
+++ b/layout/generic/test/mochitest.ini
@@ -74,16 +74,17 @@ support-files = bug633762_iframe.html
 [test_bug735641.html]
 [test_bug748961.html]
 [test_bug784410.html]
 [test_bug785324.html]
 [test_bug791616.html]
 [test_bug831780.html]
 [test_bug841361.html]
 [test_bug904810.html]
+[test_bug938772.html]
 [test_contained_plugin_transplant.html]
 [test_image_selection.html]
 [test_image_selection_2.html]
 [test_invalidate_during_plugin_paint.html]
 [test_movement_by_characters.html]
 [test_movement_by_words.html]
 # Disable the caret movement by word test on Linux because the shortcut keys
 # are defined in system level.  So, it depends on the environment.
new file mode 100644
--- /dev/null
+++ b/layout/generic/test/test_bug938772.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=938772
+-->
+<title>Test for Bug 938772</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=938772">Mozilla Bug 938772</a>
+<p id="display"></p>
+<iframe id="i"></iframe>
+<pre id="test">
+<script>
+SimpleTest.waitForExplicitFinish();
+
+i.onload = function() {
+  ok(!i.contentDocument.getElementById("v").failed,
+     "Check whether an error was reported");
+  SimpleTest.finish();
+};
+i.src = "data:text/html,<base href='http://basetag/basetag'><video id='v' onerror='v.failed=true'></video>";
+</script>
+
--- a/media/webrtc/signaling/test/Makefile.in
+++ b/media/webrtc/signaling/test/Makefile.in
@@ -2,16 +2,17 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 LIBS = \
   $(XPCOM_LIBS) \
   $(NSPR_LIBS) \
   $(NSS_LIBS) \
   $(REALTIME_LIBS) \
+  $(MOZ_JS_LIBS) \
   $(DEPTH)/xpcom/glue/$(LIB_PREFIX)xpcomglue_s.$(LIB_SUFFIX) \
   $(DEPTH)/media/mtransport/standalone/$(LIB_PREFIX)mtransport_s.$(LIB_SUFFIX) \
   $(DEPTH)/media/webrtc/signalingtest/signaling_ecc/$(LIB_PREFIX)ecc.$(LIB_SUFFIX) \
   $(DEPTH)/media/webrtc/signalingtest/signaling_sipcc/$(LIB_PREFIX)sipcc.$(LIB_SUFFIX) \
   $(DEPTH)/layout/media/webrtc/$(LIB_PREFIX)webrtc.$(LIB_SUFFIX) \
   $(DEPTH)/layout/media/$(LIB_PREFIX)gkmedias.$(LIB_SUFFIX) \
   $(DEPTH)/media/webrtc/trunk/testing/gtest_gtest/$(LIB_PREFIX)gtest.$(LIB_SUFFIX) \
   $(DEPTH)/netwerk/srtp/src/$(LIB_PREFIX)nksrtp_s.$(LIB_SUFFIX) \
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -101,21 +101,20 @@ pref("dom.workers.maxPerDomain", 20);
 
 // Whether or not Shared Web Workers are enabled.
 pref("dom.workers.sharedWorkers.enabled", false);
 
 // Whether nonzero values can be returned from performance.timing.*
 pref("dom.enable_performance", true);
 
 // Whether the Gamepad API is enabled
+pref("dom.gamepad.enabled", true);
 #ifdef RELEASE_BUILD
-pref("dom.gamepad.enabled", false);
 pref("dom.gamepad.non_standard_events.enabled", false);
 #else
-pref("dom.gamepad.enabled", true);
 pref("dom.gamepad.non_standard_events.enabled", true);
 #endif
 
 // Fastback caching - if this pref is negative, then we calculate the number
 // of content viewers to cache based on the amount of available memory.
 pref("browser.sessionhistory.max_total_viewers", -1);
 
 pref("ui.use_native_colors", true);
--- a/xpcom/glue/nsTArray.h
+++ b/xpcom/glue/nsTArray.h
@@ -660,17 +660,17 @@ struct nsTArray_CopyChooser {
 };
 
 //
 // Some classes require constructors/destructors to be called, so they are
 // specialized here.
 //
 template <class E>
 struct nsTArray_CopyChooser<JS::Heap<E> > {
-  typedef nsTArray_CopyWithConstructors<E> Type;
+  typedef nsTArray_CopyWithConstructors<JS::Heap<E> > Type;
 };
 
 template<>
 struct nsTArray_CopyChooser<nsRegion> {
   typedef nsTArray_CopyWithConstructors<nsRegion> Type;
 };
 
 template<>
new file mode 100644
--- /dev/null
+++ b/xpcom/glue/tests/gtest/TestGCPostBarriers.cpp
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Tests that generational garbage collection post-barriers are correctly
+ * implemented for nsTArrays that contain JavaScript Values.
+ */
+
+#include "jsapi.h"
+#include "nsTArray.h"
+
+#include "gtest/gtest.h"
+
+#include "js/Tracer.h"
+#include "js/HeapAPI.h"
+
+#include "mozilla/CycleCollectedJSRuntime.h"
+
+using namespace JS;
+using namespace mozilla;
+
+typedef nsTArray<Heap<JSObject*> > ArrayT;
+
+static void
+TraceArray(JSTracer* trc, void* data)
+{
+  ArrayT* array = static_cast<ArrayT *>(data);
+  for (unsigned i = 0; i < array->Length(); ++i)
+    JS_CallHeapObjectTracer(trc, &array->ElementAt(i), "array-element");
+}
+
+static void
+RunTest(JSRuntime* rt, JSContext* cx)
+{
+  JS_GC(rt);
+
+  /*
+   * Create an array with space for half the final number of elements to test
+   * that moving Heap<T> elements works correctly.
+   */
+  const int elements = 100;
+  ArrayT* array = new ArrayT(elements / 2);
+  ASSERT_TRUE(array != nullptr);
+  JS_AddExtraGCRootsTracer(rt, TraceArray, array);
+
+  /*
+   * Create the array and fill it with new JS objects. With GGC these will be
+   * allocated in the nursery.
+   */
+  RootedValue value(cx);
+  const char* property = "foo";
+  JS::shadow::Runtime* srt = reinterpret_cast<JS::shadow::Runtime*>(rt);
+  for (int i = 0; i < elements; ++i) {
+    RootedObject obj(cx, JS_NewObject(cx, nullptr, nullptr, nullptr));
+#ifdef JSGC_GENERATIONAL
+    ASSERT_TRUE(js::gc::IsInsideNursery(srt, obj));
+#else
+    ASSERT_FALSE(js::gc::IsInsideNursery(srt, obj));
+#endif
+    value = Int32Value(i);
+    ASSERT_TRUE(JS_SetProperty(cx, obj, property, value));
+    array->AppendElement(obj);
+  }
+
+  /*
+   * If postbarriers are not working, we will crash here when we try to mark
+   * objects that have been moved to the tenured heap.
+   */
+  JS_GC(rt);
+
+  /*
+   * Sanity check that our array contains what we expect.
+   */
+  for (int i = 0; i < elements; ++i) {
+    RootedObject obj(cx, array->ElementAt(i));
+    ASSERT_FALSE(js::gc::IsInsideNursery(srt, obj));
+    ASSERT_TRUE(JS_GetProperty(cx, obj, property, &value));
+    ASSERT_TRUE(value.isInt32());
+    ASSERT_EQ(i, value.toInt32());
+  }
+
+  JS_RemoveExtraGCRootsTracer(rt, TraceArray, array);
+}
+
+static void
+CreateGlobalAndRunTest(JSRuntime* rt, JSContext* cx)
+{
+  static const JSClass GlobalClass = {
+    "global", JSCLASS_GLOBAL_FLAGS,
+    JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
+  };
+
+  JS::CompartmentOptions options;
+  options.setVersion(JSVERSION_LATEST);
+  JS::RootedObject global(cx);
+  global = JS_NewGlobalObject(cx, &GlobalClass, nullptr, JS::FireOnNewGlobalHook, options);
+  ASSERT_TRUE(global != nullptr);
+
+  JS_AddNamedObjectRoot(cx, global.address(), "test-global");
+  JSCompartment *oldCompartment = JS_EnterCompartment(cx, global);
+
+  RunTest(rt, cx);
+
+  JS_LeaveCompartment(cx, oldCompartment);
+  JS_RemoveObjectRoot(cx, global.address());
+}
+
+TEST(GCPostBarriers, nsTArray) {
+  CycleCollectedJSRuntime* ccrt = CycleCollectedJSRuntime::Get();
+  ASSERT_TRUE(ccrt != nullptr);
+  JSRuntime* rt = ccrt->Runtime();
+  ASSERT_TRUE(rt != nullptr);
+
+  JSContext *cx = JS_NewContext(rt, 8192);
+  ASSERT_TRUE(cx != nullptr);
+  JS_BeginRequest(cx);
+
+  CreateGlobalAndRunTest(rt, cx);
+
+  JS_EndRequest(cx);
+  JS_DestroyContext(cx);
+}
--- a/xpcom/glue/tests/gtest/moz.build
+++ b/xpcom/glue/tests/gtest/moz.build
@@ -1,16 +1,17 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'TestFileUtils.cpp',
+    'TestGCPostBarriers.cpp',
 ]
 
 LOCAL_INCLUDES = [
     '../..',
 ]
 
 LIBRARY_NAME = 'xpcom_glue_gtest'