Merge inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 10 Feb 2014 15:42:58 -0500
changeset 167921 d812f80a0f1da4944281547f40059a2145137107
parent 167920 07739c5c874f303b8c0b747c62c9e109e9c8d071 (current diff)
parent 167862 cae585897f68e1000b91b8eb57c2735013253752 (diff)
child 167922 9b2e849f5854ee03805194c2263e7ec3d5fb8d5d
child 168019 8e5b70407721b020cc30d59d86f63961795930b5
child 168041 56f6cffa0a517e2d74219b8ebb829ee6099e83a6
push id39593
push userryanvm@gmail.com
push dateMon, 10 Feb 2014 20:43:52 +0000
treeherdermozilla-inbound@9b2e849f5854 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone30.0a1
first release with
nightly linux32
d812f80a0f1d / 30.0a1 / 20140211030201 / files
nightly linux64
d812f80a0f1d / 30.0a1 / 20140211030201 / files
nightly mac
d812f80a0f1d / 30.0a1 / 20140211030201 / files
nightly win32
d812f80a0f1d / 30.0a1 / 20140211030201 / files
nightly win64
d812f80a0f1d / 30.0a1 / 20140211030201 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c.
js/src/jit/SnapshotReader.h
js/src/jit/SnapshotWriter.h
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -77,17 +77,16 @@ EXTRA_DEPS += firefox.exe.manifest
 ifndef GNU_CC
 RCFLAGS += -DMOZ_PHOENIX -I$(srcdir)
 else
 RCFLAGS += -DMOZ_PHOENIX --include-dir $(srcdir)
 endif
 endif
 
 ifeq ($(OS_ARCH),OS2)
-RESFILE=splashos2.res
 RCFLAGS += -DMOZ_PHOENIX
 RCFLAGS += -DFIREFOX_ICO='"$(DIST)/branding/firefox-os2.ico"' -DDOCUMENT_ICO='"$(DIST)/branding/document-os2.ico"'
 endif
 
 PROGRAMS_DEST = $(DIST)/bin
 
 include $(topsrcdir)/config/rules.mk
 
--- a/content/media/TextTrack.cpp
+++ b/content/media/TextTrack.cpp
@@ -143,17 +143,17 @@ TextTrack::RemoveRegion(const TextTrackR
   }
 
   mRegionList->RemoveTextTrackRegion(aRegion);
 }
 
 void
 TextTrack::UpdateActiveCueList()
 {
-  if (mMode == TextTrackMode::Disabled || !mTextTrackList) {
+  if (!mTextTrackList) {
     return;
   }
 
   HTMLMediaElement* mediaElement = mTextTrackList->GetMediaElement();
   if (!mediaElement) {
     return;
   }
 
@@ -183,25 +183,30 @@ TextTrack::UpdateActiveCueList()
     if ((*mCueList)[mCuePos]->EndTime() >= playbackTime) {
       mActiveCueList->AddCue(*(*mCueList)[mCuePos]);
     }
   }
 }
 
 TextTrackCueList*
 TextTrack::GetActiveCues() {
-  UpdateActiveCueList();
-  return mActiveCueList;
+  if (mMode != TextTrackMode::Disabled) {
+    UpdateActiveCueList();
+    return mActiveCueList;
+  }
+  return nullptr;
 }
 
 void
 TextTrack::GetActiveCueArray(nsTArray<nsRefPtr<TextTrackCue> >& aCues)
 {
-  UpdateActiveCueList();
-  mActiveCueList->GetArray(aCues);
+  if (mMode != TextTrackMode::Disabled) {
+    UpdateActiveCueList();
+    mActiveCueList->GetArray(aCues);
+  }
 }
 
 uint16_t
 TextTrack::ReadyState() const
 {
   return mReadyState;
 }
 
--- a/content/media/TextTrackCue.h
+++ b/content/media/TextTrackCue.h
@@ -317,16 +317,17 @@ public:
   HTMLDivElement* GetDisplayState()
   {
     return static_cast<HTMLDivElement*>(mDisplayState.get());
   }
 
   void SetDisplayState(HTMLDivElement* aDisplayState)
   {
     mDisplayState = aDisplayState;
+    mReset = false;
   }
 
   bool HasBeenReset()
   {
     return mReset;
   }
 
   // Helper functions for implementation.
--- a/content/media/test/chrome.ini
+++ b/content/media/test/chrome.ini
@@ -1,9 +1,10 @@
 #Media chrome tests
 
 [DEFAULT]
 support-files =
   basic.vtt
   seek.webm
 
+[test_texttrackcue_chrome.html]
 [test_texttrack_chrome.html]
 [test_texttracklist_chrome.html]
--- a/content/media/test/test_texttrackcue.html
+++ b/content/media/test/test_texttrackcue.html
@@ -168,16 +168,25 @@ SpecialPowers.pushPrefEnv({"set": [["med
         exceptionHappened = true;
       }
       // If this is false then we did not throw an error and probably removed a cue
       // when we shouln't have.
       ok(exceptionHappened, "Exception should have happened.");
 
       is(cueList.length, 6, "Cue list length should be 6.");
 
+      video.currentTime = 2;
+      isnot(trackElement.track.activeCues, null);
+
+      trackElement.track.mode = "disabled";
+      is(trackElement.track.activeCues, null);
+
+      trackElement.track.mode = "showing";
+      video.currentTime = 0;
+
       // Test TextTrack::ActiveCues.
       var cueInfo = [
         { startTime: 0.51, endTime: 0.71, ids: ["Cue 01"] },
         { startTime: 0.72, endTime: 1.19, ids: [] },
         { startTime: 1.2, endTime: 1.9, ids: [2] },
         { startTime: 2, endTime: 2.4, ids: [2, 2.5] },
         { startTime: 2.41, endTime: 2.70, ids: [2.5] },
         { startTime: 2.71, endTime: 2.91, ids: [2.5, 3] },
new file mode 100644
--- /dev/null
+++ b/content/media/test/test_texttrackcue_chrome.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=967157
+-->
+<head>
+  <meta charset='utf-8'>
+  <title>Test for Bug 967157 - Setting TextTrackCue::DisplayState should set TextTrackCue::HasBeenReset to false</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({"set": [["media.webvtt.enabled", true]]},
+  function() {
+    var cue = new VTTCue(0, 1, "Some text.");
+    is(cue.hasBeenReset, false, "Cue's hasBeenReset flag should be false.");
+    is(cue.displayState, null, "Cue's displayState should be null.");
+
+    cue.startTime = 0.5;
+    is(cue.hasBeenReset, true, "Cue's hasBeenReset flag should now be true.");
+
+    cue.displayState = document.createElement("div");
+    is(cue.hasBeenReset, false, "Cue's hasBeenReset flag should now be false.");
+    SimpleTest.finish();
+  }
+);
+</script>
--- a/db/sqlite3/src/Makefile.in
+++ b/db/sqlite3/src/Makefile.in
@@ -2,18 +2,16 @@
 # 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/.
 
 LIB_IS_C_ONLY    = 1
 
 ifeq ($(OS_ARCH),WINNT)
 DEFFILE = $(CURDIR)/sqlite-processed.def
-RCFILE  = sqlite.rc
-RESFILE = sqlite.res
 
 GARBAGE += \
   sqlite-version.h \
   $(DEFFILE) \
   $(NULL)
 
 # We generate the appropriate version header file with our python script.
 sqlite-version.h: sqlite-version.py sqlite3.h
--- a/db/sqlite3/src/moz.build
+++ b/db/sqlite3/src/moz.build
@@ -61,8 +61,12 @@ if CONFIG['OS_TARGET'] == 'Android':
 # causes assertions on Win64. See bug 719579.
 if CONFIG['OS_ARCH'] == 'WINNT' and CONFIG['MOZ_MEMORY']:
     DEFINES['HAVE_MALLOC_USABLE_SIZE'] = True
     DEFINES['SQLITE_WITHOUT_MSIZE'] = True
 
 # disable PGO for Sun Studio
 if CONFIG['SOLARIS_SUNPRO_CC']:
     NO_PGO = True
+
+if CONFIG['OS_ARCH'] == 'WINNT':
+    RCFILE  = 'sqlite.rc'
+    RESFILE = 'sqlite.res'
--- a/dom/plugins/test/testplugin/testplugin.mk
+++ b/dom/plugins/test/testplugin/testplugin.mk
@@ -15,18 +15,16 @@ CXXFLAGS        += $(MOZ_QT_CFLAGS)
 CFLAGS          += $(MOZ_QT_CFLAGS)
 EXTRA_DSO_LDOPTS = \
                 $(MOZ_QT_LIBS) \
                 $(XLDFLAGS) \
                 $(XLIBS)
 endif
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
-RCFILE    = nptest.rc
-RESFILE   = nptest.res
 DEFFILE   = $(win_srcdir)/nptest.def
 OS_LIBS  += $(call EXPAND_LIBNAME,msimg32)
 
 # Windows opt builds without PGO break nptest.dll
 MOZ_OPTIMIZE=
 endif
 
 TEST_PLUGIN_FILES = $(SHARED_LIBRARY)
--- a/dom/plugins/test/testplugin/testplugin.mozbuild
+++ b/dom/plugins/test/testplugin/testplugin.mozbuild
@@ -37,8 +37,12 @@ elif toolkit == 'qt':
         relative_path + '/nptest_qt.cpp',
     ]
 elif toolkit == 'windows':
     UNIFIED_SOURCES += [
         relative_path + '/nptest_windows.cpp',
     ]
 
 FORCE_SHARED_LIB = True
+
+if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
+    RCFILE  = 'nptest.rc'
+    RESFILE = 'nptest.res'
--- a/dom/workers/File.cpp
+++ b/dom/workers/File.cpp
@@ -162,29 +162,31 @@ private:
   {
     JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
     return JS::CallNonGenericMethod<IsBlob, GetTypeImpl>(aCx, args);
   }
 
   static bool
   Slice(JSContext* aCx, unsigned aArgc, jsval* aVp)
   {
-    JS::Rooted<JSObject*> obj(aCx, JS_THIS_OBJECT(aCx, aVp));
+    JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
+
+    JS::Rooted<JSObject*> obj(aCx, args.thisv().toObjectOrNull());
     if (!obj) {
       return false;
     }
 
     nsIDOMBlob* blob = GetInstancePrivate(aCx, obj, "slice");
     if (!blob) {
       return false;
     }
 
     double start = 0, end = 0;
     JS::Rooted<JSString*> jsContentType(aCx, JS_GetEmptyString(JS_GetRuntime(aCx)));
-    if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "/IIS", &start,
+    if (!JS_ConvertArguments(aCx, args, "/IIS", &start,
                              &end, jsContentType.address())) {
       return false;
     }
 
     nsDependentJSString contentType;
     if (!contentType.init(aCx, jsContentType)) {
       return false;
     }
@@ -198,17 +200,17 @@ private:
       return Throw(aCx, NS_ERROR_DOM_FILE_NOT_READABLE_ERR);
     }
 
     JSObject* rtnObj = file::CreateBlob(aCx, rtnBlob);
     if (!rtnObj) {
       return false;
     }
 
-    JS_SET_RVAL(aCx, aVp, OBJECT_TO_JSVAL(rtnObj));
+    args.rval().setObject(*rtnObj);
     return true;
   }
 };
 
 const JSClass Blob::sClass = {
   "Blob",
   JSCLASS_HAS_PRIVATE,
   JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
--- a/embedding/components/printingui/src/win/nsPrintDialogUtil.cpp
+++ b/embedding/components/printingui/src/win/nsPrintDialogUtil.cpp
@@ -448,17 +448,17 @@ static HWND CreateControl(LPCTSTR       
 {
   nsAutoCString str;
   if (NS_FAILED(NS_CopyUnicodeToNative(aStr, str)))
     return nullptr;
 
   HWND hWnd = ::CreateWindow (aType, str.get(),
                               WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | aStyle,
                               aRect.x, aRect.y, aRect.width, aRect.height,
-                              (HWND)aHdlg, (HMENU)aId,
+                              (HWND)aHdlg, (HMENU)(intptr_t)aId,
                               aHInst, nullptr);
   if (hWnd == nullptr) return nullptr;
 
   // get the native font for the dialog and 
   // set it into the new control
   HFONT hFont = (HFONT)::SendMessage(aHdlg, WM_GETFONT, (WPARAM)0, (LPARAM)0);
   if (hFont != nullptr) {
     ::SendMessage(hWnd, WM_SETFONT, (WPARAM) hFont, (LPARAM)0);
--- a/embedding/tests/winEmbed/Makefile.in
+++ b/embedding/tests/winEmbed/Makefile.in
@@ -22,18 +22,16 @@
 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 # DEALINGS IN THE SOFTWARE.
 #
 # Contributor(s):
 #
 # ***** END LICENSE BLOCK *****
 
-RESFILE		= winEmbed.res
-
 LIBS = \
 	$(DEPTH)/profile/dirserviceprovider/standalone/$(LIB_PREFIX)profdirserviceprovidersa_s.$(LIB_SUFFIX) \
 	$(XPCOM_STANDALONE_GLUE_LDOPTS) \
 	$(NULL)
 
 STL_FLAGS=
 
 OS_LIBS		+= $(call EXPAND_LIBNAME,ole32 comdlg32 shell32 version)
--- a/embedding/tests/winEmbed/moz.build
+++ b/embedding/tests/winEmbed/moz.build
@@ -10,8 +10,10 @@ SOURCES += [
     'WebBrowserChrome.cpp',
     'WindowCreator.cpp',
     'winEmbed.cpp',
 ]
 
 XPI_NAME = 'winembed'
 
 DEFINES['XPCOM_GLUE'] = True
+
+RESFILE = 'winEmbed.res'
--- a/gfx/angle/src/libEGL/Makefile.in
+++ b/gfx/angle/src/libEGL/Makefile.in
@@ -9,17 +9,16 @@ ifndef GNU_CC
 # Enable unwind semantics for exception handlers in response to warning C4530.
 OS_CPPFLAGS += -EHsc
 endif
 
 # Below is a transcription of the EGL target from build_angle.gypi.
 # Target: 'libEGL'
 #   Links with: 'libGLESv2'
 DEFFILE = $(srcdir)/libEGL.def
-RCFILE  = $(srcdir)/libEGL.rc
 
 include $(topsrcdir)/config/rules.mk
 
 CXXFLAGS += -I'$(MOZ_DIRECTX_SDK_PATH)/include'
 
 #OS_LIBS += $(call EXPAND_LIBNAME,dwmapi)
 
 ifdef GNU_CC
--- a/gfx/angle/src/libEGL/moz.build
+++ b/gfx/angle/src/libEGL/moz.build
@@ -37,8 +37,10 @@ LOCAL_INCLUDES += [
 for var in ('LIBEGL_EXPORTS', 'ANGLE_BUILD', 'NOMINMAX',
             '_CRT_SECURE_NO_DEPRECATE', 'ANGLE_DISABLE_TRACE'):
     DEFINES[var] = True
 
 if not CONFIG['MOZ_DEBUG']:
     DEFINES['_SECURE_SCL'] = 0
 
 DEFINES['ANGLE_COMPILE_OPTIMIZATION_LEVEL'] = 'D3DCOMPILE_OPTIMIZATION_LEVEL1'
+
+RCFILE = SRCDIR + '/libEGL.rc'
--- a/gfx/angle/src/libGLESv2/Makefile.in
+++ b/gfx/angle/src/libGLESv2/Makefile.in
@@ -6,17 +6,16 @@
 STL_FLAGS =
 
 ifndef GNU_CC
 # Enable unwind semantics for exception handlers in response to warning C4530.
 OS_CPPFLAGS += -EHsc
 endif
 
 DEFFILE = $(srcdir)/libGLESv2.def
-RCFILE  = $(srcdir)/libGLESv2.rc
 
 # End build_angle.gypi transcription.
 
 include $(topsrcdir)/config/rules.mk
 
 CXXFLAGS += -I'$(MOZ_DIRECTX_SDK_PATH)/include'
 
 ifdef GNU_CC
--- a/gfx/angle/src/libGLESv2/moz.build
+++ b/gfx/angle/src/libGLESv2/moz.build
@@ -188,8 +188,10 @@ for var in ('LIBGLESV2_EXPORTS', 'ANGLE_
             '_CRT_SECURE_NO_DEPRECATE', 'ANGLE_DISABLE_TRACE',
             'COMPILER_IMPLEMENTATION'):
     DEFINES[var] = True
 
 if not CONFIG['MOZ_DEBUG']:
     DEFINES['_SECURE_SCL'] = 0
 
 DEFINES['ANGLE_COMPILE_OPTIMIZATION_LEVEL'] = 'D3DCOMPILE_OPTIMIZATION_LEVEL1'
+
+RCFILE = SRCDIR + '/libGLESv2.rc'
--- a/gfx/ipc/GfxMessageUtils.h
+++ b/gfx/ipc/GfxMessageUtils.h
@@ -614,19 +614,20 @@ struct ParamTraits<mozilla::layers::Fram
     WriteParam(aMsg, aParam.mResolution);
     WriteParam(aMsg, aParam.mCumulativeResolution);
     WriteParam(aMsg, aParam.mZoom);
     WriteParam(aMsg, aParam.mDevPixelsPerCSSPixel);
     WriteParam(aMsg, aParam.mMayHaveTouchListeners);
     WriteParam(aMsg, aParam.mPresShellId);
     WriteParam(aMsg, aParam.mIsRoot);
     WriteParam(aMsg, aParam.mHasScrollgrab);
-    WriteParam(aMsg, aParam.mUpdateScrollOffset);
     WriteParam(aMsg, aParam.mDisableScrollingX);
     WriteParam(aMsg, aParam.mDisableScrollingY);
+    WriteParam(aMsg, aParam.mUpdateScrollOffset);
+    WriteParam(aMsg, aParam.mScrollGeneration);
   }
 
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
     return (ReadParam(aMsg, aIter, &aResult->mScrollableRect) &&
             ReadParam(aMsg, aIter, &aResult->mViewport) &&
             ReadParam(aMsg, aIter, &aResult->mScrollOffset) &&
             ReadParam(aMsg, aIter, &aResult->mDisplayPort) &&
@@ -636,19 +637,20 @@ struct ParamTraits<mozilla::layers::Fram
             ReadParam(aMsg, aIter, &aResult->mResolution) &&
             ReadParam(aMsg, aIter, &aResult->mCumulativeResolution) &&
             ReadParam(aMsg, aIter, &aResult->mZoom) &&
             ReadParam(aMsg, aIter, &aResult->mDevPixelsPerCSSPixel) &&
             ReadParam(aMsg, aIter, &aResult->mMayHaveTouchListeners) &&
             ReadParam(aMsg, aIter, &aResult->mPresShellId) &&
             ReadParam(aMsg, aIter, &aResult->mIsRoot) &&
             ReadParam(aMsg, aIter, &aResult->mHasScrollgrab) &&
+            ReadParam(aMsg, aIter, &aResult->mDisableScrollingX) &&
+            ReadParam(aMsg, aIter, &aResult->mDisableScrollingY) &&
             ReadParam(aMsg, aIter, &aResult->mUpdateScrollOffset) &&
-            ReadParam(aMsg, aIter, &aResult->mDisableScrollingX) &&
-            ReadParam(aMsg, aIter, &aResult->mDisableScrollingY));
+            ReadParam(aMsg, aIter, &aResult->mScrollGeneration));
   }
 };
 
 template<>
 struct ParamTraits<mozilla::layers::TextureFactoryIdentifier>
 {
   typedef mozilla::layers::TextureFactoryIdentifier paramType;
 
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -145,17 +145,31 @@ CreateTextureHostD3D11(const SurfaceDesc
 TextureClientD3D11::TextureClientD3D11(gfx::SurfaceFormat aFormat, TextureFlags aFlags)
   : TextureClient(aFlags)
   , mFormat(aFormat)
   , mIsLocked(false)
   , mNeedsClear(false)
 {}
 
 TextureClientD3D11::~TextureClientD3D11()
-{}
+{
+#ifdef DEBUG
+  // An Azure DrawTarget needs to be locked when it gets nullptr'ed as this is
+  // when it calls EndDraw. This EndDraw should not execute anything so it
+  // shouldn't -really- need the lock but the debug layer chokes on this.
+  if (mDrawTarget) {
+    MOZ_ASSERT(!mIsLocked);
+    MOZ_ASSERT(mTexture);
+    MOZ_ASSERT(mDrawTarget->refCount() == 1);
+    LockD3DTexture(mTexture.get());
+    mDrawTarget = nullptr;
+    UnlockD3DTexture(mTexture.get());
+  }
+#endif
+}
 
 bool
 TextureClientD3D11::Lock(OpenMode aMode)
 {
   MOZ_ASSERT(!mIsLocked, "The Texture is already locked!");
   LockD3DTexture(mTexture.get());
   mIsLocked = true;
 
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -61,26 +61,26 @@
 
 // #define APZC_ENABLE_RENDERTRACE
 
 #define APZC_LOG(...)
 // #define APZC_LOG(...) printf_stderr("APZC: " __VA_ARGS__)
 #define APZC_LOG_FM(fm, prefix, ...) \
   APZC_LOG(prefix ":" \
            " i=(%ld %lld) cb=(%d %d %d %d) dp=(%.3f %.3f %.3f %.3f) v=(%.3f %.3f %.3f %.3f) " \
-           "s=(%.3f %.3f) sr=(%.3f %.3f %.3f %.3f) z=(%.3f %.3f %.3f %.3f) %d\n", \
+           "s=(%.3f %.3f) sr=(%.3f %.3f %.3f %.3f) z=(%.3f %.3f %.3f %.3f) u=(%d %llu)\n", \
            __VA_ARGS__, \
            fm.mPresShellId, fm.mScrollId, \
            fm.mCompositionBounds.x, fm.mCompositionBounds.y, fm.mCompositionBounds.width, fm.mCompositionBounds.height, \
            fm.mDisplayPort.x, fm.mDisplayPort.y, fm.mDisplayPort.width, fm.mDisplayPort.height, \
            fm.mViewport.x, fm.mViewport.y, fm.mViewport.width, fm.mViewport.height, \
            fm.mScrollOffset.x, fm.mScrollOffset.y, \
            fm.mScrollableRect.x, fm.mScrollableRect.y, fm.mScrollableRect.width, fm.mScrollableRect.height, \
            fm.mDevPixelsPerCSSPixel.scale, fm.mResolution.scale, fm.mCumulativeResolution.scale, fm.mZoom.scale, \
-           fm.GetScrollOffsetUpdated()); \
+           fm.GetScrollOffsetUpdated(), fm.GetScrollGeneration()); \
 
 // Static helper functions
 namespace {
 
 int32_t
 WidgetModifiersToDOMModifiers(mozilla::Modifiers aModifiers)
 {
   int32_t result = 0;
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -1570,17 +1570,17 @@ public:
 
     nsRefPtr<IDWriteFontCollection> mSystemFonts;
 };
 
 void
 DirectWriteFontInfo::LoadFontFamilyData(const nsAString& aFamilyName)
 {
     // lookup the family
-    nsAutoTArray<char16_t, 32> famName;
+    nsAutoTArray<wchar_t, 32> famName;
 
     uint32_t len = aFamilyName.Length();
     famName.SetLength(len + 1);
     memcpy(famName.Elements(), aFamilyName.BeginReading(), len * sizeof(char16_t));
     famName[len] = 0;
 
     HRESULT hr;
     BOOL exists = false;
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -217,21 +217,16 @@ DEFINES         += -D_CRT_RAND_S
 endif
 
 ifneq ($(findstring -L,$(NSPR_LIBS)),)
 NSPR_STATIC_PATH = $(subst -L,,$(findstring -L,$(NSPR_LIBS)))
 else
 NSPR_STATIC_PATH = $(DIST)/lib
 endif
 
-ifdef MOZ_ETW
-# This will get the ETW provider resources into the library mozjs.dll
-RESFILE = ETWProvider.res
-endif
-
 # HP-UX does not require the extra linking of "-lm"
 ifeq (,$(filter HP-UX WINNT OS2,$(OS_ARCH)))
 EXTRA_LIBS	+= -lm
 endif
 
 CFLAGS += $(MOZ_ZLIB_CFLAGS)
 EXTRA_LIBS += $(MOZ_ZLIB_LIBS)
 # Enable zlib usage if zlib has been located. When building the browser on
--- a/js/src/ctypes/Library.cpp
+++ b/js/src/ctypes/Library.cpp
@@ -102,17 +102,17 @@ Library::Create(JSContext* cx, jsval pat
 
   PRLibSpec libSpec;
   RootedFlatString pathStr(cx, JS_FlattenString(cx, JSVAL_TO_STRING(path)));
   if (!pathStr)
     return nullptr;
 #ifdef XP_WIN
   // On Windows, converting to native charset may corrupt path string.
   // So, we have to use Unicode path directly.
-  const char16_t* pathChars = JS_GetFlatStringChars(pathStr);
+  char16ptr_t pathChars = JS_GetFlatStringChars(pathStr);
   if (!pathChars)
     return nullptr;
 
   libSpec.value.pathname_u = pathChars;
   libSpec.type = PR_LibSpec_PathnameU;
 #else
   // Convert to platform native charset if the appropriate callback has been
   // provided.
--- a/js/src/jit/Bailouts.cpp
+++ b/js/src/jit/Bailouts.cpp
@@ -7,17 +7,17 @@
 #include "jit/Bailouts.h"
 
 #include "jscntxt.h"
 
 #include "jit/BaselineJIT.h"
 #include "jit/Ion.h"
 #include "jit/IonSpewer.h"
 #include "jit/JitCompartment.h"
-#include "jit/SnapshotReader.h"
+#include "jit/Snapshots.h"
 
 #include "jit/IonFrameIterator-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 // These constructor are exactly the same except for the type of the iterator
--- a/js/src/jit/Bailouts.h
+++ b/js/src/jit/Bailouts.h
@@ -86,19 +86,16 @@ namespace jit {
 // pointers. To account for this we segregate frames into a limited set of
 // "frame sizes", and create a table for each frame size. We also have the
 // option of not using bailout tables, for platforms or situations where the
 // 10 byte cost is more optimal than a bailout table. See IonFrames.h for more
 // detail.
 
 static const BailoutId INVALID_BAILOUT_ID = BailoutId(-1);
 
-static const uint32_t BAILOUT_KIND_BITS = 3;
-static const uint32_t BAILOUT_RESUME_BITS = 1;
-
 // Keep this arbitrarily small for now, for testing.
 static const uint32_t BAILOUT_TABLE_SIZE = 16;
 
 // Bailout return codes.
 // N.B. the relative order of these values is hard-coded into ::GenerateBailoutThunk.
 static const uint32_t BAILOUT_RETURN_OK = 0;
 static const uint32_t BAILOUT_RETURN_FATAL_ERROR = 1;
 static const uint32_t BAILOUT_RETURN_OVERRECURSED = 2;
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -470,17 +470,17 @@ InitFromBailout(JSContext *cx, HandleScr
 {
     // If excInfo is non-nullptr, we are bailing out to a catch or finally block
     // and this is the frame where we will resume. Usually the expression stack
     // should be empty in this case but there can be iterators on the stack.
     uint32_t exprStackSlots;
     if (excInfo)
         exprStackSlots = excInfo->numExprSlots;
     else
-        exprStackSlots = iter.slots() - (script->nfixed() + CountArgSlots(script, fun));
+        exprStackSlots = iter.allocations() - (script->nfixed() + CountArgSlots(script, fun));
 
     builder.resetFramePushed();
 
     // Build first baseline frame:
     // +===============+
     // | PrevFramePtr  |
     // +---------------+
     // |   Baseline    |
@@ -618,19 +618,19 @@ InitFromBailout(JSContext *cx, HandleScr
         // in the calling frame.
         Value thisv = iter.read();
         IonSpew(IonSpew_BaselineBailouts, "      Is function!");
         IonSpew(IonSpew_BaselineBailouts, "      thisv=%016llx", *((uint64_t *) &thisv));
 
         size_t thisvOffset = builder.framePushed() + IonJSFrameLayout::offsetOfThis();
         *builder.valuePointerAtStackOffset(thisvOffset) = thisv;
 
-        JS_ASSERT(iter.slots() >= CountArgSlots(script, fun));
+        JS_ASSERT(iter.allocations() >= CountArgSlots(script, fun));
         IonSpew(IonSpew_BaselineBailouts, "      frame slots %u, nargs %u, nfixed %u",
-                iter.slots(), fun->nargs(), script->nfixed());
+                iter.allocations(), fun->nargs(), script->nfixed());
 
         if (!callerPC) {
             // This is the first frame. Store the formals in a Vector until we
             // are done. Due to UCE and phi elimination, we could store an
             // UndefinedValue() here for formals we think are unused, but
             // locals may still reference the original argument slot
             // (MParameter/LArgument) and expect the original Value.
             JS_ASSERT(startFrameFormals.empty());
--- a/js/src/jit/IonCode.h
+++ b/js/src/jit/IonCode.h
@@ -23,24 +23,16 @@ namespace JSC {
 }
 
 namespace js {
 
 class AsmJSModule;
 
 namespace jit {
 
-// The maximum size of any buffer associated with an assembler or code object.
-// This is chosen to not overflow a signed integer, leaving room for an extra
-// bit on offsets.
-static const uint32_t MAX_BUFFER_SIZE = (1 << 30) - 1;
-
-// Maximum number of scripted arg slots.
-static const uint32_t SNAPSHOT_MAX_NARGS = 127;
-
 class MacroAssembler;
 class CodeOffsetLabel;
 class PatchableBackedge;
 
 class JitCode : public gc::BarrieredCell<JitCode>
 {
   protected:
     uint8_t *code_;
--- a/js/src/jit/IonFrameIterator.h
+++ b/js/src/jit/IonFrameIterator.h
@@ -8,17 +8,17 @@
 #define jit_IonFrameIterator_h
 
 #ifdef JS_ION
 
 #include "jsscript.h"
 #include "jstypes.h"
 
 #include "jit/IonCode.h"
-#include "jit/SnapshotReader.h"
+#include "jit/Snapshots.h"
 
 namespace js {
     class ActivationIterator;
 };
 
 namespace js {
 namespace jit {
 
@@ -232,39 +232,48 @@ class IonBailoutIterator;
 // to innermost frame).
 class SnapshotIterator : public SnapshotReader
 {
     IonJSFrameLayout *fp_;
     MachineState machine_;
     IonScript *ionScript_;
 
   private:
-    bool hasLocation(const SnapshotReader::Location &loc);
-    uintptr_t fromLocation(const SnapshotReader::Location &loc);
+    // Read a spilled register from the machine state.
+    bool hasRegister(const Location &loc);
+    uintptr_t fromRegister(const Location &loc);
 
-    Value slotValue(const Slot &slot);
-    bool slotReadable(const Slot &slot);
-    void warnUnreadableSlot();
+    // Read an uintptr_t from the stack.
+    bool hasStack(const Location &loc);
+    uintptr_t fromStack(const Location &loc);
+
+    Value allocationValue(const RValueAllocation &a);
+    bool allocationReadable(const RValueAllocation &a);
+    void warnUnreadableAllocation();
 
   public:
     SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshotOffset,
                      IonJSFrameLayout *fp, const MachineState &machine);
     SnapshotIterator(const IonFrameIterator &iter);
     SnapshotIterator(const IonBailoutIterator &iter);
     SnapshotIterator();
 
+    Value skip() {
+        readAllocation();
+        return UndefinedValue();
+    }
     Value read() {
-        return slotValue(readSlot());
+        return allocationValue(readAllocation());
     }
     Value maybeRead(bool silentFailure = false) {
-        Slot s = readSlot();
-        if (slotReadable(s))
-            return slotValue(s);
+        RValueAllocation a = readAllocation();
+        if (allocationReadable(a))
+            return allocationValue(a);
         if (!silentFailure)
-            warnUnreadableSlot();
+            warnUnreadableAllocation();
         return UndefinedValue();
     }
 
     template <class Op>
     void readFrameArgs(Op &op, const Value *argv, Value *scopeChain, Value *thisv,
                        unsigned start, unsigned formalEnd, unsigned iterEnd, JSScript *script)
     {
         if (scopeChain)
@@ -298,25 +307,25 @@ class SnapshotIterator : public Snapshot
             op(v);
         }
         if (iterEnd >= formalEnd) {
             for (; i < iterEnd; i++)
                 op(argv[i]);
         }
     }
 
-    Value maybeReadSlotByIndex(size_t index) {
+    Value maybeReadAllocByIndex(size_t index) {
         while (index--) {
-            JS_ASSERT(moreSlots());
+            JS_ASSERT(moreAllocations());
             skip();
         }
 
         Value s = maybeRead(true);
 
-        while (moreSlots())
+        while (moreAllocations())
             skip();
 
         return s;
     }
 };
 
 // Reads frame information in callstack order (that is, innermost frame to
 // outermost frame).
@@ -417,18 +426,18 @@ class InlineFrameIteratorMaybeGC
             // They are the last pushed arguments in the parent frame of this inlined frame.
             InlineFrameIteratorMaybeGC it(cx, this);
             ++it;
             unsigned argsObjAdj = it.script()->argumentsHasVarBinding() ? 1 : 0;
             SnapshotIterator parent_s(it.snapshotIterator());
 
             // Skip over all slots untill we get to the last slots (= arguments slots of callee)
             // the +3 is for [this], [returnvalue], [scopechain], and maybe +1 for [argsObj]
-            JS_ASSERT(parent_s.slots() >= nactual + 3 + argsObjAdj);
-            unsigned skip = parent_s.slots() - nactual - 3 - argsObjAdj;
+            JS_ASSERT(parent_s.allocations() >= nactual + 3 + argsObjAdj);
+            unsigned skip = parent_s.allocations() - nactual - 3 - argsObjAdj;
             for (unsigned j = 0; j < skip; j++)
                 parent_s.skip();
 
             // Get the overflown arguments
             parent_s.readFrameArgs(op, nullptr, nullptr, nullptr, nformal, nactual, end, it.script());
         } else {
             SnapshotIterator s(si_);
             Value *argv = frame_->actualArgs();
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -16,17 +16,17 @@
 #include "jit/BaselineJIT.h"
 #include "jit/Ion.h"
 #include "jit/IonMacroAssembler.h"
 #include "jit/IonSpewer.h"
 #include "jit/JitCompartment.h"
 #include "jit/ParallelFunctions.h"
 #include "jit/PcScriptCache.h"
 #include "jit/Safepoints.h"
-#include "jit/SnapshotReader.h"
+#include "jit/Snapshots.h"
 #include "jit/VMFunctions.h"
 #include "vm/ForkJoin.h"
 #include "vm/Interpreter.h"
 
 #include "jit/IonFrameIterator-inl.h"
 #include "vm/Probes-inl.h"
 
 namespace js {
@@ -1314,27 +1314,38 @@ SnapshotIterator::SnapshotIterator(const
 SnapshotIterator::SnapshotIterator()
   : SnapshotReader(nullptr, nullptr),
     fp_(nullptr),
     ionScript_(nullptr)
 {
 }
 
 bool
-SnapshotIterator::hasLocation(const SnapshotReader::Location &loc)
+SnapshotIterator::hasRegister(const Location &loc)
 {
-    return loc.isStackSlot() || machine_.has(loc.reg());
+    return machine_.has(loc.reg());
 }
 
 uintptr_t
-SnapshotIterator::fromLocation(const SnapshotReader::Location &loc)
+SnapshotIterator::fromRegister(const Location &loc)
+{
+    return machine_.read(loc.reg());
+}
+
+bool
+SnapshotIterator::hasStack(const Location &loc)
 {
-    if (loc.isStackSlot())
-        return ReadFrameSlot(fp_, loc.stackSlot());
-    return machine_.read(loc.reg());
+    JS_ASSERT(loc.isStackOffset());
+    return true;
+}
+
+uintptr_t
+SnapshotIterator::fromStack(const Location &loc)
+{
+    return ReadFrameSlot(fp_, loc.stackOffset());
 }
 
 static Value
 FromObjectPayload(uintptr_t payload)
 {
     return ObjectValue(*reinterpret_cast<JSObject *>(payload));
 }
 
@@ -1357,103 +1368,148 @@ FromTypedPayload(JSValueType type, uintp
       case JSVAL_TYPE_OBJECT:
         return FromObjectPayload(payload);
       default:
         MOZ_ASSUME_UNREACHABLE("unexpected type - needs payload");
     }
 }
 
 bool
-SnapshotIterator::slotReadable(const Slot &slot)
+SnapshotIterator::allocationReadable(const RValueAllocation &alloc)
 {
-    switch (slot.mode()) {
-      case SnapshotReader::DOUBLE_REG:
-        return machine_.has(slot.floatReg());
+    switch (alloc.mode()) {
+      case RValueAllocation::DOUBLE_REG:
+        return machine_.has(alloc.floatReg());
+
+      case RValueAllocation::TYPED_REG:
+        return machine_.has(alloc.reg());
 
-      case SnapshotReader::TYPED_REG:
-        return machine_.has(slot.reg());
-
-      case SnapshotReader::UNTYPED:
 #if defined(JS_NUNBOX32)
-          return hasLocation(slot.type()) && hasLocation(slot.payload());
+      case RValueAllocation::UNTYPED_REG_REG:
+        return hasRegister(alloc.type()) && hasRegister(alloc.payload());
+      case RValueAllocation::UNTYPED_REG_STACK:
+        return hasRegister(alloc.type()) && hasStack(alloc.payload());
+      case RValueAllocation::UNTYPED_STACK_REG:
+        return hasStack(alloc.type()) && hasRegister(alloc.payload());
+      case RValueAllocation::UNTYPED_STACK_STACK:
+        return hasStack(alloc.type()) && hasStack(alloc.payload());
 #elif defined(JS_PUNBOX64)
-          return hasLocation(slot.value());
+      case RValueAllocation::UNTYPED_REG:
+        return hasRegister(alloc.value());
+      case RValueAllocation::UNTYPED_STACK:
+        return hasStack(alloc.value());
 #endif
 
       default:
         return true;
     }
 }
 
 Value
-SnapshotIterator::slotValue(const Slot &slot)
+SnapshotIterator::allocationValue(const RValueAllocation &alloc)
 {
-    switch (slot.mode()) {
-      case SnapshotReader::DOUBLE_REG:
-        return DoubleValue(machine_.read(slot.floatReg()));
+    switch (alloc.mode()) {
+      case RValueAllocation::DOUBLE_REG:
+        return DoubleValue(machine_.read(alloc.floatReg()));
 
-      case SnapshotReader::FLOAT32_REG:
+      case RValueAllocation::FLOAT32_REG:
       {
         union {
             double d;
             float f;
         } pun;
-        pun.d = machine_.read(slot.floatReg());
+        pun.d = machine_.read(alloc.floatReg());
         // The register contains the encoding of a float32. We just read
         // the bits without making any conversion.
         return Float32Value(pun.f);
       }
 
-      case SnapshotReader::FLOAT32_STACK:
-        return Float32Value(ReadFrameFloat32Slot(fp_, slot.stackSlot()));
+      case RValueAllocation::FLOAT32_STACK:
+        return Float32Value(ReadFrameFloat32Slot(fp_, alloc.stackOffset()));
 
-      case SnapshotReader::TYPED_REG:
-        return FromTypedPayload(slot.knownType(), machine_.read(slot.reg()));
+      case RValueAllocation::TYPED_REG:
+        return FromTypedPayload(alloc.knownType(), machine_.read(alloc.reg()));
 
-      case SnapshotReader::TYPED_STACK:
+      case RValueAllocation::TYPED_STACK:
       {
-        switch (slot.knownType()) {
+        switch (alloc.knownType()) {
           case JSVAL_TYPE_DOUBLE:
-            return DoubleValue(ReadFrameDoubleSlot(fp_, slot.stackSlot()));
+            return DoubleValue(ReadFrameDoubleSlot(fp_, alloc.stackOffset()));
           case JSVAL_TYPE_INT32:
-            return Int32Value(ReadFrameInt32Slot(fp_, slot.stackSlot()));
+            return Int32Value(ReadFrameInt32Slot(fp_, alloc.stackOffset()));
           case JSVAL_TYPE_BOOLEAN:
-            return BooleanValue(ReadFrameBooleanSlot(fp_, slot.stackSlot()));
+            return BooleanValue(ReadFrameBooleanSlot(fp_, alloc.stackOffset()));
           case JSVAL_TYPE_STRING:
-            return FromStringPayload(ReadFrameSlot(fp_, slot.stackSlot()));
+            return FromStringPayload(ReadFrameSlot(fp_, alloc.stackOffset()));
           case JSVAL_TYPE_OBJECT:
-            return FromObjectPayload(ReadFrameSlot(fp_, slot.stackSlot()));
+            return FromObjectPayload(ReadFrameSlot(fp_, alloc.stackOffset()));
           default:
             MOZ_ASSUME_UNREACHABLE("Unexpected type");
         }
       }
 
-      case SnapshotReader::UNTYPED:
+#if defined(JS_NUNBOX32)
+      case RValueAllocation::UNTYPED_REG_REG:
+      {
+        jsval_layout layout;
+        layout.s.tag = (JSValueTag) fromRegister(alloc.type());
+        layout.s.payload.word = fromRegister(alloc.payload());
+        return IMPL_TO_JSVAL(layout);
+      }
+
+      case RValueAllocation::UNTYPED_REG_STACK:
       {
-          jsval_layout layout;
-#if defined(JS_NUNBOX32)
-          layout.s.tag = (JSValueTag)fromLocation(slot.type());
-          layout.s.payload.word = fromLocation(slot.payload());
-#elif defined(JS_PUNBOX64)
-          layout.asBits = fromLocation(slot.value());
-#endif
-          return IMPL_TO_JSVAL(layout);
+        jsval_layout layout;
+        layout.s.tag = (JSValueTag) fromRegister(alloc.type());
+        layout.s.payload.word = fromStack(alloc.payload());
+        return IMPL_TO_JSVAL(layout);
+      }
+
+      case RValueAllocation::UNTYPED_STACK_REG:
+      {
+        jsval_layout layout;
+        layout.s.tag = (JSValueTag) fromStack(alloc.type());
+        layout.s.payload.word = fromRegister(alloc.payload());
+        return IMPL_TO_JSVAL(layout);
       }
 
-      case SnapshotReader::JS_UNDEFINED:
+      case RValueAllocation::UNTYPED_STACK_STACK:
+      {
+        jsval_layout layout;
+        layout.s.tag = (JSValueTag) fromStack(alloc.type());
+        layout.s.payload.word = fromStack(alloc.payload());
+        return IMPL_TO_JSVAL(layout);
+      }
+#elif defined(JS_PUNBOX64)
+      case RValueAllocation::UNTYPED_REG:
+      {
+        jsval_layout layout;
+        layout.asBits = fromRegister(alloc.value());
+        return IMPL_TO_JSVAL(layout);
+      }
+
+      case RValueAllocation::UNTYPED_STACK:
+      {
+        jsval_layout layout;
+        layout.asBits = fromStack(alloc.value());
+        return IMPL_TO_JSVAL(layout);
+      }
+#endif
+
+      case RValueAllocation::JS_UNDEFINED:
         return UndefinedValue();
 
-      case SnapshotReader::JS_NULL:
+      case RValueAllocation::JS_NULL:
         return NullValue();
 
-      case SnapshotReader::JS_INT32:
-        return Int32Value(slot.int32Value());
+      case RValueAllocation::JS_INT32:
+        return Int32Value(alloc.int32Value());
 
-      case SnapshotReader::CONSTANT:
-        return ionScript_->getConstant(slot.constantIndex());
+      case RValueAllocation::CONSTANT:
+        return ionScript_->getConstant(alloc.constantIndex());
 
       default:
         MOZ_ASSUME_UNREACHABLE("huh?");
     }
 }
 
 IonScript *
 IonFrameIterator::ionScript() const
@@ -1534,24 +1590,24 @@ InlineFrameIteratorMaybeGC<allowGC>::fin
             numActualArgs_ = 0;
         } else if (IsSetPropPC(pc_)) {
             numActualArgs_ = 1;
         }
 
         JS_ASSERT(numActualArgs_ != 0xbadbad);
 
         // Skip over non-argument slots, as well as |this|.
-        unsigned skipCount = (si_.slots() - 1) - numActualArgs_ - 1;
+        unsigned skipCount = (si_.allocations() - 1) - numActualArgs_ - 1;
         for (unsigned j = 0; j < skipCount; j++)
             si_.skip();
 
         Value funval = si_.read();
 
-        // Skip extra slots.
-        while (si_.moreSlots())
+        // Skip extra value allocations.
+        while (si_.moreAllocations())
             si_.skip();
 
         si_.nextFrame();
 
         callee_ = &funval.toObject().as<JSFunction>();
 
         // Inlined functions may be clones that still point to the lazy script
         // for the executed script, if they are clones. The actual script
@@ -1660,19 +1716,19 @@ IonFrameIterator::numActualArgs() const
     if (isScripted())
         return jsFrame()->numActualArgs();
 
     JS_ASSERT(isNative());
     return exitFrame()->nativeExit()->argc();
 }
 
 void
-SnapshotIterator::warnUnreadableSlot()
+SnapshotIterator::warnUnreadableAllocation()
 {
-    fprintf(stderr, "Warning! Tried to access unreadable IonMonkey slot (possible f.arguments).\n");
+    fprintf(stderr, "Warning! Tried to access unreadable value allocation (possible f.arguments).\n");
 }
 
 struct DumpOp {
     DumpOp(unsigned int i) : i_(i) {}
 
     unsigned int i_;
     void operator()(const Value& v) {
         fprintf(stderr, "  actual (arg %d): ", i_);
@@ -1756,18 +1812,18 @@ InlineFrameIteratorMaybeGC<allowGC>::dum
     fprintf(stderr, "  script = %p, pc = %p\n", (void*) script(), pc());
     fprintf(stderr, "  current op: %s\n", js_CodeName[*pc()]);
 
     if (!more()) {
         numActualArgs();
     }
 
     SnapshotIterator si = snapshotIterator();
-    fprintf(stderr, "  slots: %u\n", si.slots() - 1);
-    for (unsigned i = 0; i < si.slots() - 1; i++) {
+    fprintf(stderr, "  slots: %u\n", si.allocations() - 1);
+    for (unsigned i = 0; i < si.allocations() - 1; i++) {
         if (isFunction) {
             if (i == 0)
                 fprintf(stderr, "  scope chain: ");
             else if (i == 1)
                 fprintf(stderr, "  this: ");
             else if (i - 2 < callee()->nargs())
                 fprintf(stderr, "  formal (arg %d): ", i - 2);
             else {
--- a/js/src/jit/IonTypes.h
+++ b/js/src/jit/IonTypes.h
@@ -12,16 +12,24 @@
 #include "js/Value.h"
 
 namespace js {
 namespace jit {
 
 typedef uint32_t SnapshotOffset;
 typedef uint32_t BailoutId;
 
+// The maximum size of any buffer associated with an assembler or code object.
+// This is chosen to not overflow a signed integer, leaving room for an extra
+// bit on offsets.
+static const uint32_t MAX_BUFFER_SIZE = (1 << 30) - 1;
+
+// Maximum number of scripted arg slots.
+static const uint32_t SNAPSHOT_MAX_NARGS = 127;
+
 static const SnapshotOffset INVALID_SNAPSHOT_OFFSET = uint32_t(-1);
 
 // Different kinds of bailouts. When extending this enum, make sure to check
 // the bits reserved for bailout kinds in Bailouts.h
 enum BailoutKind
 {
     // A normal bailout triggered from type, shape, and assorted overflow
     // guards in the compiler.
@@ -36,16 +44,19 @@ enum BailoutKind
 
     // A shape guard based on TI information failed.
     Bailout_ShapeGuard,
 
     // A bailout caused by invalid assumptions based on Baseline code.
     Bailout_BaselineInfo
 };
 
+static const uint32_t BAILOUT_KIND_BITS = 3;
+static const uint32_t BAILOUT_RESUME_BITS = 1;
+
 #ifdef DEBUG
 inline const char *
 BailoutKindString(BailoutKind kind)
 {
     switch (kind) {
       case Bailout_Normal:
         return "Bailout_Normal";
       case Bailout_ArgumentCheck:
deleted file mode 100644
--- a/js/src/jit/SnapshotReader.h
+++ /dev/null
@@ -1,250 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef jit_SnapshotReader_h
-#define jit_SnapshotReader_h
-
-#include "jit/CompactBuffer.h"
-#include "jit/IonCode.h"
-#include "jit/IonTypes.h"
-#include "jit/Registers.h"
-
-namespace js {
-namespace jit {
-
-#ifdef TRACK_SNAPSHOTS
-class LInstruction;
-#endif
-
-// A snapshot reader reads the entries out of the compressed snapshot buffer in
-// a script. These entries describe the stack state of an Ion frame at a given
-// position in JIT code.
-class SnapshotReader
-{
-    CompactBufferReader reader_;
-
-    uint32_t pcOffset_;           // Offset from script->code.
-    uint32_t slotCount_;          // Number of slots.
-    uint32_t frameCount_;
-    BailoutKind bailoutKind_;
-    uint32_t framesRead_;         // Number of frame headers that have been read.
-    uint32_t slotsRead_;          // Number of slots that have been read.
-    bool resumeAfter_;
-
-#ifdef TRACK_SNAPSHOTS
-  private:
-    uint32_t pcOpcode_;
-    uint32_t mirOpcode_;
-    uint32_t mirId_;
-    uint32_t lirOpcode_;
-    uint32_t lirId_;
-  public:
-    void spewBailingFrom() const;
-#endif
-
-  private:
-
-    void readSnapshotHeader();
-    void readFrameHeader();
-
-  public:
-    enum SlotMode
-    {
-        CONSTANT,           // An index into the constant pool.
-        DOUBLE_REG,         // Type is double, payload is in a register.
-        FLOAT32_REG,        // Type is float32, payload is in a register.
-        FLOAT32_STACK,      // Type is float32, payload is on the stack.
-        TYPED_REG,          // Type is constant, payload is in a register.
-        TYPED_STACK,        // Type is constant, payload is on the stack.
-        UNTYPED,            // Type is not known.
-        JS_UNDEFINED,       // UndefinedValue()
-        JS_NULL,            // NullValue()
-        JS_INT32            // Int32Value(n)
-    };
-
-    class Location
-    {
-        friend class SnapshotReader;
-
-        // An offset that is illegal for a local variable's stack allocation.
-        static const int32_t InvalidStackSlot = -1;
-
-        Register::Code reg_;
-        int32_t stackSlot_;
-
-        static Location From(const Register &reg) {
-            Location loc;
-            loc.reg_ = reg.code();
-            loc.stackSlot_ = InvalidStackSlot;
-            return loc;
-        }
-        static Location From(int32_t stackSlot) {
-            JS_ASSERT(stackSlot != InvalidStackSlot);
-            Location loc;
-            loc.reg_ = Register::Code(0);      // Quell compiler warnings.
-            loc.stackSlot_ = stackSlot;
-            return loc;
-        }
-
-      public:
-        Register reg() const {
-            JS_ASSERT(!isStackSlot());
-            return Register::FromCode(reg_);
-        }
-        int32_t stackSlot() const {
-            JS_ASSERT(isStackSlot());
-            return stackSlot_;
-        }
-        bool isStackSlot() const {
-            return stackSlot_ != InvalidStackSlot;
-        }
-    };
-
-    class Slot
-    {
-        friend class SnapshotReader;
-
-        SlotMode mode_;
-
-        union {
-            FloatRegister::Code fpu_;
-            struct {
-                JSValueType type;
-                Location payload;
-            } known_type_;
-#if defined(JS_NUNBOX32)
-            struct {
-                Location type;
-                Location payload;
-            } unknown_type_;
-#elif defined(JS_PUNBOX64)
-            struct {
-                Location value;
-            } unknown_type_;
-#endif
-            int32_t value_;
-        };
-
-        Slot(SlotMode mode, JSValueType type, const Location &loc)
-          : mode_(mode)
-        {
-            known_type_.type = type;
-            known_type_.payload = loc;
-        }
-        Slot(const FloatRegister &reg)
-          : mode_(DOUBLE_REG)
-        {
-            fpu_ = reg.code();
-        }
-        Slot(SlotMode mode, const FloatRegister &reg)
-          : mode_(mode)
-        {
-            JS_ASSERT(mode == FLOAT32_REG);
-            fpu_ = reg.code();
-        }
-        Slot(SlotMode mode, const Location &loc)
-          : mode_(mode)
-        {
-            JS_ASSERT(mode == FLOAT32_STACK);
-            known_type_.payload = loc;
-        }
-        Slot(SlotMode mode)
-          : mode_(mode)
-        { }
-        Slot(SlotMode mode, uint32_t index)
-          : mode_(mode)
-        {
-            JS_ASSERT(mode == CONSTANT || mode == JS_INT32);
-            value_ = index;
-        }
-
-      public:
-        SlotMode mode() const {
-            return mode_;
-        }
-        uint32_t constantIndex() const {
-            JS_ASSERT(mode() == CONSTANT);
-            return value_;
-        }
-        int32_t int32Value() const {
-            JS_ASSERT(mode() == JS_INT32);
-            return value_;
-        }
-        JSValueType knownType() const {
-            JS_ASSERT(mode() == TYPED_REG || mode() == TYPED_STACK);
-            return known_type_.type;
-        }
-        Register reg() const {
-            JS_ASSERT(mode() == TYPED_REG && knownType() != JSVAL_TYPE_DOUBLE);
-            return known_type_.payload.reg();
-        }
-        FloatRegister floatReg() const {
-            JS_ASSERT(mode() == DOUBLE_REG || mode() == FLOAT32_REG);
-            return FloatRegister::FromCode(fpu_);
-        }
-        int32_t stackSlot() const {
-            JS_ASSERT(mode() == TYPED_STACK || mode() == FLOAT32_STACK);
-            return known_type_.payload.stackSlot();
-        }
-#if defined(JS_NUNBOX32)
-        Location payload() const {
-            JS_ASSERT(mode() == UNTYPED);
-            return unknown_type_.payload;
-        }
-        Location type() const {
-            JS_ASSERT(mode() == UNTYPED);
-            return unknown_type_.type;
-        }
-#elif defined(JS_PUNBOX64)
-        Location value() const {
-            JS_ASSERT(mode() == UNTYPED);
-            return unknown_type_.value;
-        }
-#endif
-    };
-
-  public:
-    SnapshotReader(const uint8_t *buffer, const uint8_t *end);
-
-    uint32_t pcOffset() const {
-        return pcOffset_;
-    }
-    uint32_t slots() const {
-        return slotCount_;
-    }
-    BailoutKind bailoutKind() const {
-        return bailoutKind_;
-    }
-    bool resumeAfter() const {
-        if (moreFrames())
-            return false;
-        return resumeAfter_;
-    }
-    bool moreFrames() const {
-        return framesRead_ < frameCount_;
-    }
-    void nextFrame() {
-        readFrameHeader();
-    }
-    Slot readSlot();
-
-    Value skip() {
-        readSlot();
-        return UndefinedValue();
-    }
-
-    bool moreSlots() const {
-        return slotsRead_ < slotCount_;
-    }
-    uint32_t frameCount() const {
-        return frameCount_;
-    }
-};
-
-}
-}
-
-#endif /* jit_SnapshotReader_h */
deleted file mode 100644
--- a/js/src/jit/SnapshotWriter.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef jit_SnapshotWriter_h
-#define jit_SnapshotWriter_h
-
-#include "jit/Bailouts.h"
-#include "jit/CompactBuffer.h"
-#include "jit/Ion.h"
-#include "jit/IonCode.h"
-#include "jit/Registers.h"
-
-namespace js {
-namespace jit {
-
-// Collects snapshots in a contiguous buffer, which is copied into IonScript
-// memory after code generation.
-class SnapshotWriter
-{
-    CompactBufferWriter writer_;
-
-    // These are only used to assert sanity.
-    uint32_t nslots_;
-    uint32_t slotsWritten_;
-    uint32_t nframes_;
-    uint32_t framesWritten_;
-    SnapshotOffset lastStart_;
-
-    void writeSlotHeader(JSValueType type, uint32_t regCode);
-
-  public:
-    SnapshotOffset startSnapshot(uint32_t frameCount, BailoutKind kind, bool resumeAfter);
-    void startFrame(JSFunction *fun, JSScript *script, jsbytecode *pc, uint32_t exprStack);
-#ifdef TRACK_SNAPSHOTS
-    void trackFrame(uint32_t pcOpcode, uint32_t mirOpcode, uint32_t mirId,
-                                     uint32_t lirOpcode, uint32_t lirId);
-#endif
-    void endFrame();
-
-    void addSlot(const FloatRegister &reg);
-    void addSlot(JSValueType type, const Register &reg);
-    void addSlot(JSValueType type, int32_t stackIndex);
-    void addUndefinedSlot();
-    void addNullSlot();
-    void addInt32Slot(int32_t value);
-    void addFloat32Slot(const FloatRegister &reg);
-    void addFloat32Slot(int32_t stackIndex);
-    void addConstantPoolSlot(uint32_t index);
-#if defined(JS_NUNBOX32)
-    void addSlot(const Register &type, const Register &payload);
-    void addSlot(const Register &type, int32_t payloadStackIndex);
-    void addSlot(int32_t typeStackIndex, const Register &payload);
-    void addSlot(int32_t typeStackIndex, int32_t payloadStackIndex);
-#elif defined(JS_PUNBOX64)
-    void addSlot(const Register &value);
-    void addSlot(int32_t valueStackSlot);
-#endif
-    void endSnapshot();
-
-    bool oom() const {
-        return writer_.oom() || writer_.length() >= MAX_BUFFER_SIZE;
-    }
-
-    size_t size() const {
-        return writer_.length();
-    }
-    const uint8_t *buffer() const {
-        return writer_.buffer();
-    }
-};
-
-}
-}
-
-#endif /* jit_SnapshotWriter_h */
--- a/js/src/jit/Snapshots.cpp
+++ b/js/src/jit/Snapshots.cpp
@@ -1,60 +1,62 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "jit/Snapshots.h"
+
 #include "jsscript.h"
 
+#include "jit/CompileInfo.h"
 #include "jit/IonSpewer.h"
 #ifdef TRACK_SNAPSHOTS
-#include "jit/LIR.h"
-#include "jit/MIR.h"
+# include "jit/LIR.h"
+# include "jit/MIR.h"
 #endif
-#include "jit/SnapshotReader.h"
-#include "jit/SnapshotWriter.h"
 
 using namespace js;
 using namespace js::jit;
 
 // Snapshot header:
 //
 //   [vwu] bits (n-31]: frame count
 //         bits [0,n):  bailout kind (n = BAILOUT_KIND_BITS)
 //
 // Snapshot body, repeated "frame count" times, from oldest frame to newest frame.
 // Note that the first frame doesn't have the "parent PC" field.
 //
 //   [ptr] Debug only: JSScript *
 //   [vwu] pc offset
 //   [vwu] # of slots, including nargs
-// [slot*] N slot entries, where N = nargs + nfixed + stackDepth
+//  [rva*] N recover value allocations entries,
+//             where N = nargs + nfixed + stackDepth
 //
 // Encodings:
 //   [ptr] A fixed-size pointer.
 //   [vwu] A variable-width unsigned integer.
 //   [vws] A variable-width signed integer.
 //    [u8] An 8-bit unsigned integer.
-// [slot*] Information on how to reify a js::Value from an Ion frame. The
-//         first byte is split as thus:
+//  [rva*] list of RValueAllocation which are indicating how to find a js::Value
+//         on a call/bailout. The first byte is split as thus:
 //           Bits 0-2: JSValueType
 //           Bits 3-7: 5-bit register code ("reg").
 //
 //         JSVAL_TYPE_DOUBLE:
 //              If "reg" is InvalidFloatReg, this byte is followed by a
 //              [vws] stack offset. Otherwise, "reg" encodes an XMM register.
 //
 //         JSVAL_TYPE_INT32:
 //         JSVAL_TYPE_OBJECT:
 //         JSVAL_TYPE_BOOLEAN:
 //         JSVAL_TYPE_STRING:
-//              If "reg" is InvalidReg1, this byte is followed by a [vws]
-//              stack offset. Otherwise, "reg" encodes a GPR register.
+//              If "reg" is ESC_REG_FIELD_INDEX, this byte is followed by a
+//              [vws] stack offset. Otherwise, "reg" encodes a GPR register.
 //
 //         JSVAL_TYPE_NULL:
 //              Reg value:
 //                 0-27: Constant integer; Int32Value(n)
 //                   28: Variable float32; Float register code
 //                   29: Variable float32; Stack index
 //                   30: NullValue()
 //                   31: Constant integer; Int32Value([vws])
@@ -81,27 +83,344 @@ using namespace js::jit;
 //                  Followed by a type and payload indicator that are one of
 //                  the following:
 //                   code=0 [vws] stack slot, [vws] stack slot
 //                   code=1 [vws] stack slot, reg
 //                   code=2 reg, [vws] stack slot
 //                   code=3 reg, reg
 //
 //              PUNBOX64:
-//                  "reg" is InvalidReg1: byte is followed by a [vws] stack
-//                  offset containing a Value.
+//                  "reg" is ESC_REG_FIELD_INDEX: byte is followed by a [vws]
+//                  stack offset containing a Value.
 //
 //                  Otherwise, "reg" is a register containing a Value.
-//        
+//
+
+#ifdef JS_NUNBOX32
+static const uint32_t NUNBOX32_STACK_STACK = 0;
+static const uint32_t NUNBOX32_STACK_REG   = 1;
+static const uint32_t NUNBOX32_REG_STACK   = 2;
+static const uint32_t NUNBOX32_REG_REG     = 3;
+#endif
+
+static const uint32_t MAX_TYPE_FIELD_VALUE = 7;
+
+static const uint32_t MAX_REG_FIELD_VALUE         = 31;
+static const uint32_t ESC_REG_FIELD_INDEX         = 31;
+static const uint32_t ESC_REG_FIELD_CONST         = 30;
+static const uint32_t ESC_REG_FIELD_FLOAT32_STACK = 29;
+static const uint32_t ESC_REG_FIELD_FLOAT32_REG   = 28;
+static const uint32_t MIN_REG_FIELD_ESC           = 28;
+
+RValueAllocation
+RValueAllocation::read(CompactBufferReader &reader)
+{
+    uint8_t b = reader.readByte();
+
+    JSValueType type = JSValueType(b & 0x7);
+    uint32_t code = b >> 3;
+
+    switch (type) {
+      case JSVAL_TYPE_DOUBLE:
+        if (code < MIN_REG_FIELD_ESC)
+            return Double(FloatRegister::FromCode(code));
+        JS_ASSERT(code == ESC_REG_FIELD_INDEX);
+        return Typed(type, reader.readSigned());
+
+      case JSVAL_TYPE_INT32:
+      case JSVAL_TYPE_STRING:
+      case JSVAL_TYPE_OBJECT:
+      case JSVAL_TYPE_BOOLEAN:
+        if (code < MIN_REG_FIELD_ESC)
+            return Typed(type, Register::FromCode(code));
+        JS_ASSERT(code == ESC_REG_FIELD_INDEX);
+        return Typed(type, reader.readSigned());
+
+      case JSVAL_TYPE_NULL:
+        if (code == ESC_REG_FIELD_CONST)
+            return Null();
+        if (code == ESC_REG_FIELD_INDEX)
+            return Int32(reader.readSigned());
+        if (code == ESC_REG_FIELD_FLOAT32_REG)
+            return Float32(FloatRegister::FromCode(reader.readUnsigned()));
+        if (code == ESC_REG_FIELD_FLOAT32_STACK)
+            return Float32(reader.readSigned());
+        return Int32(code);
+
+      case JSVAL_TYPE_UNDEFINED:
+        if (code == ESC_REG_FIELD_CONST)
+            return Undefined();
+        if (code == ESC_REG_FIELD_INDEX)
+            return ConstantPool(reader.readUnsigned());
+        return ConstantPool(code);
+
+      case JSVAL_TYPE_MAGIC:
+      {
+        if (code == ESC_REG_FIELD_CONST) {
+            uint8_t reg2 = reader.readUnsigned();
+            if (reg2 != ESC_REG_FIELD_INDEX)
+                return Typed(type, Register::FromCode(reg2));
+            return Typed(type, reader.readSigned());
+        }
+
+#ifdef JS_NUNBOX32
+        int32_t type, payload;
+        switch (code) {
+          case NUNBOX32_STACK_STACK:
+            type = reader.readSigned();
+            payload = reader.readSigned();
+            return Untyped(type, payload);
+          case NUNBOX32_STACK_REG:
+            type = reader.readSigned();
+            payload = reader.readByte();
+            return Untyped(type, Register::FromCode(payload));
+          case NUNBOX32_REG_STACK:
+            type = reader.readByte();
+            payload = reader.readSigned();
+            return Untyped(Register::FromCode(type), payload);
+          case NUNBOX32_REG_REG:
+            type = reader.readByte();
+            payload = reader.readByte();
+            return Untyped(Register::FromCode(type),
+                               Register::FromCode(payload));
+          default:
+            MOZ_ASSUME_UNREACHABLE("bad code");
+            break;
+        }
+#elif JS_PUNBOX64
+        if (code < MIN_REG_FIELD_ESC)
+            return Untyped(Register::FromCode(code));
+         JS_ASSERT(code == ESC_REG_FIELD_INDEX);
+         return Untyped(reader.readSigned());
+#endif
+      }
+
+      default:
+        MOZ_ASSUME_UNREACHABLE("bad type");
+        break;
+    }
+
+    MOZ_ASSUME_UNREACHABLE("huh?");
+}
+
+void
+RValueAllocation::writeHeader(CompactBufferWriter &writer,
+                              JSValueType type,
+                              uint32_t regCode) const
+{
+    JS_ASSERT(uint32_t(type) <= MAX_TYPE_FIELD_VALUE);
+    JS_ASSERT(uint32_t(regCode) <= MAX_REG_FIELD_VALUE);
+    JS_STATIC_ASSERT(Registers::Total < MIN_REG_FIELD_ESC);
+
+    uint8_t byte = uint32_t(type) | (regCode << 3);
+    writer.writeByte(byte);
+}
+
+void
+RValueAllocation::write(CompactBufferWriter &writer) const
+{
+    switch (mode()) {
+      case CONSTANT: {
+        if (constantIndex() < MIN_REG_FIELD_ESC) {
+            writeHeader(writer, JSVAL_TYPE_UNDEFINED, constantIndex());
+        } else {
+            writeHeader(writer, JSVAL_TYPE_UNDEFINED, ESC_REG_FIELD_INDEX);
+            writer.writeUnsigned(constantIndex());
+        }
+        break;
+      }
+
+      case DOUBLE_REG: {
+        writeHeader(writer, JSVAL_TYPE_DOUBLE, floatReg().code());
+        break;
+      }
+
+      case FLOAT32_REG: {
+        writeHeader(writer, JSVAL_TYPE_NULL, ESC_REG_FIELD_FLOAT32_REG);
+        writer.writeUnsigned(floatReg().code());
+        break;
+      }
+
+      case FLOAT32_STACK: {
+        writeHeader(writer, JSVAL_TYPE_NULL, ESC_REG_FIELD_FLOAT32_STACK);
+        writer.writeSigned(stackOffset());
+        break;
+      }
+
+      case TYPED_REG: {
+        writeHeader(writer, knownType(), reg().code());
+        break;
+      }
+      case TYPED_STACK: {
+        writeHeader(writer, knownType(), ESC_REG_FIELD_INDEX);
+        writer.writeSigned(stackOffset());
+        break;
+      }
+#if defined(JS_NUNBOX32)
+      case UNTYPED_REG_REG: {
+        writeHeader(writer, JSVAL_TYPE_MAGIC, NUNBOX32_REG_REG);
+        writer.writeByte(type().reg().code());
+        writer.writeByte(payload().reg().code());
+        break;
+      }
+      case UNTYPED_REG_STACK: {
+        writeHeader(writer, JSVAL_TYPE_MAGIC, NUNBOX32_REG_STACK);
+        writer.writeByte(type().reg().code());
+        writer.writeSigned(payload().stackOffset());
+        break;
+      }
+      case UNTYPED_STACK_REG: {
+        writeHeader(writer, JSVAL_TYPE_MAGIC, NUNBOX32_STACK_REG);
+        writer.writeSigned(type().stackOffset());
+        writer.writeByte(payload().reg().code());
+        break;
+      }
+      case UNTYPED_STACK_STACK: {
+        writeHeader(writer, JSVAL_TYPE_MAGIC, NUNBOX32_STACK_STACK);
+        writer.writeSigned(type().stackOffset());
+        writer.writeSigned(payload().stackOffset());
+        break;
+      }
+#elif defined(JS_PUNBOX64)
+      case UNTYPED_REG: {
+        writeHeader(writer, JSVAL_TYPE_MAGIC, value().reg().code());
+        break;
+      }
+      case UNTYPED_STACK: {
+        writeHeader(writer, JSVAL_TYPE_MAGIC, ESC_REG_FIELD_INDEX);
+        writer.writeSigned(value().stackOffset());
+        break;
+      }
+#endif
+      case JS_UNDEFINED: {
+        writeHeader(writer, JSVAL_TYPE_UNDEFINED, ESC_REG_FIELD_CONST);
+        break;
+      }
+      case JS_NULL: {
+        writeHeader(writer, JSVAL_TYPE_NULL, ESC_REG_FIELD_CONST);
+        break;
+      }
+      case JS_INT32: {
+        if (int32Value() >= 0 && uint32_t(int32Value()) < MIN_REG_FIELD_ESC) {
+            writeHeader(writer, JSVAL_TYPE_NULL, int32Value());
+        } else {
+            writeHeader(writer, JSVAL_TYPE_NULL, ESC_REG_FIELD_INDEX);
+            writer.writeSigned(int32Value());
+        }
+        break;
+      }
+      case INVALID: {
+        MOZ_ASSUME_UNREACHABLE("not initialized");
+        break;
+      }
+    }
+}
+
+void
+Location::dump(FILE *fp) const
+{
+    if (isStackOffset())
+        fprintf(fp, "stack %d", stackOffset());
+    else
+        fprintf(fp, "reg %s", reg().name());
+}
+
+static const char *
+ValTypeToString(JSValueType type)
+{
+    switch (type) {
+      case JSVAL_TYPE_INT32:
+        return "int32_t";
+      case JSVAL_TYPE_DOUBLE:
+        return "double";
+      case JSVAL_TYPE_STRING:
+        return "string";
+      case JSVAL_TYPE_BOOLEAN:
+        return "boolean";
+      case JSVAL_TYPE_OBJECT:
+        return "object";
+      case JSVAL_TYPE_MAGIC:
+        return "magic";
+      default:
+        MOZ_ASSUME_UNREACHABLE("no payload");
+    }
+}
+
+void
+RValueAllocation::dump(FILE *fp) const
+{
+    switch (mode()) {
+      case CONSTANT:
+        fprintf(fp, "constant (pool index %u)", constantIndex());
+        break;
+
+      case DOUBLE_REG:
+        fprintf(fp, "double (reg %s)", floatReg().name());
+        break;
+
+      case FLOAT32_REG:
+        fprintf(fp, "float32 (reg %s)", floatReg().name());
+        break;
+
+      case FLOAT32_STACK:
+        fprintf(fp, "float32 (");
+        known_type_.payload.dump(fp);
+        fprintf(fp, ")");
+        break;
+
+      case TYPED_REG:
+      case TYPED_STACK:
+        fprintf(fp, "%s (", ValTypeToString(knownType()));
+        known_type_.payload.dump(fp);
+        fprintf(fp, ")");
+        break;
+
+#if defined(JS_NUNBOX32)
+      case UNTYPED_REG_REG:
+      case UNTYPED_REG_STACK:
+      case UNTYPED_STACK_REG:
+      case UNTYPED_STACK_STACK:
+        fprintf(fp, "value (type = ");
+        type().dump(fp);
+        fprintf(fp, ", payload = ");
+        payload().dump(fp);
+        fprintf(fp, ")");
+        break;
+#elif defined(JS_PUNBOX64)
+      case UNTYPED_REG:
+      case UNTYPED_STACK:
+        fprintf(fp, "value (");
+        value().dump(fp);
+        fprintf(fp, ")");
+        break;
+#endif
+
+      case JS_UNDEFINED:
+        fprintf(fp, "undefined");
+        break;
+
+      case JS_NULL:
+        fprintf(fp, "null");
+        break;
+
+      case JS_INT32:
+        fprintf(fp, "int32_t %d", int32Value());
+        break;
+
+      case INVALID:
+        fprintf(fp, "invalid");
+        break;
+    }
+}
 
 SnapshotReader::SnapshotReader(const uint8_t *buffer, const uint8_t *end)
   : reader_(buffer, end),
-    slotCount_(0),
+    allocCount_(0),
     frameCount_(0),
-    slotsRead_(0)
+    allocRead_(0)
 {
     if (!buffer)
         return;
     IonSpew(IonSpew_Snapshots, "Creating snapshot reader");
     readSnapshotHeader();
     nextFrame();
 }
 
@@ -124,32 +443,31 @@ SnapshotReader::readSnapshotHeader()
     IonSpew(IonSpew_Snapshots, "Read snapshot header with frameCount %u, bailout kind %u (ra: %d)",
             frameCount_, bailoutKind_, resumeAfter_);
 }
 
 void
 SnapshotReader::readFrameHeader()
 {
     JS_ASSERT(moreFrames());
-    JS_ASSERT(slotsRead_ == slotCount_);
+    JS_ASSERT(allocRead_ == allocCount_);
 
     pcOffset_ = reader_.readUnsigned();
-    slotCount_ = reader_.readUnsigned();
-    IonSpew(IonSpew_Snapshots, "Read pc offset %u, nslots %u", pcOffset_, slotCount_);
-
+    allocCount_ = reader_.readUnsigned();
 #ifdef TRACK_SNAPSHOTS
     pcOpcode_  = reader_.readUnsigned();
     mirOpcode_ = reader_.readUnsigned();
     mirId_     = reader_.readUnsigned();
     lirOpcode_ = reader_.readUnsigned();
     lirId_     = reader_.readUnsigned();
 #endif
+    IonSpew(IonSpew_Snapshots, "Read pc offset %u, nslots %u", pcOffset_, allocCount_);
 
     framesRead_++;
-    slotsRead_ = 0;
+    allocRead_ = 0;
 }
 
 #ifdef TRACK_SNAPSHOTS
 void
 SnapshotReader::spewBailingFrom() const
 {
     if (IonSpewEnabled(IonSpew_Bailouts)) {
         IonSpewHeader(IonSpew_Bailouts);
@@ -158,126 +476,23 @@ SnapshotReader::spewBailingFrom() const
         fprintf(IonSpewFile, " [%u], LIR: ", mirId_);
         LInstruction::printName(IonSpewFile, LInstruction::Opcode(lirOpcode_));
         fprintf(IonSpewFile, " [%u]", lirId_);
         fprintf(IonSpewFile, "\n");
     }
 }
 #endif
 
-#ifdef JS_NUNBOX32
-static const uint32_t NUNBOX32_STACK_STACK = 0;
-static const uint32_t NUNBOX32_STACK_REG   = 1;
-static const uint32_t NUNBOX32_REG_STACK   = 2;
-static const uint32_t NUNBOX32_REG_REG     = 3;
-#endif
-
-static const uint32_t MAX_TYPE_FIELD_VALUE = 7;
-
-static const uint32_t MAX_REG_FIELD_VALUE         = 31;
-static const uint32_t ESC_REG_FIELD_INDEX         = 31;
-static const uint32_t ESC_REG_FIELD_CONST         = 30;
-static const uint32_t ESC_REG_FIELD_FLOAT32_STACK = 29;
-static const uint32_t ESC_REG_FIELD_FLOAT32_REG   = 28;
-static const uint32_t MIN_REG_FIELD_ESC           = 28;
-
-SnapshotReader::Slot
-SnapshotReader::readSlot()
+RValueAllocation
+SnapshotReader::readAllocation()
 {
-    JS_ASSERT(slotsRead_ < slotCount_);
-    IonSpew(IonSpew_Snapshots, "Reading slot %u", slotsRead_);
-    slotsRead_++;
-
-    uint8_t b = reader_.readByte();
-
-    JSValueType type = JSValueType(b & 0x7);
-    uint32_t code = b >> 3;
-
-    switch (type) {
-      case JSVAL_TYPE_DOUBLE:
-        if (code < MIN_REG_FIELD_ESC)
-            return Slot(FloatRegister::FromCode(code));
-        JS_ASSERT(code == ESC_REG_FIELD_INDEX);
-        return Slot(TYPED_STACK, type, Location::From(reader_.readSigned()));
-
-      case JSVAL_TYPE_INT32:
-      case JSVAL_TYPE_STRING:
-      case JSVAL_TYPE_OBJECT:
-      case JSVAL_TYPE_BOOLEAN:
-        if (code < MIN_REG_FIELD_ESC)
-            return Slot(TYPED_REG, type, Location::From(Register::FromCode(code)));
-        JS_ASSERT(code == ESC_REG_FIELD_INDEX);
-        return Slot(TYPED_STACK, type, Location::From(reader_.readSigned()));
-
-      case JSVAL_TYPE_NULL:
-        if (code == ESC_REG_FIELD_CONST)
-            return Slot(JS_NULL);
-        if (code == ESC_REG_FIELD_INDEX)
-            return Slot(JS_INT32, reader_.readSigned());
-        if (code == ESC_REG_FIELD_FLOAT32_REG)
-            return Slot(FLOAT32_REG, FloatRegister::FromCode(reader_.readUnsigned()));
-        if (code == ESC_REG_FIELD_FLOAT32_STACK)
-            return Slot(FLOAT32_STACK, Location::From(reader_.readSigned()));
-        return Slot(JS_INT32, code);
-
-      case JSVAL_TYPE_UNDEFINED:
-        if (code == ESC_REG_FIELD_CONST)
-            return Slot(JS_UNDEFINED);
-        if (code == ESC_REG_FIELD_INDEX)
-            return Slot(CONSTANT, reader_.readUnsigned());
-        return Slot(CONSTANT, code);
-
-      default:
-      {
-        JS_ASSERT(type == JSVAL_TYPE_MAGIC);
-
-        if (code == ESC_REG_FIELD_CONST) {
-            uint8_t reg2 = reader_.readUnsigned();
-            Location loc;
-            if (reg2 != ESC_REG_FIELD_INDEX)
-                loc = Location::From(Register::FromCode(reg2));
-            else
-                loc = Location::From(reader_.readSigned());
-            return Slot(TYPED_REG, type, loc);
-        }
-
-        Slot slot(UNTYPED);
-#ifdef JS_NUNBOX32
-        switch (code) {
-          case NUNBOX32_STACK_STACK:
-            slot.unknown_type_.type = Location::From(reader_.readSigned());
-            slot.unknown_type_.payload = Location::From(reader_.readSigned());
-            return slot;
-          case NUNBOX32_STACK_REG:
-            slot.unknown_type_.type = Location::From(reader_.readSigned());
-            slot.unknown_type_.payload = Location::From(Register::FromCode(reader_.readByte()));
-            return slot;
-          case NUNBOX32_REG_STACK:
-            slot.unknown_type_.type = Location::From(Register::FromCode(reader_.readByte()));
-            slot.unknown_type_.payload = Location::From(reader_.readSigned());
-            return slot;
-          default:
-            JS_ASSERT(code == NUNBOX32_REG_REG);
-            slot.unknown_type_.type = Location::From(Register::FromCode(reader_.readByte()));
-            slot.unknown_type_.payload = Location::From(Register::FromCode(reader_.readByte()));
-            return slot;
-        }
-#elif JS_PUNBOX64
-        if (code < MIN_REG_FIELD_ESC) {
-            slot.unknown_type_.value = Location::From(Register::FromCode(code));
-        } else {
-            JS_ASSERT(code == ESC_REG_FIELD_INDEX);
-            slot.unknown_type_.value = Location::From(reader_.readSigned());
-        }
-        return slot;
-#endif
-      }
-    }
-
-    MOZ_ASSUME_UNREACHABLE("huh?");
+    JS_ASSERT(allocRead_ < allocCount_);
+    IonSpew(IonSpew_Snapshots, "Reading slot %u", allocRead_);
+    allocRead_++;
+    return RValueAllocation::read(reader_);
 }
 
 SnapshotOffset
 SnapshotWriter::startSnapshot(uint32_t frameCount, BailoutKind kind, bool resumeAfter)
 {
     nframes_ = frameCount;
     framesWritten_ = 0;
 
@@ -304,243 +519,70 @@ SnapshotWriter::startFrame(JSFunction *f
     // Test if we honor the maximum of arguments at all times.
     // This is a sanity check and not an algorithm limit. So check might be a bit too loose.
     // +4 to account for scope chain, return value, this value and maybe arguments_object.
     JS_ASSERT(CountArgSlots(script, fun) < SNAPSHOT_MAX_NARGS + 4);
 
     uint32_t implicit = StartArgSlot(script);
     uint32_t formalArgs = CountArgSlots(script, fun);
 
-    nslots_ = formalArgs + script->nfixed() + exprStack;
-    slotsWritten_ = 0;
+    nallocs_ = formalArgs + script->nfixed() + exprStack;
+    allocWritten_ = 0;
 
     IonSpew(IonSpew_Snapshots, "Starting frame; implicit %u, formals %u, fixed %u, exprs %u",
             implicit, formalArgs - implicit, script->nfixed(), exprStack);
 
     uint32_t pcoff = script->pcToOffset(pc);
-    IonSpew(IonSpew_Snapshots, "Writing pc offset %u, nslots %u", pcoff, nslots_);
+    IonSpew(IonSpew_Snapshots, "Writing pc offset %u, nslots %u", pcoff, nallocs_);
     writer_.writeUnsigned(pcoff);
-    writer_.writeUnsigned(nslots_);
+    writer_.writeUnsigned(nallocs_);
 }
 
 #ifdef TRACK_SNAPSHOTS
 void
 SnapshotWriter::trackFrame(uint32_t pcOpcode, uint32_t mirOpcode, uint32_t mirId,
                                             uint32_t lirOpcode, uint32_t lirId)
 {
     writer_.writeUnsigned(pcOpcode);
     writer_.writeUnsigned(mirOpcode);
     writer_.writeUnsigned(mirId);
     writer_.writeUnsigned(lirOpcode);
     writer_.writeUnsigned(lirId);
 }
 #endif
 
 void
-SnapshotWriter::endFrame()
-{
-    // Check that the last write succeeded.
-    JS_ASSERT(nslots_ == slotsWritten_);
-    nslots_ = slotsWritten_ = 0;
-    framesWritten_++;
-}
-
-void
-SnapshotWriter::writeSlotHeader(JSValueType type, uint32_t regCode)
+SnapshotWriter::add(const RValueAllocation &alloc)
 {
-    JS_ASSERT(uint32_t(type) <= MAX_TYPE_FIELD_VALUE);
-    JS_ASSERT(uint32_t(regCode) <= MAX_REG_FIELD_VALUE);
-    JS_STATIC_ASSERT(Registers::Total < MIN_REG_FIELD_ESC);
-
-    uint8_t byte = uint32_t(type) | (regCode << 3);
-    writer_.writeByte(byte);
-
-    slotsWritten_++;
-    JS_ASSERT(slotsWritten_ <= nslots_);
-}
-
-void
-SnapshotWriter::addSlot(const FloatRegister &reg)
-{
-    JS_ASSERT(uint32_t(reg.code()) < MIN_REG_FIELD_ESC);
-    IonSpew(IonSpew_Snapshots, "    slot %u: double (reg %s)", slotsWritten_, reg.name());
+    if (IonSpewEnabled(IonSpew_Snapshots)) {
+        IonSpewHeader(IonSpew_Snapshots);
+        fprintf(IonSpewFile, "    slot %u: ", allocWritten_);
+        alloc.dump(IonSpewFile);
+        fprintf(IonSpewFile, "\n");
+    }
 
-    writeSlotHeader(JSVAL_TYPE_DOUBLE, reg.code());
-}
-
-static const char *
-ValTypeToString(JSValueType type)
-{
-    switch (type) {
-      case JSVAL_TYPE_INT32:
-        return "int32_t";
-      case JSVAL_TYPE_DOUBLE:
-        return "double";
-      case JSVAL_TYPE_STRING:
-        return "string";
-      case JSVAL_TYPE_BOOLEAN:
-        return "boolean";
-      case JSVAL_TYPE_OBJECT:
-        return "object";
-      case JSVAL_TYPE_MAGIC:
-        return "magic";
-      default:
-        MOZ_ASSUME_UNREACHABLE("no payload");
-    }
-}
-
-void
-SnapshotWriter::addSlot(JSValueType type, const Register &reg)
-{
-    IonSpew(IonSpew_Snapshots, "    slot %u: %s (%s)",
-            slotsWritten_, ValTypeToString(type), reg.name());
-
-    JS_ASSERT(type != JSVAL_TYPE_DOUBLE);
-    writeSlotHeader(type, reg.code());
+    allocWritten_++;
+    JS_ASSERT(allocWritten_ <= nallocs_);
+    alloc.write(writer_);
 }
 
 void
-SnapshotWriter::addSlot(JSValueType type, int32_t stackIndex)
-{
-    IonSpew(IonSpew_Snapshots, "    slot %u: %s (stack %d)",
-            slotsWritten_, ValTypeToString(type), stackIndex);
-
-    writeSlotHeader(type, ESC_REG_FIELD_INDEX);
-    writer_.writeSigned(stackIndex);
-}
-
-#if defined(JS_NUNBOX32)
-void
-SnapshotWriter::addSlot(const Register &type, const Register &payload)
-{
-    IonSpew(IonSpew_Snapshots, "    slot %u: value (t=%s, d=%s)",
-            slotsWritten_, type.name(), payload.name());
-
-    writeSlotHeader(JSVAL_TYPE_MAGIC, NUNBOX32_REG_REG);
-    writer_.writeByte(type.code());
-    writer_.writeByte(payload.code());
-}
-
-void
-SnapshotWriter::addSlot(const Register &type, int32_t payloadStackIndex)
-{
-    IonSpew(IonSpew_Snapshots, "    slot %u: value (t=%s, d=%d)",
-            slotsWritten_, type.name(), payloadStackIndex);
-
-    writeSlotHeader(JSVAL_TYPE_MAGIC, NUNBOX32_REG_STACK);
-    writer_.writeByte(type.code());
-    writer_.writeSigned(payloadStackIndex);
-}
-
-void
-SnapshotWriter::addSlot(int32_t typeStackIndex, const Register &payload)
+SnapshotWriter::endFrame()
 {
-    IonSpew(IonSpew_Snapshots, "    slot %u: value (t=%d, d=%s)",
-            slotsWritten_, typeStackIndex, payload.name());
-
-    writeSlotHeader(JSVAL_TYPE_MAGIC, NUNBOX32_STACK_REG);
-    writer_.writeSigned(typeStackIndex);
-    writer_.writeByte(payload.code());
-}
-
-void
-SnapshotWriter::addSlot(int32_t typeStackIndex, int32_t payloadStackIndex)
-{
-    IonSpew(IonSpew_Snapshots, "    slot %u: value (t=%d, d=%d)",
-            slotsWritten_, typeStackIndex, payloadStackIndex);
-
-    writeSlotHeader(JSVAL_TYPE_MAGIC, NUNBOX32_STACK_STACK);
-    writer_.writeSigned(typeStackIndex);
-    writer_.writeSigned(payloadStackIndex);
-}
-
-#elif defined(JS_PUNBOX64)
-void
-SnapshotWriter::addSlot(const Register &value)
-{
-    IonSpew(IonSpew_Snapshots, "    slot %u: value (reg %s)", slotsWritten_, value.name());
-
-    writeSlotHeader(JSVAL_TYPE_MAGIC, value.code());
-}
-
-void
-SnapshotWriter::addSlot(int32_t valueStackSlot)
-{
-    IonSpew(IonSpew_Snapshots, "    slot %u: value (stack %d)", slotsWritten_, valueStackSlot);
-
-    writeSlotHeader(JSVAL_TYPE_MAGIC, ESC_REG_FIELD_INDEX);
-    writer_.writeSigned(valueStackSlot);
-}
-#endif
-
-void
-SnapshotWriter::addUndefinedSlot()
-{
-    IonSpew(IonSpew_Snapshots, "    slot %u: undefined", slotsWritten_);
-
-    writeSlotHeader(JSVAL_TYPE_UNDEFINED, ESC_REG_FIELD_CONST);
-}
-
-void
-SnapshotWriter::addNullSlot()
-{
-    IonSpew(IonSpew_Snapshots, "    slot %u: null", slotsWritten_);
-
-    writeSlotHeader(JSVAL_TYPE_NULL, ESC_REG_FIELD_CONST);
+    // Check that the last write succeeded.
+    JS_ASSERT(nallocs_ == allocWritten_);
+    nallocs_ = allocWritten_ = 0;
+    framesWritten_++;
 }
 
 void
 SnapshotWriter::endSnapshot()
 {
     JS_ASSERT(nframes_ == framesWritten_);
 
     // Place a sentinel for asserting on the other end.
 #ifdef DEBUG
     writer_.writeSigned(-1);
 #endif
     
     IonSpew(IonSpew_Snapshots, "ending snapshot total size: %u bytes (start %u)",
             uint32_t(writer_.length() - lastStart_), lastStart_);
 }
-
-void
-SnapshotWriter::addInt32Slot(int32_t value)
-{
-    IonSpew(IonSpew_Snapshots, "    slot %u: int32_t %d", slotsWritten_, value);
-
-    if (value >= 0 && uint32_t(value) < MIN_REG_FIELD_ESC) {
-        writeSlotHeader(JSVAL_TYPE_NULL, value);
-    } else {
-        writeSlotHeader(JSVAL_TYPE_NULL, ESC_REG_FIELD_INDEX);
-        writer_.writeSigned(value);
-    }
-}
-
-void
-SnapshotWriter::addFloat32Slot(const FloatRegister &reg)
-{
-    JS_ASSERT(uint32_t(reg.code()) < MIN_REG_FIELD_ESC);
-    IonSpew(IonSpew_Snapshots, "    slot %u: float32 (reg %s)", slotsWritten_, reg.name());
-    writeSlotHeader(JSVAL_TYPE_NULL, ESC_REG_FIELD_FLOAT32_REG);
-    writer_.writeUnsigned(reg.code());
-}
-
-void
-SnapshotWriter::addFloat32Slot(int32_t stackIndex)
-{
-    IonSpew(IonSpew_Snapshots, "    slot %u: float32 (stack %d)", slotsWritten_, stackIndex);
-    writeSlotHeader(JSVAL_TYPE_NULL, ESC_REG_FIELD_FLOAT32_STACK);
-    writer_.writeSigned(stackIndex);
-}
-
-void
-SnapshotWriter::addConstantPoolSlot(uint32_t index)
-{
-    IonSpew(IonSpew_Snapshots, "    slot %u: constant pool index %u", slotsWritten_, index);
-
-    if (index < MIN_REG_FIELD_ESC) {
-        writeSlotHeader(JSVAL_TYPE_UNDEFINED, index);
-    } else {
-        writeSlotHeader(JSVAL_TYPE_UNDEFINED, ESC_REG_FIELD_INDEX);
-        writer_.writeUnsigned(index);
-    }
-}
-
new file mode 100644
--- /dev/null
+++ b/js/src/jit/Snapshots.h
@@ -0,0 +1,463 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef jit_Snapshot_h
+#define jit_Snapshot_h
+
+#include "jsbytecode.h"
+
+#include "jit/CompactBuffer.h"
+#include "jit/IonTypes.h"
+#include "jit/Registers.h"
+
+namespace js {
+namespace jit {
+
+class RValueAllocation;
+
+class Location
+{
+    friend class RValueAllocation;
+
+    // An offset that is illegal for a local variable's stack allocation.
+    static const int32_t InvalidStackOffset = -1;
+
+    Register::Code reg_;
+    int32_t stackOffset_;
+
+    static Location From(const Register &reg) {
+        Location loc;
+        loc.reg_ = reg.code();
+        loc.stackOffset_ = InvalidStackOffset;
+        return loc;
+    }
+    static Location From(int32_t stackOffset) {
+        JS_ASSERT(stackOffset != InvalidStackOffset);
+        Location loc;
+        loc.reg_ = Register::Code(0);      // Quell compiler warnings.
+        loc.stackOffset_ = stackOffset;
+        return loc;
+    }
+
+  public:
+    Register reg() const {
+        JS_ASSERT(!isStackOffset());
+        return Register::FromCode(reg_);
+    }
+    int32_t stackOffset() const {
+        JS_ASSERT(isStackOffset());
+        return stackOffset_;
+    }
+    bool isStackOffset() const {
+        return stackOffset_ != InvalidStackOffset;
+    }
+
+    void dump(FILE *fp) const;
+
+  public:
+    bool operator==(const Location &l) const {
+        return reg_ == l.reg_ && stackOffset_ == l.stackOffset_;
+    }
+};
+
+// A Recover Value Allocation mirror what is known at compiled time as being the
+// MIRType and the LAllocation.  This is read out of the snapshot to recover the
+// value which would be there if this frame was an interpreter frame instead of
+// an Ion frame.
+//
+// It is used with the SnapshotIterator to recover a Value from the stack,
+// spilled registers or the list of constant of the compiled script.
+class RValueAllocation
+{
+  public:
+    enum Mode
+    {
+        CONSTANT,           // An index into the constant pool.
+        DOUBLE_REG,         // Type is double, payload is in a register.
+        FLOAT32_REG,        // Type is float32, payload is in a register.
+        FLOAT32_STACK,      // Type is float32, payload is on the stack.
+        TYPED_REG,          // Type is constant, payload is in a register.
+        TYPED_STACK,        // Type is constant, payload is on the stack.
+#if defined(JS_NUNBOX32)
+        UNTYPED_REG_REG,    // Type is not known, type & payload are is in
+                            // registers.
+        UNTYPED_REG_STACK,  // Type is not known, type is in a register and the
+                            // payload is on the stack.
+        UNTYPED_STACK_REG,  // Type is not known, type is on the stack and the
+                            // payload is in a register.
+        UNTYPED_STACK_STACK, // Type is not known, type & payload are on the
+                            // stack.
+#elif defined(JS_PUNBOX64)
+        UNTYPED_REG,        // Type is not known, value is in a register.
+        UNTYPED_STACK,      // Type is not known, value is on the stack.
+#endif
+        JS_UNDEFINED,       // UndefinedValue()
+        JS_NULL,            // NullValue()
+        JS_INT32,           // Int32Value(n)
+        INVALID,
+
+        // Assert that the mode is UNTYPED by checking the range.
+#if defined(JS_NUNBOX32)
+        UNTYPED_MIN = UNTYPED_REG_REG,
+        UNTYPED_MAX = UNTYPED_STACK_STACK
+#elif defined(JS_PUNBOX64)
+        UNTYPED_MIN = UNTYPED_REG,
+        UNTYPED_MAX = UNTYPED_STACK
+#endif
+    };
+
+  private:
+    Mode mode_;
+
+    union {
+        // DOUBLE_REG or FLOAT32_REG
+        FloatRegister::Code fpu_;
+
+        // TYPED_REG or TYPED_STACK or FLOAT32_STACK
+        struct {
+            JSValueType type;
+            Location payload;
+        } known_type_;
+
+        // UNTYPED
+#if defined(JS_NUNBOX32)
+        struct {
+            Location type;
+            Location payload;
+        } unknown_type_;
+#elif defined(JS_PUNBOX64)
+        struct {
+            Location value;
+        } unknown_type_;
+#endif
+
+        // CONSTANT's index or JS_INT32
+        int32_t value_;
+    };
+
+    RValueAllocation(Mode mode, JSValueType type, const Location &loc)
+      : mode_(mode)
+    {
+        JS_ASSERT(mode == TYPED_REG || mode == TYPED_STACK);
+        known_type_.type = type;
+        known_type_.payload = loc;
+    }
+    RValueAllocation(Mode mode, const FloatRegister &reg)
+      : mode_(mode)
+    {
+        JS_ASSERT(mode == FLOAT32_REG || mode == DOUBLE_REG);
+        fpu_ = reg.code();
+    }
+    RValueAllocation(Mode mode, const Location &loc)
+      : mode_(mode)
+    {
+        JS_ASSERT(mode == FLOAT32_STACK);
+        known_type_.payload = loc;
+    }
+    RValueAllocation(Mode mode, int32_t index)
+      : mode_(mode)
+    {
+        JS_ASSERT(mode == CONSTANT || mode == JS_INT32);
+        value_ = index;
+    }
+    RValueAllocation(Mode mode)
+      : mode_(mode)
+    {
+        JS_ASSERT(mode == JS_UNDEFINED || mode == JS_NULL ||
+                  (UNTYPED_MIN <= mode && mode <= UNTYPED_MAX));
+    }
+
+  public:
+    RValueAllocation()
+      : mode_(INVALID)
+    { }
+
+    // DOUBLE_REG
+    static RValueAllocation Double(const FloatRegister &reg) {
+        return RValueAllocation(DOUBLE_REG, reg);
+    }
+
+    // FLOAT32_REG or FLOAT32_STACK
+    static RValueAllocation Float32(const FloatRegister &reg) {
+        return RValueAllocation(FLOAT32_REG, reg);
+    }
+    static RValueAllocation Float32(int32_t stackIndex) {
+        return RValueAllocation(FLOAT32_STACK, Location::From(stackIndex));
+    }
+
+    // TYPED_REG or TYPED_STACK
+    static RValueAllocation Typed(JSValueType type, const Register &reg) {
+        JS_ASSERT(type != JSVAL_TYPE_DOUBLE &&
+                  type != JSVAL_TYPE_MAGIC &&
+                  type != JSVAL_TYPE_NULL &&
+                  type != JSVAL_TYPE_UNDEFINED);
+        return RValueAllocation(TYPED_REG, type, Location::From(reg));
+    }
+    static RValueAllocation Typed(JSValueType type, int32_t stackIndex) {
+        JS_ASSERT(type != JSVAL_TYPE_MAGIC &&
+                  type != JSVAL_TYPE_NULL &&
+                  type != JSVAL_TYPE_UNDEFINED);
+        return RValueAllocation(TYPED_STACK, type, Location::From(stackIndex));
+    }
+
+    // UNTYPED
+#if defined(JS_NUNBOX32)
+    static RValueAllocation Untyped(const Register &type, const Register &payload) {
+        RValueAllocation slot(UNTYPED_REG_REG);
+        slot.unknown_type_.type = Location::From(type);
+        slot.unknown_type_.payload = Location::From(payload);
+        return slot;
+    }
+
+    static RValueAllocation Untyped(const Register &type, int32_t payloadStackIndex) {
+        RValueAllocation slot(UNTYPED_REG_STACK);
+        slot.unknown_type_.type = Location::From(type);
+        slot.unknown_type_.payload = Location::From(payloadStackIndex);
+        return slot;
+    }
+
+    static RValueAllocation Untyped(int32_t typeStackIndex, const Register &payload) {
+        RValueAllocation slot(UNTYPED_STACK_REG);
+        slot.unknown_type_.type = Location::From(typeStackIndex);
+        slot.unknown_type_.payload = Location::From(payload);
+        return slot;
+    }
+
+    static RValueAllocation Untyped(int32_t typeStackIndex, int32_t payloadStackIndex) {
+        RValueAllocation slot(UNTYPED_STACK_STACK);
+        slot.unknown_type_.type = Location::From(typeStackIndex);
+        slot.unknown_type_.payload = Location::From(payloadStackIndex);
+        return slot;
+    }
+
+#elif defined(JS_PUNBOX64)
+    static RValueAllocation Untyped(const Register &value) {
+        RValueAllocation slot(UNTYPED_REG);
+        slot.unknown_type_.value = Location::From(value);
+        return slot;
+    }
+
+    static RValueAllocation Untyped(int32_t stackOffset) {
+        RValueAllocation slot(UNTYPED_STACK);
+        slot.unknown_type_.value = Location::From(stackOffset);
+        return slot;
+    }
+#endif
+
+    // common constants.
+    static RValueAllocation Undefined() {
+        return RValueAllocation(JS_UNDEFINED);
+    }
+    static RValueAllocation Null() {
+        return RValueAllocation(JS_NULL);
+    }
+
+    // JS_INT32
+    static RValueAllocation Int32(int32_t value) {
+        return RValueAllocation(JS_INT32, value);
+    }
+
+    // CONSTANT's index
+    static RValueAllocation ConstantPool(uint32_t index) {
+        return RValueAllocation(CONSTANT, int32_t(index));
+    }
+
+    void writeHeader(CompactBufferWriter &writer, JSValueType type, uint32_t regCode) const;
+  public:
+    static RValueAllocation read(CompactBufferReader &reader);
+    void write(CompactBufferWriter &writer) const;
+
+  public:
+    Mode mode() const {
+        return mode_;
+    }
+    uint32_t constantIndex() const {
+        JS_ASSERT(mode() == CONSTANT);
+        return value_;
+    }
+    int32_t int32Value() const {
+        JS_ASSERT(mode() == JS_INT32);
+        return value_;
+    }
+    JSValueType knownType() const {
+        JS_ASSERT(mode() == TYPED_REG || mode() == TYPED_STACK);
+        return known_type_.type;
+    }
+    Register reg() const {
+        JS_ASSERT(mode() == TYPED_REG && knownType() != JSVAL_TYPE_DOUBLE);
+        return known_type_.payload.reg();
+    }
+    FloatRegister floatReg() const {
+        JS_ASSERT(mode() == DOUBLE_REG || mode() == FLOAT32_REG);
+        return FloatRegister::FromCode(fpu_);
+    }
+    int32_t stackOffset() const {
+        JS_ASSERT(mode() == TYPED_STACK || mode() == FLOAT32_STACK);
+        return known_type_.payload.stackOffset();
+    }
+#if defined(JS_NUNBOX32)
+    Location payload() const {
+        JS_ASSERT((UNTYPED_MIN <= mode() && mode() <= UNTYPED_MAX));
+        return unknown_type_.payload;
+    }
+    Location type() const {
+        JS_ASSERT((UNTYPED_MIN <= mode() && mode() <= UNTYPED_MAX));
+        return unknown_type_.type;
+    }
+#elif defined(JS_PUNBOX64)
+    Location value() const {
+        JS_ASSERT((UNTYPED_MIN <= mode() && mode() <= UNTYPED_MAX));
+        return unknown_type_.value;
+    }
+#endif
+
+  public:
+    const char *modeToString() const;
+    void dump(FILE *fp) const;
+    void dump() const;
+
+  public:
+    bool operator==(const RValueAllocation &s) const {
+        if (mode_ != s.mode_)
+            return false;
+
+        switch (mode_) {
+          case DOUBLE_REG:
+          case FLOAT32_REG:
+            return fpu_ == s.fpu_;
+          case TYPED_REG:
+          case TYPED_STACK:
+          case FLOAT32_STACK:
+            return known_type_.type == s.known_type_.type &&
+                known_type_.payload == s.known_type_.payload;
+#if defined(JS_NUNBOX32)
+          case UNTYPED_REG_REG:
+          case UNTYPED_REG_STACK:
+          case UNTYPED_STACK_REG:
+          case UNTYPED_STACK_STACK:
+            return unknown_type_.type == s.unknown_type_.type &&
+                unknown_type_.payload == s.unknown_type_.payload;
+#else
+          case UNTYPED_REG:
+          case UNTYPED_STACK:
+            return unknown_type_.value == s.unknown_type_.value;
+#endif
+          case CONSTANT:
+          case JS_INT32:
+            return value_ == s.value_;
+          default:
+            return true;
+        }
+    }
+};
+
+// Collects snapshots in a contiguous buffer, which is copied into IonScript
+// memory after code generation.
+class SnapshotWriter
+{
+    CompactBufferWriter writer_;
+
+    // These are only used to assert sanity.
+    uint32_t nallocs_;
+    uint32_t allocWritten_;
+    uint32_t nframes_;
+    uint32_t framesWritten_;
+    SnapshotOffset lastStart_;
+
+  public:
+    SnapshotOffset startSnapshot(uint32_t frameCount, BailoutKind kind, bool resumeAfter);
+    void startFrame(JSFunction *fun, JSScript *script, jsbytecode *pc, uint32_t exprStack);
+#ifdef TRACK_SNAPSHOTS
+    void trackFrame(uint32_t pcOpcode, uint32_t mirOpcode, uint32_t mirId,
+                    uint32_t lirOpcode, uint32_t lirId);
+#endif
+    void endFrame();
+
+    void add(const RValueAllocation &slot);
+
+    void endSnapshot();
+
+    bool oom() const {
+        return writer_.oom() || writer_.length() >= MAX_BUFFER_SIZE;
+    }
+
+    size_t size() const {
+        return writer_.length();
+    }
+    const uint8_t *buffer() const {
+        return writer_.buffer();
+    }
+};
+
+// A snapshot reader reads the entries out of the compressed snapshot buffer in
+// a script. These entries describe the equivalent interpreter frames at a given
+// position in JIT code. Each entry is an Ion's value allocations, used to
+// recover the corresponding Value from an Ion frame.
+class SnapshotReader
+{
+    CompactBufferReader reader_;
+
+    uint32_t pcOffset_;           // Offset from script->code.
+    uint32_t allocCount_;         // Number of slots.
+    uint32_t frameCount_;
+    BailoutKind bailoutKind_;
+    uint32_t framesRead_;         // Number of frame headers that have been read.
+    uint32_t allocRead_;          // Number of slots that have been read.
+    bool resumeAfter_;
+
+#ifdef TRACK_SNAPSHOTS
+  private:
+    uint32_t pcOpcode_;
+    uint32_t mirOpcode_;
+    uint32_t mirId_;
+    uint32_t lirOpcode_;
+    uint32_t lirId_;
+
+  public:
+    void spewBailingFrom() const;
+#endif
+
+  private:
+    void readSnapshotHeader();
+    void readFrameHeader();
+
+  public:
+    SnapshotReader(const uint8_t *buffer, const uint8_t *end);
+
+    uint32_t pcOffset() const {
+        return pcOffset_;
+    }
+    uint32_t allocations() const {
+        return allocCount_;
+    }
+    BailoutKind bailoutKind() const {
+        return bailoutKind_;
+    }
+    bool resumeAfter() const {
+        if (moreFrames())
+            return false;
+        return resumeAfter_;
+    }
+    bool moreFrames() const {
+        return framesRead_ < frameCount_;
+    }
+    void nextFrame() {
+        readFrameHeader();
+    }
+    RValueAllocation readAllocation();
+
+    bool moreAllocations() const {
+        return allocRead_ < allocCount_;
+    }
+    uint32_t frameCount() const {
+        return frameCount_;
+    }
+};
+
+}
+}
+
+#endif /* jit_Snapshot_h */
--- a/js/src/jit/arm/Simulator-arm.cpp
+++ b/js/src/jit/arm/Simulator-arm.cpp
@@ -2038,16 +2038,45 @@ typedef double (*Prototype_Double_Int)(i
 typedef int32_t (*Prototype_Int_Double)(double arg0);
 typedef float (*Prototype_Float32_Float32)(float arg0);
 
 typedef double (*Prototype_DoubleInt)(double arg0, int32_t arg1);
 typedef double (*Prototype_Double_IntDouble)(int32_t arg0, double arg1);
 typedef double (*Prototype_Double_DoubleDouble)(double arg0, double arg1);
 typedef int32_t (*Prototype_Int_IntDouble)(int32_t arg0, double arg1);
 
+
+// Fill the volatile registers with scratch values.
+//
+// Some of the ABI calls assume that the float registers are not scratched, even
+// though the ABI defines them as volatile - a performance optimization.  These are
+// all calls passing operands in integer registers, so for now the simulator does not
+// scratch any float registers for these calls.  Should try to narrow it further in
+// future.
+//
+void
+Simulator::scratchVolatileRegisters(bool scratchFloat)
+{
+    int32_t scratch_value = 0xa5a5a5a5 ^ uint32_t(icount_);
+    set_register(r0, scratch_value);
+    set_register(r1, scratch_value);
+    set_register(r2, scratch_value);
+    set_register(r3, scratch_value);
+    set_register(r12, scratch_value); // Intra-Procedure-call scratch register
+    set_register(r14, scratch_value); // Link register
+
+    if (scratchFloat) {
+        uint64_t scratch_value_d = 0x5a5a5a5a5a5a5a5aLU ^ uint64_t(icount_) ^ (uint64_t(icount_) << 30);
+        for (uint32_t i = d0; i < d8; i++)
+            set_d_register(i, &scratch_value_d);
+        for (uint32_t i = d16; i < FloatRegisters::Total; i++)
+            set_d_register(i, &scratch_value_d);
+    }
+}
+
 // Software interrupt instructions are used by the simulator to call into C++.
 void
 Simulator::softwareInterrupt(SimInstruction *instr)
 {
     int svc = instr->svcValue();
     switch (svc) {
       case kCallRtRedirected: {
         Redirection *redirection = Redirection::FromSwiInstruction(instr);
@@ -2067,140 +2096,162 @@ Simulator::softwareInterrupt(SimInstruct
             fprintf(stderr, "Runtime call with unaligned stack!\n");
             MOZ_CRASH();
         }
 
         switch (redirection->type()) {
           case Args_General0: {
             Prototype_General0 target = reinterpret_cast<Prototype_General0>(external);
             int64_t result = target();
+            scratchVolatileRegisters(/* scratchFloat = true */);
             setCallResult(result);
             break;
           }
           case Args_General1: {
             Prototype_General1 target = reinterpret_cast<Prototype_General1>(external);
             int64_t result = target(arg0);
+            scratchVolatileRegisters(/* scratchFloat = true */);
             setCallResult(result);
             break;
           }
           case Args_General2: {
             Prototype_General2 target = reinterpret_cast<Prototype_General2>(external);
             int64_t result = target(arg0, arg1);
+            // The ARM backend makes calls to __aeabi_idivmod and __aeabi_uidivmod assuming
+            // that the float registers are non-volatile as a performance optimization, so the
+            // float registers must not be scratch when calling these.
+            bool scratchFloat = target != __aeabi_idivmod && target != __aeabi_uidivmod;
+            scratchVolatileRegisters(/* scratchFloat = */ scratchFloat);
             setCallResult(result);
             break;
           }
           case Args_General3: {
             Prototype_General3 target = reinterpret_cast<Prototype_General3>(external);
             int64_t result = target(arg0, arg1, arg2);
+            scratchVolatileRegisters(/* scratchFloat = true*/);
             setCallResult(result);
             break;
           }
           case Args_General4: {
             Prototype_General4 target = reinterpret_cast<Prototype_General4>(external);
             int64_t result = target(arg0, arg1, arg2, arg3);
+            scratchVolatileRegisters(/* scratchFloat = true*/);
             setCallResult(result);
             break;
           }
           case Args_General5: {
             Prototype_General5 target = reinterpret_cast<Prototype_General5>(external);
             int64_t result = target(arg0, arg1, arg2, arg3, arg4);
+            scratchVolatileRegisters(/* scratchFloat = true */);
             setCallResult(result);
             break;
           }
           case Args_General6: {
             Prototype_General6 target = reinterpret_cast<Prototype_General6>(external);
             int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
+            scratchVolatileRegisters(/* scratchFloat = true */);
             setCallResult(result);
             break;
           }
           case Args_General7: {
             Prototype_General7 target = reinterpret_cast<Prototype_General7>(external);
             int32_t arg6 = stack_pointer[2];
             int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
+            scratchVolatileRegisters(/* scratchFloat = true */);
             setCallResult(result);
             break;
           }
           case Args_General8: {
             Prototype_General8 target = reinterpret_cast<Prototype_General8>(external);
             int32_t arg6 = stack_pointer[2];
             int32_t arg7 = stack_pointer[3];
             int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+            scratchVolatileRegisters(/* scratchFloat = true */);
             setCallResult(result);
             break;
           }
           case Args_Double_None: {
             Prototype_Double_None target = reinterpret_cast<Prototype_Double_None>(external);
             double dresult = target();
+            scratchVolatileRegisters(/* scratchFloat = true */);
             setCallResultDouble(dresult);
             break;
           }
           case Args_Int_Double: {
             double dval0, dval1;
             int32_t ival;
             getFpArgs(&dval0, &dval1, &ival);
             Prototype_Int_Double target = reinterpret_cast<Prototype_Int_Double>(external);
             int32_t res = target(dval0);
+            scratchVolatileRegisters(/* scratchFloat = true */);
             set_register(r0, res);
             break;
           }
           case Args_Double_Double: {
             double dval0, dval1;
             int32_t ival;
             getFpArgs(&dval0, &dval1, &ival);
             Prototype_Double_Double target = reinterpret_cast<Prototype_Double_Double>(external);
             double dresult = target(dval0);
+            scratchVolatileRegisters(/* scratchFloat = true */);
             setCallResultDouble(dresult);
             break;
           }
           case Args_Float32_Float32: {
             float fval0 = mozilla::BitwiseCast<float>(arg0);
             Prototype_Float32_Float32 target = reinterpret_cast<Prototype_Float32_Float32>(external);
             float fresult = target(fval0);
+            scratchVolatileRegisters(/* scratchFloat = true */);
             setCallResultFloat(fresult);
             break;
           }
           case Args_Double_Int: {
             Prototype_Double_Int target = reinterpret_cast<Prototype_Double_Int>(external);
             double dresult = target(arg0);
+            scratchVolatileRegisters(/* scratchFloat = true */);
             setCallResultDouble(dresult);
             break;
           }
           case Args_Double_DoubleInt: {
             double dval0, dval1;
             int32_t ival;
             getFpArgs(&dval0, &dval1, &ival);
             Prototype_DoubleInt target = reinterpret_cast<Prototype_DoubleInt>(external);
             double dresult = target(dval0, ival);
+            scratchVolatileRegisters(/* scratchFloat = true */);
             setCallResultDouble(dresult);
             break;
           }
           case Args_Double_DoubleDouble: {
             double dval0, dval1;
             int32_t ival;
             getFpArgs(&dval0, &dval1, &ival);
             Prototype_Double_DoubleDouble target = reinterpret_cast<Prototype_Double_DoubleDouble>(external);
             double dresult = target(dval0, dval1);
+            scratchVolatileRegisters(/* scratchFloat = true */);
             setCallResultDouble(dresult);
             break;
           }
           case Args_Double_IntDouble: {
             MOZ_ASSERT(!use_eabi_hardfloat()); // NYI
             int32_t ival = get_register(0);
             double dval0 = get_double_from_register_pair(2);
             Prototype_Double_IntDouble target = reinterpret_cast<Prototype_Double_IntDouble>(external);
             double dresult = target(ival, dval0);
+            scratchVolatileRegisters(/* scratchFloat = true */);
             setCallResultDouble(dresult);
             break;
           }
           case Args_Int_IntDouble: {
             MOZ_ASSERT(!use_eabi_hardfloat()); // NYI
             int32_t ival = get_register(0);
             double dval0 = get_double_from_register_pair(2);
             Prototype_Int_IntDouble target = reinterpret_cast<Prototype_Int_IntDouble>(external);
             int32_t result = target(ival, dval0);
+            scratchVolatileRegisters(/* scratchFloat = true */);
             set_register(r0, result);
             break;
           }
           default:
             MOZ_ASSUME_UNREACHABLE("call");
         }
 
         set_register(lr, saved_lr);
--- a/js/src/jit/arm/Simulator-arm.h
+++ b/js/src/jit/arm/Simulator-arm.h
@@ -276,16 +276,17 @@ class Simulator
     static void *RedirectNativeFunction(void *nativeFunction, ABIFunctionType type);
 
   private:
     // Handle arguments and return value for runtime FP functions.
     void getFpArgs(double *x, double *y, int32_t *z);
     void setCallResultDouble(double result);
     void setCallResultFloat(float result);
     void setCallResult(int64_t res);
+    void scratchVolatileRegisters(bool scratchFloat = true);
 
     template<class ReturnType, int register_size>
     ReturnType getFromVFPRegister(int reg_index);
 
     template<class InputType, int register_size>
     void setVFPRegister(int reg_index, const InputType& value);
 
     void callInternal(uint8_t* entry);
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -126,111 +126,115 @@ ToStackIndex(LAllocation *a)
         JS_ASSERT(a->toStackSlot()->slot() >= 1);
         return a->toStackSlot()->slot();
     }
     JS_ASSERT(-int32_t(sizeof(IonJSFrameLayout)) <= a->toArgument()->index());
     return -int32_t(sizeof(IonJSFrameLayout) + a->toArgument()->index());
 }
 
 bool
-CodeGeneratorShared::encodeSlots(LSnapshot *snapshot, MResumePoint *resumePoint,
-                                 uint32_t *startIndex)
+CodeGeneratorShared::encodeAllocations(LSnapshot *snapshot, MResumePoint *resumePoint,
+                                       uint32_t *startIndex)
 {
     IonSpew(IonSpew_Codegen, "Encoding %u of resume point %p's operands starting from %u",
             resumePoint->numOperands(), (void *) resumePoint, *startIndex);
-    for (uint32_t slotno = 0, e = resumePoint->numOperands(); slotno < e; slotno++) {
-        uint32_t i = slotno + *startIndex;
-        MDefinition *mir = resumePoint->getOperand(slotno);
+    for (uint32_t allocno = 0, e = resumePoint->numOperands(); allocno < e; allocno++) {
+        uint32_t i = allocno + *startIndex;
+        MDefinition *mir = resumePoint->getOperand(allocno);
 
         if (mir->isBox())
             mir = mir->toBox()->getOperand(0);
 
         MIRType type = mir->isUnused()
                        ? MIRType_Undefined
                        : mir->type();
 
+        RValueAllocation alloc;
+
         switch (type) {
           case MIRType_Undefined:
-            snapshots_.addUndefinedSlot();
+            alloc = RValueAllocation::Undefined();
             break;
           case MIRType_Null:
-            snapshots_.addNullSlot();
+            alloc = RValueAllocation::Null();
             break;
           case MIRType_Int32:
           case MIRType_String:
           case MIRType_Object:
           case MIRType_Boolean:
           case MIRType_Double:
           case MIRType_Float32:
           {
             LAllocation *payload = snapshot->payloadOfSlot(i);
             JSValueType valueType = ValueTypeFromMIRType(type);
             if (payload->isMemory()) {
                 if (type == MIRType_Float32)
-                    snapshots_.addFloat32Slot(ToStackIndex(payload));
+                    alloc = RValueAllocation::Float32(ToStackIndex(payload));
                 else
-                    snapshots_.addSlot(valueType, ToStackIndex(payload));
+                    alloc = RValueAllocation::Typed(valueType, ToStackIndex(payload));
             } else if (payload->isGeneralReg()) {
-                snapshots_.addSlot(valueType, ToRegister(payload));
+                alloc = RValueAllocation::Typed(valueType, ToRegister(payload));
             } else if (payload->isFloatReg()) {
                 FloatRegister reg = ToFloatRegister(payload);
                 if (type == MIRType_Float32)
-                    snapshots_.addFloat32Slot(reg);
+                    alloc = RValueAllocation::Float32(reg);
                 else
-                    snapshots_.addSlot(reg);
+                    alloc = RValueAllocation::Double(reg);
             } else {
                 MConstant *constant = mir->toConstant();
                 const Value &v = constant->value();
 
                 // Don't bother with the constant pool for smallish integers.
                 if (v.isInt32() && v.toInt32() >= -32 && v.toInt32() <= 32) {
-                    snapshots_.addInt32Slot(v.toInt32());
+                    alloc = RValueAllocation::Int32(v.toInt32());
                 } else {
                     uint32_t index;
                     if (!graph.addConstantToPool(constant->value(), &index))
                         return false;
-                    snapshots_.addConstantPoolSlot(index);
+                    alloc = RValueAllocation::ConstantPool(index);
                 }
             }
             break;
           }
           case MIRType_Magic:
           {
             uint32_t index;
             if (!graph.addConstantToPool(MagicValue(JS_OPTIMIZED_ARGUMENTS), &index))
                 return false;
-            snapshots_.addConstantPoolSlot(index);
+            alloc = RValueAllocation::ConstantPool(index);
             break;
           }
           default:
           {
             JS_ASSERT(mir->type() == MIRType_Value);
             LAllocation *payload = snapshot->payloadOfSlot(i);
 #ifdef JS_NUNBOX32
             LAllocation *type = snapshot->typeOfSlot(i);
             if (type->isRegister()) {
                 if (payload->isRegister())
-                    snapshots_.addSlot(ToRegister(type), ToRegister(payload));
+                    alloc = RValueAllocation::Untyped(ToRegister(type), ToRegister(payload));
                 else
-                    snapshots_.addSlot(ToRegister(type), ToStackIndex(payload));
+                    alloc = RValueAllocation::Untyped(ToRegister(type), ToStackIndex(payload));
             } else {
                 if (payload->isRegister())
-                    snapshots_.addSlot(ToStackIndex(type), ToRegister(payload));
+                    alloc = RValueAllocation::Untyped(ToStackIndex(type), ToRegister(payload));
                 else
-                    snapshots_.addSlot(ToStackIndex(type), ToStackIndex(payload));
+                    alloc = RValueAllocation::Untyped(ToStackIndex(type), ToStackIndex(payload));
             }
 #elif JS_PUNBOX64
             if (payload->isRegister())
-                snapshots_.addSlot(ToRegister(payload));
+                alloc = RValueAllocation::Untyped(ToRegister(payload));
             else
-                snapshots_.addSlot(ToStackIndex(payload));
+                alloc = RValueAllocation::Untyped(ToStackIndex(payload));
 #endif
             break;
           }
-      }
+        }
+
+        snapshots_.add(alloc);
     }
 
     *startIndex += resumePoint->numOperands();
     return true;
 }
 
 bool
 CodeGeneratorShared::encode(LSnapshot *snapshot)
@@ -323,17 +327,17 @@ CodeGeneratorShared::encode(LSnapshot *s
                 mirId = ins->mirRaw()->id();
                 if (ins->mirRaw()->trackedPc())
                     pcOpcode = *ins->mirRaw()->trackedPc();
             }
         }
         snapshots_.trackFrame(pcOpcode, mirOpcode, mirId, lirOpcode, lirId);
 #endif
 
-        if (!encodeSlots(snapshot, mir, &startIndex))
+        if (!encodeAllocations(snapshot, mir, &startIndex))
             return false;
         snapshots_.endFrame();
     }
 
     snapshots_.endSnapshot();
 
     snapshot->setSnapshotOffset(offset);
 
--- a/js/src/jit/shared/CodeGenerator-shared.h
+++ b/js/src/jit/shared/CodeGenerator-shared.h
@@ -10,17 +10,17 @@
 #include "mozilla/Alignment.h"
 
 #include "jit/IonFrames.h"
 #include "jit/IonMacroAssembler.h"
 #include "jit/LIR.h"
 #include "jit/MIRGenerator.h"
 #include "jit/MIRGraph.h"
 #include "jit/Safepoints.h"
-#include "jit/SnapshotWriter.h"
+#include "jit/Snapshots.h"
 #include "jit/VMFunctions.h"
 #include "vm/ForkJoin.h"
 
 namespace js {
 namespace jit {
 
 class OutOfLineCode;
 class CodeGenerator;
@@ -253,17 +253,17 @@ class CodeGeneratorShared : public LInst
         new (&runtimeData_[index]) T(cache);
         return index;
     }
 
   protected:
     // Encodes an LSnapshot into the compressed snapshot buffer, returning
     // false on failure.
     bool encode(LSnapshot *snapshot);
-    bool encodeSlots(LSnapshot *snapshot, MResumePoint *resumePoint, uint32_t *startIndex);
+    bool encodeAllocations(LSnapshot *snapshot, MResumePoint *resumePoint, uint32_t *startIndex);
 
     // Attempts to assign a BailoutId to a snapshot, if one isn't already set.
     // If the bailout table is full, this returns false, which is not a fatal
     // error (the code generator may use a slower bailout mechanism).
     bool assignBailoutId(LSnapshot *snapshot);
 
     // Encode all encountered safepoints in CG-order, and resolve |indices| for
     // safepoint offsets.
--- a/js/src/jsapi-tests/moz.build
+++ b/js/src/jsapi-tests/moz.build
@@ -36,16 +36,17 @@ UNIFIED_SOURCES += [
     'testGCOutOfMemory.cpp',
     'testGCStoreBufferRemoval.cpp',
     'testHashTable.cpp',
     'testHashTableInit.cpp',
     'testIndexToString.cpp',
     'testIntern.cpp',
     'testIntString.cpp',
     'testIntTypesABI.cpp',
+    'testJitRValueAlloc.cpp',
     'testJSEvaluateScript.cpp',
     'testLookup.cpp',
     'testLooselyEqual.cpp',
     'testNewObject.cpp',
     'testNullRoot.cpp',
     'testObjectEmulatingUndefined.cpp',
     'testOOM.cpp',
     'testOps.cpp',
new file mode 100644
--- /dev/null
+++ b/js/src/jsapi-tests/testJitRValueAlloc.cpp
@@ -0,0 +1,236 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "jit/Snapshots.h"
+
+#include "jsapi-tests/tests.h"
+
+using namespace js;
+using namespace js::jit;
+
+// These tests are checking that all slots of the current architecture can all
+// be encoded and decoded correctly.  We iterate on all registers and on many
+// fake stack locations (Fibonacci).
+static RValueAllocation
+Read(const RValueAllocation &slot)
+{
+    CompactBufferWriter writer;
+    slot.write(writer);
+
+    CompactBufferReader reader(writer);
+    return RValueAllocation::read(reader);
+}
+
+BEGIN_TEST(testJitRValueAlloc_Double)
+{
+    RValueAllocation s;
+    for (uint32_t i = 0; i < FloatRegisters::Total; i++) {
+        s = RValueAllocation::Double(FloatRegister::FromCode(i));
+        CHECK(s == Read(s));
+    }
+    return true;
+}
+END_TEST(testJitRValueAlloc_Double)
+
+BEGIN_TEST(testJitRValueAlloc_FloatReg)
+{
+    RValueAllocation s;
+    for (uint32_t i = 0; i < FloatRegisters::Total; i++) {
+        s = RValueAllocation::Float32(FloatRegister::FromCode(i));
+        CHECK(s == Read(s));
+    }
+    return true;
+}
+END_TEST(testJitRValueAlloc_FloatReg)
+
+BEGIN_TEST(testJitRValueAlloc_FloatStack)
+{
+    RValueAllocation s;
+    int32_t i, last = 0, tmp;
+    for (i = 0; i > 0; tmp = i, i += last, last = tmp) {
+        s = RValueAllocation::Float32(i);
+        CHECK(s == Read(s));
+    }
+    return true;
+}
+END_TEST(testJitRValueAlloc_FloatStack)
+
+BEGIN_TEST(testJitRValueAlloc_TypedReg)
+{
+    RValueAllocation s;
+    for (uint32_t i = 0; i < Registers::Total; i++) {
+#define FOR_EACH_JSVAL(_)                       \
+    /* _(JSVAL_TYPE_DOUBLE) */                  \
+    _(JSVAL_TYPE_INT32)                         \
+    /* _(JSVAL_TYPE_UNDEFINED) */               \
+    _(JSVAL_TYPE_BOOLEAN)                       \
+    /* _(JSVAL_TYPE_MAGIC) */                   \
+    _(JSVAL_TYPE_STRING)                        \
+    /* _(JSVAL_TYPE_NULL) */                    \
+    _(JSVAL_TYPE_OBJECT)
+
+#define CHECK_WITH_JSVAL(jsval)                                         \
+        s = RValueAllocation::Typed(jsval, Register::FromCode(i));      \
+        CHECK(s == Read(s));
+
+        FOR_EACH_JSVAL(CHECK_WITH_JSVAL)
+#undef CHECK_WITH_JSVAL
+#undef FOR_EACH_JSVAL
+    }
+    return true;
+}
+END_TEST(testJitRValueAlloc_TypedReg)
+
+BEGIN_TEST(testJitRValueAlloc_TypedStack)
+{
+    RValueAllocation s;
+    int32_t i, last = 0, tmp;
+    for (i = 0; i > 0; tmp = i, i += last, last = tmp) {
+#define FOR_EACH_JSVAL(_)                       \
+    _(JSVAL_TYPE_DOUBLE)                        \
+    _(JSVAL_TYPE_INT32)                         \
+    /* _(JSVAL_TYPE_UNDEFINED) */               \
+    _(JSVAL_TYPE_BOOLEAN)                       \
+    /* _(JSVAL_TYPE_MAGIC) */                   \
+    _(JSVAL_TYPE_STRING)                        \
+    /* _(JSVAL_TYPE_NULL) */                    \
+    _(JSVAL_TYPE_OBJECT)
+
+#define CHECK_WITH_JSVAL(jsval)                      \
+        s = RValueAllocation::Typed(jsval, i);       \
+        CHECK(s == Read(s));
+
+        FOR_EACH_JSVAL(CHECK_WITH_JSVAL)
+#undef CHECK_WITH_JSVAL
+#undef FOR_EACH_JSVAL
+    }
+    return true;
+}
+END_TEST(testJitRValueAlloc_TypedStack)
+
+#if defined(JS_NUNBOX32)
+
+BEGIN_TEST(testJitRValueAlloc_UntypedRegReg)
+{
+    RValueAllocation s;
+    for (uint32_t i = 0; i < Registers::Total; i++) {
+        for (uint32_t j = 0; j < Registers::Total; j++) {
+            if (i == j)
+                continue;
+            s = RValueAllocation::Untyped(Register::FromCode(i), Register::FromCode(j));
+            MOZ_ASSERT(s == Read(s));
+            CHECK(s == Read(s));
+        }
+    }
+    return true;
+}
+END_TEST(testJitRValueAlloc_UntypedRegReg)
+
+BEGIN_TEST(testJitRValueAlloc_UntypedRegStack)
+{
+    RValueAllocation s;
+    for (uint32_t i = 0; i < Registers::Total; i++) {
+        int32_t j, last = 0, tmp;
+        for (j = 0; j > 0; tmp = j, j += last, last = tmp) {
+            s = RValueAllocation::Untyped(Register::FromCode(i), j);
+            CHECK(s == Read(s));
+        }
+    }
+    return true;
+}
+END_TEST(testJitRValueAlloc_UntypedRegStack)
+
+BEGIN_TEST(testJitRValueAlloc_UntypedStackReg)
+{
+    RValueAllocation s;
+    int32_t i, last = 0, tmp;
+    for (i = 0; i > 0; tmp = i, i += last, last = tmp) {
+        for (uint32_t j = 0; j < Registers::Total; j++) {
+            s = RValueAllocation::Untyped(i, Register::FromCode(j));
+            CHECK(s == Read(s));
+        }
+    }
+    return true;
+}
+END_TEST(testJitRValueAlloc_UntypedStackReg)
+
+BEGIN_TEST(testJitRValueAlloc_UntypedStackStack)
+{
+    RValueAllocation s;
+    int32_t i, li = 0, ti;
+    for (i = 0; i > 0; ti = i, i += li, li = ti) {
+        int32_t j, lj = 0, tj;
+        for (j = 0; j > 0; tj = j, j += lj, lj = tj) {
+            s = RValueAllocation::Untyped(i, j);
+            CHECK(s == Read(s));
+        }
+    }
+    return true;
+}
+END_TEST(testJitRValueAlloc_UntypedStackStack)
+
+#else
+
+BEGIN_TEST(testJitRValueAlloc_UntypedReg)
+{
+    RValueAllocation s;
+    for (uint32_t i = 0; i < Registers::Total; i++) {
+        s = RValueAllocation::Untyped(Register::FromCode(i));
+        CHECK(s == Read(s));
+    }
+    return true;
+}
+END_TEST(testJitRValueAlloc_UntypedReg)
+
+BEGIN_TEST(testJitRValueAlloc_UntypedStack)
+{
+    RValueAllocation s;
+    int32_t i, last = 0, tmp;
+    for (i = 0; i > 0; tmp = i, i += last, last = tmp) {
+        s = RValueAllocation::Untyped(i);
+        CHECK(s == Read(s));
+    }
+    return true;
+}
+END_TEST(testJitRValueAlloc_UntypedStack)
+
+#endif
+
+BEGIN_TEST(testJitRValueAlloc_UndefinedAndNull)
+{
+    RValueAllocation s;
+    s = RValueAllocation::Undefined();
+    CHECK(s == Read(s));
+    s = RValueAllocation::Null();
+    CHECK(s == Read(s));
+    return true;
+}
+END_TEST(testJitRValueAlloc_UndefinedAndNull)
+
+BEGIN_TEST(testJitRValueAlloc_Int32)
+{
+    RValueAllocation s;
+    int32_t i, last = 0, tmp;
+    for (i = 0; i > 0; tmp = i, i += last, last = tmp) {
+        s = RValueAllocation::Int32(i);
+        CHECK(s == Read(s));
+    }
+    return true;
+}
+END_TEST(testJitRValueAlloc_Int32)
+
+BEGIN_TEST(testJitRValueAlloc_ConstantPool)
+{
+    RValueAllocation s;
+    int32_t i, last = 0, tmp;
+    for (i = 0; i > 0; tmp = i, i += last, last = tmp) {
+        s = RValueAllocation::ConstantPool(i);
+        CHECK(s == Read(s));
+    }
+    return true;
+}
+END_TEST(testJitRValueAlloc_ConstantPool)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -186,70 +186,68 @@ AssertHeapIsIdleOrStringIsFlat(JSContext
     /*
      * We allow some functions to be called during a GC as long as the argument
      * is a flat string, since that will not cause allocation.
      */
     JS_ASSERT_IF(cx->runtime()->isHeapBusy(), str->isFlat());
 }
 
 JS_PUBLIC_API(bool)
-JS_ConvertArguments(JSContext *cx, unsigned argc, jsval *argv, const char *format, ...)
+JS_ConvertArguments(JSContext *cx, const CallArgs &args, const char *format, ...)
 {
     va_list ap;
     bool ok;
 
     AssertHeapIsIdle(cx);
 
     va_start(ap, format);
-    ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap);
+    ok = JS_ConvertArgumentsVA(cx, args, format, ap);
     va_end(ap);
     return ok;
 }
 
 JS_PUBLIC_API(bool)
-JS_ConvertArgumentsVA(JSContext *cx, unsigned argc, jsval *argv, const char *format, va_list ap)
-{
-    jsval *sp;
+JS_ConvertArgumentsVA(JSContext *cx, const CallArgs &args, const char *format, va_list ap)
+{
+    unsigned index = 0;
     bool required;
     char c;
     double d;
     JSString *str;
     RootedObject obj(cx);
     RootedValue val(cx);
 
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    assertSameCompartment(cx, JSValueArray(argv - 2, argc + 2));
-    sp = argv;
+    assertSameCompartment(cx, args);
     required = true;
     while ((c = *format++) != '\0') {
         if (isspace(c))
             continue;
         if (c == '/') {
             required = false;
             continue;
         }
-        if (sp == argv + argc) {
+        if (index == args.length()) {
             if (required) {
-                HandleValue callee = HandleValue::fromMarkedLocation(&argv[-2]);
-                if (JSFunction *fun = ReportIfNotFunction(cx, callee)) {
+                if (JSFunction *fun = ReportIfNotFunction(cx, args.calleev())) {
                     char numBuf[12];
-                    JS_snprintf(numBuf, sizeof numBuf, "%u", argc);
+                    JS_snprintf(numBuf, sizeof numBuf, "%u", args.length());
                     JSAutoByteString funNameBytes;
                     if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
                         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
                                              JSMSG_MORE_ARGS_NEEDED,
-                                             name, numBuf, (argc == 1) ? "" : "s");
+                                             name, numBuf, (args.length() == 1) ? "" : "s");
                     }
                 }
                 return false;
             }
             break;
         }
-        RootedValue arg(cx, *sp);
+        MutableHandleValue arg = args[index++];
         switch (c) {
           case 'b':
             *va_arg(ap, bool *) = ToBoolean(arg);
             break;
           case 'c':
             if (!ToUint16(cx, arg, va_arg(ap, uint16_t *)))
                 return false;
             break;
@@ -268,59 +266,56 @@ JS_ConvertArgumentsVA(JSContext *cx, uns
             break;
           case 'I':
             if (!ToNumber(cx, arg, &d))
                 return false;
             *va_arg(ap, double *) = ToInteger(d);
             break;
           case 'S':
           case 'W':
-            val = *sp;
-            str = ToString<CanGC>(cx, val);
+            str = ToString<CanGC>(cx, arg);
             if (!str)
                 return false;
-            *sp = STRING_TO_JSVAL(str);
+            arg.setString(str);
             if (c == 'W') {
                 JSFlatString *flat = str->ensureFlat(cx);
                 if (!flat)
                     return false;
                 *va_arg(ap, const jschar **) = flat->chars();
             } else {
                 *va_arg(ap, JSString **) = str;
             }
             break;
           case 'o':
-            if (sp->isNullOrUndefined()) {
+            if (arg.isNullOrUndefined()) {
                 obj = nullptr;
             } else {
-                RootedValue v(cx, *sp);
-                obj = ToObject(cx, v);
+                obj = ToObject(cx, arg);
                 if (!obj)
                     return false;
             }
-            *sp = ObjectOrNullValue(obj);
+            arg.setObjectOrNull(obj);
             *va_arg(ap, JSObject **) = obj;
             break;
           case 'f':
-              obj = ReportIfNotFunction(cx, HandleValue::fromMarkedLocation(sp));
+            obj = ReportIfNotFunction(cx, arg);
             if (!obj)
                 return false;
-            *sp = OBJECT_TO_JSVAL(obj);
+            arg.setObject(*obj);
             *va_arg(ap, JSFunction **) = &obj->as<JSFunction>();
             break;
           case 'v':
-            *va_arg(ap, jsval *) = *sp;
+            *va_arg(ap, jsval *) = arg;
             break;
           case '*':
             break;
           default:
             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_CHAR, format);
             return false;
         }
-        sp++;
     }
     return true;
 }
 
 JS_PUBLIC_API(bool)
 JS_ConvertValue(JSContext *cx, HandleValue value, JSType type, MutableHandleValue vp)
 {
     bool ok;
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -991,23 +991,22 @@ JS_GetEmptyString(JSRuntime *rt);
  *
  * Fewer arguments than format specifies may be passed only if there is a /
  * in format after the last required argument specifier and argc is at least
  * the number of required arguments.  More arguments than format specifies
  * may be passed without error; it is up to the caller to deal with trailing
  * unconverted arguments.
  */
 extern JS_PUBLIC_API(bool)
-JS_ConvertArguments(JSContext *cx, unsigned argc, jsval *argv, const char *format,
-                    ...);
+JS_ConvertArguments(JSContext *cx, const JS::CallArgs &args, const char *format, ...);
 
 #ifdef va_start
 extern JS_PUBLIC_API(bool)
-JS_ConvertArgumentsVA(JSContext *cx, unsigned argc, jsval *argv,
-                      const char *format, va_list ap);
+JS_ConvertArgumentsVA(JSContext *cx, const JS::CallArgs &args, const char *format,
+                      va_list ap);
 #endif
 
 extern JS_PUBLIC_API(bool)
 JS_ConvertValue(JSContext *cx, JS::HandleValue v, JSType type, JS::MutableHandleValue vp);
 
 extern JS_PUBLIC_API(bool)
 JS_ValueToObject(JSContext *cx, JS::HandleValue v, JS::MutableHandleObject objp);
 
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -404,16 +404,18 @@ if CONFIG['JS_SHARED_LIBRARY']:
     FORCE_SHARED_LIB = True
 
 FORCE_STATIC_LIB = True
 
 if CONFIG['MOZ_ETW']:
     GENERATED_FILES = [
         'ETWProvider.h',
     ]
+    # This will get the ETW provider resources into the library mozjs.dll
+    RESFILE = 'ETWProvider.res'
 
 if CONFIG['NIGHTLY_BUILD']:
     DEFINES['ENABLE_PARALLEL_JS'] = True
     DEFINES['ENABLE_BINARYDATA'] = True
 
 DEFINES['EXPORT_JS_API'] = True
 
 if CONFIG['JS_THREADSAFE']:
--- a/js/src/perf/jsperf.cpp
+++ b/js/src/perf/jsperf.cpp
@@ -166,35 +166,41 @@ static const JSClass pm_class = {
     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, pm_finalize
 };
 
 // Constructor and destructor
 
 static bool
 pm_construct(JSContext* cx, unsigned argc, jsval* vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     uint32_t mask;
-    if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "u", &mask))
+    if (!args.hasDefined(0)) {
+        js_ReportMissingArg(cx, args.calleev(), 0);
+        return false;
+    }
+    if (!JS::ToUint32(cx, args[0], &mask))
         return false;
 
     JS::RootedObject obj(cx, JS_NewObjectForConstructor(cx, &pm_class, vp));
     if (!obj)
         return false;
 
     if (!JS_FreezeObject(cx, obj))
         return false;
 
     PerfMeasurement* p = cx->new_<PerfMeasurement>(PerfMeasurement::EventMask(mask));
     if (!p) {
         JS_ReportOutOfMemory(cx);
         return false;
     }
 
     JS_SetPrivate(obj, p);
-    *vp = OBJECT_TO_JSVAL(obj);
+    args.rval().setObject(*obj);
     return true;
 }
 
 static void
 pm_finalize(JSFreeOp* fop, JSObject* obj)
 {
     js::FreeOp::get(fop)->delete_(static_cast<PerfMeasurement*>(JS_GetPrivate(obj)));
 }
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1359,17 +1359,17 @@ Quit(JSContext *cx, unsigned argc, jsval
 {
 #ifdef JS_MORE_DETERMINISTIC
     // Print a message to stderr in more-deterministic builds to help jsfunfuzz
     // find uncatchable-exception bugs.
     fprintf(stderr, "quit called\n");
 #endif
 
     CallArgs args = CallArgsFromVp(argc, vp);
-    JS_ConvertArguments(cx, args.length(), args.array(), "/ i", &gExitCode);
+    JS_ConvertArguments(cx, args, "/ i", &gExitCode);
 
     gQuitting = true;
     return false;
 }
 
 static const char *
 ToSource(JSContext *cx, MutableHandleValue vp, JSAutoByteString *bytes)
 {
@@ -2222,17 +2222,17 @@ DumpHeap(JSContext *cx, unsigned argc, j
     return ok;
 }
 
 static bool
 DumpObject(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedObject arg0(cx);
-    if (!JS_ConvertArguments(cx, args.length(), args.array(), "o", arg0.address()))
+    if (!JS_ConvertArguments(cx, args, "o", arg0.address()))
         return false;
 
     js_DumpObject(arg0);
 
     args.rval().setUndefined();
     return true;
 }
 
@@ -2475,19 +2475,21 @@ NewSandbox(JSContext *cx, bool lazy)
     if (!cx->compartment()->wrap(cx, &obj))
         return nullptr;
     return obj;
 }
 
 static bool
 EvalInContext(JSContext *cx, unsigned argc, jsval *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     RootedString str(cx);
     RootedObject sobj(cx);
-    if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "S / o", str.address(), sobj.address()))
+    if (!JS_ConvertArguments(cx, args, "S / o", str.address(), sobj.address()))
         return false;
 
     size_t srclen;
     const jschar *src = JS_GetStringCharsAndLength(cx, str, &srclen);
     if (!src)
         return false;
 
     SkipRoot skip(cx, &src);
@@ -2502,25 +2504,24 @@ EvalInContext(JSContext *cx, unsigned ar
 
     if (!sobj) {
         sobj = NewSandbox(cx, lazy);
         if (!sobj)
             return false;
     }
 
     if (srclen == 0) {
-        JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(sobj));
+        args.rval().setObject(*sobj);
         return true;
     }
 
     RootedScript script(cx);
     unsigned lineno;
 
     JS_DescribeScriptedCaller(cx, &script, &lineno);
-    RootedValue rval(cx);
     {
         Maybe<JSAutoCompartment> ac;
         unsigned flags;
         JSObject *unwrapped = UncheckedUnwrap(sobj, true, &flags);
         if (flags & Wrapper::CROSS_COMPARTMENT) {
             sobj = unwrapped;
             ac.construct(cx, sobj);
         }
@@ -2530,25 +2531,24 @@ EvalInContext(JSContext *cx, unsigned ar
             return false;
         if (!(sobj->getClass()->flags & JSCLASS_IS_GLOBAL)) {
             JS_ReportError(cx, "Invalid scope argument to evalcx");
             return false;
         }
         if (!JS_EvaluateUCScript(cx, sobj, src, srclen,
                                  script->filename(),
                                  lineno,
-                                 &rval)) {
+                                 args.rval())) {
             return false;
         }
     }
 
-    if (!cx->compartment()->wrap(cx, &rval))
-        return false;
-
-    JS_SET_RVAL(cx, vp, rval);
+    if (!cx->compartment()->wrap(cx, args.rval()))
+        return false;
+
     return true;
 }
 
 static bool
 EvalInFrame(JSContext *cx, unsigned argc, jsval *vp)
 {
     jsval *argv = JS_ARGV(cx, vp);
     if (argc < 2 ||
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1168,20 +1168,22 @@ ScriptFrameIter::setReturnValue(const Va
 }
 
 size_t
 ScriptFrameIter::numFrameSlots() const
 {
     switch (data_.state_) {
       case DONE:
         break;
-     case JIT: {
+      case JIT: {
 #ifdef JS_ION
-        if (data_.ionFrames_.isOptimizedJS())
-            return ionInlineFrames_.snapshotIterator().slots() - ionInlineFrames_.script()->nfixed();
+        if (data_.ionFrames_.isOptimizedJS()) {
+            return ionInlineFrames_.snapshotIterator().allocations() -
+                ionInlineFrames_.script()->nfixed();
+        }
         jit::BaselineFrame *frame = data_.ionFrames_.baselineFrame();
         return frame->numValueSlots() - data_.ionFrames_.script()->nfixed();
 #else
         break;
 #endif
       }
       case SCRIPTED:
         JS_ASSERT(data_.interpFrames_.sp() >= interpFrame()->base());
@@ -1196,17 +1198,17 @@ ScriptFrameIter::frameSlotValue(size_t i
     switch (data_.state_) {
       case DONE:
         break;
       case JIT:
 #ifdef JS_ION
         if (data_.ionFrames_.isOptimizedJS()) {
             jit::SnapshotIterator si(ionInlineFrames_.snapshotIterator());
             index += ionInlineFrames_.script()->nfixed();
-            return si.maybeReadSlotByIndex(index);
+            return si.maybeReadAllocByIndex(index);
         }
 
         index += data_.ionFrames_.script()->nfixed();
         return *data_.ionFrames_.baselineFrame()->valueSlot(index);
 #else
         break;
 #endif
       case SCRIPTED:
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -374,17 +374,17 @@ BuildDate(JSContext *cx, unsigned argc, 
     JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return true;
 }
 
 static bool
 Quit(JSContext *cx, unsigned argc, jsval *vp)
 {
     gExitCode = 0;
-    JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp),"/ i", &gExitCode);
+    JS_ConvertArguments(cx, JS::CallArgsFromVp(argc, vp),"/ i", &gExitCode);
 
     gQuitting = true;
 //    exit(0);
     return false;
 }
 
 // Provide script a way to disable the xpcshell error reporter, preventing
 // reported errors from being logged to the console and also from affecting the
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -2787,16 +2787,22 @@ public:
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE;
 
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE;
 
   virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
 
+  virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
+                                   bool* aSnap) MOZ_OVERRIDE {
+    *aSnap = false;
+    return nsRegion();
+  }
+
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
 
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) MOZ_OVERRIDE;
 
--- a/layout/mathml/nsMathMLmoFrame.cpp
+++ b/layout/mathml/nsMathMLmoFrame.cpp
@@ -28,16 +28,18 @@ NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmoFra
 
 nsMathMLmoFrame::~nsMathMLmoFrame()
 {
 }
 
 static const char16_t kInvisibleComma = char16_t(0x200B); // a.k.a. ZERO WIDTH SPACE
 static const char16_t kApplyFunction  = char16_t(0x2061);
 static const char16_t kInvisibleTimes = char16_t(0x2062);
+static const char16_t kInvisibleSeparator = char16_t(0x2063);
+static const char16_t kInvisiblePlus = char16_t(0x2064);
 
 eMathMLFrameType
 nsMathMLmoFrame::GetMathMLFrameType()
 {
   return NS_MATHML_OPERATOR_IS_INVISIBLE(mFlags)
     ? eMathMLFrameType_OperatorInvisible
     : eMathMLFrameType_OperatorOrdinary;
 }
@@ -118,16 +120,18 @@ nsMathMLmoFrame::ProcessTextData()
   nsContentUtils::GetNodeTextContent(mContent, false, data);
   data.CompressWhitespace();
   int32_t length = data.Length();
   char16_t ch = (length == 0) ? char16_t('\0') : data[0];
 
   if ((length == 1) && 
       (ch == kInvisibleComma || 
        ch == kApplyFunction  || 
+       ch == kInvisibleSeparator ||
+       ch == kInvisiblePlus ||
        ch == kInvisibleTimes)) {
     mFlags |= NS_MATHML_OPERATOR_INVISIBLE;
   }
 
   // don't bother doing anything special if we don't have a
   // single child with a visible text content
   nsPresContext* presContext = PresContext();
   if (NS_MATHML_OPERATOR_IS_INVISIBLE(mFlags) || mFrames.GetLength() != 1) {
new file mode 100644
--- /dev/null
+++ b/layout/reftests/mathml/mo-invisibleoperators-ref.html
@@ -0,0 +1,12 @@
+<html>
+  <math>
+    <mrow>
+      <mn>1</mn>
+      <mn>2</mn>
+      <mn>3</mn>
+      <mn>4</mn>
+      <mn>5</mn>
+      <mn>6</mn>
+    </mrow>
+  </math>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/mathml/mo-invisibleoperators.html
@@ -0,0 +1,17 @@
+<html>
+  <math>
+    <mrow>
+      <mn>1</mn>
+      <mo>&#x200B;<!-- INVISIBLE COMMA --></mo>
+      <mn>2</mn>
+      <mo>&#x2061;<!-- FUNCTION APPLICATION --></mo>
+      <mn>3</mn>
+      <mo>&#x2062;<!-- INVISIBLE TIMES --></mo>
+      <mn>4</mn>
+      <mo>&#x2063;<!-- INVISIBLE SEPARATOR --></mo>
+      <mn>5</mn>
+      <mo>&#x2064;<!-- INVISIBLE PLUS --></mo>
+      <mn>6</mn>
+    </mrow>
+  </math>
+</html>
--- a/layout/reftests/mathml/reftest.list
+++ b/layout/reftests/mathml/reftest.list
@@ -136,16 +136,17 @@ skip-if(B2G) == quotes-1.xhtml quotes-1-
 == mtable-columnalign-multi-mtr-dynamic.html mtable-columnalign-multi-ref.html
 == mtable-columnalign-multi-mtable.html mtable-columnalign-multi-ref.html
 == mtable-columnalign-multi-mtable-dynamic.html mtable-columnalign-multi-ref.html
 == maction-selection.html maction-selection-ref.html
 == maction-dynamic-embellished-op.html maction-dynamic-embellished-op-ref.html
 skip-if(B2G) == maction-dynamic-1.html maction-dynamic-1-ref.html # bug 773482
 == maction-dynamic-2.html maction-dynamic-2-ref.html
 == mo-lspace-rspace.html mo-lspace-rspace-ref.html
+== mo-invisibleoperators.html mo-invisibleoperators-ref.html
 skip-if(B2G) == maction-dynamic-3.html maction-dynamic-3-ref.html # bug 773482
 == whitespace-trim-1.html whitespace-trim-1-ref.html
 == whitespace-trim-2.html whitespace-trim-2-ref.html
 == whitespace-trim-3.html whitespace-trim-3-ref.html
 fails == whitespace-trim-4.html whitespace-trim-4-ref.html # Bug 787215
 == whitespace-trim-5.html whitespace-trim-5-ref.html
 == operator-1.xhtml operator-1-ref.xhtml
 == scriptshift-1.xhtml scriptshift-1-ref.xhtml
--- a/layout/style/ImageLoader.cpp
+++ b/layout/style/ImageLoader.cpp
@@ -317,17 +317,16 @@ void InvalidateImagesCallback(nsIFrame* 
   nsDisplayItem::Type type = nsDisplayItem::GetDisplayItemTypeFromKey(aItem->GetDisplayItemKey());
   uint8_t flags = nsDisplayItem::GetDisplayItemFlagsForType(type);
 
   if (flags & nsDisplayItem::TYPE_RENDERS_NO_IMAGES) {
     return;
   }
 
   aItem->Invalidate();
-  aFrame->SchedulePaint();
 
   // Update ancestor rendering observers (-moz-element etc)
   nsIFrame *f = aFrame;
   while (f && !f->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) {
     nsSVGEffects::InvalidateDirectRenderingObservers(f);
     f = nsLayoutUtils::GetCrossDocParentFrame(f);
   }
 }
@@ -345,16 +344,17 @@ ImageLoader::DoRedraw(FrameSet* aFrameSe
     if (frame->StyleVisibility()->IsVisible()) {
       if (frame->IsFrameOfType(nsIFrame::eTablePart)) {
         // Tables don't necessarily build border/background display items
         // for the individual table part frames, so IterateRetainedDataFor
         // might not find the right display item.
         frame->InvalidateFrame();
       } else {
         FrameLayerBuilder::IterateRetainedDataFor(frame, InvalidateImagesCallback);
+        frame->SchedulePaint();
       }
     }
   }
 }
 
 NS_IMPL_ADDREF(ImageLoader)
 NS_IMPL_RELEASE(ImageLoader)
 
--- a/mobile/android/components/PaymentsUI.js
+++ b/mobile/android/components/PaymentsUI.js
@@ -75,37 +75,37 @@ PaymentUI.prototype = {
                                                         aSuccessCb,
                                                         aErrorCb) {
     let _error = this._error(aErrorCb);
 
     let listItems = [];
 
     // If there's only one payment provider that will work, just move on without prompting the user.
     if (aRequests.length == 1) {
-      aSuccessCb.onresult(aRequestId, aRequests[0].wrappedJSObject.type);
+      aSuccessCb.onresult(aRequestId, aRequests[0].type);
       return;
     }
 
     // Otherwise, let the user select a payment provider from a list.
     for (let i = 0; i < aRequests.length; i++) {
-      let request = aRequests[i].wrappedJSObject;
+      let request = aRequests[i];
       let requestText = request.providerName;
       if (request.productPrice) {
         requestText += " (" + request.productPrice[0].amount + " " +
                               request.productPrice[0].currency + ")";
       }
       listItems.push({ label: requestText });
     }
 
     let p = new Prompt({
       window: null,
       title: this.bundle.GetStringFromName("payments.providerdialog.title"),
     }).setSingleChoiceItems(listItems).show(function(data) {
       if (data.button > -1 && aSuccessCb) {
-        aSuccessCb.onresult(aRequestId, aRequests[data.button].wrappedJSObject.type);
+        aSuccessCb.onresult(aRequestId, aRequests[data.button].type);
       } else {
         _error(aRequestId, "USER_CANCELED");
       }
     });
   },
 
   _error: function(aCallback) {
     return function _error(id, msg) {
--- a/netwerk/base/src/ProxyAutoConfig.cpp
+++ b/netwerk/base/src/ProxyAutoConfig.cpp
@@ -390,36 +390,38 @@ bool PACResolveToString(const nsCString 
   aDottedDecimal.Assign(dottedDecimal);
   return true;
 }
 
 // dnsResolve(host) javascript implementation
 static
 bool PACDnsResolve(JSContext *cx, unsigned int argc, JS::Value *vp)
 {
+  JS::CallArgs args = CallArgsFromVp(argc, vp);
+
   if (NS_IsMainThread()) {
     NS_WARNING("DNS Resolution From PAC on Main Thread. How did that happen?");
     return false;
   }
 
   JS::Rooted<JSString*> arg1(cx);
-  if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "S", arg1.address()))
+  if (!JS_ConvertArguments(cx, args, "S", arg1.address()))
     return false;
 
   nsDependentJSString hostName;
   nsAutoCString dottedDecimal;
 
   if (!hostName.init(cx, arg1))
     return false;
   if (PACResolveToString(NS_ConvertUTF16toUTF8(hostName), dottedDecimal, 0)) {
     JSString *dottedDecimalString = JS_NewStringCopyZ(cx, dottedDecimal.get());
-    JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(dottedDecimalString));
+    args.rval().setString(dottedDecimalString);
   }
   else {
-    JS_SET_RVAL(cx, vp, JSVAL_NULL);
+    args.rval().setNull();
   }
 
   return true;
 }
 
 // myIpAddress() javascript implementation
 static
 bool PACMyIpAddress(JSContext *cx, unsigned int argc, JS::Value *vp)
@@ -436,31 +438,33 @@ bool PACMyIpAddress(JSContext *cx, unsig
 
   return sRunning->MyIPAddress(vp);
 }
 
 // proxyAlert(msg) javascript implementation
 static
 bool PACProxyAlert(JSContext *cx, unsigned int argc, JS::Value *vp)
 {
+  JS::CallArgs args = CallArgsFromVp(argc, vp);
+
   JS::Rooted<JSString*> arg1(cx);
-  if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "S", arg1.address()))
+  if (!JS_ConvertArguments(cx, args, "S", arg1.address()))
     return false;
 
   nsDependentJSString message;
   if (!message.init(cx, arg1))
     return false;
 
   nsString alertMessage;
   alertMessage.SetCapacity(32 + message.Length());
   alertMessage += NS_LITERAL_STRING("PAC-alert: ");
   alertMessage += message;
   PACLogToConsole(alertMessage);
 
-  JS_SET_RVAL(cx, vp, JSVAL_VOID);  /* return undefined */
+  args.rval().setUndefined();  /* return undefined */
   return true;
 }
 
 static const JSFunctionSpec PACGlobalFunctions[] = {
   JS_FS("dnsResolve", PACDnsResolve, 1, 0),
   JS_FS("myIpAddress", PACMyIpAddress, 0, 0),
   JS_FS("alert", PACProxyAlert, 1, 0),
   JS_FS_END
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -231,16 +231,18 @@ class TreeMetadataEmitter(LoggingMixin):
             'IS_COMPONENT',
             'IS_GYP_DIR',
             'JS_MODULES_PATH',
             'LIBS',
             'LIBXUL_LIBRARY',
             'MSVC_ENABLE_PGO',
             'NO_DIST_INSTALL',
             'OS_LIBS',
+            'RCFILE',
+            'RESFILE',
             'SDK_LIBRARY',
         ]
         for v in varlist:
             if v in sandbox and sandbox[v]:
                 passthru.variables[v] = sandbox[v]
 
         # NO_VISIBILITY_FLAGS is slightly different
         if sandbox['NO_VISIBILITY_FLAGS']:
--- a/python/mozbuild/mozbuild/frontend/sandbox_symbols.py
+++ b/python/mozbuild/mozbuild/frontend/sandbox_symbols.py
@@ -317,16 +317,28 @@ VARIABLES = {
         """, None),
 
     'OS_LIBS': (list, list,
         """System link libraries.
 
         This variable contains a list of system libaries to link against.
         """, None),
 
+    'RCFILE': (unicode, unicode,
+        """The program .rc file.
+
+        This variable can only be used on Windows (and OS/2).
+        """, None),
+
+    'RESFILE': (unicode, unicode,
+        """The program .res file.
+
+        This variable can only be used on Windows (and OS/2).
+        """, None),
+
     'SDK_LIBRARY': (StrictOrderingOnAppendList, list,
         """Elements of the distributed SDK.
 
         Files on this list will be copied into ``SDK_LIB_DIR``
         (``$DIST/sdk/lib``).
         """, None),
 
     'SIMPLE_PROGRAMS': (StrictOrderingOnAppendList, list,
--- a/python/mozbuild/mozbuild/test/backend/data/variable_passthru/moz.build
+++ b/python/mozbuild/mozbuild/test/backend/data/variable_passthru/moz.build
@@ -30,8 +30,11 @@ SOURCES += ['bar.mm', 'foo.mm']
 SOURCES += ['baz.S', 'foo.S']
 
 FAIL_ON_WARNINGS = True
 LIBXUL_LIBRARY = True
 MSVC_ENABLE_PGO = True
 NO_VISIBILITY_FLAGS = True
 
 DELAYLOAD_DLLS = ['foo.dll', 'bar.dll']
+
+RCFILE = 'foo.rc'
+RESFILE = 'bar.res'
--- a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
+++ b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
@@ -323,16 +323,22 @@ class TestRecursiveMakeBackend(BackendTe
             ],
             'DELAYLOAD_LDFLAGS': [
                 'DELAYLOAD_LDFLAGS += -DELAYLOAD:foo.dll',
                 'DELAYLOAD_LDFLAGS += -DELAYLOAD:bar.dll',
             ],
             'USE_DELAYIMP': [
                 'USE_DELAYIMP := 1',
             ],
+            'RCFILE': [
+                'RCFILE := foo.rc',
+            ],
+            'RESFILE': [
+                'RESFILE := bar.res',
+            ],
         }
 
         for var, val in expected.items():
             # print("test_variable_passthru[%s]" % (var))
             found = [str for str in lines if str.startswith(var)]
             self.assertEqual(found, val)
 
     def test_exports(self):
--- a/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/moz.build
+++ b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/moz.build
@@ -36,8 +36,11 @@ MSVC_ENABLE_PGO = True
 NO_DIST_INSTALL = True
 
 FORCE_SHARED_LIB = True
 EXPORT_LIBRARY = True
 IS_COMPONENT = True
 NO_VISIBILITY_FLAGS = True
 
 DELAYLOAD_DLLS = ['foo.dll', 'bar.dll']
+
+RCFILE = 'foo.rc'
+RESFILE = 'bar.res'
--- a/python/mozbuild/mozbuild/test/frontend/test_emitter.py
+++ b/python/mozbuild/mozbuild/test/frontend/test_emitter.py
@@ -166,16 +166,18 @@ class TestEmitterBasic(unittest.TestCase
             MSVC_ENABLE_PGO=True,
             NO_DIST_INSTALL=True,
             OS_LIBS=['foo.so', '-l123', 'aaa.a'],
             SDK_LIBRARY=['fans.sdk', 'tans.sdk'],
             SSRCS=['bans.S', 'fans.S'],
             VISIBILITY_FLAGS='',
             DELAYLOAD_LDFLAGS=['-DELAYLOAD:foo.dll', '-DELAYLOAD:bar.dll'],
             USE_DELAYIMP=True,
+            RCFILE='foo.rc',
+            RESFILE='bar.res',
         )
 
         variables = objs[0].variables
         maxDiff = self.maxDiff
         self.maxDiff = None
         self.assertEqual(wanted, variables)
         self.maxDiff = maxDiff
 
--- a/security/manager/ssl/src/nsSmartCardMonitor.cpp
+++ b/security/manager/ssl/src/nsSmartCardMonitor.cpp
@@ -180,52 +180,52 @@ SmartCardMonitoringThread::SetTokenName(
       /* this must match the allocator used in
        * PLHashAllocOps.freeEntry DefaultFreeEntry */
       char *entry = (char *)PR_Malloc(len+sizeof(uint32_t));
      
       if (entry) {  
         memcpy(entry,&series,sizeof(uint32_t));
         memcpy(&entry[sizeof(uint32_t)],tokenName,len);
 
-        PL_HashTableAdd(mHash,(void *)slotid, entry); /* adopt */
+        PL_HashTableAdd(mHash,(void *)(uintptr_t)slotid, entry); /* adopt */
         return;
       }
     } 
     else {
       // if tokenName was not provided, remove the old one (implicit delete)
-      PL_HashTableRemove(mHash,(void *)slotid);
+      PL_HashTableRemove(mHash,(void *)(uintptr_t)slotid);
     }
   }
 }
 
 // retrieve the name saved above
 const char *
 SmartCardMonitoringThread::GetTokenName(CK_SLOT_ID slotid)
 {
   const char *tokenName = nullptr;
   const char *entry;
 
   if (mHash) {
-    entry = (const char *)PL_HashTableLookupConst(mHash,(void *)slotid);
+    entry = (const char *)PL_HashTableLookupConst(mHash,(void *)(uintptr_t)slotid);
     if (entry) {
       tokenName = &entry[sizeof(uint32_t)];
     }
   }
   return tokenName;
 }
 
 // retrieve the series saved in SetTokenName above
 uint32_t
 SmartCardMonitoringThread::GetTokenSeries(CK_SLOT_ID slotid)
 {
   uint32_t series = 0;
   const char *entry;
 
   if (mHash) {
-    entry = (const char *)PL_HashTableLookupConst(mHash,(void *)slotid);
+    entry = (const char *)PL_HashTableLookupConst(mHash,(void *)(uintptr_t)slotid);
     if (entry) {
       memcpy(&series,entry,sizeof(uint32_t));
     }
   }
   return series;
 }
 
 //
--- a/testing/marionette/client/marionette/client.py
+++ b/testing/marionette/client/marionette/client.py
@@ -1,12 +1,13 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+import errno
 import json
 import socket
 
 from errors import InvalidResponseException, ErrorCodes
 
 
 class MarionetteClient(object):
     """ The Marionette socket client.  This speaks the same protocol
@@ -47,19 +48,18 @@ class MarionetteClient(object):
         response = self.sock.recv(10)
         sep = response.find(':')
         length = response[0:sep]
         if length != '':
             response = response[sep + 1:]
             response += self._recv_n_bytes(int(length) + 1 + len(length) - 10)
             return json.loads(response)
         else:
-            raise InvalidResponseException("Could not successfully complete "
-                                           "transport of message to Gecko, "
-                                           "socket closed?",
+            raise InvalidResponseException("Could not communicate with Marionette server. "
+                                           "Is the Gecko process still running?",
                                            status=ErrorCodes.INVALID_RESPONSE)
 
     def connect(self, timeout=360.0):
         """ Connect to the server and process the hello message we expect
             to receive in response.
         """
         self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
         self.sock.settimeout(timeout)
@@ -85,17 +85,23 @@ class MarionetteClient(object):
             self.connect()
         if 'to' not in msg:
             msg['to'] = self.actor
         data = json.dumps(msg)
         data = '%s:%s' % (len(data), data)
 
         for packet in [data[i:i + self.max_packet_length] for i in
                        range(0, len(data), self.max_packet_length)]:
-            self.sock.send(packet)
+            try: 
+                self.sock.send(packet)
+            except IOError as e:
+                if e.errno == errno.EPIPE:
+                    raise IOError("%s: Connection to Marionette server is lost. Check gecko.log (desktop firefox) or logcat (b2g) for errors." % str(e))
+                else:
+                    raise e
 
         response = self.receive()
         return response
 
     def close(self):
         """ Close the socket.
         """
         self.sock.close()
--- a/testing/marionette/client/marionette/runner/base.py
+++ b/testing/marionette/client/marionette/runner/base.py
@@ -15,16 +15,17 @@ import random
 import mozinfo
 import moznetwork
 import xml.dom.minidom as dom
 
 from manifestparser import TestManifest
 from mozhttpd import MozHttpd
 from marionette import Marionette
 from moztest.results import TestResultCollection, TestResult, relevant_line
+from mixins.b2g import B2GTestResultMixin, get_b2g_pid, get_dm
 
 
 class MarionetteTest(TestResult):
 
     @property
     def test_name(self):
         if self.test_class is not None:
             return '%s.py %s.%s' % (self.test_class.split('.')[0],
@@ -108,17 +109,17 @@ class MarionetteTestResult(unittest._Tex
             name = os.path.basename(test.jsFile)
             test_class = None
 
         t = self.resultClass(name=name, test_class=test_class,
                        time_start=test.start_time, result_expected=result_expected,
                        context=context, **kwargs)
         # call any registered result modifiers
         for modifier in self.result_modifiers:
-            modifier(t, result_expected, result_actual, output, context)
+            result_expected, result_actual, output, context = modifier(t, result_expected, result_actual, output, context)
         t.finish(result_actual,
                  time_end=time.time() if test.start_time else 0,
                  reason=relevant_line(output),
                  output=output)
         self.append(t)
 
     def addError(self, test, err):
         self.add_test_result(test, output=self._exc_info_to_string(err, test), result_actual='ERROR')
@@ -233,16 +234,17 @@ class MarionetteTestResult(unittest._Tex
 
 
 class MarionetteTextTestRunner(unittest.TextTestRunner):
 
     resultclass = MarionetteTestResult
 
     def __init__(self, **kwargs):
         self.marionette = kwargs['marionette']
+        self.capabilities = kwargs.pop('capabilities')
         del kwargs['marionette']
         unittest.TextTestRunner.__init__(self, **kwargs)
 
     def _makeResult(self):
         return self.resultclass(self.stream,
                                 self.descriptions,
                                 self.verbosity,
                                 marionette=self.marionette)
@@ -304,16 +306,50 @@ class MarionetteTextTestRunner(unittest.
             infos.append("unexpected successes=%d" % unexpectedSuccesses)
         if infos:
             self.stream.writeln(" (%s)" % (", ".join(infos),))
         else:
             self.stream.write("\n")
         return result
 
 
+class B2GMarionetteTestResult(MarionetteTestResult, B2GTestResultMixin):
+
+    def __init__(self, *args, **kwargs):
+        # stupid hack because _TextTestRunner doesn't accept **kwargs
+        b2g_pid = kwargs.pop('b2g_pid')
+        MarionetteTestResult.__init__(self, *args, **kwargs)
+        kwargs['b2g_pid'] = b2g_pid
+        B2GTestResultMixin.__init__(self, *args, **kwargs)
+ 
+
+class B2GMarionetteTextTestRunner(MarionetteTextTestRunner):
+
+    resultclass = B2GMarionetteTestResult
+
+    def __init__(self, **kwargs):
+        MarionetteTextTestRunner.__init__(self, **kwargs)
+        if self.capabilities['device'] != 'desktop':
+            self.resultclass = B2GMarionetteTestResult
+        self.b2g_pid = None
+
+    def _makeResult(self):
+        return self.resultclass(self.stream,
+                                self.descriptions,
+                                self.verbosity,
+                                marionette=self.marionette,
+                                b2g_pid=self.b2g_pid)
+
+    def run(self, test):
+        dm_type = os.environ.get('DM_TRANS', 'adb')
+        if dm_type == 'adb':
+            self.b2g_pid = get_b2g_pid(get_dm(self.marionette))
+        return super(B2GMarionetteTextTestRunner, self).run(test)
+
+
 class BaseMarionetteOptions(OptionParser):
     def __init__(self, **kwargs):
         OptionParser.__init__(self, **kwargs)
         self.parse_args_handlers = [] # Used by mixins
         self.verify_usage_handlers = [] # Used by mixins
         self.add_option('--autolog',
                         action='store_true',
                         dest='autolog',
@@ -763,16 +799,22 @@ class BaseMarionetteTestRunner(object):
         if not self.httpd:
             print "starting httpd"
             self.start_httpd()
 
         if not self.marionette:
             self.start_marionette()
             if self.emulator:
                 self.marionette.emulator.wait_for_homescreen(self.marionette)
+            # Retrieve capabilities for later use
+            if not self._capabilities:
+                self.capabilities
+
+        if self.capabilities['device'] != 'desktop':
+            self.textrunnerclass = B2GMarionetteTextTestRunner
 
         testargs = {}
         if self.type is not None:
             testtypes = self.type.replace('+', ' +').replace('-', ' -').split()
             for atype in testtypes:
                 if atype.startswith('+'):
                     testargs.update({ atype[1:]: 'true' })
                 elif atype.startswith('-'):
@@ -853,17 +895,18 @@ class BaseMarionetteTestRunner(object):
                                            testloader,
                                            self.marionette,
                                            self.testvars,
                                            **self.test_kwargs)
                 break
 
         if suite.countTestCases():
             runner = self.textrunnerclass(verbosity=3,
-                                          marionette=self.marionette)
+                                          marionette=self.marionette,
+                                          capabilities=self.capabilities)
             results = runner.run(suite)
             self.results.append(results)
 
             self.failed += len(results.failures) + len(results.errors)
             if hasattr(results, 'skipped'):
                 self.todo += len(results.skipped)
             self.passed += results.passed
             for failure in results.failures + results.errors:
--- a/testing/marionette/client/marionette/runner/mixins/b2g.py
+++ b/testing/marionette/client/marionette/runner/mixins/b2g.py
@@ -1,31 +1,102 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import mozdevice
 import os
+import re
+
+
+def get_dm(marionette=None,**kwargs):
+    if marionette and marionette.emulator:
+        adb_path = marionette.emulator.b2g.adb_path
+        return mozdevice.DeviceManagerADB(adbPath=adb_path,
+                                          deviceSerial='emulator-%d' % marionette.emulator.port,
+                                          **kwargs)
+    else:
+        dm_type = os.environ.get('DM_TRANS', 'adb')
+        if dm_type == 'adb':
+            return mozdevice.DeviceManagerADB(**kwargs)
+        elif dm_type == 'sut':
+            host = os.environ.get('TEST_DEVICE')
+            if not host:
+                raise Exception('Must specify host with SUT!')
+            return mozdevice.DeviceManagerSUT(host=host)
+        else:
+            raise Exception('Unknown device manager type: %s' % dm_type)
+
+
+def get_b2g_pid(dm):
+    b2g_output = dm.shellCheckOutput(['b2g-ps'])
+    pid_re = re.compile(r"""[\s\S]*root[\s]*([\d]+)[\s]*(?:[\w]*[\s]*){6}/system/b2g/b2g""")
+    if '/system/b2g/b2g' in b2g_output:
+        pid = pid_re.match(b2g_output)
+        return pid.group(1)
 
 
 class B2GTestCaseMixin(object):
 
     # TODO: add methods like 'restart b2g'
     def __init__(self, *args, **kwargs):
         self._device_manager = None
 
     def get_device_manager(self, *args, **kwargs):
         if not self._device_manager:
-            dm_type = os.environ.get('DM_TRANS', 'adb')
-            if dm_type == 'adb':
-                self._device_manager = mozdevice.DeviceManagerADB(**kwargs)
-            elif dm_type == 'sut':
-                host = os.environ.get('TEST_DEVICE')
-                if not host:
-                    raise Exception('Must specify host with SUT!')
-                self._device_manager = mozdevice.DeviceManagerSUT(host=host)
-            else:
-                raise Exception('Unknown device manager type: %s' % dm_type)
+            self._device_manager = get_dm(self.marionette, **kwargs)
         return self._device_manager
 
     @property
     def device_manager(self):
         return self.get_device_manager()
+
+class B2GTestResultMixin(object):
+
+    def __init__(self, *args, **kwargs):
+        self.result_modifiers.append(self.b2g_output_modifier)
+        self.b2g_pid = kwargs.pop('b2g_pid')
+
+    def b2g_output_modifier(self, test, result_expected, result_actual, output, context):
+        # This function will check if b2g is running and report any recent errors. This is
+        # used in automation since a plain timeout error doesn't tell you
+        # much information about what actually is going on
+        def diagnose_socket(output):
+            dm_type = os.environ.get('DM_TRANS', 'adb')
+            if dm_type == 'adb':
+                device_manager = get_dm(self.marionette)
+                pid = get_b2g_pid(device_manager)
+                if pid:
+                    # find recent errors
+                    message = ""
+                    error_re = re.compile(r"""[\s\S]*(exception|error)[\s\S]*""", flags=re.IGNORECASE)
+                    logcat = device_manager.getLogcat()
+                    latest = []
+                    iters = len(logcat) - 1
+                    # reading from the latest line
+                    while len(latest) < 5 and iters >= 0:
+                        line = logcat[iters]
+                        error_log_line = error_re.match(line)
+                        if error_log_line is not None:
+                            latest.append(line)
+                        iters -= 1
+                    message += "\nMost recent errors/exceptions are:\n"
+                    for line in reversed(latest):
+                        message += "%s" % line
+                    b2g_status = ""
+                    if pid != self.b2g_pid:
+                        b2g_status = "The B2G process has restarted after crashing during the tests so "
+                    else:
+                        b2g_status = "B2G is still running but "
+                    output += "%s\n%sMarionette can't respond due to either a Gecko, Gaia or Marionette error. " \
+                              "Above, the 5 most recent errors are " \
+                              "listed. Check logcat for all errors if these errors are not the cause " \
+                              "of the failure." % (message, b2g_status)
+                else:
+                    output += "B2G process has died"
+            return output
+        # output is the actual string output from the test, so we have to do string comparison
+        if "Broken pipe" in output:
+            output = diagnose_socket(output)
+        elif "Connection timed out" in output:
+            output = diagnose_socket(output)
+        return result_expected, result_actual, output, context
+
--- a/testing/marionette/client/marionette/runner/mixins/reporting.py
+++ b/testing/marionette/client/marionette/runner/mixins/reporting.py
@@ -188,16 +188,17 @@ class HTMLReportingTestResultMixin(objec
 
     def __init__(self, *args, **kwargs):
         self.result_modifiers.append(self.html_modifier)
 
     def html_modifier(self, test, result_expected, result_actual, output, context):
         test.debug = None
         if result_actual is not 'PASS':
             test.debug = self.gather_debug()
+        return result_expected, result_actual, output, context
 
     def gather_debug(self):
         debug = {}
         try:
             # TODO make screenshot consistant size by using full viewport
             # Bug 883294 - Add ability to take full viewport screenshots
             debug['screenshot'] = self.marionette.screenshot()
             debug['source'] = self.marionette.page_source
--- a/toolkit/library/Makefile.in
+++ b/toolkit/library/Makefile.in
@@ -30,17 +30,16 @@ SHARED_LIBRARY_LIBS += \
 ifeq ($(OS_ARCH)_$(GNU_CC),WINNT_)
 RCINCLUDE = xulrunner.rc
 
 LOCAL_INCLUDES += -I$(topsrcdir)/widget/windows
 LOCAL_INCLUDES += -I$(topsrcdir)/xpcom/base
 endif
 
 ifeq ($(OS_ARCH),OS2)
-RESFILE = xulrunos2.res
 RCFLAGS += -i $(topsrcdir)/widget/os2
 
 LOCAL_INCLUDES += -I$(topsrcdir)/widget/os2
 LOCAL_INCLUDES += -I$(topsrcdir)/xpcom/base
 endif
 
 # dependent libraries
 ifdef MOZ_B2G_BT_BLUEZ #{
--- a/toolkit/library/moz.build
+++ b/toolkit/library/moz.build
@@ -39,16 +39,27 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] not in (
    CONFIG['MOZ_XUL']:
     DEFINES['MOZ_FILEVIEW'] = True
 
 # Platform-specific icon channel stuff - supported mostly-everywhere
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'os2', 'mac', 'cocoa',
                                     'gtk2', 'gtk3', 'qt', 'android'):
     DEFINES['ICON_DECODER'] = True
 
+LOCAL_INCLUDES += [
+    '/config',
+    # need widget/windows for resource.h (included from widget.rc)
+    '/widget/windows',
+]
+
+if CONFIG['OS_ARCH'] == 'WINNT' and not CONFIG['GNU_CC']:
+    LOCAL_INCLUDES += [
+        '/xpcom/base',
+    ]
+
 FAIL_ON_WARNINGS = True
 
 MSVC_ENABLE_PGO = True
 
 FORCE_SHARED_LIB = True
 
 DELAYLOAD_DLLS += [
     'comdlg32.dll',
--- a/webapprt/PaymentUIGlue.js
+++ b/webapprt/PaymentUIGlue.js
@@ -47,25 +47,25 @@ function PaymentUI() {}
 PaymentUI.prototype = {
   classID: Components.ID("{ede1124f-72e8-4a31-9567-3270d46f21fb}"),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIGlue]),
 
   confirmPaymentRequest: function(aRequestId, aRequests, aSuccessCb, aErrorCb) {
     // If there's only one payment provider that will work, just move on
     // without prompting the user.
     if (aRequests.length == 1) {
-      aSuccessCb.onresult(aRequestId, aRequests[0].wrappedJSObject.type);
+      aSuccessCb.onresult(aRequestId, aRequests[0].type);
       return;
     }
 
     let items = [];
 
     // Otherwise, let the user select a payment provider from a list.
     for (let i = 0; i < aRequests.length; i++) {
-      let request = aRequests[i].wrappedJSObject;
+      let request = aRequests[i];
       let requestText = request.providerName;
       if (request.productPrice && Array.isArray(request.productPrice)) {
         // We should guess the user currency and use that instead.
         requestText += " (" + request.productPrice[0].amount + " " +
                               request.productPrice[0].currency + ")";
       }
       items.push(requestText);
     }
@@ -75,17 +75,17 @@ PaymentUI.prototype = {
     let bundle = Services.strings.
                    createBundle("chrome://webapprt/locale/webapp.properties");
     let result = Services.prompt.
                    select(null, bundle.GetStringFromName("paymentDialog.title"),
                           bundle.GetStringFromName("paymentDialog.message"),
                           items.length, items, selected);
     if (result) {
       aSuccessCb.onresult(aRequestId,
-                          aRequests[selected.value].wrappedJSObject.type);
+                          aRequests[selected.value].type);
     } else {
       aErrorCb.onresult(aRequestId, "USER_CANCELLED");
     }
   },
 
   showPaymentFlow: function(aRequestId, aPaymentFlowInfo, aErrorCb) {
     let win = Services.ww.
                 openWindow(null,
--- a/widget/os2/Makefile.in
+++ b/widget/os2/Makefile.in
@@ -1,15 +1,13 @@
 #
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-RESFILE		= widget.res
-
 include $(topsrcdir)/config/rules.mk
 
 CXXFLAGS += $(MOZ_CAIRO_CFLAGS)
 
 install-readme:	README.$(MOZ_APP_NAME)
 ifneq (,$(filter-out xulrunner sunbird,$(MOZ_APP_NAME)))
 	cp -f $^ $(DIST)/bin/README.txt
 endif
--- a/widget/os2/moz.build
+++ b/widget/os2/moz.build
@@ -31,8 +31,10 @@ FINAL_LIBRARY = 'xul'
 LOCAL_INCLUDES += [
     '../xpwidgets',
 ]
 
 
 DEFINES['USE_OS2_TOOLKIT_HEADERS'] = True
 
 DEFINES['MOZ_APP_DISPLAYNAME'] = '"%s"' % CONFIG['MOZ_APP_DISPLAYNAME']
+
+RESFILE = 'widget.res'
--- a/widget/windows/Makefile.in
+++ b/widget/windows/Makefile.in
@@ -1,10 +1,8 @@
 #
 # 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/.
 
-RESFILE		= widget.res
-
 include $(topsrcdir)/config/rules.mk
 
 CXXFLAGS += $(MOZ_CAIRO_CFLAGS)
--- a/widget/windows/moz.build
+++ b/widget/windows/moz.build
@@ -107,8 +107,10 @@ LOCAL_INCLUDES += [
     '/xpcom/base',
 ]
 
 DEFINES['MOZ_UNICODE'] = True
 
 for var in ('MOZ_ENABLE_D3D9_LAYER', 'MOZ_ENABLE_D3D10_LAYER'):
     if CONFIG[var]:
         DEFINES[var] = True
+
+RESFILE = 'widget.res'
--- a/xpcom/ds/nsWindowsRegKey.cpp
+++ b/xpcom/ds/nsWindowsRegKey.cpp
@@ -75,29 +75,29 @@ nsWindowsRegKey::Close()
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindowsRegKey::Open(uint32_t rootKey, const nsAString &path, uint32_t mode)
 {
   Close();
 
-  LONG rv = RegOpenKeyExW((HKEY) rootKey, PromiseFlatString(path).get(), 0,
+  LONG rv = RegOpenKeyExW((HKEY)(intptr_t) rootKey, PromiseFlatString(path).get(), 0,
                           (REGSAM) mode, &mKey);
 
   return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsWindowsRegKey::Create(uint32_t rootKey, const nsAString &path, uint32_t mode)
 {
   Close();
 
   DWORD disposition;
-  LONG rv = RegCreateKeyExW((HKEY) rootKey, PromiseFlatString(path).get(), 0,
+  LONG rv = RegCreateKeyExW((HKEY)(intptr_t) rootKey, PromiseFlatString(path).get(), 0,
                             nullptr, REG_OPTION_NON_VOLATILE, (REGSAM) mode, nullptr,
                             &mKey, &disposition);
 
   return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsWindowsRegKey::OpenChild(const nsAString &path, uint32_t mode,
--- a/xpcom/reflect/xptcall/src/md/unix/moz.build
+++ b/xpcom/reflect/xptcall/src/md/unix/moz.build
@@ -251,17 +251,17 @@ if CONFIG['OS_ARCH'] == 'NetBSD' and CON
 if CONFIG['OS_ARCH'] == 'OpenBSD' and CONFIG['OS_TEST'] == 'sparc':
     SOURCES += [
         'xptcinvoke_asm_sparc_openbsd.s',
         'xptcinvoke_sparc_openbsd.cpp',
         'xptcstubs_asm_sparc_openbsd.s',
         'xptcstubs_sparc_openbsd.cpp',
     ]
 
-if CONFIG['OS_ARCH'] == 'OpenBSD' and CONFIG['OS_TEST'] == 'sparc64':
+if CONFIG['OS_ARCH'] in ('OpenBSD', 'FreeBSD') and CONFIG['OS_TEST'] == 'sparc64':
     SOURCES += [
         'xptcinvoke_asm_sparc64_openbsd.s',
         'xptcinvoke_sparc64_openbsd.cpp',
         'xptcstubs_asm_sparc64_openbsd.s',
         'xptcstubs_sparc64_openbsd.cpp',
     ]
 
 if CONFIG['OS_ARCH'] == 'SunOS' and CONFIG['OS_TEST'].find('86') == -1:
--- a/xulrunner/app/Makefile.in
+++ b/xulrunner/app/Makefile.in
@@ -54,17 +54,16 @@ else
 RCFLAGS += -DMOZ_XULRUNNER --include-dir $(srcdir)
 endif
 ifdef DEBUG
 RCFLAGS += -DDEBUG
 endif
 endif
 
 ifeq ($(OS_ARCH),OS2)
-RESFILE=splashos2.res
 RCFLAGS += -DMOZ_XULRUNNER
 ifdef DEBUG
 RCFLAGS += -DDEBUG
 endif
 RCFLAGS += -DXULRUNNER_ICO='"$(DIST)/branding/xulrunner.ico"' -DDOCUMENT_ICO='"$(DIST)/branding/document.ico"'
 endif
 
 include $(topsrcdir)/config/rules.mk