merge mozilla-central to b2g-inbound
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 11 Oct 2013 11:24:32 +0200
changeset 150500 a91e7a44eb857d9c0635ff0974bd3804c1ec9878
parent 150499 a658fcd210b5fad7e8f18d2fa73483e9da39676d (current diff)
parent 150438 6b101d4c6d241e3fa39b5ce71f122243fe2c118c (diff)
child 150501 a82f2ffec20007a7ee376fb88777c110811c0292
push id25444
push userryanvm@gmail.com
push dateFri, 11 Oct 2013 21:00:01 +0000
treeherdermozilla-central@558cf02e6b9b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-central to b2g-inbound
media/webrtc/shared_libs.mk
mobile/android/base/resources/xml/preferences.xml.in
mobile/android/base/resources/xml/preferences_customize.xml.in
mobile/android/base/resources/xml/searchable.xml.in
mobile/android/base/resources/xml/sync_authenticator.xml.in
mobile/android/base/resources/xml/sync_options.xml.in
mobile/android/base/resources/xml/sync_syncadapter.xml.in
--- a/configure.in
+++ b/configure.in
@@ -4009,17 +4009,16 @@ MOZ_OPUS=1
 MOZ_WEBM=1
 MOZ_DASH=
 MOZ_DIRECTSHOW=
 MOZ_WMF=
 MOZ_WEBRTC=1
 MOZ_PEERCONNECTION=
 MOZ_SRTP=
 MOZ_WEBRTC_SIGNALING=
-MOZ_WEBRTC_IN_LIBXUL=
 MOZ_WEBRTC_ASSERT_ALWAYS=1
 MOZ_SCTP=
 MOZ_MEDIA_PLUGINS=
 MOZ_MEDIA_NAVIGATOR=
 MOZ_OMX_PLUGIN=
 MOZ_VP8=
 MOZ_VP8_ERROR_CONCEALMENT=
 MOZ_VP8_ENCODER=
@@ -5186,33 +5185,29 @@ if test -n "$MOZ_WEBRTC"; then
     MOZ_RAW=1
     MOZ_VP8=1
     MOZ_VP8_ENCODER=1
     MOZ_VP8_ERROR_CONCEALMENT=1
 
 dnl enable once Signaling lands
     MOZ_WEBRTC_SIGNALING=1
     AC_DEFINE(MOZ_WEBRTC_SIGNALING)
-    if test "${OS_TARGET}" = "WINNT"; then
-        MOZ_WEBRTC_IN_LIBXUL=1
-    fi
 dnl enable once PeerConnection lands
     MOZ_PEERCONNECTION=1
     AC_DEFINE(MOZ_PEERCONNECTION)
     MOZ_SCTP=1
     MOZ_SRTP=1
     AC_DEFINE(MOZ_SCTP)
     AC_DEFINE(MOZ_SRTP)
 fi
 
 AC_SUBST(MOZ_WEBRTC)
 AC_SUBST(MOZ_WEBRTC_LEAKING_TESTS)
 AC_SUBST(MOZ_WEBRTC_SIGNALING)
 AC_SUBST(MOZ_PEERCONNECTION)
-AC_SUBST(MOZ_WEBRTC_IN_LIBXUL)
 AC_SUBST(MOZ_WEBRTC_ASSERT_ALWAYS)
 AC_SUBST(MOZ_SCTP)
 AC_SUBST(MOZ_SRTP)
 
 dnl Use integers over floats for audio on B2G and Android, because audio
 dnl backends for those platforms don't support floats.
 if test "$OS_TARGET" = "Android"; then
     MOZ_SAMPLE_TYPE_S16=1
--- a/content/canvas/test/webgl/non-conf-tests/mochitest.ini
+++ b/content/canvas/test/webgl/non-conf-tests/mochitest.ini
@@ -1,8 +1,9 @@
 [DEFAULT]
 support-files =
   driver-info.js
   webgl-util.js
 
+[test_highp_fs.html]
 [test_webgl_available.html]
 [test_webgl_conformance.html]
 [test_webgl_request_mismatch.html]
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/non-conf-tests/test_highp_fs.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<title>WebGL test: `highp` support</title>
+<script src="/MochiKit/MochiKit.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<script src="driver-info.js"></script>
+<script src="webgl-util.js"></script>
+<script id="shader-vs" type="x-shader/x-vertex">
+
+void main(void) {
+  gl_Position = vec4(vec3(0.0), 1.0);
+}
+
+</script>
+<script id="shader-fs" type="x-shader/x-fragment">
+
+precision highp float;
+
+void main(void) {
+  gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
+}
+
+</script>
+<body>
+<canvas id="c"></canvas>
+<script>
+
+// Give ourselves a scope to return early from:
+(function() {
+  var gl = WebGLUtil.getWebGL('c');
+  if (!gl) {
+    todo(false, 'WebGL is unavailable.');
+    return;
+  }
+
+  // Catch actual WebGLUtil errors, not GL errors.
+  function errorFunc(str) {
+    ok(false, 'Error: ' + str);
+  }
+  WebGLUtil.setErrorFunc(errorFunc);
+
+  function checkGLError(func, info) {
+    var error = gl.getError();
+    var prefix = info ? ('[' + info + '] ') : ''
+    func(!error, prefix + 'gl.getError should be 0x0, was 0x' + error.toString(16) + '.');
+  }
+
+  var format = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT);
+  var prog = WebGLUtil.createProgramByIds(gl, 'shader-vs', 'shader-fs');
+  checkGLError(ok);
+  
+  if (format) {
+    ok(prog, 'Frag shader with unconditional `precision highp float` should ' +
+             'link if `getShaderPrecisionFormat` gives a format for it.');
+  } else {
+    ok(!prog, 'Frag shader with unconditional `precision highp float` should ' +
+              'NOT link if `getShaderPrecisionFormat` gives NO format for it.');
+  }
+})();
+
+</script>
+
--- a/content/canvas/test/webgl/non-conf-tests/webgl-util.js
+++ b/content/canvas/test/webgl/non-conf-tests/webgl-util.js
@@ -1,26 +1,42 @@
 WebGLUtil = (function() {
   // ---------------------------------------------------------------------------
-  // Error handling
+  // Error handling (for obvious failures, such as invalid element ids)
 
   function defaultErrorFunc(str) {
     console.log('Error: ' + str);
   }
 
   var gErrorFunc = defaultErrorFunc;
   function setErrorFunc(func) {
     gErrorFunc = func;
   }
 
   function error(str) {
     gErrorFunc(str);
   }
 
   // ---------------------------------------------------------------------------
+  // Warning handling (for failures that may be intentional)
+
+  function defaultWarningFunc(str) {
+    console.log('Warning: ' + str);
+  }
+
+  var gWarningFunc = defaultWarningFunc;
+  function setWarningFunc(func) {
+    gWarningFunc = func;
+  }
+
+  function warning(str) {
+    gWarningFunc(str);
+  }
+
+  // ---------------------------------------------------------------------------
   // WebGL helpers
 
   function getWebGL(canvasId, requireConformant) {
     // `requireConformant` will default to falsey if it is not supplied.
 
     var canvas = document.getElementById(canvasId);
 
     var gl = null;
@@ -58,29 +74,29 @@ WebGLUtil = (function() {
   // Returns a valid shader, or null on errors.
   function createShaderById(gl, id) {
     var elem = document.getElementById(id);
     if (!elem) {
       error('Failed to create shader from non-existent id \'' + id + '\'.');
       return null;
     }
 
-    var src = getContentById(id);
+    var src = getContentFromElem(elem);
 
     var shader;
     if (elem.type == "x-shader/x-fragment") {
       shader = gl.createShader(gl.FRAGMENT_SHADER);
-    } else if (shaderScript.type == "x-shader/x-vertex") {
+    } else if (elem.type == "x-shader/x-vertex") {
       shader = gl.createShader(gl.VERTEX_SHADER);
     } else {
       error('Bad MIME type for shader \'' + id + '\': ' + elem.type + '.');
       return null;
     }
 
-    gl.shaderSource(shader, str);
+    gl.shaderSource(shader, src);
     gl.compileShader(shader);
 
     return shader;
   }
 
   function createProgramByIds(gl, vsId, fsId) {
     var vs = createShaderById(gl, vsId);
     var fs = createShaderById(gl, fsId);
@@ -88,27 +104,28 @@ WebGLUtil = (function() {
       return null;
 
     var prog = gl.createProgram();
     gl.attachShader(prog, vs);
     gl.attachShader(prog, fs);
     gl.linkProgram(prog);
 
     if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) {
-      var str = "Shader program linking failed:\n";
-      str += "Shader program info log:\n" + gl.getProgramInfoLog(prog) + "\n\n";
-      str += "Vert shader log:\n" + gl.getShaderInfoLog(vs) + "\n\n";
-      str += "Frag shader log:\n" + gl.getShaderInfoLog(fs);
-      error(str);
+      var str = "Shader program linking failed:";
+      str += "\nShader program info log:\n" + gl.getProgramInfoLog(prog);
+      str += "\n\nVert shader log:\n" + gl.getShaderInfoLog(vs);
+      str += "\n\nFrag shader log:\n" + gl.getShaderInfoLog(fs);
+      warning(str);
       return null;
     }
 
     return prog;
   }
 
   return {
     setErrorFunc: setErrorFunc,
+    setWarningFunc: setWarningFunc,
 
     getWebGL: getWebGL,
     createShaderById: createShaderById,
     createProgramByIds: createProgramByIds,
   };
 })();
--- a/content/media/directshow/moz.build
+++ b/content/media/directshow/moz.build
@@ -21,17 +21,17 @@ CPP_SOURCES += [
     'DirectShowReader.cpp',
     'DirectShowUtils.cpp',
     'SampleSink.cpp',
     'SourceFilter.cpp',
 ]
 
 # If WebRTC isn't being built, we need to compile the DirectShow base classes so that
 # they're available at link time.
-if not CONFIG['MOZ_WEBRTC_IN_LIBXUL']:
+if not CONFIG['MOZ_WEBRTC']:
     CPP_SOURCES += [
         TOPSRCDIR + '/media/webrtc/trunk/webrtc/modules/video_capture/windows/BaseFilter.cpp',
         TOPSRCDIR + '/media/webrtc/trunk/webrtc/modules/video_capture/windows/BaseInputPin.cpp',
         TOPSRCDIR + '/media/webrtc/trunk/webrtc/modules/video_capture/windows/BasePin.cpp',
         TOPSRCDIR + '/media/webrtc/trunk/webrtc/modules/video_capture/windows/MediaType.cpp',
     ]
 
 FAIL_ON_WARNINGS = True
--- a/gfx/2d/convolver.cpp
+++ b/gfx/2d/convolver.cpp
@@ -24,17 +24,16 @@
 // AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 // SUCH DAMAGE.
 
 #include "convolver.h"
 
 #include <algorithm>
-#include "nsAlgorithm.h"
 
 #include "skia/SkTypes.h"
 
 // note: SIMD_SSE2 is not enabled because of bugs, apparently
 
 #if defined(SIMD_SSE2)
 #include <emmintrin.h>  // ARCH_CPU_X86_FAMILY was defined in build/config.h
 #endif
--- a/gfx/2d/image_operations.cpp
+++ b/gfx/2d/image_operations.cpp
@@ -30,17 +30,16 @@
 
 #define _USE_MATH_DEFINES
 #include <algorithm>
 #include <cmath>
 #include <limits>
 
 #include "image_operations.h"
 
-#include "nsAlgorithm.h"
 #include "base/stack_container.h"
 #include "convolver.h"
 #include "skia/SkColorPriv.h"
 #include "skia/SkBitmap.h"
 #include "skia/SkRect.h"
 #include "skia/SkFontHost.h"
 
 namespace skia {
--- a/js/public/CallArgs.h
+++ b/js/public/CallArgs.h
@@ -38,17 +38,17 @@
 #include "js/RootingAPI.h"
 #include "js/Value.h"
 
 /* Typedef for native functions called by the JS VM. */
 typedef bool
 (* JSNative)(JSContext *cx, unsigned argc, JS::Value *vp);
 
 /* Typedef for native functions that may be called in parallel. */
-typedef js::ParallelResult
+typedef bool
 (* JSParallelNative)(js::ForkJoinSlice *slice, unsigned argc, JS::Value *vp);
 
 /*
  * Typedef for native functions that may be called either in parallel or
  * sequential execution.
  */
 typedef bool
 (* JSThreadSafeNative)(js::ThreadSafeContext *cx, unsigned argc, JS::Value *vp);
@@ -57,17 +57,17 @@ typedef bool
  * Convenience wrappers for passing in ThreadSafeNative to places that expect
  * a JSNative or a JSParallelNative.
  */
 template <JSThreadSafeNative threadSafeNative>
 inline bool
 JSNativeThreadSafeWrapper(JSContext *cx, unsigned argc, JS::Value *vp);
 
 template <JSThreadSafeNative threadSafeNative>
-inline js::ParallelResult
+inline bool
 JSParallelNativeThreadSafeWrapper(js::ForkJoinSlice *slice, unsigned argc, JS::Value *vp);
 
 /*
  * Compute |this| for the |vp| inside a JSNative, either boxing primitives or
  * replacing with the global object as necessary.
  *
  * This method will go away at some point: instead use |args.thisv()|.  If the
  * value is an object, no further work is required.  If that value is |null| or
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug925305.js
@@ -0,0 +1,14 @@
+function testFloat32SetElemIC(a) {
+  for (var i = 0; i < a.length; i++) {
+    var r = Math.fround(Math.random());
+    a[i] = r;
+    assertEq(a[i], r);
+  }
+}
+
+testFloat32SetElemIC(new Array(2048));
+testFloat32SetElemIC(new Array(2048));
+
+enableOsiPointRegisterChecks();
+testFloat32SetElemIC(new Array(2048));
+testFloat32SetElemIC(new Float64Array(2048));
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/parallel/bug909743.js
@@ -0,0 +1,21 @@
+if (getBuildConfiguration().parallelJS) {
+  function assertParallelExecSucceeds(opFunction) {
+    for (var i = 0; i < 100; ++i) {
+      opFunction({mode:"compile"});
+    }
+  }
+  function assertArraySeqParResultsEq(arr, op, func) {
+    assertParallelExecSucceeds(
+      function (m) { 
+        return arr[op + "Par"].apply(arr, [func, m]); 
+      }
+    );
+  }
+  function range(n, m) {
+    var result = [];
+    for (var i = n; i < m; i++)
+      result.push(i);
+    return result;
+  }
+  assertArraySeqParResultsEq(range(0, 512), "map", function(e) { return e+'x'; });
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/parallel/ic-setelement.js
@@ -0,0 +1,135 @@
+load(libdir + "parallelarray-helpers.js");
+
+function set(a, n) {
+  // Padding to prevent inlining.
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  for (var i = 0; i < n; i++)
+    a[i] = i;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+}
+set({}, 1024);
+set({}, 1024);
+function Foo() { }
+set(new Foo, 1024);
+
+function testSetDense() {
+  assertArraySeqParResultsEq(
+    range(0, minItemsTestingThreshold),
+    "map",
+    function (i) {
+      var a1 = [];
+      // Defines .foo
+      set(a1, i+1);
+      return a1[i];
+    });
+}
+
+if (getBuildConfiguration().parallelJS) {
+  testSetDense();
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/parallel/ic-setproperty.js
@@ -0,0 +1,111 @@
+load(libdir + "parallelarray-helpers.js");
+
+function set(o, v) {
+  // Padding to prevent inlining.
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  o.foo = v;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+}
+set({ foo: 0 }, 42);
+
+function testSetPropertySlot() {
+  assertArraySeqParResultsEq(
+    range(0, minItemsTestingThreshold),
+    "map",
+    function (i) {
+      var o1 = {};
+      var o2 = {};
+      var o3 = {};
+      var o4 = {};
+      // Defines .foo
+      set(o1, i + 1);
+      set(o2, i + 2);
+      set(o3, i + 3);
+      set(o4, i + 4);
+      // Sets .foo
+      set(o1, i + 5);
+      set(o2, i + 6);
+      set(o3, i + 7);
+      set(o4, i + 8);
+      return o1.foo + o2.foo + o3.foo + o4.foo;
+    });
+}
+
+function testSetArrayLength() {
+  assertArraySeqParResultsEq(
+    range(0, minItemsTestingThreshold),
+    "map",
+    function (i) {
+      var a = [];
+      a.length = i;
+      return a.length;
+    });
+}
+
+if (getBuildConfiguration().parallelJS) {
+  testSetPropertySlot();
+  testSetArrayLength();
+}
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -1420,17 +1420,17 @@ jit::FinishBailoutToBaseline(BaselineBai
         return false;
 
     // Create arguments objects for bailed out frames, to maintain the invariant
     // that script->needsArgsObj() implies frame->hasArgsObj().
     RootedScript innerScript(cx, nullptr);
     RootedScript outerScript(cx, nullptr);
 
     JS_ASSERT(cx->currentlyRunningInJit());
-    IonFrameIterator iter(cx->mainThread().ionTop);
+    IonFrameIterator iter(cx);
 
     uint32_t frameno = 0;
     while (frameno < numFrames) {
         JS_ASSERT(!iter.isOptimizedJS());
 
         if (iter.isBaselineJS()) {
             BaselineFrame *frame = iter.baselineFrame();
 
--- a/js/src/jit/BaselineFrame.cpp
+++ b/js/src/jit/BaselineFrame.cpp
@@ -152,17 +152,17 @@ BaselineFrame::initForOsr(StackFrame *fp
     if (cx->compartment()->debugMode()) {
         // In debug mode, update any Debugger.Frame objects for the StackFrame to
         // point to the BaselineFrame.
 
         // The caller pushed a fake return address. ScriptFrameIter, used by the
         // debugger, wants a valid return address, but it's okay to just pick one.
         // In debug mode there's always at least 1 ICEntry (since there are always
         // debug prologue/epilogue calls).
-        IonFrameIterator iter(cx->mainThread().ionTop);
+        IonFrameIterator iter(cx);
         JS_ASSERT(iter.returnAddress() == nullptr);
         BaselineScript *baseline = fp->script()->baselineScript();
         iter.current()->setReturnAddress(baseline->returnAddressForIC(baseline->icEntry(0)));
 
         if (!Debugger::handleBaselineOsr(cx, fp, this))
             return false;
     }
 
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -18,16 +18,17 @@
 #ifdef JS_ION_PERF
 # include "jit/PerfSpewer.h"
 #endif
 #include "jit/VMFunctions.h"
 
 #include "jsboolinlines.h"
 #include "jsscriptinlines.h"
 
+#include "jit/IonFrames-inl.h"
 #include "vm/Interpreter-inl.h"
 #include "vm/ScopeObject-inl.h"
 
 namespace js {
 namespace jit {
 
 #ifdef DEBUG
 void
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -149,17 +149,17 @@ CodeGenerator::CodeGenerator(MIRGenerato
 
 CodeGenerator::~CodeGenerator()
 {
     JS_ASSERT_IF(!gen->compilingAsmJS(), masm.numAsmJSAbsoluteLinks() == 0);
     js_delete(unassociatedScriptCounts_);
 }
 
 typedef bool (*StringToNumberFn)(ThreadSafeContext *, JSString *, double *);
-typedef ParallelResult (*StringToNumberParFn)(ForkJoinSlice *, JSString *, double *);
+typedef bool (*StringToNumberParFn)(ForkJoinSlice *, JSString *, double *);
 static const VMFunctionsModal StringToNumberInfo = VMFunctionsModal(
     FunctionInfo<StringToNumberFn>(StringToNumber),
     FunctionInfo<StringToNumberParFn>(StringToNumberPar));
 
 bool
 CodeGenerator::visitValueToInt32(LValueToInt32 *lir)
 {
     ValueOperand operand = ToValue(lir, LValueToInt32::Input);
@@ -644,17 +644,17 @@ CodeGenerator::visitTypeObjectDispatch(L
 
     // Unknown function: jump to fallback block.
     LBlock *fallback = mir->getFallback()->lir();
     masm.jump(fallback->label());
     return true;
 }
 
 typedef JSFlatString *(*IntToStringFn)(ThreadSafeContext *, int);
-typedef ParallelResult (*IntToStringParFn)(ForkJoinSlice *, int, MutableHandleString);
+typedef JSFlatString *(*IntToStringParFn)(ForkJoinSlice *, int);
 static const VMFunctionsModal IntToStringInfo = VMFunctionsModal(
     FunctionInfo<IntToStringFn>(Int32ToString<CanGC>),
     FunctionInfo<IntToStringParFn>(IntToStringPar));
 
 bool
 CodeGenerator::visitIntToString(LIntToString *lir)
 {
     Register input = ToRegister(lir->input());
@@ -671,17 +671,17 @@ CodeGenerator::visitIntToString(LIntToSt
     masm.movePtr(ImmPtr(&GetIonContext()->runtime->staticStrings.intStaticTable), output);
     masm.loadPtr(BaseIndex(output, input, ScalePointer), output);
 
     masm.bind(ool->rejoin());
     return true;
 }
 
 typedef JSString *(*DoubleToStringFn)(ThreadSafeContext *, double);
-typedef ParallelResult (*DoubleToStringParFn)(ForkJoinSlice *, double, MutableHandleString);
+typedef JSString *(*DoubleToStringParFn)(ForkJoinSlice *, double);
 static const VMFunctionsModal DoubleToStringInfo = VMFunctionsModal(
     FunctionInfo<DoubleToStringFn>(NumberToString<CanGC>),
     FunctionInfo<DoubleToStringParFn>(DoubleToStringPar));
 
 bool
 CodeGenerator::visitDoubleToString(LDoubleToString *lir)
 {
     FloatRegister input = ToFloatRegister(lir->input());
@@ -985,17 +985,16 @@ CodeGenerator::visitParameter(LParameter
 bool
 CodeGenerator::visitCallee(LCallee *lir)
 {
     // read number of actual arguments from the JS frame.
     Register callee = ToRegister(lir->output());
     Address ptr(StackPointer, frameSize() + IonJSFrameLayout::offsetOfCalleeToken());
 
     masm.loadPtr(ptr, callee);
-    masm.clearCalleeTag(callee, gen->info().executionMode());
     return true;
 }
 
 bool
 CodeGenerator::visitStart(LStart *lir)
 {
     return true;
 }
@@ -1850,17 +1849,17 @@ CodeGenerator::visitCallGeneric(LCallGen
     masm.loadBaselineOrIonRaw(objreg, objreg, executionMode, &invoke);
 
     // Nestle the StackPointer up to the argument vector.
     masm.freeStack(unusedStack);
 
     // Construct the IonFramePrefix.
     uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), IonFrame_OptimizedJS);
     masm.Push(Imm32(call->numActualArgs()));
-    masm.PushCalleeToken(calleereg, executionMode);
+    masm.Push(calleereg);
     masm.Push(Imm32(descriptor));
 
     // Check whether the provided arguments satisfy target argc.
     masm.load16ZeroExtend(Address(calleereg, offsetof(JSFunction, nargs)), nargsreg);
     masm.cmp32(nargsreg, Imm32(call->numStackArgs()));
     masm.j(Assembler::Above, &thunk);
 
     masm.jump(&makeCall);
@@ -1971,17 +1970,17 @@ CodeGenerator::visitCallKnown(LCallKnown
         masm.loadBaselineOrIonNoArgCheck(objreg, objreg, executionMode, &uncompiled);
 
     // Nestle the StackPointer up to the argument vector.
     masm.freeStack(unusedStack);
 
     // Construct the IonFramePrefix.
     uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), IonFrame_OptimizedJS);
     masm.Push(Imm32(call->numActualArgs()));
-    masm.PushCalleeToken(calleereg, executionMode);
+    masm.Push(calleereg);
     masm.Push(Imm32(descriptor));
 
     // Finally call the function in objreg.
     uint32_t callOffset = masm.callIon(objreg);
     if (!markSafepointAt(callOffset, call))
         return false;
 
     // Increment to remove IonFramePrefix; decrement to fill FrameSizeClass.
@@ -3858,17 +3857,17 @@ CodeGenerator::visitModD(LModD *ins)
     if (gen->compilingAsmJS())
         masm.callWithABI(AsmJSImm_ModD, MacroAssembler::DOUBLE);
     else
         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, NumberMod), MacroAssembler::DOUBLE);
     return true;
 }
 
 typedef bool (*BinaryFn)(JSContext *, MutableHandleValue, MutableHandleValue, Value *);
-typedef ParallelResult (*BinaryParFn)(ForkJoinSlice *, HandleValue, HandleValue, Value *);
+typedef bool (*BinaryParFn)(ForkJoinSlice *, HandleValue, HandleValue, Value *);
 
 static const VMFunction AddInfo = FunctionInfo<BinaryFn>(js::AddValues);
 static const VMFunction SubInfo = FunctionInfo<BinaryFn>(js::SubValues);
 static const VMFunction MulInfo = FunctionInfo<BinaryFn>(js::MulValues);
 static const VMFunction DivInfo = FunctionInfo<BinaryFn>(js::DivValues);
 static const VMFunction ModInfo = FunctionInfo<BinaryFn>(js::ModValues);
 static const VMFunctionsModal UrshInfo = VMFunctionsModal(
     FunctionInfo<BinaryFn>(js::UrshValues),
@@ -3900,17 +3899,17 @@ CodeGenerator::visitBinaryV(LBinaryV *li
         return callVM(UrshInfo, lir);
 
       default:
         MOZ_ASSUME_UNREACHABLE("Unexpected binary op");
     }
 }
 
 typedef bool (*StringCompareFn)(JSContext *, HandleString, HandleString, bool *);
-typedef ParallelResult (*StringCompareParFn)(ForkJoinSlice *, HandleString, HandleString, bool *);
+typedef bool (*StringCompareParFn)(ForkJoinSlice *, HandleString, HandleString, bool *);
 static const VMFunctionsModal StringsEqualInfo = VMFunctionsModal(
     FunctionInfo<StringCompareFn>(jit::StringsEqual<true>),
     FunctionInfo<StringCompareParFn>(jit::StringsEqualPar));
 static const VMFunctionsModal StringsNotEqualInfo = VMFunctionsModal(
     FunctionInfo<StringCompareFn>(jit::StringsEqual<false>),
     FunctionInfo<StringCompareParFn>(jit::StringsUnequalPar));
 
 bool
@@ -3972,18 +3971,17 @@ CodeGenerator::visitCompareS(LCompareS *
     Register right = ToRegister(lir->right());
     Register output = ToRegister(lir->output());
     Register temp = ToRegister(lir->temp());
 
     return emitCompareS(lir, op, left, right, output, temp);
 }
 
 typedef bool (*CompareFn)(JSContext *, MutableHandleValue, MutableHandleValue, bool *);
-typedef ParallelResult (*CompareParFn)(ForkJoinSlice *, MutableHandleValue, MutableHandleValue,
-                                       bool *);
+typedef bool (*CompareParFn)(ForkJoinSlice *, MutableHandleValue, MutableHandleValue, bool *);
 static const VMFunctionsModal EqInfo = VMFunctionsModal(
     FunctionInfo<CompareFn>(jit::LooselyEqual<true>),
     FunctionInfo<CompareParFn>(jit::LooselyEqualPar));
 static const VMFunctionsModal NeInfo = VMFunctionsModal(
     FunctionInfo<CompareFn>(jit::LooselyEqual<false>),
     FunctionInfo<CompareParFn>(jit::LooselyUnequalPar));
 static const VMFunctionsModal StrictEqInfo = VMFunctionsModal(
     FunctionInfo<CompareFn>(jit::StrictlyEqual<true>),
@@ -4256,18 +4254,17 @@ CodeGenerator::visitEmulatesUndefinedAnd
 
     Register objreg = ToRegister(lir->input());
 
     testObjectTruthy(objreg, unequal, equal, ToRegister(lir->temp()), ool);
     return true;
 }
 
 typedef JSString *(*ConcatStringsFn)(ThreadSafeContext *, HandleString, HandleString);
-typedef ParallelResult (*ConcatStringsParFn)(ForkJoinSlice *, HandleString, HandleString,
-                                             MutableHandleString);
+typedef JSString *(*ConcatStringsParFn)(ForkJoinSlice *, HandleString, HandleString);
 static const VMFunctionsModal ConcatStringsInfo = VMFunctionsModal(
     FunctionInfo<ConcatStringsFn>(ConcatStrings<CanGC>),
     FunctionInfo<ConcatStringsParFn>(ConcatStringsPar));
 
 bool
 CodeGenerator::emitConcat(LInstruction *lir, Register lhs, Register rhs, Register output)
 {
     OutOfLineCode *ool = oolCallVM(ConcatStringsInfo, lir, (ArgList(), lhs, rhs),
@@ -4452,25 +4449,36 @@ IonCompartment::generateStringConcatStub
     masm.lshiftPtr(Imm32(JSString::LENGTH_SHIFT), temp2);
     masm.orPtr(Imm32(JSString::FIXED_FLAGS), temp2);
     masm.storePtr(temp2, Address(output, JSString::offsetOfLengthAndFlags()));
 
     // Set chars pointer, keep in temp2 for copy loop below.
     masm.computeEffectiveAddress(Address(output, JSShortString::offsetOfInlineStorage()), temp2);
     masm.storePtr(temp2, Address(output, JSShortString::offsetOfChars()));
 
-    // Copy lhs chars. Temp1 still holds the lhs length. Note that this
-    // advances temp2 to point to the next char.
-    masm.loadPtr(Address(lhs, JSString::offsetOfChars()), temp3);
-    CopyStringChars(masm, temp2, temp3, temp1, temp4);
-
-    // Copy rhs chars.
-    masm.loadPtr(Address(rhs, JSString::offsetOfChars()), temp3);
-    masm.loadStringLength(rhs, temp1);
-    CopyStringChars(masm, temp2, temp3, temp1, temp4);
+    {
+        // We use temp4 in this block, which in parallel execution also holds
+        // a live ForkJoinSlice pointer. If we are compiling for parallel
+        // execution, be sure to save and restore the ForkJoinSlice.
+        if (mode == ParallelExecution)
+            masm.push(temp4);
+
+        // Copy lhs chars. Temp1 still holds the lhs length. Note that this
+        // advances temp2 to point to the next char.
+        masm.loadPtr(Address(lhs, JSString::offsetOfChars()), temp3);
+        CopyStringChars(masm, temp2, temp3, temp1, temp4);
+
+        // Copy rhs chars.
+        masm.loadPtr(Address(rhs, JSString::offsetOfChars()), temp3);
+        masm.loadStringLength(rhs, temp1);
+        CopyStringChars(masm, temp2, temp3, temp1, temp4);
+
+        if (mode == ParallelExecution)
+            masm.pop(temp4);
+    }
 
     // Null-terminate.
     masm.store16(Imm32(0), Address(temp2, 0));
     masm.ret();
 
     masm.bind(&failurePopTemps);
     masm.pop(temp2);
     masm.pop(temp1);
@@ -4838,18 +4846,17 @@ CodeGenerator::visitStoreElementHoleV(LS
         masm.storeValue(value, BaseIndex(elements, ToRegister(lir->index()), TimesEight));
 
     masm.bind(ool->rejoin());
     return true;
 }
 
 typedef bool (*SetObjectElementFn)(JSContext *, HandleObject, HandleValue, HandleValue,
                                    bool strict);
-typedef ParallelResult (*SetElementParFn)(ForkJoinSlice *, HandleObject, HandleValue,
-                                          HandleValue, bool);
+typedef bool (*SetElementParFn)(ForkJoinSlice *, HandleObject, HandleValue, HandleValue, bool);
 static const VMFunctionsModal SetObjectElementInfo = VMFunctionsModal(
     FunctionInfo<SetObjectElementFn>(SetObjectElement),
     FunctionInfo<SetElementParFn>(SetElementPar));
 
 bool
 CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole *ool)
 {
     Register object, elements;
@@ -5446,19 +5453,18 @@ CodeGenerator::visitRunOncePrologue(LRun
 {
     pushArg(ImmGCPtr(lir->mir()->block()->info().script()));
     return callVM(RunOnceScriptPrologueInfo, lir);
 }
 
 
 typedef JSObject *(*InitRestParameterFn)(JSContext *, uint32_t, Value *, HandleObject,
                                          HandleObject);
-typedef ParallelResult (*InitRestParameterParFn)(ForkJoinSlice *, uint32_t, Value *,
-                                                 HandleObject, HandleObject,
-                                                 MutableHandleObject);
+typedef JSObject *(*InitRestParameterParFn)(ForkJoinSlice *, uint32_t, Value *,
+                                            HandleObject, HandleObject);
 static const VMFunctionsModal InitRestParameterInfo = VMFunctionsModal(
     FunctionInfo<InitRestParameterFn>(InitRestParameter),
     FunctionInfo<InitRestParameterParFn>(InitRestParameterPar));
 
 bool
 CodeGenerator::emitRest(LInstruction *lir, Register array, Register numActuals,
                         Register temp0, Register temp1, unsigned numFormals,
                         JSObject *templateObject)
@@ -6024,16 +6030,54 @@ CodeGenerator::addGetPropertyCache(LInst
         return addCache(ins, allocateCache(cache));
       }
       default:
         MOZ_ASSUME_UNREACHABLE("Bad execution mode");
     }
 }
 
 bool
+CodeGenerator::addSetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
+                                   PropertyName *name, ConstantOrRegister value, bool strict,
+                                   bool needsTypeBarrier)
+{
+    switch (gen->info().executionMode()) {
+      case SequentialExecution: {
+          SetPropertyIC cache(liveRegs, objReg, name, value, strict, needsTypeBarrier);
+          return addCache(ins, allocateCache(cache));
+      }
+      case ParallelExecution: {
+          SetPropertyParIC cache(objReg, name, value, strict, needsTypeBarrier);
+          return addCache(ins, allocateCache(cache));
+      }
+      default:
+        MOZ_ASSUME_UNREACHABLE("Bad execution mode");
+    }
+}
+
+bool
+CodeGenerator::addSetElementCache(LInstruction *ins, Register obj, Register unboxIndex,
+                                  Register temp, FloatRegister tempFloat, ValueOperand index,
+                                  ConstantOrRegister value, bool strict)
+{
+    switch (gen->info().executionMode()) {
+      case SequentialExecution: {
+        SetElementIC cache(obj, unboxIndex, temp, tempFloat, index, value, strict);
+        return addCache(ins, allocateCache(cache));
+      }
+      case ParallelExecution: {
+        SetElementParIC cache(obj, unboxIndex, temp, tempFloat, index, value, strict);
+        return addCache(ins, allocateCache(cache));
+      }
+      default:
+        MOZ_ASSUME_UNREACHABLE("Bad execution mode");
+    }
+}
+
+bool
 CodeGenerator::visitGetPropertyCacheV(LGetPropertyCacheV *ins)
 {
     RegisterSet liveRegs = ins->safepoint()->liveRegs();
     Register objReg = ToRegister(ins->getOperand(0));
     PropertyName *name = ins->mir()->name();
     bool allowGetters = ins->mir()->allowGetters();
     TypedOrValueRegister output = TypedOrValueRegister(GetValueOutput(ins));
 
@@ -6076,18 +6120,17 @@ CodeGenerator::visitGetPropertyIC(OutOfL
         return false;
     StoreValueTo(ic->output()).generate(this);
     restoreLiveIgnore(lir, StoreValueTo(ic->output()).clobbered());
 
     masm.jump(ool->rejoin());
     return true;
 }
 
-typedef ParallelResult (*GetPropertyParICFn)(ForkJoinSlice *, size_t, HandleObject,
-                                             MutableHandleValue);
+typedef bool (*GetPropertyParICFn)(ForkJoinSlice *, size_t, HandleObject, MutableHandleValue);
 const VMFunction GetPropertyParIC::UpdateInfo =
     FunctionInfo<GetPropertyParICFn>(GetPropertyParIC::update);
 
 bool
 CodeGenerator::visitGetPropertyParIC(OutOfLineUpdateCache *ool, DataPtr<GetPropertyParIC> &ic)
 {
     LInstruction *lir = ool->lir();
     saveLive(lir);
@@ -6168,19 +6211,18 @@ CodeGenerator::visitSetElementCacheV(LSe
 {
     Register obj = ToRegister(ins->object());
     Register unboxIndex = ToTempUnboxRegister(ins->tempToUnboxIndex());
     Register temp = ToRegister(ins->temp());
     FloatRegister tempFloat = ToFloatRegister(ins->tempFloat());
     ValueOperand index = ToValue(ins, LSetElementCacheV::Index);
     ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LSetElementCacheV::Value));
 
-    SetElementIC cache(obj, unboxIndex, temp, tempFloat, index, value, ins->mir()->strict());
-
-    return addCache(ins, allocateCache(cache));
+    return addSetElementCache(ins, obj, unboxIndex, temp, tempFloat, index, value,
+                              ins->mir()->strict());
 }
 
 bool
 CodeGenerator::visitSetElementCacheT(LSetElementCacheT *ins)
 {
     Register obj = ToRegister(ins->object());
     Register unboxIndex = ToTempUnboxRegister(ins->tempToUnboxIndex());
     Register temp = ToRegister(ins->temp());
@@ -6188,19 +6230,18 @@ CodeGenerator::visitSetElementCacheT(LSe
     ValueOperand index = ToValue(ins, LSetElementCacheT::Index);
     ConstantOrRegister value;
     const LAllocation *tmp = ins->value();
     if (tmp->isConstant())
         value = *tmp->toConstant();
     else
         value = TypedOrValueRegister(ins->mir()->value()->type(), ToAnyRegister(tmp));
 
-    SetElementIC cache(obj, unboxIndex, temp, tempFloat, index, value, ins->mir()->strict());
-
-    return addCache(ins, allocateCache(cache));
+    return addSetElementCache(ins, obj, unboxIndex, temp, tempFloat, index, value,
+                              ins->mir()->strict());
 }
 
 typedef bool (*SetElementICFn)(JSContext *, size_t, HandleObject, HandleValue, HandleValue);
 const VMFunction SetElementIC::UpdateInfo =
     FunctionInfo<SetElementICFn>(SetElementIC::update);
 
 bool
 CodeGenerator::visitSetElementIC(OutOfLineUpdateCache *ool, DataPtr<SetElementIC> &ic)
@@ -6215,18 +6256,40 @@ CodeGenerator::visitSetElementIC(OutOfLi
     if (!callVM(SetElementIC::UpdateInfo, lir))
         return false;
     restoreLive(lir);
 
     masm.jump(ool->rejoin());
     return true;
 }
 
-typedef ParallelResult (*GetElementParICFn)(ForkJoinSlice *, size_t, HandleObject,
-                                            HandleValue, MutableHandleValue);
+typedef bool (*SetElementParICFn)(ForkJoinSlice *, size_t, HandleObject, HandleValue, HandleValue);
+const VMFunction SetElementParIC::UpdateInfo =
+    FunctionInfo<SetElementParICFn>(SetElementParIC::update);
+
+bool
+CodeGenerator::visitSetElementParIC(OutOfLineUpdateCache *ool, DataPtr<SetElementParIC> &ic)
+{
+    LInstruction *lir = ool->lir();
+    saveLive(lir);
+
+    pushArg(ic->value());
+    pushArg(ic->index());
+    pushArg(ic->object());
+    pushArg(Imm32(ool->getCacheIndex()));
+    if (!callVM(SetElementParIC::UpdateInfo, lir))
+        return false;
+    restoreLive(lir);
+
+    masm.jump(ool->rejoin());
+    return true;
+}
+
+typedef bool (*GetElementParICFn)(ForkJoinSlice *, size_t, HandleObject, HandleValue,
+                                  MutableHandleValue);
 const VMFunction GetElementParIC::UpdateInfo =
     FunctionInfo<GetElementParICFn>(GetElementParIC::update);
 
 bool
 CodeGenerator::visitGetElementParIC(OutOfLineUpdateCache *ool, DataPtr<GetElementParIC> &ic)
 {
     LInstruction *lir = ool->lir();
     saveLive(lir);
@@ -6271,18 +6334,21 @@ CodeGenerator::visitBindNameIC(OutOfLine
     restoreLiveIgnore(lir, StoreRegisterTo(ic->outputReg()).clobbered());
 
     masm.jump(ool->rejoin());
     return true;
 }
 
 typedef bool (*SetPropertyFn)(JSContext *, HandleObject,
                               HandlePropertyName, const HandleValue, bool, jsbytecode *);
-static const VMFunction SetPropertyInfo =
-    FunctionInfo<SetPropertyFn>(SetProperty);
+typedef bool (*SetPropertyParFn)(ForkJoinSlice *, HandleObject,
+                                 HandlePropertyName, const HandleValue, bool, jsbytecode *);
+static const VMFunctionsModal SetPropertyInfo = VMFunctionsModal(
+    FunctionInfo<SetPropertyFn>(SetProperty),
+    FunctionInfo<SetPropertyParFn>(SetPropertyPar));
 
 bool
 CodeGenerator::visitCallSetProperty(LCallSetProperty *ins)
 {
     ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LCallSetProperty::Value));
 
     const Register objReg = ToRegister(ins->getOperand(0));
 
@@ -6334,36 +6400,34 @@ CodeGenerator::visitCallDeleteElement(LC
 
 bool
 CodeGenerator::visitSetPropertyCacheV(LSetPropertyCacheV *ins)
 {
     RegisterSet liveRegs = ins->safepoint()->liveRegs();
     Register objReg = ToRegister(ins->getOperand(0));
     ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LSetPropertyCacheV::Value));
 
-    SetPropertyIC cache(liveRegs, objReg, ins->mir()->name(), value, ins->mir()->strict(),
-                        ins->mir()->needsTypeBarrier());
-    return addCache(ins, allocateCache(cache));
+    return addSetPropertyCache(ins, liveRegs, objReg, ins->mir()->name(), value,
+                               ins->mir()->strict(), ins->mir()->needsTypeBarrier());
 }
 
 bool
 CodeGenerator::visitSetPropertyCacheT(LSetPropertyCacheT *ins)
 {
     RegisterSet liveRegs = ins->safepoint()->liveRegs();
     Register objReg = ToRegister(ins->getOperand(0));
     ConstantOrRegister value;
 
     if (ins->getOperand(1)->isConstant())
         value = ConstantOrRegister(*ins->getOperand(1)->toConstant());
     else
         value = TypedOrValueRegister(ins->valueType(), ToAnyRegister(ins->getOperand(1)));
 
-    SetPropertyIC cache(liveRegs, objReg, ins->mir()->name(), value, ins->mir()->strict(),
-                        ins->mir()->needsTypeBarrier());
-    return addCache(ins, allocateCache(cache));
+    return addSetPropertyCache(ins, liveRegs, objReg, ins->mir()->name(), value,
+                               ins->mir()->strict(), ins->mir()->needsTypeBarrier());
 }
 
 typedef bool (*SetPropertyICFn)(JSContext *, size_t, HandleObject, HandleValue);
 const VMFunction SetPropertyIC::UpdateInfo =
     FunctionInfo<SetPropertyICFn>(SetPropertyIC::update);
 
 bool
 CodeGenerator::visitSetPropertyIC(OutOfLineUpdateCache *ool, DataPtr<SetPropertyIC> &ic)
@@ -6377,41 +6441,62 @@ CodeGenerator::visitSetPropertyIC(OutOfL
     if (!callVM(SetPropertyIC::UpdateInfo, lir))
         return false;
     restoreLive(lir);
 
     masm.jump(ool->rejoin());
     return true;
 }
 
+typedef bool (*SetPropertyParICFn)(ForkJoinSlice *, size_t, HandleObject, HandleValue);
+const VMFunction SetPropertyParIC::UpdateInfo =
+    FunctionInfo<SetPropertyParICFn>(SetPropertyParIC::update);
+
+bool
+CodeGenerator::visitSetPropertyParIC(OutOfLineUpdateCache *ool, DataPtr<SetPropertyParIC> &ic)
+{
+    LInstruction *lir = ool->lir();
+    saveLive(lir);
+
+    pushArg(ic->value());
+    pushArg(ic->object());
+    pushArg(Imm32(ool->getCacheIndex()));
+    if (!callVM(SetPropertyParIC::UpdateInfo, lir))
+        return false;
+    restoreLive(lir);
+
+    masm.jump(ool->rejoin());
+    return true;
+}
+
 typedef bool (*ThrowFn)(JSContext *, HandleValue);
 static const VMFunction ThrowInfo = FunctionInfo<ThrowFn>(js::Throw);
 
 bool
 CodeGenerator::visitThrow(LThrow *lir)
 {
     pushArg(ToValue(lir, LThrow::Value));
     return callVM(ThrowInfo, lir);
 }
 
 typedef bool (*BitNotFn)(JSContext *, HandleValue, int *p);
-typedef ParallelResult (*BitNotParFn)(ForkJoinSlice *, HandleValue, int32_t *);
+typedef bool (*BitNotParFn)(ForkJoinSlice *, HandleValue, int32_t *);
 static const VMFunctionsModal BitNotInfo = VMFunctionsModal(
     FunctionInfo<BitNotFn>(BitNot),
     FunctionInfo<BitNotParFn>(BitNotPar));
 
 bool
 CodeGenerator::visitBitNotV(LBitNotV *lir)
 {
     pushArg(ToValue(lir, LBitNotV::Input));
     return callVM(BitNotInfo, lir);
 }
 
 typedef bool (*BitopFn)(JSContext *, HandleValue, HandleValue, int *p);
-typedef ParallelResult (*BitopParFn)(ForkJoinSlice *, HandleValue, HandleValue, int32_t *);
+typedef bool (*BitopParFn)(ForkJoinSlice *, HandleValue, HandleValue, int32_t *);
 static const VMFunctionsModal BitAndInfo = VMFunctionsModal(
     FunctionInfo<BitopFn>(BitAnd),
     FunctionInfo<BitopParFn>(BitAndPar));
 static const VMFunctionsModal BitOrInfo = VMFunctionsModal(
     FunctionInfo<BitopFn>(BitOr),
     FunctionInfo<BitopParFn>(BitOrPar));
 static const VMFunctionsModal BitXorInfo = VMFunctionsModal(
     FunctionInfo<BitopFn>(BitXor),
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -307,19 +307,21 @@ class CodeGenerator : public CodeGenerat
     bool visitSetPropertyCacheV(LSetPropertyCacheV *ins);
     bool visitSetPropertyCacheT(LSetPropertyCacheT *ins);
     bool visitGetNameCache(LGetNameCache *ins);
     bool visitCallsiteCloneCache(LCallsiteCloneCache *ins);
 
     bool visitGetPropertyIC(OutOfLineUpdateCache *ool, DataPtr<GetPropertyIC> &ic);
     bool visitGetPropertyParIC(OutOfLineUpdateCache *ool, DataPtr<GetPropertyParIC> &ic);
     bool visitSetPropertyIC(OutOfLineUpdateCache *ool, DataPtr<SetPropertyIC> &ic);
+    bool visitSetPropertyParIC(OutOfLineUpdateCache *ool, DataPtr<SetPropertyParIC> &ic);
     bool visitGetElementIC(OutOfLineUpdateCache *ool, DataPtr<GetElementIC> &ic);
     bool visitGetElementParIC(OutOfLineUpdateCache *ool, DataPtr<GetElementParIC> &ic);
     bool visitSetElementIC(OutOfLineUpdateCache *ool, DataPtr<SetElementIC> &ic);
+    bool visitSetElementParIC(OutOfLineUpdateCache *ool, DataPtr<SetElementParIC> &ic);
     bool visitBindNameIC(OutOfLineUpdateCache *ool, DataPtr<BindNameIC> &ic);
     bool visitNameIC(OutOfLineUpdateCache *ool, DataPtr<NameIC> &ic);
     bool visitCallsiteCloneIC(OutOfLineUpdateCache *ool, DataPtr<CallsiteCloneIC> &ic);
 
     bool visitAssertRangeI(LAssertRangeI *ins);
     bool visitAssertRangeD(LAssertRangeD *ins);
     bool visitAssertRangeF(LAssertRangeF *ins);
     bool visitAssertRangeV(LAssertRangeV *ins);
@@ -331,16 +333,22 @@ class CodeGenerator : public CodeGenerat
     }
 
   private:
     bool addGetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
                              PropertyName *name, TypedOrValueRegister output,
                              bool allowGetters);
     bool addGetElementCache(LInstruction *ins, Register obj, ConstantOrRegister index,
                             TypedOrValueRegister output, bool monitoredResult);
+    bool addSetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
+                             PropertyName *name, ConstantOrRegister value, bool strict,
+                             bool needsTypeBarrier);
+    bool addSetElementCache(LInstruction *ins, Register obj, Register unboxIndex, Register temp,
+                            FloatRegister tempFloat, ValueOperand index, ConstantOrRegister value,
+                            bool strict);
     bool checkForAbortPar(LInstruction *lir);
 
     bool generateBranchV(const ValueOperand &value, Label *ifTrue, Label *ifFalse, FloatRegister fr);
 
     bool emitAllocateGCThingPar(LInstruction *lir, const Register &objReg, const Register &sliceReg,
                                 const Register &tempReg1, const Register &tempReg2,
                                 JSObject *templateObj);
 
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -2176,17 +2176,17 @@ jit::FastInvoke(JSContext *cx, HandleFun
 
 static void
 InvalidateActivation(FreeOp *fop, uint8_t *ionTop, bool invalidateAll)
 {
     IonSpew(IonSpew_Invalidate, "BEGIN invalidating activation");
 
     size_t frameno = 1;
 
-    for (IonFrameIterator it(ionTop); !it.done(); ++it, ++frameno) {
+    for (IonFrameIterator it(ionTop, SequentialExecution); !it.done(); ++it, ++frameno) {
         JS_ASSERT_IF(frameno == 1, it.type() == IonFrame_Exit);
 
 #ifdef DEBUG
         switch (it.type()) {
           case IonFrame_Exit:
             IonSpew(IonSpew_Invalidate, "#%d exit frame @ %p", frameno, it.fp());
             break;
           case IonFrame_BaselineJS:
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -1911,17 +1911,17 @@ AnalyzePoppedThis(JSContext *cx, types::
                   bool *phandled)
 {
     // Determine the effect that a use of the |this| value when calling |new|
     // on a script has on the properties definitely held by the new object.
 
     if (ins->isCallSetProperty()) {
         MCallSetProperty *setprop = ins->toCallSetProperty();
 
-        if (setprop->obj() != thisValue)
+        if (setprop->object() != thisValue)
             return true;
 
         // Don't use GetAtomId here, we need to watch for SETPROP on
         // integer properties and bail out. We can't mark the aggregate
         // JSID_VOID type property as being in a definite slot.
         if (setprop->name() == cx->names().classPrototype ||
             setprop->name() == cx->names().proto ||
             setprop->name() == cx->names().constructor)
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -13,19 +13,21 @@
 #include "builtin/TypeRepresentation.h"
 #include "jit/Ion.h"
 #include "jit/IonLinker.h"
 #include "jit/IonSpewer.h"
 #include "jit/Lowering.h"
 #ifdef JS_ION_PERF
 # include "jit/PerfSpewer.h"
 #endif
+#include "jit/ParallelFunctions.h"
 #include "jit/VMFunctions.h"
 #include "vm/Shape.h"
 
+#include "jit/IonFrames-inl.h"
 #include "vm/Interpreter-inl.h"
 #include "vm/Shape-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::DebugOnly;
 
@@ -1219,17 +1221,17 @@ GetPropertyIC::tryAttachNative(JSContext
 
     MacroAssembler masm(cx);
     RepatchStubAppender attacher(*this);
     const char *attachKind;
 
     switch (type) {
       case CanAttachReadSlot:
         GenerateReadSlot(cx, ion, masm, attacher, obj, holder,
-                            shape, object(), output());
+                         shape, object(), output());
         attachKind = idempotent() ? "idempotent reading"
                                     : "non idempotent reading";
         break;
       case CanAttachCallGetter:
         masm.setFramePushed(ion->frameSize());
         if (!GenerateCallGetter(cx, ion, masm, attacher, obj, name, holder, shape,
                                 liveRegs_, object(), output(), returnAddr))
         {
@@ -1844,83 +1846,83 @@ GetPropertyParIC::attachTypedArrayLength
     DispatchStubPrepender attacher(*this);
     GenerateTypedArrayLength(cx, masm, attacher, obj, object(), output());
 
     JS_ASSERT(!hasTypedArrayLengthStub_);
     hasTypedArrayLengthStub_ = true;
     return linkAndAttachStub(cx, masm, attacher, ion, "parallel typed array length");
 }
 
-ParallelResult
+bool
 GetPropertyParIC::update(ForkJoinSlice *slice, size_t cacheIndex,
                          HandleObject obj, MutableHandleValue vp)
 {
     AutoFlushCache afc("GetPropertyParCache", slice->runtime()->ionRuntime());
 
     IonScript *ion = GetTopIonJSScript(slice)->parallelIonScript();
     GetPropertyParIC &cache = ion->getCache(cacheIndex).toGetPropertyPar();
 
     // Grab the property early, as the pure path is fast anyways and doesn't
     // need a lock. If we can't do it purely, bail out of parallel execution.
     if (!GetPropertyPure(slice, obj, NameToId(cache.name()), vp.address()))
-        return TP_RETRY_SEQUENTIALLY;
+        return false;
 
     // Avoid unnecessary locking if cannot attach stubs.
     if (!cache.canAttachStub())
-        return TP_SUCCESS;
+        return true;
 
     {
         // Lock the context before mutating the cache. Ideally we'd like to do
         // finer-grained locking, with one lock per cache. However, generating
         // new jitcode uses a global ExecutableAllocator tied to the runtime.
         LockedJSContext cx(slice);
 
         if (cache.canAttachStub()) {
             bool alreadyStubbed;
             if (!cache.hasOrAddStubbedShape(cx, obj->lastProperty(), &alreadyStubbed))
-                return TP_FATAL;
+                return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
             if (alreadyStubbed)
-                return TP_SUCCESS;
+                return true;
 
             // See note about the stub limit in GetPropertyCache.
             bool attachedStub = false;
 
             {
                 RootedShape shape(cx);
                 RootedObject holder(cx);
                 RootedPropertyName name(cx, cache.name());
 
                 GetPropertyIC::NativeGetPropCacheability canCache =
                     CanAttachNativeGetProp(cx, cache, obj, name, &holder, &shape);
 
                 if (canCache == GetPropertyIC::CanAttachReadSlot) {
                     if (!cache.attachReadSlot(cx, ion, obj, holder, shape))
-                        return TP_FATAL;
+                        return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
                     attachedStub = true;
                 }
 
                 if (!attachedStub && canCache == GetPropertyIC::CanAttachArrayLength) {
                     if (!cache.attachArrayLength(cx, ion, obj))
-                        return TP_FATAL;
+                        return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
                     attachedStub = true;
                 }
             }
 
             if (!attachedStub && !cache.hasTypedArrayLengthStub() &&
                 obj->is<TypedArrayObject>() && slice->names().length == cache.name() &&
                 (cache.output().type() == MIRType_Value || cache.output().type() == MIRType_Int32))
             {
                 if (!cache.attachTypedArrayLength(cx, ion, obj))
-                    return TP_FATAL;
+                    return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
                 attachedStub = true;
             }
         }
     }
 
-    return TP_SUCCESS;
+    return true;
 }
 
 void
 IonCache::disable()
 {
     reset();
     this->disabled_ = 1;
 }
@@ -1931,108 +1933,112 @@ IonCache::reset()
     this->stubCount_ = 0;
 }
 
 void
 IonCache::destroy()
 {
 }
 
-bool
-SetPropertyIC::attachNativeExisting(JSContext *cx, IonScript *ion, HandleObject obj,
-                                    HandleShape shape, bool checkTypeset)
+static void
+GenerateSetSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
+                JSObject *obj, Shape *shape, Register object, ConstantOrRegister value,
+                bool needsTypeBarrier, bool checkTypeset)
 {
     JS_ASSERT(obj->isNative());
 
-    MacroAssembler masm(cx);
-    RepatchStubAppender attacher(*this);
-
     Label failures, barrierFailure;
     masm.branchPtr(Assembler::NotEqual,
-                   Address(object(), JSObject::offsetOfShape()),
+                   Address(object, JSObject::offsetOfShape()),
                    ImmGCPtr(obj->lastProperty()), &failures);
 
     // Guard that the incoming value is in the type set for the property
     // if a type barrier is required.
-    if (needsTypeBarrier()) {
+    if (needsTypeBarrier) {
         // We can't do anything that would change the HeapTypeSet, so
         // just guard that it's already there.
 
         // Obtain and guard on the TypeObject of the object.
-        types::TypeObject *type = obj->getType(cx);
+        types::TypeObject *type = obj->type();
         masm.branchPtr(Assembler::NotEqual,
-                       Address(object(), JSObject::offsetOfType()),
+                       Address(object, JSObject::offsetOfType()),
                        ImmGCPtr(type), &failures);
 
         if (checkTypeset) {
-            TypedOrValueRegister valReg = value().reg();
-            types::HeapTypeSet *propTypes = type->maybeGetProperty(NameToId(name()));
+            TypedOrValueRegister valReg = value.reg();
+            types::HeapTypeSet *propTypes = type->maybeGetProperty(shape->propid());
             JS_ASSERT(propTypes);
             JS_ASSERT(!propTypes->unknown());
 
-            Register scratchReg = object();
+            Register scratchReg = object;
             masm.push(scratchReg);
 
             masm.guardTypeSet(valReg, propTypes, scratchReg, &barrierFailure);
-            masm.pop(object());
+            masm.pop(object);
         }
     }
 
     if (obj->isFixedSlot(shape->slot())) {
-        Address addr(object(), JSObject::getFixedSlotOffset(shape->slot()));
+        Address addr(object, JSObject::getFixedSlotOffset(shape->slot()));
 
         if (cx->zone()->needsBarrier())
             masm.callPreBarrier(addr, MIRType_Value);
 
-        masm.storeConstantOrRegister(value(), addr);
+        masm.storeConstantOrRegister(value, addr);
     } else {
-        Register slotsReg = object();
-        masm.loadPtr(Address(object(), JSObject::offsetOfSlots()), slotsReg);
+        Register slotsReg = object;
+        masm.loadPtr(Address(object, JSObject::offsetOfSlots()), slotsReg);
 
         Address addr(slotsReg, obj->dynamicSlotIndex(shape->slot()) * sizeof(Value));
 
         if (cx->zone()->needsBarrier())
             masm.callPreBarrier(addr, MIRType_Value);
 
-        masm.storeConstantOrRegister(value(), addr);
+        masm.storeConstantOrRegister(value, addr);
     }
 
     attacher.jumpRejoin(masm);
 
     if (barrierFailure.used()) {
         masm.bind(&barrierFailure);
-        masm.pop(object());
+        masm.pop(object);
     }
 
     masm.bind(&failures);
     attacher.jumpNextStub(masm);
-
+}
+
+bool
+SetPropertyIC::attachSetSlot(JSContext *cx, IonScript *ion, HandleObject obj,
+                             HandleShape shape, bool checkTypeset)
+{
+    MacroAssembler masm(cx);
+    RepatchStubAppender attacher(*this);
+    GenerateSetSlot(cx, masm, attacher, obj, shape, object(), value(), needsTypeBarrier(),
+                    checkTypeset);
     return linkAndAttachStub(cx, masm, attacher, ion, "setting");
 }
 
 static bool
 IsCacheableSetPropCallNative(HandleObject obj, HandleObject holder, HandleShape shape)
 {
-    if (!obj->isNative())
-        return false;
+    JS_ASSERT(obj->isNative());
 
     if (!shape || !IsCacheableProtoChain(obj, holder))
         return false;
 
     return shape->hasSetterValue() && shape->setterObject() &&
            shape->setterObject()->is<JSFunction>() &&
            shape->setterObject()->as<JSFunction>().isNative();
 }
 
 static bool
-IsCacheableSetPropCallPropertyOp(HandleObject obj, HandleObject holder,
-                                 HandleShape shape)
+IsCacheableSetPropCallPropertyOp(HandleObject obj, HandleObject holder, HandleShape shape)
 {
-    if (!obj->isNative())
-        return false;
+    JS_ASSERT(obj->isNative());
 
     if (!shape)
         return false;
 
     if (!IsCacheableProtoChain(obj, holder))
         return false;
 
     if (shape->hasSlot())
@@ -2477,17 +2483,17 @@ SetPropertyIC::attachDOMProxyUnshadowed(
     // Failure.
     masm.bind(&failures);
     attacher.jumpNextStub(masm);
 
     return linkAndAttachStub(cx, masm, attacher, ion, "DOM proxy unshadowed set");
 }
 
 bool
-SetPropertyIC::attachSetterCall(JSContext *cx, IonScript *ion,
+SetPropertyIC::attachCallSetter(JSContext *cx, IonScript *ion,
                                 HandleObject obj, HandleObject holder, HandleShape shape,
                                 void *returnAddr)
 {
     JS_ASSERT(obj->isNative());
 
     MacroAssembler masm(cx);
     RepatchStubAppender attacher(*this);
 
@@ -2512,120 +2518,125 @@ SetPropertyIC::attachSetterCall(JSContex
 
     // Jump to next stub.
     masm.bind(&failure);
     attacher.jumpNextStub(masm);
 
     return linkAndAttachStub(cx, masm, attacher, ion, "setter call");
 }
 
-bool
-SetPropertyIC::attachNativeAdding(JSContext *cx, IonScript *ion, JSObject *obj,
-                                  HandleShape oldShape, HandleShape newShape,
-                                  HandleShape propShape)
+static void
+GenerateAddSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
+                JSObject *obj, Shape *oldShape, Register object, ConstantOrRegister value)
 {
     JS_ASSERT(obj->isNative());
 
-    MacroAssembler masm(cx);
-    RepatchStubAppender attacher(*this);
-
     Label failures;
 
-    /* Guard the type of the object */
-    masm.branchPtr(Assembler::NotEqual, Address(object(), JSObject::offsetOfType()),
+    // Guard the type of the object
+    masm.branchPtr(Assembler::NotEqual, Address(object, JSObject::offsetOfType()),
                    ImmGCPtr(obj->type()), &failures);
 
-    /* Guard shapes along prototype chain. */
-    masm.branchTestObjShape(Assembler::NotEqual, object(), oldShape, &failures);
+    // Guard shapes along prototype chain.
+    masm.branchTestObjShape(Assembler::NotEqual, object, oldShape, &failures);
 
     Label protoFailures;
-    masm.push(object());    // save object reg because we clobber it
+    masm.push(object);    // save object reg because we clobber it
 
     JSObject *proto = obj->getProto();
-    Register protoReg = object();
+    Register protoReg = object;
     while (proto) {
         Shape *protoShape = proto->lastProperty();
 
         // load next prototype
         masm.loadPtr(Address(protoReg, JSObject::offsetOfType()), protoReg);
         masm.loadPtr(Address(protoReg, offsetof(types::TypeObject, proto)), protoReg);
 
         // Ensure that its shape matches.
         masm.branchTestObjShape(Assembler::NotEqual, protoReg, protoShape, &protoFailures);
 
         proto = proto->getProto();
     }
 
-    masm.pop(object());     // restore object reg
-
-    /* Changing object shape.  Write the object's new shape. */
-    Address shapeAddr(object(), JSObject::offsetOfShape());
+    masm.pop(object);     // restore object reg
+
+    // Changing object shape.  Write the object's new shape.
+    Shape *newShape = obj->lastProperty();
+    Address shapeAddr(object, JSObject::offsetOfShape());
     if (cx->zone()->needsBarrier())
         masm.callPreBarrier(shapeAddr, MIRType_Shape);
     masm.storePtr(ImmGCPtr(newShape), shapeAddr);
 
-    /* Set the value on the object. */
-    if (obj->isFixedSlot(propShape->slot())) {
-        Address addr(object(), JSObject::getFixedSlotOffset(propShape->slot()));
-        masm.storeConstantOrRegister(value(), addr);
+    // Set the value on the object. Since this is an add, obj->lastProperty()
+    // must be the shape of the property we are adding.
+    if (obj->isFixedSlot(newShape->slot())) {
+        Address addr(object, JSObject::getFixedSlotOffset(newShape->slot()));
+        masm.storeConstantOrRegister(value, addr);
     } else {
-        Register slotsReg = object();
-
-        masm.loadPtr(Address(object(), JSObject::offsetOfSlots()), slotsReg);
-
-        Address addr(slotsReg, obj->dynamicSlotIndex(propShape->slot()) * sizeof(Value));
-        masm.storeConstantOrRegister(value(), addr);
+        Register slotsReg = object;
+
+        masm.loadPtr(Address(object, JSObject::offsetOfSlots()), slotsReg);
+
+        Address addr(slotsReg, obj->dynamicSlotIndex(newShape->slot()) * sizeof(Value));
+        masm.storeConstantOrRegister(value, addr);
     }
 
-    /* Success. */
+    // Success.
     attacher.jumpRejoin(masm);
 
-    /* Failure. */
+    // Failure.
     masm.bind(&protoFailures);
-    masm.pop(object());
+    masm.pop(object);
     masm.bind(&failures);
 
     attacher.jumpNextStub(masm);
-
+}
+
+bool
+SetPropertyIC::attachAddSlot(JSContext *cx, IonScript *ion, JSObject *obj, HandleShape oldShape)
+{
+    MacroAssembler masm(cx);
+    RepatchStubAppender attacher(*this);
+    GenerateAddSlot(cx, masm, attacher, obj, oldShape, object(), value());
     return linkAndAttachStub(cx, masm, attacher, ion, "adding");
 }
 
 static bool
-IsPropertySetInlineable(JSContext *cx, const SetPropertyIC &cache, HandleObject obj,
-                        HandleId id, MutableHandleShape pshape, bool *checkTypeset)
+IsPropertySetInlineable(HandleObject obj, HandleId id, MutableHandleShape pshape,
+                        ConstantOrRegister val, bool needsTypeBarrier, bool *checkTypeset)
 {
-    if (!obj->isNative())
-        return false;
-
-    pshape.set(obj->nativeLookup(cx, id));
+    JS_ASSERT(obj->isNative());
+
+    // Do a pure non-proto chain climbing lookup. See note in
+    // CanAttachNativeGetProp.
+    pshape.set(obj->nativeLookupPure(id));
 
     if (!pshape)
         return false;
 
     if (!pshape->hasSlot())
         return false;
 
     if (!pshape->hasDefaultSetter())
         return false;
 
     if (!pshape->writable())
         return false;
 
     bool shouldCheck = false;
-    types::TypeObject *type = obj->getType(cx);
-    if (cache.needsTypeBarrier() && !type->unknownProperties()) {
+    types::TypeObject *type = obj->type();
+    if (needsTypeBarrier && !type->unknownProperties()) {
         types::HeapTypeSet *propTypes = type->maybeGetProperty(id);
         if (!propTypes)
             return false;
         if (!propTypes->unknown()) {
             shouldCheck = true;
-            ConstantOrRegister val = cache.value();
             if (val.constant()) {
                 // If the input is a constant, then don't bother if the barrier will always fail.
-                if (!propTypes->hasType(types::GetValueType(cache.value().value())))
+                if (!propTypes->hasType(types::GetValueType(val.value())))
                     return false;
                 shouldCheck = false;
             } else {
                 TypedOrValueRegister reg = val.reg();
                 // We can do the same trick as above for primitive types of specialized registers.
                 // TIs handling of objects is complicated enough to warrant a runtime
                 // check, as we can't statically handle the case where the typeset
                 // contains the specific object, but doesn't have ANYOBJECT set.
@@ -2640,89 +2651,121 @@ IsPropertySetInlineable(JSContext *cx, c
     }
 
     *checkTypeset = shouldCheck;
 
     return true;
 }
 
 static bool
-IsPropertyAddInlineable(JSContext *cx, HandleObject obj, HandleId id, uint32_t oldSlots,
-                        MutableHandleShape pShape)
+IsPropertyAddInlineable(HandleObject obj, HandleId id, uint32_t oldSlots, HandleShape oldShape)
 {
-    if (!obj->isNative())
+    JS_ASSERT(obj->isNative());
+
+    // If the shape of the object did not change, then this was not an add.
+    if (obj->lastProperty() == oldShape)
         return false;
 
-    // This is not a Add, the property exists.
-    if (pShape.get())
-        return false;
-
-    RootedShape shape(cx, obj->nativeLookup(cx, id));
+    Shape *shape = obj->nativeLookupPure(id);
     if (!shape || shape->inDictionary() || !shape->hasSlot() || !shape->hasDefaultSetter())
         return false;
 
+    // If we have a shape at this point and the object's shape changed, then
+    // the shape must be the one we just added.
+    JS_ASSERT(shape == obj->lastProperty());
+
     // If object has a non-default resolve hook, don't inline
     if (obj->getClass()->resolve != JS_ResolveStub)
         return false;
 
     // Likewise for a non-default addProperty hook, since we'll need
     // to invoke it.
     if (obj->getClass()->addProperty != JS_PropertyStub)
         return false;
 
     if (!obj->nonProxyIsExtensible() || !shape->writable())
         return false;
 
-    // walk up the object prototype chain and ensure that all prototypes
+    // Walk up the object prototype chain and ensure that all prototypes
     // are native, and that all prototypes have no getter or setter
     // defined on the property
     for (JSObject *proto = obj->getProto(); proto; proto = proto->getProto()) {
-        // if prototype is non-native, don't optimize
+        // If prototype is non-native, don't optimize
         if (!proto->isNative())
             return false;
 
-        // if prototype defines this property in a non-plain way, don't optimize
-        Shape *protoShape = proto->nativeLookup(cx, id);
+        // If prototype defines this property in a non-plain way, don't optimize
+        Shape *protoShape = proto->nativeLookupPure(id);
         if (protoShape && !protoShape->hasDefaultSetter())
             return false;
 
-        // Otherise, if there's no such property, watch out for a resolve hook that would need
-        // to be invoked and thus prevent inlining of property addition.
+        // Otherwise, if there's no such property, watch out for a resolve
+        // hook that would need to be invoked and thus prevent inlining of
+        // property addition.
         if (proto->getClass()->resolve != JS_ResolveStub)
              return false;
     }
 
     // Only add a IC entry if the dynamic slots didn't change when the shapes
     // changed.  Need to ensure that a shape change for a subsequent object
     // won't involve reallocating the slot array.
     if (obj->numDynamicSlots() != oldSlots)
         return false;
 
-    pShape.set(shape);
     return true;
 }
 
+static SetPropertyIC::NativeSetPropCacheability
+CanAttachNativeSetProp(HandleObject obj, HandleId id, ConstantOrRegister val,
+                       bool needsTypeBarrier, MutableHandleObject holder,
+                       MutableHandleShape shape, bool *checkTypeset)
+{
+    if (!obj->isNative())
+        return SetPropertyIC::CanAttachNone;
+
+    // See if the property exists on the object.
+    if (IsPropertySetInlineable(obj, id, shape, val, needsTypeBarrier, checkTypeset))
+        return SetPropertyIC::CanAttachSetSlot;
+
+    // If we couldn't find the property on the object itself, do a full, but
+    // still pure lookup for setters.
+    if (!LookupPropertyPure(obj, id, holder.address(), shape.address()))
+        return SetPropertyIC::CanAttachNone;
+
+    // If the object doesn't have the property, we don't know if we can attach
+    // a stub to add the property until we do the VM call to add.
+    if (!shape)
+        return SetPropertyIC::MaybeCanAttachAddSlot;
+
+    if (IsCacheableSetPropCallPropertyOp(obj, holder, shape) ||
+        IsCacheableSetPropCallNative(obj, holder, shape))
+    {
+        return SetPropertyIC::CanAttachCallSetter;
+    }
+
+    return SetPropertyIC::CanAttachNone;
+}
+
 bool
 SetPropertyIC::update(JSContext *cx, size_t cacheIndex, HandleObject obj,
                       HandleValue value)
 {
     AutoFlushCache afc ("SetPropertyCache", cx->runtime()->ionRuntime());
 
     void *returnAddr;
     RootedScript script(cx, GetTopIonJSScript(cx, &returnAddr));
     IonScript *ion = script->ionScript();
     SetPropertyIC &cache = ion->getCache(cacheIndex).toSetProperty();
     RootedPropertyName name(cx, cache.name());
     RootedId id(cx, AtomToId(name));
-    RootedShape shape(cx);
-    RootedObject holder(cx);
 
     // Stop generating new stubs once we hit the stub count limit, see
     // GetPropertyCache.
     bool inlinable = cache.canAttachStub() && !obj->watched();
+    NativeSetPropCacheability canCache = CanAttachNone;
     bool addedSetterStub = false;
     if (inlinable) {
         if (!addedSetterStub && obj->is<ProxyObject>()) {
             if (IsCacheableDOMProxy(obj)) {
                 DOMProxyShadowsResult shadows = GetDOMProxyShadowsCheck()(cx, obj, id);
                 if (shadows == ShadowCheckFailed)
                     return false;
                 if (shadows == Shadows) {
@@ -2740,64 +2783,162 @@ SetPropertyIC::update(JSContext *cx, siz
             }
 
             if (!addedSetterStub && !cache.hasGenericProxyStub()) {
                 if (!cache.attachGenericProxy(cx, ion, returnAddr))
                     return false;
                 addedSetterStub = true;
             }
         }
+
+        // Make sure the object de-lazifies its type. We do this here so that
+        // the parallel IC can share code that assumes that native objects all
+        // have a type object.
+        if (obj->isNative() && !obj->getType(cx))
+            return false;
+
         RootedShape shape(cx);
+        RootedObject holder(cx);
         bool checkTypeset;
-        if (!addedSetterStub && IsPropertySetInlineable(cx, cache, obj, id, &shape, &checkTypeset)) {
-            if (!cache.attachNativeExisting(cx, ion, obj, shape, checkTypeset))
+        canCache = CanAttachNativeSetProp(obj, id, cache.value(), cache.needsTypeBarrier(),
+                                          &holder, &shape, &checkTypeset);
+
+        if (!addedSetterStub && canCache == CanAttachSetSlot) {
+            if (!cache.attachSetSlot(cx, ion, obj, shape, checkTypeset))
                 return false;
             addedSetterStub = true;
-        } else if (!addedSetterStub) {
-            RootedObject holder(cx);
-            if (!JSObject::lookupProperty(cx, obj, name, &holder, &shape))
+        }
+
+        if (!addedSetterStub && canCache == CanAttachCallSetter) {
+            if (!cache.attachCallSetter(cx, ion, obj, holder, shape, returnAddr))
                 return false;
-
-            if (IsCacheableSetPropCallPropertyOp(obj, holder, shape) ||
-                IsCacheableSetPropCallNative(obj, holder, shape))
-            {
-                if (!cache.attachSetterCall(cx, ion, obj, holder, shape, returnAddr))
-                    return false;
-                addedSetterStub = true;
-            }
+            addedSetterStub = true;
         }
     }
 
     uint32_t oldSlots = obj->numDynamicSlots();
     RootedShape oldShape(cx, obj->lastProperty());
 
     // Set/Add the property on the object, the inlined cache are setup for the next execution.
     if (!SetProperty(cx, obj, name, value, cache.strict(), cache.pc()))
         return false;
 
     // The property did not exist before, now we can try to inline the property add.
-    if (inlinable && !addedSetterStub && !cache.needsTypeBarrier() &&
-        obj->lastProperty() != oldShape &&
-        IsPropertyAddInlineable(cx, obj, id, oldSlots, &shape))
+    if (!addedSetterStub && canCache == MaybeCanAttachAddSlot &&
+        !cache.needsTypeBarrier() &&
+        IsPropertyAddInlineable(obj, id, oldSlots, oldShape))
     {
-        RootedShape newShape(cx, obj->lastProperty());
-        if (!cache.attachNativeAdding(cx, ion, obj, oldShape, newShape, shape))
+        if (!cache.attachAddSlot(cx, ion, obj, oldShape))
             return false;
     }
 
     return true;
 }
 
 void
 SetPropertyIC::reset()
 {
     RepatchIonCache::reset();
     hasGenericProxyStub_ = false;
 }
 
+bool
+SetPropertyParIC::update(ForkJoinSlice *slice, size_t cacheIndex, HandleObject obj,
+                         HandleValue value)
+{
+    JS_ASSERT(slice->isThreadLocal(obj));
+
+    AutoFlushCache afc("SetPropertyParCache", slice->runtime()->ionRuntime());
+
+    IonScript *ion = GetTopIonJSScript(slice)->parallelIonScript();
+    SetPropertyParIC &cache = ion->getCache(cacheIndex).toSetPropertyPar();
+
+    RootedValue v(slice, value);
+    RootedId id(slice, AtomToId(cache.name()));
+
+    // Avoid unnecessary locking if cannot attach stubs.
+    if (!cache.canAttachStub()) {
+        return baseops::SetPropertyHelper<ParallelExecution>(slice, obj, obj, id, 0,
+                                                             &v, cache.strict());
+    }
+
+    SetPropertyIC::NativeSetPropCacheability canCache = SetPropertyIC::CanAttachNone;
+    bool attachedStub = false;
+
+    {
+        LockedJSContext cx(slice);
+
+        if (cache.canAttachStub()) {
+            bool alreadyStubbed;
+            if (!cache.hasOrAddStubbedShape(cx, obj->lastProperty(), &alreadyStubbed))
+                return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
+            if (alreadyStubbed) {
+                return baseops::SetPropertyHelper<ParallelExecution>(slice, obj, obj, id, 0,
+                                                                     &v, cache.strict());
+            }
+
+            // If the object has a lazy type, we need to de-lazify it, but
+            // this is not safe in parallel.
+            if (obj->hasLazyType())
+                return false;
+
+            {
+                RootedShape shape(slice);
+                RootedObject holder(slice);
+                bool checkTypeset;
+                canCache = CanAttachNativeSetProp(obj, id, cache.value(), cache.needsTypeBarrier(),
+                                                  &holder, &shape, &checkTypeset);
+
+                if (canCache == SetPropertyIC::CanAttachSetSlot) {
+                    if (!cache.attachSetSlot(cx, ion, obj, shape, checkTypeset))
+                        return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
+                    attachedStub = true;
+                }
+            }
+        }
+    }
+
+    uint32_t oldSlots = obj->numDynamicSlots();
+    RootedShape oldShape(slice, obj->lastProperty());
+
+    if (!baseops::SetPropertyHelper<ParallelExecution>(slice, obj, obj, id, 0, &v, cache.strict()))
+        return false;
+
+    if (!attachedStub && canCache == SetPropertyIC::MaybeCanAttachAddSlot &&
+        !cache.needsTypeBarrier() &&
+        IsPropertyAddInlineable(obj, id, oldSlots, oldShape))
+    {
+        LockedJSContext cx(slice);
+        if (cache.canAttachStub() && !cache.attachAddSlot(cx, ion, obj, oldShape))
+            return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
+    }
+
+    return true;
+}
+
+bool
+SetPropertyParIC::attachSetSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj, Shape *shape,
+                                  bool checkTypeset)
+{
+    MacroAssembler masm(cx);
+    DispatchStubPrepender attacher(*this);
+    GenerateSetSlot(cx, masm, attacher, obj, shape, object(), value(), needsTypeBarrier(),
+                    checkTypeset);
+    return linkAndAttachStub(cx, masm, attacher, ion, "parallel setting");
+}
+
+bool
+SetPropertyParIC::attachAddSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj, Shape *oldShape)
+{
+    MacroAssembler masm(cx);
+    DispatchStubPrepender attacher(*this);
+    GenerateAddSlot(cx, masm, attacher, obj, oldShape, object(), value());
+    return linkAndAttachStub(cx, masm, attacher, ion, "parallel adding");
+}
+
 const size_t GetElementIC::MAX_FAILED_UPDATES = 16;
 
 /* static */ bool
 GetElementIC::canAttachGetProp(JSObject *obj, const Value &idval, jsid id)
 {
     uint32_t dummy;
     return (obj->isNative() &&
             idval.isString() &&
@@ -3235,25 +3376,25 @@ GetElementIC::reset()
 {
     RepatchIonCache::reset();
     hasDenseStub_ = false;
     hasStrictArgumentsStub_ = false;
     hasNormalArgumentsStub_ = false;
 }
 
 static bool
-IsElementSetInlineable(HandleObject obj, HandleValue index)
+IsDenseElementSetInlineable(JSObject *obj, const Value &idval)
 {
     if (!obj->is<ArrayObject>())
         return false;
 
     if (obj->watched())
         return false;
 
-    if (!index.isInt32())
+    if (!idval.isInt32())
         return false;
 
     // The object may have a setter definition,
     // either directly, or via a prototype, or via the target object for a prototype
     // which is a proxy, that handles a particular integer write.
     // Scan the prototype and shape chain to make sure that this is not the case.
     JSObject *curObj = obj;
     while (curObj) {
@@ -3266,45 +3407,51 @@ IsElementSetInlineable(HandleObject obj,
             return false;
 
         curObj = curObj->getProto();
     }
 
     return true;
 }
 
-bool
-SetElementIC::attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval)
+static bool
+IsTypedArrayElementSetInlineable(JSObject *obj, const Value &idval, const Value &value)
+{
+    // Don't bother attaching stubs for assigning strings and objects.
+    return (obj->is<TypedArrayObject>() && idval.isInt32() &&
+            !value.isString() && !value.isObject());
+}
+
+static bool
+GenerateSetDenseElement(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
+                        JSObject *obj, const Value &idval, Register object, ValueOperand indexVal,
+                        ConstantOrRegister value, Register tempToUnboxIndex, Register temp)
 {
     JS_ASSERT(obj->isNative());
     JS_ASSERT(idval.isInt32());
 
     Label failures;
     Label outOfBounds; // index >= capacity || index > initialized length
 
-    MacroAssembler masm(cx);
-    RepatchStubAppender attacher(*this);
-
     // Guard object is a dense array.
-    RootedShape shape(cx, obj->lastProperty());
+    Shape *shape = obj->lastProperty();
     if (!shape)
         return false;
-    masm.branchTestObjShape(Assembler::NotEqual, object(), shape, &failures);
+    masm.branchTestObjShape(Assembler::NotEqual, object, shape, &failures);
 
     // Ensure the index is an int32 value.
-    ValueOperand indexVal = index();
     masm.branchTestInt32(Assembler::NotEqual, indexVal, &failures);
 
     // Unbox the index.
-    Register index = masm.extractInt32(indexVal, tempToUnboxIndex());
+    Register index = masm.extractInt32(indexVal, tempToUnboxIndex);
 
     {
         // Load obj->elements.
-        Register elements = temp();
-        masm.loadPtr(Address(object(), JSObject::offsetOfElements()), elements);
+        Register elements = temp;
+        masm.loadPtr(Address(object, JSObject::offsetOfElements()), elements);
 
         // Compute the location of the element.
         BaseIndex target(elements, index, TimesEight);
 
         // Guard that we can increase the initialized length.
         Address capacity(elements, ObjectElements::offsetOfCapacity());
         masm.branch32(Assembler::BelowOrEqual, capacity, index, &outOfBounds);
 
@@ -3337,30 +3484,45 @@ SetElementIC::attachDenseElement(JSConte
             // Mark old element.
             masm.bind(&markElem);
             if (cx->zone()->needsBarrier())
                 masm.callPreBarrier(target, MIRType_Value);
         }
 
         // Call post barrier if necessary, and recalculate elements pointer if it got cobbered.
         Register postBarrierScratch = elements;
-        if (masm.maybeCallPostBarrier(object(), value(), postBarrierScratch))
-            masm.loadPtr(Address(object(), JSObject::offsetOfElements()), elements);
+        if (masm.maybeCallPostBarrier(object, value, postBarrierScratch))
+            masm.loadPtr(Address(object, JSObject::offsetOfElements()), elements);
 
         // Store the value.
         masm.bind(&storeElem);
-        masm.storeConstantOrRegister(value(), target);
+        masm.storeConstantOrRegister(value, target);
     }
     attacher.jumpRejoin(masm);
 
     // All failures flow to here.
     masm.bind(&outOfBounds);
     masm.bind(&failures);
     attacher.jumpNextStub(masm);
 
+    return true;
+}
+
+bool
+SetElementIC::attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval)
+{
+    MacroAssembler masm(cx);
+    RepatchStubAppender attacher(*this);
+    if (!GenerateSetDenseElement(cx, masm, attacher, obj, idval,
+                                 object(), index(), value(),
+                                 tempToUnboxIndex(), temp()))
+    {
+        return false;
+    }
+
     setHasDenseStub();
     return linkAndAttachStub(cx, masm, attacher, ion, "dense array");
 }
 
 static bool
 GenerateSetTypedArrayElement(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
                              TypedArrayObject *tarr, Register object,
                              ValueOperand indexVal, ConstantOrRegister value,
@@ -3438,24 +3600,16 @@ GenerateSetTypedArrayElement(JSContext *
         masm.pop(object);
     }
 
     masm.bind(&failures);
     attacher.jumpNextStub(masm);
     return true;
 }
 
-/* static */ bool
-SetElementIC::canAttachTypedArrayElement(JSObject *obj, const Value &idval, const Value &value)
-{
-    // Don't bother attaching stubs for assigning strings and objects.
-    return (obj->is<TypedArrayObject>() && idval.isInt32() &&
-            !value.isString() && !value.isObject());
-}
-
 bool
 SetElementIC::attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayObject *tarr)
 {
     MacroAssembler masm(cx);
     RepatchStubAppender attacher(*this);
     if (!GenerateSetTypedArrayElement(cx, masm, attacher, tarr,
                                       object(), index(), value(),
                                       tempToUnboxIndex(), temp(), tempFloat()))
@@ -3470,22 +3624,22 @@ bool
 SetElementIC::update(JSContext *cx, size_t cacheIndex, HandleObject obj,
                      HandleValue idval, HandleValue value)
 {
     IonScript *ion = GetTopIonJSScript(cx)->ionScript();
     SetElementIC &cache = ion->getCache(cacheIndex).toSetElement();
 
     bool attachedStub = false;
     if (cache.canAttachStub()) {
-        if (!cache.hasDenseStub() && IsElementSetInlineable(obj, idval)) {
+        if (!cache.hasDenseStub() && IsDenseElementSetInlineable(obj, idval)) {
             if (!cache.attachDenseElement(cx, ion, obj, idval))
                 return false;
             attachedStub = true;
         }
-        if (!attachedStub && canAttachTypedArrayElement(obj, idval, value)) {
+        if (!attachedStub && IsTypedArrayElementSetInlineable(obj, idval, value)) {
             TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
             if (!cache.attachTypedArrayElement(cx, ion, tarr))
                 return false;
         }
     }
 
     if (!SetObjectElement(cx, obj, idval, value, cache.strict()))
         return false;
@@ -3495,16 +3649,86 @@ SetElementIC::update(JSContext *cx, size
 void
 SetElementIC::reset()
 {
     RepatchIonCache::reset();
     hasDenseStub_ = false;
 }
 
 bool
+SetElementParIC::attachDenseElement(LockedJSContext &cx, IonScript *ion, JSObject *obj,
+                                    const Value &idval)
+{
+    MacroAssembler masm(cx);
+    DispatchStubPrepender attacher(*this);
+    if (!GenerateSetDenseElement(cx, masm, attacher, obj, idval,
+                                 object(), index(), value(),
+                                 tempToUnboxIndex(), temp()))
+    {
+        return false;
+    }
+
+    return linkAndAttachStub(cx, masm, attacher, ion, "parallel dense array");
+}
+
+bool
+SetElementParIC::attachTypedArrayElement(LockedJSContext &cx, IonScript *ion,
+                                         TypedArrayObject *tarr)
+{
+    MacroAssembler masm(cx);
+    DispatchStubPrepender attacher(*this);
+    if (!GenerateSetTypedArrayElement(cx, masm, attacher, tarr,
+                                      object(), index(), value(),
+                                      tempToUnboxIndex(), temp(), tempFloat()))
+    {
+        return false;
+    }
+
+    return linkAndAttachStub(cx, masm, attacher, ion, "parallel typed array");
+}
+
+bool
+SetElementParIC::update(ForkJoinSlice *slice, size_t cacheIndex, HandleObject obj,
+                        HandleValue idval, HandleValue value)
+{
+    IonScript *ion = GetTopIonJSScript(slice)->parallelIonScript();
+    SetElementParIC &cache = ion->getCache(cacheIndex).toSetElementPar();
+
+    // Avoid unnecessary locking if cannot attach stubs.
+    if (!cache.canAttachStub())
+        return SetElementPar(slice, obj, idval, value, cache.strict());
+
+    {
+        LockedJSContext cx(slice);
+
+        if (cache.canAttachStub()) {
+            bool alreadyStubbed;
+            if (!cache.hasOrAddStubbedShape(cx, obj->lastProperty(), &alreadyStubbed))
+                return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
+            if (alreadyStubbed)
+                return SetElementPar(slice, obj, idval, value, cache.strict());
+
+            bool attachedStub = false;
+            if (IsDenseElementSetInlineable(obj, idval)) {
+                if (!cache.attachDenseElement(cx, ion, obj, idval))
+                    return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
+                attachedStub = true;
+            }
+            if (!attachedStub && IsTypedArrayElementSetInlineable(obj, idval, value)) {
+                TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
+                if (!cache.attachTypedArrayElement(cx, ion, tarr))
+                    return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
+            }
+        }
+    }
+
+    return SetElementPar(slice, obj, idval, value, cache.strict());
+}
+
+bool
 GetElementParIC::attachReadSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj,
                                 const Value &idval, PropertyName *name, JSObject *holder,
                                 Shape *shape)
 {
     MacroAssembler masm(cx);
     DispatchStubPrepender attacher(*this);
 
     // Guard on the index value.
@@ -3535,85 +3759,84 @@ GetElementParIC::attachTypedArrayElement
                                          TypedArrayObject *tarr, const Value &idval)
 {
     MacroAssembler masm(cx);
     DispatchStubPrepender attacher(*this);
     GenerateGetTypedArrayElement(cx, masm, attacher, tarr, idval, object(), index(), output());
     return linkAndAttachStub(cx, masm, attacher, ion, "parallel typed array");
 }
 
-ParallelResult
+bool
 GetElementParIC::update(ForkJoinSlice *slice, size_t cacheIndex, HandleObject obj,
                         HandleValue idval, MutableHandleValue vp)
 {
     AutoFlushCache afc("GetElementParCache", slice->runtime()->ionRuntime());
 
     IonScript *ion = GetTopIonJSScript(slice)->parallelIonScript();
     GetElementParIC &cache = ion->getCache(cacheIndex).toGetElementPar();
 
     // Try to get the element early, as the pure path doesn't need a lock. If
     // we can't do it purely, bail out of parallel execution.
     if (!GetObjectElementOperationPure(slice, obj, idval, vp.address()))
-        return TP_RETRY_SEQUENTIALLY;
+        return false;
 
     // Avoid unnecessary locking if cannot attach stubs.
     if (!cache.canAttachStub())
-        return TP_SUCCESS;
+        return true;
 
     {
         LockedJSContext cx(slice);
 
         if (cache.canAttachStub()) {
             bool alreadyStubbed;
             if (!cache.hasOrAddStubbedShape(cx, obj->lastProperty(), &alreadyStubbed))
-                return TP_FATAL;
+                return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
             if (alreadyStubbed)
-                return TP_SUCCESS;
+                return true;
 
             jsid id;
             if (!ValueToIdPure(idval, &id))
-                return TP_FATAL;
+                return false;
 
             bool attachedStub = false;
-
             if (cache.monitoredResult() &&
                 GetElementIC::canAttachGetProp(obj, idval, id))
             {
                 RootedShape shape(cx);
                 RootedObject holder(cx);
                 RootedPropertyName name(cx, JSID_TO_ATOM(id)->asPropertyName());
 
                 GetPropertyIC::NativeGetPropCacheability canCache =
                     CanAttachNativeGetProp(cx, cache, obj, name, &holder, &shape);
 
                 if (canCache == GetPropertyIC::CanAttachReadSlot)
                 {
                     if (!cache.attachReadSlot(cx, ion, obj, idval, name, holder, shape))
-                        return TP_FATAL;
+                        return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
                     attachedStub = true;
                 }
             }
             if (!attachedStub &&
                 GetElementIC::canAttachDenseElement(obj, idval))
             {
                 if (!cache.attachDenseElement(cx, ion, obj, idval))
-                    return TP_FATAL;
+                    return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
                 attachedStub = true;
             }
             if (!attachedStub &&
                 GetElementIC::canAttachTypedArrayElement(obj, idval, cache.output()))
             {
                 if (!cache.attachTypedArrayElement(cx, ion, &obj->as<TypedArrayObject>(), idval))
-                    return TP_FATAL;
+                    return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
                 attachedStub = true;
             }
         }
     }
 
-    return TP_SUCCESS;
+    return true;
 }
 
 bool
 BindNameIC::attachGlobal(JSContext *cx, IonScript *ion, JSObject *scopeChain)
 {
     JS_ASSERT(scopeChain->is<GlobalObject>());
 
     MacroAssembler masm(cx);
--- a/js/src/jit/IonCaches.h
+++ b/js/src/jit/IonCaches.h
@@ -24,17 +24,19 @@ namespace jit {
     _(GetProperty)                                              \
     _(SetProperty)                                              \
     _(GetElement)                                               \
     _(SetElement)                                               \
     _(BindName)                                                 \
     _(Name)                                                     \
     _(CallsiteClone)                                            \
     _(GetPropertyPar)                                           \
-    _(GetElementPar)
+    _(GetElementPar)                                            \
+    _(SetPropertyPar)                                           \
+    _(SetElementPar)
 
 // Forward declarations of Cache kinds.
 #define FORWARD_DECLARE(kind) class kind##IC;
 IONCACHE_KIND_LIST(FORWARD_DECLARE)
 #undef FORWARD_DECLARE
 
 class IonCacheVisitor
 {
@@ -673,22 +675,28 @@ class SetPropertyIC : public RepatchIonC
     }
     bool needsTypeBarrier() const {
         return needsTypeBarrier_;
     }
     bool hasGenericProxyStub() const {
         return hasGenericProxyStub_;
     }
 
-    bool attachNativeExisting(JSContext *cx, IonScript *ion, HandleObject obj,
-                              HandleShape shape, bool checkTypeset);
-    bool attachSetterCall(JSContext *cx, IonScript *ion, HandleObject obj,
+    enum NativeSetPropCacheability {
+        CanAttachNone,
+        CanAttachSetSlot,
+        MaybeCanAttachAddSlot,
+        CanAttachCallSetter
+    };
+
+    bool attachSetSlot(JSContext *cx, IonScript *ion, HandleObject obj, HandleShape shape,
+                       bool checkTypeset);
+    bool attachCallSetter(JSContext *cx, IonScript *ion, HandleObject obj,
                           HandleObject holder, HandleShape shape, void *returnAddr);
-    bool attachNativeAdding(JSContext *cx, IonScript *ion, JSObject *obj, HandleShape oldshape,
-                            HandleShape newshape, HandleShape propshape);
+    bool attachAddSlot(JSContext *cx, IonScript *ion, JSObject *obj, HandleShape oldShape);
     bool attachGenericProxy(JSContext *cx, IonScript *ion, void *returnAddr);
     bool attachDOMProxyShadowed(JSContext *cx, IonScript *ion, HandleObject obj,
                                 void *returnAddr);
     bool attachDOMProxyUnshadowed(JSContext *cx, IonScript *ion, HandleObject obj,
                                   void *returnAddr);
 
     static bool
     update(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue value);
@@ -767,17 +775,17 @@ class GetElementIC : public RepatchIonCa
     bool attachGetProp(JSContext *cx, IonScript *ion, HandleObject obj, const Value &idval, HandlePropertyName name);
     bool attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval);
     bool attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayObject *tarr,
                                  const Value &idval);
     bool attachArgumentsElement(JSContext *cx, IonScript *ion, JSObject *obj);
 
     static bool
     update(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue idval,
-                MutableHandleValue vp);
+           MutableHandleValue vp);
 
     void incFailedUpdates() {
         failedUpdates_++;
     }
     void resetFailedUpdates() {
         failedUpdates_ = 0;
     }
     bool shouldDisable() const {
@@ -843,18 +851,16 @@ class SetElementIC : public RepatchIonCa
     bool hasDenseStub() const {
         return hasDenseStub_;
     }
     void setHasDenseStub() {
         JS_ASSERT(!hasDenseStub());
         hasDenseStub_ = true;
     }
 
-    static bool canAttachTypedArrayElement(JSObject *obj, const Value &idval, const Value &value);
-
     bool attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval);
     bool attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayObject *tarr);
 
     static bool
     update(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue idval,
            HandleValue value);
 };
 
@@ -1044,18 +1050,18 @@ class GetPropertyParIC : public Parallel
     bool allowGetters() const { return false; }
     bool allowArrayLength(Context, HandleObject) const { return true; }
 
     bool attachReadSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj, JSObject *holder,
                         Shape *shape);
     bool attachArrayLength(LockedJSContext &cx, IonScript *ion, JSObject *obj);
     bool attachTypedArrayLength(LockedJSContext &cx, IonScript *ion, JSObject *obj);
 
-    static ParallelResult update(ForkJoinSlice *slice, size_t cacheIndex, HandleObject obj,
-                                 MutableHandleValue vp);
+    static bool update(ForkJoinSlice *slice, size_t cacheIndex, HandleObject obj,
+                       MutableHandleValue vp);
 };
 
 class GetElementParIC : public ParallelIonCache
 {
   protected:
     Register object_;
     ConstantOrRegister index_;
     TypedOrValueRegister output_;
@@ -1100,19 +1106,133 @@ class GetElementParIC : public ParallelI
     bool allowArrayLength(Context, HandleObject) const { return false; }
 
     bool attachReadSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj, const Value &idval,
                         PropertyName *name, JSObject *holder, Shape *shape);
     bool attachDenseElement(LockedJSContext &cx, IonScript *ion, JSObject *obj, const Value &idval);
     bool attachTypedArrayElement(LockedJSContext &cx, IonScript *ion, TypedArrayObject *tarr,
                                  const Value &idval);
 
-    static ParallelResult update(ForkJoinSlice *slice, size_t cacheIndex, HandleObject obj, HandleValue idval,
-                                 MutableHandleValue vp);
+    static bool update(ForkJoinSlice *slice, size_t cacheIndex, HandleObject obj, HandleValue idval,
+                       MutableHandleValue vp);
+
+};
+
+class SetPropertyParIC : public ParallelIonCache
+{
+  protected:
+    Register object_;
+    PropertyName *name_;
+    ConstantOrRegister value_;
+    bool strict_;
+    bool needsTypeBarrier_;
+
+  public:
+    SetPropertyParIC(Register object, PropertyName *name, ConstantOrRegister value,
+                     bool strict, bool needsTypeBarrier)
+      : object_(object),
+        name_(name),
+        value_(value),
+        strict_(strict),
+        needsTypeBarrier_(needsTypeBarrier)
+    {
+    }
+
+    CACHE_HEADER(SetPropertyPar)
+
+#ifdef JS_CPU_X86
+    // x86 lacks a general purpose scratch register for dispatch caches and
+    // must be given one manually.
+    void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
+#endif
+
+    Register object() const {
+        return object_;
+    }
+    PropertyName *name() const {
+        return name_;
+    }
+    ConstantOrRegister value() const {
+        return value_;
+    }
+    bool strict() const {
+        return strict_;
+    }
+    bool needsTypeBarrier() const {
+        return needsTypeBarrier_;
+    }
+
+    bool attachSetSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj, Shape *shape,
+                       bool checkTypeset);
+    bool attachAddSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj, Shape *oldShape);
+
+    static bool update(ForkJoinSlice *slice, size_t cacheIndex, HandleObject obj,
+                       HandleValue value);
+};
 
+class SetElementParIC : public ParallelIonCache
+{
+  protected:
+    Register object_;
+    Register tempToUnboxIndex_;
+    Register temp_;
+    FloatRegister tempFloat_;
+    ValueOperand index_;
+    ConstantOrRegister value_;
+    bool strict_;
+
+  public:
+    SetElementParIC(Register object, Register tempToUnboxIndex, Register temp,
+                    FloatRegister tempFloat, ValueOperand index, ConstantOrRegister value,
+                    bool strict)
+      : object_(object),
+        tempToUnboxIndex_(tempToUnboxIndex),
+        temp_(temp),
+        tempFloat_(tempFloat),
+        index_(index),
+        value_(value),
+        strict_(strict)
+    {
+    }
+
+    CACHE_HEADER(SetElementPar)
+
+#ifdef JS_CPU_X86
+    // x86 lacks a general purpose scratch register for dispatch caches and
+    // must be given one manually.
+    void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
+#endif
+
+    Register object() const {
+        return object_;
+    }
+    Register tempToUnboxIndex() const {
+        return tempToUnboxIndex_;
+    }
+    Register temp() const {
+        return temp_;
+    }
+    FloatRegister tempFloat() const {
+        return tempFloat_;
+    }
+    ValueOperand index() const {
+        return index_;
+    }
+    ConstantOrRegister value() const {
+        return value_;
+    }
+    bool strict() const {
+        return strict_;
+    }
+
+    bool attachDenseElement(LockedJSContext &cx, IonScript *ion, JSObject *obj, const Value &idval);
+    bool attachTypedArrayElement(LockedJSContext &cx, IonScript *ion, TypedArrayObject *tarr);
+
+    static bool update(ForkJoinSlice *slice, size_t cacheIndex, HandleObject obj,
+                       HandleValue idval, HandleValue value);
 };
 
 #undef CACHE_HEADER
 
 // Implement cache casts now that the compiler can see the inheritance.
 #define CACHE_CASTS(ickind)                                             \
     ickind##IC &IonCache::to##ickind()                                  \
     {                                                                   \
--- a/js/src/jit/IonFrameIterator.h
+++ b/js/src/jit/IonFrameIterator.h
@@ -80,31 +80,34 @@ class IonFrameIterator
     uint8_t *current_;
     FrameType type_;
     uint8_t *returnAddressToFp_;
     size_t frameSize_;
 
   private:
     mutable const SafepointIndex *cachedSafepointIndex_;
     const JitActivation *activation_;
+    ExecutionMode mode_;
 
     void dumpBaseline() const;
 
   public:
-    IonFrameIterator(uint8_t *top)
+    explicit IonFrameIterator(uint8_t *top, ExecutionMode mode)
       : current_(top),
         type_(IonFrame_Exit),
         returnAddressToFp_(nullptr),
         frameSize_(0),
         cachedSafepointIndex_(nullptr),
-        activation_(nullptr)
+        activation_(nullptr),
+        mode_(mode)
     { }
 
-    IonFrameIterator(const ActivationIterator &activations);
-    IonFrameIterator(IonJSFrameLayout *fp);
+    explicit IonFrameIterator(JSContext *cx);
+    explicit IonFrameIterator(const ActivationIterator &activations);
+    explicit IonFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode);
 
     // Current frame information.
     FrameType type() const {
         return type_;
     }
     uint8_t *fp() const {
         return current_;
     }
@@ -146,17 +149,16 @@ class IonFrameIterator
     bool isOOLNative() const;
     bool isOOLPropertyOp() const;
     bool isOOLProxy() const;
     bool isDOMExit() const;
     bool isEntry() const {
         return type_ == IonFrame_Entry;
     }
     bool isFunctionFrame() const;
-    bool isParallelFunctionFrame() const;
 
     bool isConstructing() const;
 
     void *calleeToken() const;
     JSFunction *callee() const;
     JSFunction *maybeCallee() const;
     unsigned numActualArgs() const;
     JSScript *script() const;
--- a/js/src/jit/IonFrames-inl.h
+++ b/js/src/jit/IonFrames-inl.h
@@ -8,16 +8,17 @@
 #define jit_IonFrames_inl_h
 
 #ifdef JS_ION
 
 #include "jit/IonFrames.h"
 
 #include "jit/IonFrameIterator.h"
 #include "jit/LIR.h"
+#include "vm/ForkJoin.h"
 
 #include "jit/IonFrameIterator-inl.h"
 
 namespace js {
 namespace jit {
 
 inline void
 SafepointIndex::resolve()
@@ -64,23 +65,35 @@ IonFrameIterator::exitFrame() const
     JS_ASSERT(type() == IonFrame_Exit);
     JS_ASSERT(!isFakeExitFrame());
     return (IonExitFrameLayout *) fp();
 }
 
 inline BaselineFrame *
 GetTopBaselineFrame(JSContext *cx)
 {
-    IonFrameIterator iter(cx->mainThread().ionTop);
+    IonFrameIterator iter(cx);
     JS_ASSERT(iter.type() == IonFrame_Exit);
     ++iter;
     if (iter.isBaselineStub())
         ++iter;
     JS_ASSERT(iter.isBaselineJS());
     return iter.baselineFrame();
 }
 
+inline JSScript *
+GetTopIonJSScript(JSContext *cx, void **returnAddrOut = nullptr)
+{
+    return GetTopIonJSScript(cx->mainThread().ionTop, returnAddrOut, SequentialExecution);
+}
+
+inline JSScript *
+GetTopIonJSScript(ForkJoinSlice *slice, void **returnAddrOut = nullptr)
+{
+    return GetTopIonJSScript(slice->perThreadData->ionTop, returnAddrOut, ParallelExecution);
+}
+
 } // namespace jit
 } // namespace js
 
 #endif // JS_ION
 
 #endif /* jit_IonFrames_inl_h */
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -27,31 +27,44 @@
 #include "vm/Interpreter.h"
 
 #include "jit/IonFrameIterator-inl.h"
 #include "vm/Probes-inl.h"
 
 namespace js {
 namespace jit {
 
+IonFrameIterator::IonFrameIterator(JSContext *cx)
+  : current_(cx->mainThread().ionTop),
+    type_(IonFrame_Exit),
+    returnAddressToFp_(nullptr),
+    frameSize_(0),
+    cachedSafepointIndex_(nullptr),
+    activation_(nullptr),
+    mode_(SequentialExecution)
+{
+}
+
 IonFrameIterator::IonFrameIterator(const ActivationIterator &activations)
     : current_(activations.jitTop()),
       type_(IonFrame_Exit),
       returnAddressToFp_(nullptr),
       frameSize_(0),
       cachedSafepointIndex_(nullptr),
-      activation_(activations.activation()->asJit())
+      activation_(activations.activation()->asJit()),
+      mode_(SequentialExecution)
 {
 }
 
-IonFrameIterator::IonFrameIterator(IonJSFrameLayout *fp)
+IonFrameIterator::IonFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode)
   : current_((uint8_t *)fp),
     type_(IonFrame_OptimizedJS),
     returnAddressToFp_(fp->returnAddress()),
-    frameSize_(fp->prevFrameLocalSize())
+    frameSize_(fp->prevFrameLocalSize()),
+    mode_(mode)
 {
 }
 
 bool
 IonFrameIterator::checkInvalidation() const
 {
     IonScript *dummy;
     return checkInvalidation(&dummy);
@@ -60,19 +73,19 @@ IonFrameIterator::checkInvalidation() co
 bool
 IonFrameIterator::checkInvalidation(IonScript **ionScriptOut) const
 {
     uint8_t *returnAddr = returnAddressToFp();
     JSScript *script = this->script();
     // N.B. the current IonScript is not the same as the frame's
     // IonScript if the frame has since been invalidated.
     bool invalidated;
-    if (isParallelFunctionFrame()) {
-        invalidated = !script->hasParallelIonScript() ||
-            !script->parallelIonScript()->containsReturnAddress(returnAddr);
+    if (mode_ == ParallelExecution) {
+        // Parallel execution does not have invalidating bailouts.
+        invalidated = false;
     } else {
         invalidated = !script->hasIonScript() ||
             !script->ionScript()->containsReturnAddress(returnAddr);
     }
     if (!invalidated)
         return false;
 
     int32_t invalidationDataOffset = ((int32_t *) returnAddr)[-1];
@@ -88,26 +101,24 @@ IonFrameIterator::calleeToken() const
 {
     return ((IonJSFrameLayout *) current_)->calleeToken();
 }
 
 JSFunction *
 IonFrameIterator::callee() const
 {
     JS_ASSERT(isScripted());
-    JS_ASSERT(isFunctionFrame() || isParallelFunctionFrame());
-    if (isFunctionFrame())
-        return CalleeTokenToFunction(calleeToken());
-    return CalleeTokenToParallelFunction(calleeToken());
+    JS_ASSERT(isFunctionFrame());
+    return CalleeTokenToFunction(calleeToken());
 }
 
 JSFunction *
 IonFrameIterator::maybeCallee() const
 {
-    if (isScripted() && (isFunctionFrame() || isParallelFunctionFrame()))
+    if (isScripted() && (isFunctionFrame()))
         return callee();
     return nullptr;
 }
 
 bool
 IonFrameIterator::isNative() const
 {
     if (type_ != IonFrame_Exit || isFakeExitFrame())
@@ -148,22 +159,16 @@ IonFrameIterator::isDOMExit() const
 }
 
 bool
 IonFrameIterator::isFunctionFrame() const
 {
     return CalleeTokenIsFunction(calleeToken());
 }
 
-bool
-IonFrameIterator::isParallelFunctionFrame() const
-{
-    return GetCalleeTokenTag(calleeToken()) == CalleeToken_ParallelFunction;
-}
-
 JSScript *
 IonFrameIterator::script() const
 {
     JS_ASSERT(isScripted());
     if (isBaselineJS())
         return baselineFrame()->script();
     JSScript *script = ScriptFromCalleeToken(calleeToken());
     JS_ASSERT(script);
@@ -521,17 +526,17 @@ HandleException(ResumeFromException *rfe
 
     // Clear any Ion return override that's been set.
     // This may happen if a callVM function causes an invalidation (setting the
     // override), and then fails, bypassing the bailout handlers that would
     // otherwise clear the return override.
     if (cx->runtime()->hasIonReturnOverride())
         cx->runtime()->takeIonReturnOverride();
 
-    IonFrameIterator iter(cx->mainThread().ionTop);
+    IonFrameIterator iter(cx);
     while (!iter.isEntry()) {
         bool overrecursed = false;
         if (iter.isOptimizedJS()) {
             // Search each inlined frame for live iterator objects, and close
             // them.
             InlineFrameIterator frames(cx, &iter);
             for (;;) {
                 HandleExceptionIon(cx, frames, rfe, &overrecursed);
@@ -611,24 +616,24 @@ HandleException(ResumeFromException *rfe
 
     rfe->stackPointer = iter.fp();
 }
 
 void
 HandleParallelFailure(ResumeFromException *rfe)
 {
     ForkJoinSlice *slice = ForkJoinSlice::Current();
-    IonFrameIterator iter(slice->perThreadData->ionTop);
+    IonFrameIterator iter(slice->perThreadData->ionTop, ParallelExecution);
 
     parallel::Spew(parallel::SpewBailouts, "Bailing from VM reentry");
 
     while (!iter.isEntry()) {
         if (iter.isScripted()) {
-            slice->bailoutRecord->setCause(ParallelBailoutFailedIC,
-                                           iter.script(), iter.script(), nullptr);
+            slice->bailoutRecord->updateCause(ParallelBailoutUnsupportedVM,
+                                              iter.script(), iter.script(), nullptr);
             break;
         }
         ++iter;
     }
 
     while (!iter.isEntry()) {
         if (iter.isScripted())
             PropagateAbortPar(iter.script(), iter.script());
@@ -849,17 +854,17 @@ MarkBaselineStubFrame(JSTracer *trc, con
         JS_ASSERT(ICStub::CanMakeCalls(stub->kind()));
         stub->trace(trc);
     }
 }
 
 void
 JitActivationIterator::jitStackRange(uintptr_t *&min, uintptr_t *&end)
 {
-    IonFrameIterator frames(jitTop());
+    IonFrameIterator frames(jitTop(), SequentialExecution);
 
     if (frames.isFakeExitFrame()) {
         min = reinterpret_cast<uintptr_t *>(frames.fp());
     } else {
         IonExitFrameLayout *exitFrame = frames.exitFrame();
         IonExitFooterFrame *footer = exitFrame->footer();
         const VMFunction *f = footer->function();
         if (exitFrame->isWrapperExit() && f->outParam == Type_Handle) {
@@ -1089,17 +1094,17 @@ AutoTempAllocatorRooter::trace(JSTracer 
 void
 GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes)
 {
     IonSpew(IonSpew_Snapshots, "Recover PC & Script from the last frame.");
 
     JSRuntime *rt = cx->runtime();
 
     // Recover the return address.
-    IonFrameIterator it(rt->mainThread.ionTop);
+    IonFrameIterator it(rt->mainThread.ionTop, SequentialExecution);
 
     // If the previous frame is a rectifier frame (maybe unwound),
     // skip past it.
     if (it.prevType() == IonFrame_Rectifier || it.prevType() == IonFrame_Unwound_Rectifier) {
         ++it;
         JS_ASSERT(it.prevType() == IonFrame_BaselineStub ||
                   it.prevType() == IonFrame_BaselineJS ||
                   it.prevType() == IonFrame_OptimizedJS);
@@ -1313,19 +1318,17 @@ IonFrameIterator::ionScript() const
     JS_ASSERT(type() == IonFrame_OptimizedJS);
 
     IonScript *ionScript = nullptr;
     if (checkInvalidation(&ionScript))
         return ionScript;
     switch (GetCalleeTokenTag(calleeToken())) {
       case CalleeToken_Function:
       case CalleeToken_Script:
-        return script()->ionScript();
-      case CalleeToken_ParallelFunction:
-        return script()->parallelIonScript();
+        return mode_ == ParallelExecution ? script()->parallelIonScript() : script()->ionScript();
       default:
         MOZ_ASSUME_UNREACHABLE("unknown callee token type");
     }
 }
 
 const SafepointIndex *
 IonFrameIterator::safepoint() const
 {
--- a/js/src/jit/IonFrames.h
+++ b/js/src/jit/IonFrames.h
@@ -19,76 +19,62 @@
 namespace js {
 namespace jit {
 
 typedef void * CalleeToken;
 
 enum CalleeTokenTag
 {
     CalleeToken_Function = 0x0, // untagged
-    CalleeToken_Script = 0x1,
-    CalleeToken_ParallelFunction = 0x2
+    CalleeToken_Script = 0x1
 };
 
 static inline CalleeTokenTag
 GetCalleeTokenTag(CalleeToken token)
 {
     CalleeTokenTag tag = CalleeTokenTag(uintptr_t(token) & 0x3);
-    JS_ASSERT(tag <= CalleeToken_ParallelFunction);
+    JS_ASSERT(tag <= CalleeToken_Script);
     return tag;
 }
 static inline CalleeToken
 CalleeToToken(JSFunction *fun)
 {
     return CalleeToken(uintptr_t(fun) | uintptr_t(CalleeToken_Function));
 }
 static inline CalleeToken
-CalleeToParallelToken(JSFunction *fun)
-{
-    return CalleeToken(uintptr_t(fun) | uintptr_t(CalleeToken_ParallelFunction));
-}
-static inline CalleeToken
 CalleeToToken(JSScript *script)
 {
     return CalleeToken(uintptr_t(script) | uintptr_t(CalleeToken_Script));
 }
 static inline bool
 CalleeTokenIsFunction(CalleeToken token)
 {
     return GetCalleeTokenTag(token) == CalleeToken_Function;
 }
 static inline JSFunction *
 CalleeTokenToFunction(CalleeToken token)
 {
     JS_ASSERT(CalleeTokenIsFunction(token));
     return (JSFunction *)token;
 }
-static inline JSFunction *
-CalleeTokenToParallelFunction(CalleeToken token)
-{
-    JS_ASSERT(GetCalleeTokenTag(token) == CalleeToken_ParallelFunction);
-    return (JSFunction *)(uintptr_t(token) & ~uintptr_t(0x3));
-}
 static inline JSScript *
 CalleeTokenToScript(CalleeToken token)
 {
     JS_ASSERT(GetCalleeTokenTag(token) == CalleeToken_Script);
     return (JSScript *)(uintptr_t(token) & ~uintptr_t(0x3));
 }
 
 static inline JSScript *
 ScriptFromCalleeToken(CalleeToken token)
 {
     switch (GetCalleeTokenTag(token)) {
       case CalleeToken_Script:
         return CalleeTokenToScript(token);
       case CalleeToken_Function:
         return CalleeTokenToFunction(token)->nonLazyScript();
-      case CalleeToken_ParallelFunction:
-        return CalleeTokenToParallelFunction(token)->nonLazyScript();
     }
     MOZ_ASSUME_UNREACHABLE("invalid callee token tag");
 }
 
 // In between every two frames lies a small header describing both frames. This
 // header, minimally, contains a returnAddress word and a descriptor word. The
 // descriptor describes the size and type of the previous frame, whereas the
 // returnAddress describes the address the newer frame (the callee) will return
@@ -281,41 +267,35 @@ void MarkIonCompilerRoots(JSTracer *trc)
 static inline uint32_t
 MakeFrameDescriptor(uint32_t frameSize, FrameType type)
 {
     return (frameSize << FRAMESIZE_SHIFT) | type;
 }
 
 // Returns the JSScript associated with the topmost Ion frame.
 inline JSScript *
-GetTopIonJSScript(PerThreadData *pt, void **returnAddrOut)
+GetTopIonJSScript(uint8_t *ionTop, void **returnAddrOut, ExecutionMode mode)
 {
-    IonFrameIterator iter(pt->ionTop);
+    IonFrameIterator iter(ionTop, mode);
     JS_ASSERT(iter.type() == IonFrame_Exit);
     ++iter;
 
     JS_ASSERT(iter.returnAddressToFp() != nullptr);
     if (returnAddrOut)
         *returnAddrOut = (void *) iter.returnAddressToFp();
 
     if (iter.isBaselineStub()) {
         ++iter;
         JS_ASSERT(iter.isBaselineJS());
     }
 
     JS_ASSERT(iter.isScripted());
     return iter.script();
 }
 
-inline JSScript *
-GetTopIonJSScript(ThreadSafeContext *cx, void **returnAddrOut = nullptr)
-{
-    return GetTopIonJSScript(cx->perThreadData, returnAddrOut);
-}
-
 } // namespace jit
 } // namespace js
 
 #if defined(JS_CPU_X86) || defined (JS_CPU_X64)
 # include "jit/shared/IonFrames-x86-shared.h"
 #elif defined (JS_CPU_ARM)
 # include "jit/arm/IonFrames-arm.h"
 #else
--- a/js/src/jit/IonMacroAssembler.cpp
+++ b/js/src/jit/IonMacroAssembler.cpp
@@ -1306,65 +1306,16 @@ MacroAssembler::handleFailure(ExecutionM
     }
     MacroAssemblerSpecific::handleFailureWithHandler(handler);
 
     // Doesn't actually emit code, but balances the leave()
     if (sps_)
         sps_->reenter(*this, InvalidReg);
 }
 
-void
-MacroAssembler::pushCalleeToken(Register callee, ExecutionMode mode)
-{
-    // Tag and push a callee, then clear the tag after pushing. This is needed
-    // if we dereference the callee pointer after pushing it as part of a
-    // frame.
-    tagCallee(callee, mode);
-    push(callee);
-    clearCalleeTag(callee, mode);
-}
-
-void
-MacroAssembler::PushCalleeToken(Register callee, ExecutionMode mode)
-{
-    tagCallee(callee, mode);
-    Push(callee);
-    clearCalleeTag(callee, mode);
-}
-
-void
-MacroAssembler::tagCallee(Register callee, ExecutionMode mode)
-{
-    switch (mode) {
-      case SequentialExecution:
-        // CalleeToken_Function is untagged, so we don't need to do anything.
-        return;
-      case ParallelExecution:
-        orPtr(Imm32(CalleeToken_ParallelFunction), callee);
-        return;
-      default:
-        MOZ_ASSUME_UNREACHABLE("No such execution mode");
-    }
-}
-
-void
-MacroAssembler::clearCalleeTag(Register callee, ExecutionMode mode)
-{
-    switch (mode) {
-      case SequentialExecution:
-        // CalleeToken_Function is untagged, so we don't need to do anything.
-        return;
-      case ParallelExecution:
-        andPtr(Imm32(~0x3), callee);
-        return;
-      default:
-        MOZ_ASSUME_UNREACHABLE("No such execution mode");
-    }
-}
-
 static void printf0_(const char *output) {
     printf("%s", output);
 }
 
 void
 MacroAssembler::printf(const char *output)
 {
     RegisterSet regs = RegisterSet::Volatile();
--- a/js/src/jit/IonMacroAssembler.h
+++ b/js/src/jit/IonMacroAssembler.h
@@ -402,18 +402,20 @@ class MacroAssembler : public MacroAssem
     }
 
     template <typename T>
     void storeTypedOrValue(TypedOrValueRegister src, const T &dest) {
         if (src.hasValue()) {
             storeValue(src.valueReg(), dest);
         } else if (IsFloatingPointType(src.type())) {
             FloatRegister reg = src.typedReg().fpu();
-            if (src.type() == MIRType_Float32)
-                convertFloatToDouble(reg, reg);
+            if (src.type() == MIRType_Float32) {
+                convertFloatToDouble(reg, ScratchFloatReg);
+                reg = ScratchFloatReg;
+            }
             storeDouble(reg, dest);
         } else {
             storeValue(ValueTypeFromMIRType(src.type()), src.typedReg().gpr(), dest);
         }
     }
 
     template <typename T>
     void storeConstantOrRegister(ConstantOrRegister src, const T &dest) {
@@ -548,18 +550,20 @@ class MacroAssembler : public MacroAssem
         }
     }
 
     void Push(TypedOrValueRegister v) {
         if (v.hasValue()) {
             Push(v.valueReg());
         } else if (IsFloatingPointType(v.type())) {
             FloatRegister reg = v.typedReg().fpu();
-            if (v.type() == MIRType_Float32)
-                convertFloatToDouble(reg, reg);
+            if (v.type() == MIRType_Float32) {
+                convertFloatToDouble(reg, ScratchFloatReg);
+                reg = ScratchFloatReg;
+            }
             Push(reg);
         } else {
             Push(ValueTypeFromMIRType(v.type()), v.typedReg().gpr());
         }
     }
 
     void Push(ConstantOrRegister v) {
         if (v.constant())
@@ -930,21 +934,16 @@ class MacroAssembler : public MacroAssem
         branchPtr(Assembler::Equal, scratch, ImmPtr(&ProxyObject::callableClass_), slowCheck);
         branchPtr(Assembler::Equal, scratch, ImmPtr(&ProxyObject::uncallableClass_), slowCheck);
         branchPtr(Assembler::Equal, scratch, ImmPtr(&OuterWindowProxyObject::class_), slowCheck);
 
         test32(Address(scratch, Class::offsetOfFlags()), Imm32(JSCLASS_EMULATES_UNDEFINED));
         return truthy ? Assembler::Zero : Assembler::NonZero;
     }
 
-    void pushCalleeToken(Register callee, ExecutionMode mode);
-    void PushCalleeToken(Register callee, ExecutionMode mode);
-    void tagCallee(Register callee, ExecutionMode mode);
-    void clearCalleeTag(Register callee, ExecutionMode mode);
-
   private:
     // These two functions are helpers used around call sites throughout the
     // assembler. They are called from the above call wrappers to emit the
     // necessary instrumentation.
     void leaveSPSFrame() {
         if (!sps_ || !sps_->enabled())
             return;
         // No registers are guaranteed to be available, so push/pop a register
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -4351,60 +4351,72 @@ class LCallDeleteElement : public LCallI
 
     MDeleteElement *mir() const {
         return mir_->toDeleteElement();
     }
 };
 
 // Patchable jump to stubs generated for a SetProperty cache, which stores a
 // boxed value.
-class LSetPropertyCacheV : public LInstructionHelper<0, 1 + BOX_PIECES, 1>
+class LSetPropertyCacheV : public LInstructionHelper<0, 1 + BOX_PIECES, 2>
 {
   public:
     LIR_HEADER(SetPropertyCacheV)
 
-    LSetPropertyCacheV(const LAllocation &object, const LDefinition &slots) {
+    LSetPropertyCacheV(const LAllocation &object, const LDefinition &slots,
+                       const LDefinition &temp) {
         setOperand(0, object);
         setTemp(0, slots);
+        setTemp(1, temp);
     }
 
     static const size_t Value = 1;
 
     const MSetPropertyCache *mir() const {
         return mir_->toSetPropertyCache();
     }
+
+    const LDefinition *tempForDispatchCache() {
+        return getTemp(1);
+    }
 };
 
 // Patchable jump to stubs generated for a SetProperty cache, which stores a
 // value of a known type.
-class LSetPropertyCacheT : public LInstructionHelper<0, 2, 1>
+class LSetPropertyCacheT : public LInstructionHelper<0, 2, 2>
 {
     MIRType valueType_;
 
   public:
     LIR_HEADER(SetPropertyCacheT)
 
     LSetPropertyCacheT(const LAllocation &object, const LDefinition &slots,
-                       const LAllocation &value, MIRType valueType)
+                       const LAllocation &value, const LDefinition &temp,
+                       MIRType valueType)
         : valueType_(valueType)
     {
         setOperand(0, object);
         setOperand(1, value);
         setTemp(0, slots);
+        setTemp(1, temp);
     }
 
     const MSetPropertyCache *mir() const {
         return mir_->toSetPropertyCache();
     }
     MIRType valueType() {
         return valueType_;
     }
     const char *extraName() const {
         return StringFromMIRType(valueType_);
     }
+
+    const LDefinition *tempForDispatchCache() {
+        return getTemp(1);
+    }
 };
 
 class LSetElementCacheV : public LInstructionHelper<0, 1 + 2 * BOX_PIECES, 3>
 {
   public:
     LIR_HEADER(SetElementCacheV);
 
     static const size_t Index = 1;
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -2598,17 +2598,18 @@ LIRGenerator::visitGetPropertyCache(MGet
     JS_ASSERT(ins->object()->type() == MIRType_Object);
     if (ins->type() == MIRType_Value) {
         LGetPropertyCacheV *lir = new LGetPropertyCacheV(useRegister(ins->object()));
         if (!defineBox(lir, ins))
             return false;
         return assignSafepoint(lir, ins);
     }
 
-    LGetPropertyCacheT *lir = newLGetPropertyCacheT(ins);
+    LGetPropertyCacheT *lir = new LGetPropertyCacheT(useRegister(ins->object()),
+                                                     tempForDispatchCache(ins->type()));
     if (!define(lir, ins))
         return false;
     return assignSafepoint(lir, ins);
 }
 
 bool
 LIRGenerator::visitGetPropertyPolymorphic(MGetPropertyPolymorphic *ins)
 {
@@ -2651,17 +2652,19 @@ LIRGenerator::visitGetElementCache(MGetE
         JS_ASSERT(ins->index()->type() == MIRType_Value);
         LGetElementCacheV *lir = new LGetElementCacheV(useRegister(ins->object()));
         if (!useBox(lir, LGetElementCacheV::Index, ins->index()))
             return false;
         return defineBox(lir, ins) && assignSafepoint(lir, ins);
     }
 
     JS_ASSERT(ins->index()->type() == MIRType_Int32);
-    LGetElementCacheT *lir = newLGetElementCacheT(ins);
+    LGetElementCacheT *lir = new LGetElementCacheT(useRegister(ins->object()),
+                                                   useRegister(ins->index()),
+                                                   tempForDispatchCache(ins->type()));
     return define(lir, ins) && assignSafepoint(lir, ins);
 }
 
 bool
 LIRGenerator::visitBindNameCache(MBindNameCache *ins)
 {
     JS_ASSERT(ins->scopeChain()->type() == MIRType_Object);
     JS_ASSERT(ins->type() == MIRType_Object);
@@ -2753,17 +2756,17 @@ LIRGenerator::visitCallGetElement(MCallG
     if (!defineReturn(lir, ins))
         return false;
     return assignSafepoint(lir, ins);
 }
 
 bool
 LIRGenerator::visitCallSetProperty(MCallSetProperty *ins)
 {
-    LInstruction *lir = new LCallSetProperty(useRegisterAtStart(ins->obj()));
+    LInstruction *lir = new LCallSetProperty(useRegisterAtStart(ins->object()));
     if (!useBoxAtStart(lir, LCallSetProperty::Value, ins->value()))
         return false;
     if (!add(lir, ins))
         return false;
     return assignSafepoint(lir, ins);
 }
 
 bool
@@ -2784,27 +2787,28 @@ LIRGenerator::visitDeleteElement(MDelete
     if(!useBoxAtStart(lir, LCallDeleteElement::Index, ins->index()))
         return false;
     return defineReturn(lir, ins) && assignSafepoint(lir, ins);
 }
 
 bool
 LIRGenerator::visitSetPropertyCache(MSetPropertyCache *ins)
 {
-    LUse obj = useRegisterAtStart(ins->obj());
-    LDefinition slots = tempCopy(ins->obj(), 0);
+    LUse obj = useRegisterAtStart(ins->object());
+    LDefinition slots = tempCopy(ins->object(), 0);
+    LDefinition dispatchTemp = tempForDispatchCache();
 
     LInstruction *lir;
     if (ins->value()->type() == MIRType_Value) {
-        lir = new LSetPropertyCacheV(obj, slots);
+        lir = new LSetPropertyCacheV(obj, slots, dispatchTemp);
         if (!useBox(lir, LSetPropertyCacheV::Value, ins->value()))
             return false;
     } else {
         LAllocation value = useRegisterOrConstant(ins->value());
-        lir = new LSetPropertyCacheT(obj, slots, value, ins->value()->type());
+        lir = new LSetPropertyCacheT(obj, slots, value, dispatchTemp, ins->value()->type());
     }
 
     if (!add(lir, ins))
         return false;
 
     return assignSafepoint(lir, ins);
 }
 
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -6961,17 +6961,17 @@ class MSetPropertyInstruction : public M
   protected:
     MSetPropertyInstruction(MDefinition *obj, MDefinition *value, PropertyName *name,
                             bool strict)
       : MBinaryInstruction(obj, value),
         name_(name), strict_(strict), needsBarrier_(true)
     {}
 
   public:
-    MDefinition *obj() const {
+    MDefinition *object() const {
         return getOperand(0);
     }
     MDefinition *value() const {
         return getOperand(1);
     }
     PropertyName *name() const {
         return name_;
     }
--- a/js/src/jit/ParallelFunctions.cpp
+++ b/js/src/jit/ParallelFunctions.cpp
@@ -120,18 +120,17 @@ jit::CheckOverRecursedPar(ForkJoinSlice 
 
     uintptr_t realStackLimit;
     if (slice->isMainThread())
         realStackLimit = GetNativeStackLimit(slice);
     else
         realStackLimit = slice->perThreadData->ionStackLimit;
 
     if (!JS_CHECK_STACK_SIZE(realStackLimit, &stackDummy_)) {
-        slice->bailoutRecord->setCause(ParallelBailoutOverRecursed,
-                                       nullptr, nullptr, nullptr);
+        slice->bailoutRecord->setCause(ParallelBailoutOverRecursed);
         return false;
     }
 
     return CheckInterruptPar(slice);
 }
 
 bool
 jit::CheckInterruptPar(ForkJoinSlice *slice)
@@ -154,70 +153,77 @@ jit::ExtendArrayPar(ForkJoinSlice *slice
 {
     JSObject::EnsureDenseResult res =
         array->ensureDenseElementsPreservePackedFlag(slice, 0, length);
     if (res != JSObject::ED_OK)
         return nullptr;
     return array;
 }
 
-ParallelResult
+bool
+jit::SetPropertyPar(ForkJoinSlice *slice, HandleObject obj, HandlePropertyName name,
+                    HandleValue value, bool strict, jsbytecode *pc)
+{
+    JS_ASSERT(slice->isThreadLocal(obj));
+
+    if (*pc == JSOP_SETALIASEDVAR) {
+        // See comment in jit::SetProperty.
+        Shape *shape = obj->nativeLookupPure(name);
+        JS_ASSERT(shape && shape->hasSlot());
+        return obj->nativeSetSlotIfHasType(shape, value);
+    }
+
+    // Fail early on hooks.
+    if (obj->getOps()->setProperty)
+        return TP_RETRY_SEQUENTIALLY;
+
+    RootedValue v(slice, value);
+    RootedId id(slice, NameToId(name));
+    return baseops::SetPropertyHelper<ParallelExecution>(slice, obj, obj, id, 0, &v, strict);
+}
+
+bool
 jit::SetElementPar(ForkJoinSlice *slice, HandleObject obj, HandleValue index, HandleValue value,
                    bool strict)
 {
     RootedId id(slice);
     if (!ValueToIdPure(index, id.address()))
-        return TP_RETRY_SEQUENTIALLY;
+        return false;
 
     // SetObjectElementOperation, the sequential version, has several checks
     // for certain deoptimizing behaviors, such as marking having written to
     // holes and non-indexed element accesses. We don't do that here, as we
     // can't modify any TI state anyways. If we need to add a new type, we
     // would bail out.
     RootedValue v(slice, value);
-    if (!baseops::SetPropertyHelper<ParallelExecution>(slice, obj, obj, id, 0, &v, strict))
-        return TP_RETRY_SEQUENTIALLY;
-    return TP_SUCCESS;
+    return baseops::SetPropertyHelper<ParallelExecution>(slice, obj, obj, id, 0, &v, strict);
 }
 
-ParallelResult
-jit::ConcatStringsPar(ForkJoinSlice *slice, HandleString left, HandleString right,
-                      MutableHandleString out)
+JSString *
+jit::ConcatStringsPar(ForkJoinSlice *slice, HandleString left, HandleString right)
 {
-    JSString *str = ConcatStrings<NoGC>(slice, left, right);
-    if (!str)
-        return TP_RETRY_SEQUENTIALLY;
-    out.set(str);
-    return TP_SUCCESS;
+    return ConcatStrings<NoGC>(slice, left, right);
 }
 
-ParallelResult
-jit::IntToStringPar(ForkJoinSlice *slice, int i, MutableHandleString out)
+JSFlatString *
+jit::IntToStringPar(ForkJoinSlice *slice, int i)
 {
-    JSFlatString *str = Int32ToString<NoGC>(slice, i);
-    if (!str)
-        return TP_RETRY_SEQUENTIALLY;
-    out.set(str);
-    return TP_SUCCESS;
+    return Int32ToString<NoGC>(slice, i);
 }
 
-ParallelResult
-jit::DoubleToStringPar(ForkJoinSlice *slice, double d, MutableHandleString out)
+JSString *
+jit::DoubleToStringPar(ForkJoinSlice *slice, double d)
 {
-    JSString *str = NumberToString<NoGC>(slice, d);
-    if (!str)
-        return TP_RETRY_SEQUENTIALLY;
-    out.set(str);
-    return TP_SUCCESS;
+    return NumberToString<NoGC>(slice, d);
 }
 
-ParallelResult
+bool
 jit::StringToNumberPar(ForkJoinSlice *slice, JSString *str, double *out)
 {
-    return StringToNumber(slice, str, out) ? TP_SUCCESS : TP_FATAL;
+    return StringToNumber(slice, str, out);
 }
 
 #define PAR_RELATIONAL_OP(OP, EXPECTED)                                         \
 do {                                                                            \
     /* Optimize for two int-tagged operands (typical loop control). */          \
     if (lhs.isInt32() && rhs.isInt32()) {                                       \
         *res = (lhs.toInt32() OP rhs.toInt32()) == EXPECTED;                    \
     } else if (lhs.isNumber() && rhs.isNumber()) {                              \
@@ -232,238 +238,234 @@ do {                                    
         double r = rhs.toNumber();                                              \
         *res = (l OP r) == EXPECTED;                                            \
     } else if (lhs.isNumber() && rhs.isBoolean()) {                             \
         double l = lhs.toNumber();                                              \
         bool r = rhs.toBoolean();                                               \
         *res = (l OP r) == EXPECTED;                                            \
     } else {                                                                    \
         int32_t vsZero;                                                         \
-        ParallelResult ret = CompareMaybeStringsPar(slice, lhs, rhs, &vsZero);  \
-        if (ret != TP_SUCCESS)                                                  \
-            return ret;                                                         \
+        if (!CompareMaybeStringsPar(slice, lhs, rhs, &vsZero))                  \
+            return false;                                                       \
         *res = (vsZero OP 0) == EXPECTED;                                       \
     }                                                                           \
-    return TP_SUCCESS;                                                          \
+    return true;                                                                \
 } while(0)
 
-static ParallelResult
+static bool
 CompareStringsPar(ForkJoinSlice *slice, JSString *left, JSString *right, int32_t *res)
 {
     ScopedThreadSafeStringInspector leftInspector(left);
     ScopedThreadSafeStringInspector rightInspector(right);
     if (!leftInspector.ensureChars(slice) || !rightInspector.ensureChars(slice))
-        return TP_FATAL;
+        return false;
 
-    if (!CompareChars(leftInspector.chars(), left->length(),
-                      rightInspector.chars(), right->length(),
-                      res))
-        return TP_FATAL;
-
-    return TP_SUCCESS;
+    return CompareChars(leftInspector.chars(), left->length(),
+                        rightInspector.chars(), right->length(),
+                        res);
 }
 
-static ParallelResult
+static bool
 CompareMaybeStringsPar(ForkJoinSlice *slice, HandleValue v1, HandleValue v2, int32_t *res)
 {
     if (!v1.isString())
-        return TP_RETRY_SEQUENTIALLY;
+        return false;
     if (!v2.isString())
-        return TP_RETRY_SEQUENTIALLY;
+        return false;
     return CompareStringsPar(slice, v1.toString(), v2.toString(), res);
 }
 
 template<bool Equal>
-ParallelResult
+bool
 LooselyEqualImplPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     PAR_RELATIONAL_OP(==, Equal);
 }
 
-ParallelResult
+bool
 js::jit::LooselyEqualPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     return LooselyEqualImplPar<true>(slice, lhs, rhs, res);
 }
 
-ParallelResult
+bool
 js::jit::LooselyUnequalPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     return LooselyEqualImplPar<false>(slice, lhs, rhs, res);
 }
 
 template<bool Equal>
-ParallelResult
+bool
 StrictlyEqualImplPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     if (lhs.isNumber()) {
         if (rhs.isNumber()) {
             *res = (lhs.toNumber() == rhs.toNumber()) == Equal;
-            return TP_SUCCESS;
+            return true;
         }
     } else if (lhs.isBoolean()) {
         if (rhs.isBoolean()) {
             *res = (lhs.toBoolean() == rhs.toBoolean()) == Equal;
-            return TP_SUCCESS;
+            return true;
         }
     } else if (lhs.isNull()) {
         if (rhs.isNull()) {
             *res = Equal;
-            return TP_SUCCESS;
+            return true;
         }
     } else if (lhs.isUndefined()) {
         if (rhs.isUndefined()) {
             *res = Equal;
-            return TP_SUCCESS;
+            return true;
         }
     } else if (lhs.isObject()) {
         if (rhs.isObject()) {
             *res = (lhs.toObjectOrNull() == rhs.toObjectOrNull()) == Equal;
-            return TP_SUCCESS;
+            return true;
         }
     } else if (lhs.isString()) {
         if (rhs.isString())
             return LooselyEqualImplPar<Equal>(slice, lhs, rhs, res);
     }
 
     *res = false;
-    return TP_SUCCESS;
+    return true;
 }
 
-ParallelResult
+bool
 js::jit::StrictlyEqualPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     return StrictlyEqualImplPar<true>(slice, lhs, rhs, res);
 }
 
-ParallelResult
+bool
 js::jit::StrictlyUnequalPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     return StrictlyEqualImplPar<false>(slice, lhs, rhs, res);
 }
 
-ParallelResult
+bool
 js::jit::LessThanPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     PAR_RELATIONAL_OP(<, true);
 }
 
-ParallelResult
+bool
 js::jit::LessThanOrEqualPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     PAR_RELATIONAL_OP(<=, true);
 }
 
-ParallelResult
+bool
 js::jit::GreaterThanPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     PAR_RELATIONAL_OP(>, true);
 }
 
-ParallelResult
+bool
 js::jit::GreaterThanOrEqualPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     PAR_RELATIONAL_OP(>=, true);
 }
 
 template<bool Equal>
-ParallelResult
+bool
 StringsEqualImplPar(ForkJoinSlice *slice, HandleString lhs, HandleString rhs, bool *res)
 {
     int32_t vsZero;
-    ParallelResult ret = CompareStringsPar(slice, lhs, rhs, &vsZero);
-    if (ret != TP_SUCCESS)
+    bool ret = CompareStringsPar(slice, lhs, rhs, &vsZero);
+    if (ret != true)
         return ret;
     *res = (vsZero == 0) == Equal;
-    return TP_SUCCESS;
+    return true;
 }
 
-ParallelResult
+bool
 js::jit::StringsEqualPar(ForkJoinSlice *slice, HandleString v1, HandleString v2, bool *res)
 {
     return StringsEqualImplPar<true>(slice, v1, v2, res);
 }
 
-ParallelResult
+bool
 js::jit::StringsUnequalPar(ForkJoinSlice *slice, HandleString v1, HandleString v2, bool *res)
 {
     return StringsEqualImplPar<false>(slice, v1, v2, res);
 }
 
-ParallelResult
+bool
 jit::BitNotPar(ForkJoinSlice *slice, HandleValue in, int32_t *out)
 {
     if (in.isObject())
-        return TP_RETRY_SEQUENTIALLY;
+        return false;
     int i;
     if (!NonObjectToInt32(slice, in, &i))
-        return TP_FATAL;
+        return false;
     *out = ~i;
-    return TP_SUCCESS;
+    return true;
 }
 
 #define BIT_OP(OP)                                                      \
     JS_BEGIN_MACRO                                                      \
     int32_t left, right;                                                \
     if (lhs.isObject() || rhs.isObject())                               \
         return TP_RETRY_SEQUENTIALLY;                                   \
     if (!NonObjectToInt32(slice, lhs, &left) ||                         \
         !NonObjectToInt32(slice, rhs, &right))                          \
     {                                                                   \
-        return TP_FATAL;                                                \
+        return false;                                                   \
     }                                                                   \
     *out = (OP);                                                        \
-    return TP_SUCCESS;                                                  \
+    return true;                                                        \
     JS_END_MACRO
 
-ParallelResult
+bool
 jit::BitXorPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out)
 {
     BIT_OP(left ^ right);
 }
 
-ParallelResult
+bool
 jit::BitOrPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out)
 {
     BIT_OP(left | right);
 }
 
-ParallelResult
+bool
 jit::BitAndPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out)
 {
     BIT_OP(left & right);
 }
 
-ParallelResult
+bool
 jit::BitLshPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out)
 {
     BIT_OP(left << (right & 31));
 }
 
-ParallelResult
+bool
 jit::BitRshPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out)
 {
     BIT_OP(left >> (right & 31));
 }
 
 #undef BIT_OP
 
-ParallelResult
+bool
 jit::UrshValuesPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs,
                    Value *out)
 {
     uint32_t left;
     int32_t right;
     if (lhs.isObject() || rhs.isObject())
-        return TP_RETRY_SEQUENTIALLY;
+        return false;
     if (!NonObjectToUint32(slice, lhs, &left) || !NonObjectToInt32(slice, rhs, &right))
-        return TP_FATAL;
+        return false;
     left >>= right & 31;
     out->setNumber(uint32_t(left));
-    return TP_SUCCESS;
+    return true;
 }
 
 void
 jit::AbortPar(ParallelBailoutCause cause, JSScript *outermostScript, JSScript *currentScript,
               jsbytecode *bytecode)
 {
     // Spew before asserts to help with diagnosing failures.
     Spew(SpewBailouts,
@@ -477,18 +479,17 @@ jit::AbortPar(ParallelBailoutCause cause
     JS_ASSERT(InParallelSection());
     JS_ASSERT(outermostScript != nullptr);
     JS_ASSERT(currentScript != nullptr);
     JS_ASSERT(outermostScript->hasParallelIonScript());
 
     ForkJoinSlice *slice = ForkJoinSlice::Current();
 
     JS_ASSERT(slice->bailoutRecord->depth == 0);
-    slice->bailoutRecord->setCause(cause, outermostScript,
-                                   currentScript, bytecode);
+    slice->bailoutRecord->setCause(cause, outermostScript, currentScript, bytecode);
 }
 
 void
 jit::PropagateAbortPar(JSScript *outermostScript, JSScript *currentScript)
 {
     Spew(SpewBailouts,
          "Propagate parallel abort via %p:%s:%d (%p:%s:%d)",
          outermostScript, outermostScript->filename(), outermostScript->lineno,
@@ -543,33 +544,31 @@ jit::CallToUncompiledScriptPar(JSObject 
         }
     } else {
         JS_ASSERT(func->isNative());
         Spew(SpewBailouts, "Call to native function");
     }
 #endif
 }
 
-ParallelResult
+JSObject *
 jit::InitRestParameterPar(ForkJoinSlice *slice, uint32_t length, Value *rest,
-                          HandleObject templateObj, HandleObject res,
-                          MutableHandleObject out)
+                          HandleObject templateObj, HandleObject res)
 {
     // In parallel execution, we should always have succeeded in allocation
     // before this point. We can do the allocation here like in the sequential
     // path, but duplicating the initGCThing logic is too tedious.
     JS_ASSERT(res);
     JS_ASSERT(res->is<ArrayObject>());
     JS_ASSERT(!res->getDenseInitializedLength());
     JS_ASSERT(res->type() == templateObj->type());
 
     if (length > 0) {
         JSObject::EnsureDenseResult edr =
             res->ensureDenseElementsPreservePackedFlag(slice, 0, length);
         if (edr != JSObject::ED_OK)
-            return TP_FATAL;
+            return nullptr;
         res->initDenseElements(0, rest, length);
         res->as<ArrayObject>().setLengthInt32(length);
     }
 
-    out.set(res);
-    return TP_SUCCESS;
+    return res;
 }
--- a/js/src/jit/ParallelFunctions.h
+++ b/js/src/jit/ParallelFunctions.h
@@ -20,55 +20,55 @@ bool CheckOverRecursedPar(ForkJoinSlice 
 bool CheckInterruptPar(ForkJoinSlice *slice);
 
 // Extends the given array with `length` new holes.  Returns nullptr on
 // failure or else `array`, which is convenient during code
 // generation.
 JSObject *ExtendArrayPar(ForkJoinSlice *slice, JSObject *array, uint32_t length);
 
 // Set properties and elements on thread local objects.
-ParallelResult SetElementPar(ForkJoinSlice *slice, HandleObject obj, HandleValue index,
-                             HandleValue value, bool strict);
+bool SetPropertyPar(ForkJoinSlice *slice, HandleObject obj, HandlePropertyName name,
+                    HandleValue value, bool strict, jsbytecode *pc);
+bool SetElementPar(ForkJoinSlice *slice, HandleObject obj, HandleValue index,
+                   HandleValue value, bool strict);
 
 // String related parallel functions. These tend to call existing VM functions
 // that take a ThreadSafeContext.
-ParallelResult ConcatStringsPar(ForkJoinSlice *slice, HandleString left, HandleString right,
-                                MutableHandleString out);
-ParallelResult IntToStringPar(ForkJoinSlice *slice, int i, MutableHandleString out);
-ParallelResult DoubleToStringPar(ForkJoinSlice *slice, double d, MutableHandleString out);
-ParallelResult StringToNumberPar(ForkJoinSlice *slice, JSString *str, double *out);
+JSString *ConcatStringsPar(ForkJoinSlice *slice, HandleString left, HandleString right);
+JSFlatString *IntToStringPar(ForkJoinSlice *slice, int i);
+JSString *DoubleToStringPar(ForkJoinSlice *slice, double d);
+bool StringToNumberPar(ForkJoinSlice *slice, JSString *str, double *out);
 
 // Binary and unary operator functions on values. These tend to return
 // RETRY_SEQUENTIALLY if the values are objects.
-ParallelResult StrictlyEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
-ParallelResult StrictlyUnequalPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
-ParallelResult LooselyEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
-ParallelResult LooselyUnequalPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
-ParallelResult LessThanPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
-ParallelResult LessThanOrEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
-ParallelResult GreaterThanPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
-ParallelResult GreaterThanOrEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
+bool StrictlyEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
+bool StrictlyUnequalPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
+bool LooselyEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
+bool LooselyUnequalPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
+bool LessThanPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
+bool LessThanOrEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
+bool GreaterThanPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
+bool GreaterThanOrEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
 
-ParallelResult StringsEqualPar(ForkJoinSlice *slice, HandleString v1, HandleString v2, bool *);
-ParallelResult StringsUnequalPar(ForkJoinSlice *slice, HandleString v1, HandleString v2, bool *);
+bool StringsEqualPar(ForkJoinSlice *slice, HandleString v1, HandleString v2, bool *);
+bool StringsUnequalPar(ForkJoinSlice *slice, HandleString v1, HandleString v2, bool *);
 
-ParallelResult BitNotPar(ForkJoinSlice *slice, HandleValue in, int32_t *out);
-ParallelResult BitXorPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
-ParallelResult BitOrPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
-ParallelResult BitAndPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
-ParallelResult BitLshPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
-ParallelResult BitRshPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
+bool BitNotPar(ForkJoinSlice *slice, HandleValue in, int32_t *out);
+bool BitXorPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
+bool BitOrPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
+bool BitAndPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
+bool BitLshPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
+bool BitRshPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
 
-ParallelResult UrshValuesPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs,
+bool UrshValuesPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs,
                              Value *out);
 
 // Make a new rest parameter in parallel.
-ParallelResult InitRestParameterPar(ForkJoinSlice *slice, uint32_t length, Value *rest,
-                                    HandleObject templateObj, HandleObject res,
-                                    MutableHandleObject out);
+JSObject *InitRestParameterPar(ForkJoinSlice *slice, uint32_t length, Value *rest,
+                               HandleObject templateObj, HandleObject res);
 
 // Abort and debug tracing functions.
 void AbortPar(ParallelBailoutCause cause, JSScript *outermostScript, JSScript *currentScript,
               jsbytecode *bytecode);
 void PropagateAbortPar(JSScript *outermostScript, JSScript *currentScript);
 
 void TraceLIR(IonLIRTraceData *current);
 
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ b/js/src/jit/ParallelSafetyAnalysis.cpp
@@ -196,17 +196,17 @@ class ParallelSafetyVisitor : public MIn
     SAFE_OP(FunctionEnvironment) // just a load of func env ptr
     SAFE_OP(TypeBarrier) // causes a bailout if the type is not found: a-ok with us
     SAFE_OP(MonitorTypes) // causes a bailout if the type is not found: a-ok with us
     UNSAFE_OP(PostWriteBarrier)
     SAFE_OP(GetPropertyCache)
     SAFE_OP(GetPropertyPolymorphic)
     UNSAFE_OP(SetPropertyPolymorphic)
     SAFE_OP(GetElementCache)
-    UNSAFE_OP(SetElementCache)
+    WRITE_GUARDED_OP(SetElementCache, object)
     UNSAFE_OP(BindNameCache)
     SAFE_OP(GuardShape)
     SAFE_OP(GuardObjectType)
     SAFE_OP(GuardClass)
     SAFE_OP(AssertRange)
     SAFE_OP(ArrayLength)
     SAFE_OP(TypedArrayLength)
     SAFE_OP(TypedArrayElements)
@@ -231,22 +231,22 @@ class ParallelSafetyVisitor : public MIn
     UNSAFE_OP(ClampToUint8)
     SAFE_OP(LoadFixedSlot)
     WRITE_GUARDED_OP(StoreFixedSlot, object)
     UNSAFE_OP(CallGetProperty)
     UNSAFE_OP(GetNameCache)
     UNSAFE_OP(CallGetIntrinsicValue)
     UNSAFE_OP(CallsiteCloneCache)
     UNSAFE_OP(CallGetElement)
-    UNSAFE_OP(CallSetElement)
+    WRITE_GUARDED_OP(CallSetElement, object)
     UNSAFE_OP(CallInitElementArray)
-    UNSAFE_OP(CallSetProperty)
+    WRITE_GUARDED_OP(CallSetProperty, object)
     UNSAFE_OP(DeleteProperty)
     UNSAFE_OP(DeleteElement)
-    UNSAFE_OP(SetPropertyCache)
+    WRITE_GUARDED_OP(SetPropertyCache, object)
     UNSAFE_OP(IteratorStart)
     UNSAFE_OP(IteratorNext)
     UNSAFE_OP(IteratorMore)
     UNSAFE_OP(IteratorEnd)
     SAFE_OP(StringLength)
     SAFE_OP(ArgumentsLength)
     SAFE_OP(GetFrameArgument)
     UNSAFE_OP(SetFrameArgument)
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -14,29 +14,37 @@
 #include "jit/IonFrames.h"
 #include "vm/ArrayObject.h"
 #include "vm/Debugger.h"
 #include "vm/Interpreter.h"
 
 #include "jsinferinlines.h"
 
 #include "jit/BaselineFrame-inl.h"
+#include "jit/IonFrames-inl.h"
 #include "vm/Interpreter-inl.h"
 #include "vm/StringObject-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 namespace js {
 namespace jit {
 
 // Don't explicitly initialize, it's not guaranteed that this initializer will
 // run before the constructors for static VMFunctions.
 /* static */ VMFunction *VMFunction::functions;
 
+AutoDetectInvalidation::AutoDetectInvalidation(JSContext *cx, Value *rval, IonScript *ionScript)
+  : cx_(cx),
+    ionScript_(ionScript ? ionScript : GetTopIonJSScript(cx)->ionScript()),
+    rval_(rval),
+    disabled_(false)
+{ }
+
 void
 VMFunction::addToFunctions()
 {
     static bool initialized = false;
     if (!initialized) {
         initialized = true;
         functions = nullptr;
     }
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -22,18 +22,17 @@ namespace jit {
 enum DataType {
     Type_Void,
     Type_Bool,
     Type_Int32,
     Type_Double,
     Type_Pointer,
     Type_Object,
     Type_Value,
-    Type_Handle,
-    Type_ParallelResult
+    Type_Handle
 };
 
 struct PopValues
 {
     uint32_t numValues;
 
     explicit PopValues(uint32_t numValues)
       : numValues(numValues)
@@ -215,20 +214,18 @@ struct VMFunction
         argumentRootTypes(argRootTypes),
         outParamRootType(outParamRootType),
         executionMode(executionMode),
         extraValuesToPop(extraValuesToPop)
     {
         // Check for valid failure/return type.
         JS_ASSERT_IF(outParam != Type_Void && executionMode == SequentialExecution,
                      returnType == Type_Bool);
-        JS_ASSERT_IF(executionMode == ParallelExecution, returnType == Type_ParallelResult);
         JS_ASSERT(returnType == Type_Bool ||
-                  returnType == Type_Object ||
-                  returnType == Type_ParallelResult);
+                  returnType == Type_Object);
     }
 
     VMFunction(const VMFunction &o) {
         init(o);
     }
 
     void init(const VMFunction &o) {
         JS_ASSERT(!wrapped);
@@ -275,17 +272,16 @@ template <> struct TypeToDataType<JSFlat
 template <> struct TypeToDataType<HandleObject> { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<HandleString> { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<HandlePropertyName> { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<HandleFunction> { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<Handle<StaticBlockObject *> > { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<HandleScript> { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<HandleValue> { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<MutableHandleValue> { static const DataType result = Type_Handle; };
-template <> struct TypeToDataType<ParallelResult> { static const DataType result = Type_ParallelResult; };
 
 // Convert argument types to properties of the argument known by the jit.
 template <class T> struct TypeToArgProperties {
     static const uint32_t result =
         (sizeof(T) <= sizeof(void *) ? VMFunction::Word : VMFunction::Double);
 };
 template <> struct TypeToArgProperties<const Value &> {
     static const uint32_t result = TypeToArgProperties<Value>::result | VMFunction::ByRef;
@@ -390,18 +386,18 @@ template <> struct MatchContext<JSContex
 template <> struct MatchContext<ExclusiveContext *> {
     static const ExecutionMode execMode = SequentialExecution;
 };
 template <> struct MatchContext<ForkJoinSlice *> {
     static const ExecutionMode execMode = ParallelExecution;
 };
 template <> struct MatchContext<ThreadSafeContext *> {
     // ThreadSafeContext functions can be called from either mode, but for
-    // calling from parallel they need to be wrapped first to return a
-    // ParallelResult, so we default to SequentialExecution here.
+    // calling from parallel they should be wrapped first, so we default to
+    // SequentialExecution here.
     static const ExecutionMode execMode = SequentialExecution;
 };
 
 #define FOR_EACH_ARGS_1(Macro, Sep, Last) Macro(1) Last(1)
 #define FOR_EACH_ARGS_2(Macro, Sep, Last) FOR_EACH_ARGS_1(Macro, Sep, Sep) Macro(2) Last(2)
 #define FOR_EACH_ARGS_3(Macro, Sep, Last) FOR_EACH_ARGS_2(Macro, Sep, Sep) Macro(3) Last(3)
 #define FOR_EACH_ARGS_4(Macro, Sep, Last) FOR_EACH_ARGS_3(Macro, Sep, Sep) Macro(4) Last(4)
 #define FOR_EACH_ARGS_5(Macro, Sep, Last) FOR_EACH_ARGS_4(Macro, Sep, Sep) Macro(5) Last(5)
@@ -551,22 +547,17 @@ template <class R, class Context, class 
 class AutoDetectInvalidation
 {
     JSContext *cx_;
     IonScript *ionScript_;
     Value *rval_;
     bool disabled_;
 
   public:
-    AutoDetectInvalidation(JSContext *cx, Value *rval, IonScript *ionScript = nullptr)
-      : cx_(cx),
-        ionScript_(ionScript ? ionScript : GetTopIonJSScript(cx)->ionScript()),
-        rval_(rval),
-        disabled_(false)
-    { }
+    AutoDetectInvalidation(JSContext *cx, Value *rval, IonScript *ionScript = nullptr);
 
     void disable() {
         JS_ASSERT(!disabled_);
         disabled_ = true;
     }
 
     ~AutoDetectInvalidation() {
         if (!disabled_ && ionScript_->invalidated())
--- a/js/src/jit/arm/Lowering-arm.cpp
+++ b/js/src/jit/arm/Lowering-arm.cpp
@@ -359,30 +359,16 @@ LIRGeneratorARM::newLTableSwitch(const L
 }
 
 LTableSwitchV *
 LIRGeneratorARM::newLTableSwitchV(MTableSwitch *tableswitch)
 {
     return new LTableSwitchV(temp(), tempFloat(), tableswitch);
 }
 
-LGetPropertyCacheT *
-LIRGeneratorARM::newLGetPropertyCacheT(MGetPropertyCache *ins)
-{
-    return new LGetPropertyCacheT(useRegister(ins->object()), LDefinition::BogusTemp());
-}
-
-LGetElementCacheT *
-LIRGeneratorARM::newLGetElementCacheT(MGetElementCache *ins)
-{
-    return new LGetElementCacheT(useRegister(ins->object()),
-                                 useRegister(ins->index()),
-                                 LDefinition::BogusTemp());
-}
-
 bool
 LIRGeneratorARM::visitGuardShape(MGuardShape *ins)
 {
     JS_ASSERT(ins->obj()->type() == MIRType_Object);
 
     LDefinition tempObj = temp(LDefinition::OBJECT);
     LGuardShape *guard = new LGuardShape(useRegister(ins->obj()), tempObj);
     if (!assignSnapshot(guard, ins->bailoutKind()))
--- a/js/src/jit/arm/Lowering-arm.h
+++ b/js/src/jit/arm/Lowering-arm.h
@@ -30,16 +30,22 @@ class LIRGeneratorARM : public LIRGenera
     // stores and loads; on ARM all registers are okay.
     LAllocation useByteOpRegister(MDefinition *mir);
     LAllocation useByteOpRegisterOrNonDoubleConstant(MDefinition *mir);
 
     inline LDefinition tempToUnbox() {
         return LDefinition::BogusTemp();
     }
 
+    // x64 has a scratch register, so no need for another temp for dispatch
+    // ICs.
+    LDefinition tempForDispatchCache(MIRType outputType = MIRType_None) {
+        return LDefinition::BogusTemp();
+    }
+
     void lowerUntypedPhiInput(MPhi *phi, uint32_t inputPosition, LBlock *block, size_t lirIndex);
     bool defineUntypedPhi(MPhi *phi, size_t lirIndex);
     bool lowerForShift(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir, MDefinition *lhs,
                        MDefinition *rhs);
     bool lowerUrshD(MUrsh *mir);
 
     bool lowerForALU(LInstructionHelper<1, 1, 0> *ins, MDefinition *mir,
                      MDefinition *input);
@@ -63,18 +69,16 @@ class LIRGeneratorARM : public LIRGenera
     bool visitPowHalf(MPowHalf *ins);
     bool visitAsmJSNeg(MAsmJSNeg *ins);
     bool visitAsmJSUDiv(MAsmJSUDiv *ins);
     bool visitAsmJSUMod(MAsmJSUMod *ins);
 
     LTableSwitch *newLTableSwitch(const LAllocation &in, const LDefinition &inputCopy,
                                   MTableSwitch *ins);
     LTableSwitchV *newLTableSwitchV(MTableSwitch *ins);
-    LGetPropertyCacheT *newLGetPropertyCacheT(MGetPropertyCache *ins);
-    LGetElementCacheT *newLGetElementCacheT(MGetElementCache *ins);
 
   public:
     bool visitConstant(MConstant *ins);
     bool visitBox(MBox *box);
     bool visitUnbox(MUnbox *unbox);
     bool visitReturn(MReturn *ret);
     bool lowerPhi(MPhi *phi);
     bool visitGuardShape(MGuardShape *ins);
--- a/js/src/jit/arm/Trampoline-arm.cpp
+++ b/js/src/jit/arm/Trampoline-arm.cpp
@@ -418,17 +418,16 @@ IonRuntime::generateArgumentsRectifier(J
     // Including |this|, there are (|nargs| + 1) arguments to copy.
     JS_ASSERT(ArgumentsRectifierReg == r8);
 
     // Copy number of actual arguments into r0
     masm.ma_ldr(DTRAddr(sp, DtrOffImm(IonRectifierFrameLayout::offsetOfNumActualArgs())), r0);
 
     // Load the number of |undefined|s to push into r6.
     masm.ma_ldr(DTRAddr(sp, DtrOffImm(IonRectifierFrameLayout::offsetOfCalleeToken())), r1);
-    masm.clearCalleeTag(r1, mode);
     masm.ma_ldrh(EDtrAddr(r1, EDtrOffImm(offsetof(JSFunction, nargs))), r6);
 
     masm.ma_sub(r6, r8, r2);
 
     masm.moveValue(UndefinedValue(), r5, r4);
 
     masm.ma_mov(sp, r3); // Save %sp.
     masm.ma_mov(sp, r7); // Save %sp again.
@@ -463,17 +462,17 @@ IonRuntime::generateArgumentsRectifier(J
     masm.ma_add(r6, Imm32(1), r6);
     masm.ma_lsl(Imm32(3), r6, r6);
 
     // Construct sizeDescriptor.
     masm.makeFrameDescriptor(r6, IonFrame_Rectifier);
 
     // Construct IonJSFrameLayout.
     masm.ma_push(r0); // actual arguments.
-    masm.pushCalleeToken(r1, mode);
+    masm.ma_push(r1); // callee token
     masm.ma_push(r6); // frame descriptor.
 
     // Call the target function.
     // Note that this code assumes the function is JITted.
     masm.ma_ldr(DTRAddr(r1, DtrOffImm(JSFunction::offsetOfNativeOrScript())), r3);
     masm.loadBaselineOrIonRaw(r3, r3, mode, nullptr);
     masm.ma_callIonHalfPush(r3);
 
@@ -767,19 +766,16 @@ IonRuntime::generateVMWrapper(JSContext 
 
     // Test for failure.
     switch (f.failType()) {
       case Type_Object:
       case Type_Bool:
         // Called functions return bools, which are 0/false and non-zero/true
         masm.branch32(Assembler::Equal, r0, Imm32(0), masm.failureLabel(f.executionMode));
         break;
-      case Type_ParallelResult:
-        masm.branch32(Assembler::NotEqual, r0, Imm32(TP_SUCCESS), masm.failureLabel(f.executionMode));
-        break;
       default:
         MOZ_ASSUME_UNREACHABLE("unknown failure kind");
     }
 
     // Load the outparam and free any allocated stack.
     switch (f.outParam) {
       case Type_Handle:
         masm.popRooted(f.outParamRootType, ReturnReg, JSReturnOperand);
--- a/js/src/jit/x64/Lowering-x64.cpp
+++ b/js/src/jit/x64/Lowering-x64.cpp
@@ -162,27 +162,13 @@ LIRGeneratorX64::visitAsmJSStoreHeap(MAs
 }
 
 bool
 LIRGeneratorX64::visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins)
 {
     return define(new LAsmJSLoadFuncPtr(useRegister(ins->index()), temp()), ins);
 }
 
-LGetPropertyCacheT *
-LIRGeneratorX64::newLGetPropertyCacheT(MGetPropertyCache *ins)
-{
-    return new LGetPropertyCacheT(useRegister(ins->object()), LDefinition::BogusTemp());
-}
-
-LGetElementCacheT *
-LIRGeneratorX64::newLGetElementCacheT(MGetElementCache *ins)
-{
-    return new LGetElementCacheT(useRegister(ins->object()),
-                                 useRegister(ins->index()),
-                                 LDefinition::BogusTemp());
-}
-
 bool
 LIRGeneratorX64::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins)
 {
     MOZ_ASSUME_UNREACHABLE("NYI");
 }
--- a/js/src/jit/x64/Lowering-x64.h
+++ b/js/src/jit/x64/Lowering-x64.h
@@ -30,18 +30,21 @@ class LIRGeneratorX64 : public LIRGenera
 
     // x86 has constraints on what registers can be formatted for 1-byte
     // stores and loads; on x64 all registers are okay.
     LAllocation useByteOpRegister(MDefinition *mir);
     LAllocation useByteOpRegisterOrNonDoubleConstant(MDefinition *mir);
 
     LDefinition tempToUnbox();
 
-    LGetPropertyCacheT *newLGetPropertyCacheT(MGetPropertyCache *ins);
-    LGetElementCacheT *newLGetElementCacheT(MGetElementCache *ins);
+    // x64 has a scratch register, so no need for another temp for dispatch
+    // ICs.
+    LDefinition tempForDispatchCache(MIRType outputType = MIRType_None) {
+        return LDefinition::BogusTemp();
+    }
 
   public:
     bool visitBox(MBox *box);
     bool visitUnbox(MUnbox *unbox);
     bool visitReturn(MReturn *ret);
     bool visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins);
     bool visitAsmJSLoadHeap(MAsmJSLoadHeap *ins);
     bool visitAsmJSStoreHeap(MAsmJSStoreHeap *ins);
--- a/js/src/jit/x64/Trampoline-x64.cpp
+++ b/js/src/jit/x64/Trampoline-x64.cpp
@@ -358,17 +358,16 @@ IonRuntime::generateArgumentsRectifier(J
     MacroAssembler masm(cx);
 
     // ArgumentsRectifierReg contains the |nargs| pushed onto the current frame.
     // Including |this|, there are (|nargs| + 1) arguments to copy.
     JS_ASSERT(ArgumentsRectifierReg == r8);
 
     // Load the number of |undefined|s to push into %rcx.
     masm.loadPtr(Address(rsp, IonRectifierFrameLayout::offsetOfCalleeToken()), rax);
-    masm.clearCalleeTag(rax, mode);
     masm.movzwl(Operand(rax, offsetof(JSFunction, nargs)), rcx);
     masm.subq(r8, rcx);
 
     // Copy the number of actual arguments
     masm.loadPtr(Address(rsp, IonRectifierFrameLayout::offsetOfNumActualArgs()), rdx);
 
     masm.moveValue(UndefinedValue(), r10);
 
@@ -401,17 +400,17 @@ IonRuntime::generateArgumentsRectifier(J
     }
 
     // Construct descriptor.
     masm.subq(rsp, r9);
     masm.makeFrameDescriptor(r9, IonFrame_Rectifier);
 
     // Construct IonJSFrameLayout.
     masm.push(rdx); // numActualArgs
-    masm.pushCalleeToken(rax, mode);
+    masm.push(rax); // callee token
     masm.push(r9); // descriptor
 
     // Call the target function.
     // Note that this code assumes the function is JITted.
     masm.loadPtr(Address(rax, JSFunction::offsetOfNativeOrScript()), rax);
     masm.loadBaselineOrIonRaw(rax, rax, mode, nullptr);
     masm.call(rax);
     uint32_t returnOffset = masm.currentOffset();
@@ -621,20 +620,16 @@ IonRuntime::generateVMWrapper(JSContext 
     switch (f.failType()) {
       case Type_Object:
         masm.branchTestPtr(Assembler::Zero, rax, rax, masm.failureLabel(f.executionMode));
         break;
       case Type_Bool:
         masm.testb(rax, rax);
         masm.j(Assembler::Zero, masm.failureLabel(f.executionMode));
         break;
-      case Type_ParallelResult:
-        masm.branchPtr(Assembler::NotEqual, rax, Imm32(TP_SUCCESS),
-                       masm.failureLabel(f.executionMode));
-        break;
       default:
         MOZ_ASSUME_UNREACHABLE("unknown failure kind");
     }
 
     // Load the outparam and free any allocated stack.
     switch (f.outParam) {
       case Type_Handle:
         masm.popRooted(f.outParamRootType, ReturnReg, JSReturnOperand);
--- a/js/src/jit/x86/CodeGenerator-x86.cpp
+++ b/js/src/jit/x86/CodeGenerator-x86.cpp
@@ -742,16 +742,39 @@ GetElementParIC::initializeAddCacheState
     // one, it's BogusTemp otherwise.
     JS_ASSERT(ins->isGetElementCacheV() || ins->isGetElementCacheT());
     if (ins->isGetElementCacheV() || ins->toGetElementCacheT()->temp()->isBogusTemp())
         addState->dispatchScratch = output_.scratchReg().gpr();
     else
         addState->dispatchScratch = ToRegister(ins->toGetElementCacheT()->temp());
 }
 
+void
+SetPropertyParIC::initializeAddCacheState(LInstruction *ins, AddCacheState *addState)
+{
+    // We don't have an output register to reuse, so we always need a temp.
+    JS_ASSERT(ins->isSetPropertyCacheV() || ins->isSetPropertyCacheT());
+    if (ins->isSetPropertyCacheV())
+        addState->dispatchScratch = ToRegister(ins->toSetPropertyCacheV()->tempForDispatchCache());
+    else
+        addState->dispatchScratch = ToRegister(ins->toSetPropertyCacheT()->tempForDispatchCache());
+}
+
+void
+SetElementParIC::initializeAddCacheState(LInstruction *ins, AddCacheState *addState)
+{
+    // We don't have an output register to reuse, but luckily SetElementCache
+    // already needs a temp.
+    JS_ASSERT(ins->isSetElementCacheV() || ins->isSetElementCacheT());
+    if (ins->isSetElementCacheV())
+        addState->dispatchScratch = ToRegister(ins->toSetElementCacheV()->temp());
+    else
+        addState->dispatchScratch = ToRegister(ins->toSetElementCacheT()->temp());
+}
+
 namespace js {
 namespace jit {
 
 class OutOfLineTruncate : public OutOfLineCodeBase<CodeGeneratorX86>
 {
     LTruncateDToInt32 *ins_;
 
   public:
--- a/js/src/jit/x86/Lowering-x86.cpp
+++ b/js/src/jit/x86/Lowering-x86.cpp
@@ -9,16 +9,39 @@
 #include "jit/MIR.h"
 #include "jit/x86/Assembler-x86.h"
 
 #include "jit/shared/Lowering-shared-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
+LDefinition
+LIRGeneratorX86::tempForDispatchCache(MIRType outputType)
+{
+    // x86 doesn't have a scratch register and we need one for the
+    // indirect jump for dispatch-style ICs.
+    //
+    // Note that currently we only install dispatch-style ICs for parallel
+    // execution. If this assumption changes, please change it here.
+    if (gen->info().executionMode() != ParallelExecution)
+        return LDefinition::BogusTemp();
+
+    // If we don't have an output register, we need a temp.
+    if (outputType == MIRType_None)
+        return temp();
+
+    // If we have a double output register, we need a temp.
+    if (outputType == MIRType_Double)
+        return temp();
+
+    // Otherwise we have a non-double output register and we can reuse it.
+    return LDefinition::BogusTemp();
+}
+
 bool
 LIRGeneratorX86::useBox(LInstruction *lir, size_t n, MDefinition *mir,
                         LUse::Policy policy, bool useAtStart)
 {
     JS_ASSERT(mir->type() == MIRType_Value);
 
     if (!ensureDefined(mir))
         return false;
@@ -270,35 +293,8 @@ LIRGeneratorX86::visitStoreTypedArrayEle
     return add(lir, ins);
 }
 
 bool
 LIRGeneratorX86::visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins)
 {
     return define(new LAsmJSLoadFuncPtr(useRegisterAtStart(ins->index())), ins);
 }
-
-LGetPropertyCacheT *
-LIRGeneratorX86::newLGetPropertyCacheT(MGetPropertyCache *ins)
-{
-    // Since x86 doesn't have a scratch register and we need one for the
-    // indirect jump for dispatch-style ICs, we need a temporary in the case
-    // of a double output type as we can't get a scratch from the output.
-    LDefinition scratch;
-    if (ins->type() == MIRType_Double)
-        scratch = temp();
-    else
-        scratch = LDefinition::BogusTemp();
-    return new LGetPropertyCacheT(useRegister(ins->object()), scratch);
-}
-
-LGetElementCacheT *
-LIRGeneratorX86::newLGetElementCacheT(MGetElementCache *ins)
-{
-    LDefinition scratch;
-    if (ins->type() == MIRType_Double)
-        scratch = temp();
-    else
-        scratch = LDefinition::BogusTemp();
-    return new LGetElementCacheT(useRegister(ins->object()),
-                                 useRegister(ins->index()),
-                                 scratch);
-}
--- a/js/src/jit/x86/Lowering-x86.h
+++ b/js/src/jit/x86/Lowering-x86.h
@@ -33,22 +33,21 @@ class LIRGeneratorX86 : public LIRGenera
     // give us one of {al,bl,cl,dl}. For now, just useFixed(al).
     LAllocation useByteOpRegister(MDefinition *mir);
     LAllocation useByteOpRegisterOrNonDoubleConstant(MDefinition *mir);
 
     inline LDefinition tempToUnbox() {
         return LDefinition::BogusTemp();
     }
 
+    LDefinition tempForDispatchCache(MIRType outputType = MIRType_None);
+
     void lowerUntypedPhiInput(MPhi *phi, uint32_t inputPosition, LBlock *block, size_t lirIndex);
     bool defineUntypedPhi(MPhi *phi, size_t lirIndex);
 
-    LGetPropertyCacheT *newLGetPropertyCacheT(MGetPropertyCache *ins);
-    LGetElementCacheT *newLGetElementCacheT(MGetElementCache *ins);
-
   public:
     bool visitBox(MBox *box);
     bool visitUnbox(MUnbox *unbox);
     bool visitReturn(MReturn *ret);
     bool visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins);
     bool visitAsmJSLoadHeap(MAsmJSLoadHeap *ins);
     bool visitAsmJSStoreHeap(MAsmJSStoreHeap *ins);
     bool visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins);
--- a/js/src/jit/x86/Trampoline-x86.cpp
+++ b/js/src/jit/x86/Trampoline-x86.cpp
@@ -348,17 +348,16 @@ IonRuntime::generateArgumentsRectifier(J
     MacroAssembler masm(cx);
 
     // ArgumentsRectifierReg contains the |nargs| pushed onto the current frame.
     // Including |this|, there are (|nargs| + 1) arguments to copy.
     JS_ASSERT(ArgumentsRectifierReg == esi);
 
     // Load the number of |undefined|s to push into %ecx.
     masm.loadPtr(Address(esp, IonRectifierFrameLayout::offsetOfCalleeToken()), eax);
-    masm.clearCalleeTag(eax, mode);
     masm.movzwl(Operand(eax, offsetof(JSFunction, nargs)), ecx);
     masm.subl(esi, ecx);
 
     // Copy the number of actual arguments.
     masm.loadPtr(Address(esp, IonRectifierFrameLayout::offsetOfNumActualArgs()), edx);
 
     masm.moveValue(UndefinedValue(), ebx, edi);
 
@@ -401,17 +400,17 @@ IonRuntime::generateArgumentsRectifier(J
 
     // Construct descriptor, accounting for pushed frame pointer above
     masm.lea(Operand(FramePointer, sizeof(void*)), ebx);
     masm.subl(esp, ebx);
     masm.makeFrameDescriptor(ebx, IonFrame_Rectifier);
 
     // Construct IonJSFrameLayout.
     masm.push(edx); // number of actual arguments
-    masm.pushCalleeToken(eax, mode);
+    masm.push(eax); // callee token
     masm.push(ebx); // descriptor
 
     // Call the target function.
     // Note that this assumes the function is JITted.
     masm.loadPtr(Address(eax, JSFunction::offsetOfNativeOrScript()), eax);
     masm.loadBaselineOrIonRaw(eax, eax, mode, nullptr);
     masm.call(eax);
     uint32_t returnOffset = masm.currentOffset();
@@ -655,20 +654,16 @@ IonRuntime::generateVMWrapper(JSContext 
     switch (f.failType()) {
       case Type_Object:
         masm.branchTestPtr(Assembler::Zero, eax, eax, masm.failureLabel(f.executionMode));
         break;
       case Type_Bool:
         masm.testb(eax, eax);
         masm.j(Assembler::Zero, masm.failureLabel(f.executionMode));
         break;
-      case Type_ParallelResult:
-        masm.branchPtr(Assembler::NotEqual, eax, Imm32(TP_SUCCESS),
-                       masm.failureLabel(f.executionMode));
-        break;
       default:
         MOZ_ASSUME_UNREACHABLE("unknown failure kind");
     }
 
     // Load the outparam and free any allocated stack.
     switch (f.outParam) {
       case Type_Handle:
         masm.popRooted(f.outParamRootType, ReturnReg, JSReturnOperand);
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -754,27 +754,30 @@ js::WouldDefinePastNonwritableLength(Thr
 
     if (arr->lengthIsWritable()) {
         *definesPast = false;
         return true;
     }
 
     *definesPast = true;
 
+    // Error in strict mode code or warn with strict option.
+    unsigned flags = strict ? JSREPORT_ERROR : (JSREPORT_STRICT | JSREPORT_WARNING);
+    if (cx->isForkJoinSlice())
+        return cx->asForkJoinSlice()->reportError(ParallelBailoutUnsupportedVM, flags);
+
     if (!cx->isJSContext())
         return true;
 
     JSContext *ncx = cx->asJSContext();
 
     if (!strict && !ncx->hasExtraWarningsOption())
         return true;
 
-    // Error in strict mode code or warn with strict option.
     // XXX include the index and maybe array length in the error message
-    unsigned flags = strict ? JSREPORT_ERROR : (JSREPORT_STRICT | JSREPORT_WARNING);
     return JS_ReportErrorFlagsAndNumber(ncx, flags, js_GetErrorMessage, nullptr,
                                         JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH);
 }
 
 static bool
 array_addProperty(JSContext *cx, HandleObject obj, HandleId id,
                   MutableHandleValue vp)
 {
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -344,16 +344,21 @@ PopulateReportBlame(JSContext *cx, JSErr
  * error reporter directly.
  *
  * Furthermore, callers of js_ReportOutOfMemory (viz., malloc) assume a GC does
  * not occur, so GC must be avoided or suppressed.
  */
 void
 js_ReportOutOfMemory(ThreadSafeContext *cxArg)
 {
+    if (cxArg->isForkJoinSlice()) {
+        cxArg->asForkJoinSlice()->setPendingAbortFatal(ParallelBailoutOutOfMemory);
+        return;
+    }
+
     if (!cxArg->isJSContext())
         return;
     JSContext *cx = cxArg->asJSContext();
 
     cx->runtime()->hadOutOfMemory = true;
 
     if (JS_IsRunning(cx)) {
         cx->setPendingException(StringValue(cx->names().outOfMemory));
@@ -413,17 +418,25 @@ void
 js_ReportOverRecursed(ThreadSafeContext *cx)
 {
     js_ReportOverRecursed(cx->maybeJSContext());
 }
 
 void
 js_ReportAllocationOverflow(ThreadSafeContext *cxArg)
 {
-    if (!cxArg || !cxArg->isJSContext())
+    if (!cxArg)
+        return;
+
+    if (cxArg->isForkJoinSlice()) {
+        cxArg->asForkJoinSlice()->setPendingAbortFatal(ParallelBailoutOutOfMemory);
+        return;
+    }
+
+    if (!cxArg->isJSContext())
         return;
     JSContext *cx = cxArg->asJSContext();
 
     AutoSuppressGC suppressGC(cx);
     JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_ALLOC_OVERFLOW);
 }
 
 /*
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -552,20 +552,20 @@ JSContext::currentScript(jsbytecode **pp
 template <JSThreadSafeNative threadSafeNative>
 inline bool
 JSNativeThreadSafeWrapper(JSContext *cx, unsigned argc, JS::Value *vp)
 {
     return threadSafeNative(cx, argc, vp);
 }
 
 template <JSThreadSafeNative threadSafeNative>
-inline js::ParallelResult
+inline bool
 JSParallelNativeThreadSafeWrapper(js::ForkJoinSlice *slice, unsigned argc, JS::Value *vp)
 {
-    return threadSafeNative(slice, argc, vp) ? js::TP_SUCCESS : js::TP_FATAL;
+    return threadSafeNative(slice, argc, vp);
 }
 
 /* static */ inline JSContext *
 js::ExecutionModeTraits<js::SequentialExecution>::toContextType(ExclusiveContext *cx)
 {
     return cx->asJSContext();
 }
 
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3497,25 +3497,18 @@ DefinePropertyOrElement(typename Executi
         setter == JS_StrictPropertyStub &&
         attrs == JSPROP_ENUMERATE &&
         (!obj->isIndexed() || !obj->nativeContainsPure(id)))
     {
         uint32_t index = JSID_TO_INT(id);
         bool definesPast;
         if (!WouldDefinePastNonwritableLength(cx, obj, index, setterIsStrict, &definesPast))
             return false;
-        if (definesPast) {
-            /*
-             * Strict mode changes semantics and we must throw, so bail out of
-             * parallel execution if we are strict.
-             */
-            if (mode == ParallelExecution)
-                return !setterIsStrict;
+        if (definesPast)
             return true;
-        }
 
         JSObject::EnsureDenseResult result;
         if (mode == ParallelExecution) {
             if (obj->writeToIndexWouldMarkNotPacked(index))
                 return false;
             result = obj->ensureDenseElementsPreservePackedFlag(cx, index, 1);
         } else {
             result = obj->ensureDenseElements(cx->asExclusiveContext(), index, 1);
@@ -3538,22 +3531,18 @@ DefinePropertyOrElement(typename Executi
                                         attrs, value, setterIsStrict);
         }
 
         uint32_t index;
         if (js_IdIsIndex(id, &index)) {
             bool definesPast;
             if (!WouldDefinePastNonwritableLength(cx, arr, index, setterIsStrict, &definesPast))
                 return false;
-            if (definesPast) {
-                /* Bail out of parallel execution if we are strict to throw. */
-                if (mode == ParallelExecution)
-                    return !setterIsStrict;
+            if (definesPast)
                 return true;
-            }
         }
     }
 
     AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
 
     RootedShape shape(cx, JSObject::putProperty<mode>(cx, obj, id, getter, setter,
                                                       SHAPE_INVALID_SLOT,
                                                       attrs, flags, shortid));
@@ -4581,36 +4570,57 @@ js::ReportIfUndeclaredVarAssignment(JSCo
            JS_ReportErrorFlagsAndNumber(cx,
                                         JSREPORT_WARNING | JSREPORT_STRICT |
                                         JSREPORT_STRICT_MODE_ERROR,
                                         js_GetErrorMessage, nullptr,
                                         JSMSG_UNDECLARED_VAR, bytes.ptr());
 }
 
 bool
-JSObject::reportReadOnly(JSContext *cx, jsid id, unsigned report)
+JSObject::reportReadOnly(ThreadSafeContext *cxArg, jsid id, unsigned report)
 {
+    if (cxArg->isForkJoinSlice())
+        return cxArg->asForkJoinSlice()->reportError(ParallelBailoutUnsupportedVM, report);
+
+    if (!cxArg->isJSContext())
+        return true;
+
+    JSContext *cx = cxArg->asJSContext();
     RootedValue val(cx, IdToValue(id));
     return js_ReportValueErrorFlags(cx, report, JSMSG_READ_ONLY,
                                     JSDVG_IGNORE_STACK, val, NullPtr(),
                                     nullptr, nullptr);
 }
 
 bool
-JSObject::reportNotConfigurable(JSContext *cx, jsid id, unsigned report)
+JSObject::reportNotConfigurable(ThreadSafeContext *cxArg, jsid id, unsigned report)
 {
+    if (cxArg->isForkJoinSlice())
+        return cxArg->asForkJoinSlice()->reportError(ParallelBailoutUnsupportedVM, report);
+
+    if (!cxArg->isJSContext())
+        return true;
+
+    JSContext *cx = cxArg->asJSContext();
     RootedValue val(cx, IdToValue(id));
     return js_ReportValueErrorFlags(cx, report, JSMSG_CANT_DELETE,
                                     JSDVG_IGNORE_STACK, val, NullPtr(),
                                     nullptr, nullptr);
 }
 
 bool
-JSObject::reportNotExtensible(JSContext *cx, unsigned report)
+JSObject::reportNotExtensible(ThreadSafeContext *cxArg, unsigned report)
 {
+    if (cxArg->isForkJoinSlice())
+        return cxArg->asForkJoinSlice()->reportError(ParallelBailoutUnsupportedVM, report);
+
+    if (!cxArg->isJSContext())
+        return true;
+
+    JSContext *cx = cxArg->asJSContext();
     RootedValue val(cx, ObjectValue(*this));
     return js_ReportValueErrorFlags(cx, report, JSMSG_OBJECT_NOT_EXTENSIBLE,
                                     JSDVG_IGNORE_STACK, val, NullPtr(),
                                     nullptr, nullptr);
 }
 
 bool
 JSObject::callMethod(JSContext *cx, HandleId id, unsigned argc, Value *argv, MutableHandleValue vp)
@@ -4822,26 +4832,21 @@ baseops::SetPropertyHelper(typename Exec
                 return false;
             extensible = obj->nonProxyIsExtensible();
         } else {
             if (!JSObject::isExtensible(cxArg->asJSContext(), obj, &extensible))
                 return false;
         }
 
         if (!extensible) {
-            /* Bail out of parallel execution if we are strict to throw. */
-            if (mode == ParallelExecution)
-                return !strict;
-
             /* Error in strict mode code, warn with extra warnings option, otherwise do nothing. */
-            JSContext *cx = cxArg->asJSContext();
             if (strict)
-                return obj->reportNotExtensible(cx);
-            if (cx->hasExtraWarningsOption())
-                return obj->reportNotExtensible(cx, JSREPORT_STRICT | JSREPORT_WARNING);
+                return obj->reportNotExtensible(cxArg);
+            if (mode == SequentialExecution && cxArg->asJSContext()->hasExtraWarningsOption())
+                return obj->reportNotExtensible(cxArg, JSREPORT_STRICT | JSREPORT_WARNING);
             return true;
         }
 
         if (mode == ParallelExecution) {
             if (obj->isDelegate())
                 return false;
 
             if (getter != JS_PropertyStub || !HasTypePropertyId(obj, id, vp))
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -802,19 +802,19 @@ class JSObject : public js::ObjectImpl
      * FIXME: bug 593129 -- slot allocation should be done by object methods
      * after calling object-parameter-free shape methods, avoiding coupling
      * logic across the object vs. shape module wall.
      */
     static bool allocSlot(js::ThreadSafeContext *cx, JS::HandleObject obj, uint32_t *slotp);
     void freeSlot(uint32_t slot);
 
   public:
-    static bool reportReadOnly(JSContext *cx, jsid id, unsigned report = JSREPORT_ERROR);
-    bool reportNotConfigurable(JSContext* cx, jsid id, unsigned report = JSREPORT_ERROR);
-    bool reportNotExtensible(JSContext *cx, unsigned report = JSREPORT_ERROR);
+    static bool reportReadOnly(js::ThreadSafeContext *cx, jsid id, unsigned report = JSREPORT_ERROR);
+    bool reportNotConfigurable(js::ThreadSafeContext *cx, jsid id, unsigned report = JSREPORT_ERROR);
+    bool reportNotExtensible(js::ThreadSafeContext *cx, unsigned report = JSREPORT_ERROR);
 
     /*
      * Get the property with the given id, then call it as a function with the
      * given arguments, providing this object as |this|. If the property isn't
      * callable a TypeError will be thrown. On success the value returned by
      * the call is stored in *vp.
      */
     bool callMethod(JSContext *cx, js::HandleId id, unsigned argc, js::Value *argv,
--- a/js/src/vm/ForkJoin.cpp
+++ b/js/src/vm/ForkJoin.cpp
@@ -95,26 +95,42 @@ ForkJoinSlice::requestGC(JS::gcreason::R
 }
 
 void
 ForkJoinSlice::requestZoneGC(JS::Zone *zone, JS::gcreason::Reason reason)
 {
     MOZ_ASSUME_UNREACHABLE("Not THREADSAFE build");
 }
 
+bool
+ForkJoinSlice::setPendingAbortFatal(ParallelBailoutCause cause)
+{
+    MOZ_ASSUME_UNREACHABLE("Not THREADSAFE build");
+    return false;
+}
+
 void
 ParallelBailoutRecord::setCause(ParallelBailoutCause cause,
                                 JSScript *outermostScript,
                                 JSScript *currentScript,
                                 jsbytecode *currentPc)
 {
     MOZ_ASSUME_UNREACHABLE("Not THREADSAFE build");
 }
 
 void
+js::ParallelBailoutRecord::updateCause(ParallelBailoutCause cause,
+                                       JSScript *outermostScript,
+                                       JSScript *currentScript,
+                                       jsbytecode *currentPc)
+{
+    MOZ_ASSUME_UNREACHABLE("Not THREADSAFE build");
+}
+
+void
 ParallelBailoutRecord::addTrace(JSScript *script,
                                 jsbytecode *pc)
 {
     MOZ_ASSUME_UNREACHABLE("Not THREADSAFE build");
 }
 
 bool
 js::InExclusiveParallelSection()
@@ -383,16 +399,19 @@ class ForkJoinShared : public TaskExecut
 
     // Requests a GC, either full or specific to a zone.
     void requestGC(JS::gcreason::Reason reason);
     void requestZoneGC(JS::Zone *zone, JS::gcreason::Reason reason);
 
     // Requests that computation abort.
     void setAbortFlag(bool fatal);
 
+    // Set the fatal flag for the next abort.
+    void setPendingAbortFatal() { fatal_ = true; }
+
     JSRuntime *runtime() { return cx_->runtime(); }
     JS::Zone *zone() { return cx_->zone(); }
 
     JSContext *acquireContext() { PR_Lock(cxLock_); return cx_; }
     void releaseContext() { PR_Unlock(cxLock_); }
 };
 
 class AutoEnterWarmup
@@ -970,37 +989,37 @@ BailoutExplanation(ParallelBailoutCause 
         return "no particular reason";
       case ParallelBailoutCompilationSkipped:
         return "compilation failed (method skipped)";
       case ParallelBailoutCompilationFailure:
         return "compilation failed";
       case ParallelBailoutInterrupt:
         return "interrupted";
       case ParallelBailoutFailedIC:
-        return "at runtime, the behavior changed, invalidating compiled code (IC update)";
+        return "failed to attach stub to IC";
       case ParallelBailoutHeapBusy:
         return "heap busy flag set during interrupt";
       case ParallelBailoutMainScriptNotPresent:
         return "main script not present";
       case ParallelBailoutCalledToUncompiledScript:
         return "called to uncompiled script";
       case ParallelBailoutIllegalWrite:
         return "illegal write";
       case ParallelBailoutAccessToIntrinsic:
         return "access to intrinsic";
       case ParallelBailoutOverRecursed:
         return "over recursed";
       case ParallelBailoutOutOfMemory:
         return "out of memory";
       case ParallelBailoutUnsupported:
         return "unsupported";
+      case ParallelBailoutUnsupportedVM:
+        return "unsupported operation in VM call";
       case ParallelBailoutUnsupportedStringComparison:
         return "unsupported string comparison";
-      case ParallelBailoutUnsupportedSparseArray:
-        return "unsupported sparse array";
       case ParallelBailoutRequestedGC:
         return "requested GC";
       case ParallelBailoutRequestedZoneGC:
         return "requested zone GC";
       default:
         return "no known reason";
     }
 }
@@ -1117,61 +1136,28 @@ js::ParallelDo::warmupExecution(bool sto
         Spew(SpewOps, "Warmup execution finished all the work.");
         *status = ExecutionWarmup;
         return RedLight;
     }
 
     return GreenLight;
 }
 
-class AutoEnterParallelSection
-{
-  private:
-    JSContext *cx_;
-    uint8_t *prevIonTop_;
-
-  public:
-    AutoEnterParallelSection(JSContext *cx)
-      : cx_(cx),
-        prevIonTop_(cx->mainThread().ionTop)
-    {
-        // Note: we do not allow GC during parallel sections.
-        // Moreover, we do not wish to worry about making
-        // write barriers thread-safe.  Therefore, we guarantee
-        // that there is no incremental GC in progress and force
-        // a minor GC to ensure no cross-generation pointers get
-        // created:
-
-        if (JS::IsIncrementalGCInProgress(cx->runtime())) {
-            JS::PrepareForIncrementalGC(cx->runtime());
-            JS::FinishIncrementalGC(cx->runtime(), JS::gcreason::API);
-        }
-
-        MinorGC(cx->runtime(), JS::gcreason::API);
-
-        cx->runtime()->gcHelperThread.waitBackgroundSweepEnd();
-    }
-
-    ~AutoEnterParallelSection() {
-        cx_->mainThread().ionTop = prevIonTop_;
-    }
-};
-
 js::ParallelDo::TrafficLight
 js::ParallelDo::parallelExecution(ExecutionStatus *status)
 {
     // GreenLight: bailout occurred, keep trying
     // RedLight: fatal error or all work completed
 
     // Recursive use of the ThreadPool is not supported.  Right now we
     // cannot get here because parallel code cannot invoke native
     // functions such as ForkJoin().
     JS_ASSERT(ForkJoinSlice::Current() == nullptr);
 
-    AutoEnterParallelSection enter(cx_);
+    ForkJoinActivation activation(cx_);
 
     ThreadPool *threadPool = &cx_->runtime()->threadPool;
     uint32_t numSlices = ForkJoinSlices(cx_);
 
     RootedObject rootedFun(cx_, fun_);
     ForkJoinShared shared(cx_, threadPool, rootedFun, numSlices, numSlices - 1,
                           &bailoutRecords_[0]);
     if (!shared.init()) {
@@ -1259,17 +1245,17 @@ class ParallelIonInvoke
         argv_[0] = ObjectValue(*callee);
         argv_[1] = UndefinedValue();
 
         // Find JIT code pointer.
         IonScript *ion = callee->nonLazyScript()->parallelIonScript();
         IonCode *code = ion->method();
         jitcode_ = code->raw();
         enter_ = rt->ionRuntime()->enterIon();
-        calleeToken_ = CalleeToParallelToken(callee);
+        calleeToken_ = CalleeToToken(callee);
     }
 
     bool invoke(PerThreadData *perThread) {
         RootedValue result(perThread);
         enter_(jitcode_, argc_ + 1, argv_ + 1, nullptr, calleeToken_, nullptr, 0,
                result.address());
         return !result.isMagic();
     }
@@ -1466,18 +1452,17 @@ ForkJoinShared::executePortion(PerThread
     JS_ASSERT(fun->is<JSFunction>());
     RootedFunction callee(perThread, &fun->as<JSFunction>());
     if (!callee->nonLazyScript()->hasParallelIonScript()) {
         // Sometimes, particularly with GCZeal, the parallel ion
         // script can be collected between starting the parallel
         // op and reaching this point.  In that case, we just fail
         // and fallback.
         Spew(SpewOps, "Down (Script no longer present)");
-        slice.bailoutRecord->setCause(ParallelBailoutMainScriptNotPresent,
-                                      nullptr, nullptr, nullptr);
+        slice.bailoutRecord->setCause(ParallelBailoutMainScriptNotPresent);
         setAbortFlag(false);
     } else {
         ParallelIonInvoke<3> fii(cx_->runtime(), callee, 3);
 
         fii.args[0] = Int32Value(slice.sliceId);
         fii.args[1] = Int32Value(slice.numSlices);
         fii.args[2] = BooleanValue(false);
 
@@ -1507,18 +1492,17 @@ ForkJoinShared::check(ForkJoinSlice &sli
             // requestZoneGC() methods should be invoked.
             JS_ASSERT(!cx_->runtime()->gcIsNeeded);
 
             // If interrupt is requested, bring worker threads to a halt,
             // service the interrupt, then let them start back up again.
             // AutoRendezvous autoRendezvous(slice);
             // if (!js_HandleExecutionInterrupt(cx_))
             //     return setAbortFlag(true);
-            slice.bailoutRecord->setCause(ParallelBailoutInterrupt,
-                                          nullptr, nullptr, nullptr);
+            slice.bailoutRecord->setCause(ParallelBailoutInterrupt);
             setAbortFlag(false);
             return false;
         }
     } else if (rendezvous_) {
         joinRendezvous(slice);
     }
 
     return true;
@@ -1725,30 +1709,36 @@ ForkJoinSlice::InitializeTLS()
     }
     return true;
 }
 
 void
 ForkJoinSlice::requestGC(JS::gcreason::Reason reason)
 {
     shared->requestGC(reason);
-    bailoutRecord->setCause(ParallelBailoutRequestedGC,
-                            nullptr, nullptr, nullptr);
+    bailoutRecord->setCause(ParallelBailoutRequestedGC);
     shared->setAbortFlag(false);
 }
 
 void
 ForkJoinSlice::requestZoneGC(JS::Zone *zone, JS::gcreason::Reason reason)
 {
     shared->requestZoneGC(zone, reason);
-    bailoutRecord->setCause(ParallelBailoutRequestedZoneGC,
-                            nullptr, nullptr, nullptr);
+    bailoutRecord->setCause(ParallelBailoutRequestedZoneGC);
     shared->setAbortFlag(false);
 }
 
+bool
+ForkJoinSlice::setPendingAbortFatal(ParallelBailoutCause cause)
+{
+    shared->setPendingAbortFatal();
+    bailoutRecord->setCause(cause);
+    return false;
+}
+
 /////////////////////////////////////////////////////////////////////////////
 
 uint32_t
 js::ForkJoinSlices(JSContext *cx)
 {
     // Parallel workers plus this main thread.
     return cx->runtime()->threadPool.numWorkers() + 1;
 }
@@ -1771,30 +1761,39 @@ js::ParallelBailoutRecord::reset(JSConte
 }
 
 void
 js::ParallelBailoutRecord::setCause(ParallelBailoutCause cause,
                                     JSScript *outermostScript,
                                     JSScript *currentScript,
                                     jsbytecode *currentPc)
 {
+    this->cause = cause;
+    updateCause(cause, outermostScript, currentScript, currentPc);
+}
+
+void
+js::ParallelBailoutRecord::updateCause(ParallelBailoutCause cause,
+                                       JSScript *outermostScript,
+                                       JSScript *currentScript,
+                                       jsbytecode *currentPc)
+{
     JS_ASSERT_IF(outermostScript, currentScript);
     JS_ASSERT_IF(outermostScript, outermostScript->hasParallelIonScript());
     JS_ASSERT_IF(currentScript, outermostScript);
     JS_ASSERT_IF(!currentScript, !currentPc);
 
-    this->cause = cause;
+    if (this->cause == ParallelBailoutNone)
+        this->cause = cause;
 
-    if (outermostScript) {
+    if (outermostScript)
         this->topScript = outermostScript;
-    }
 
-    if (currentScript) {
+    if (currentScript)
         addTrace(currentScript, currentPc);
-    }
 }
 
 void
 js::ParallelBailoutRecord::addTrace(JSScript *script,
                                     jsbytecode *pc)
 {
     // Ideally, this should never occur, because we should always have
     // a script when we invoke setCause, but I havent' fully
--- a/js/src/vm/ForkJoin.h
+++ b/js/src/vm/ForkJoin.h
@@ -218,41 +218,41 @@ struct IonLIRTraceData {
 };
 
 ///////////////////////////////////////////////////////////////////////////
 // Bailout tracking
 
 enum ParallelBailoutCause {
     ParallelBailoutNone,
 
-    // compiler returned Method_Skipped
+    // Compiler returned Method_Skipped
     ParallelBailoutCompilationSkipped,
 
-    // compiler returned Method_CantCompile
+    // Compiler returned Method_CantCompile
     ParallelBailoutCompilationFailure,
 
-    // the periodic interrupt failed, which can mean that either
+    // The periodic interrupt failed, which can mean that either
     // another thread canceled, the user interrupted us, etc
     ParallelBailoutInterrupt,
 
-    // an IC update failed
+    // An IC update failed
     ParallelBailoutFailedIC,
 
     // Heap busy flag was set during interrupt
     ParallelBailoutHeapBusy,
 
     ParallelBailoutMainScriptNotPresent,
     ParallelBailoutCalledToUncompiledScript,
     ParallelBailoutIllegalWrite,
     ParallelBailoutAccessToIntrinsic,
     ParallelBailoutOverRecursed,
     ParallelBailoutOutOfMemory,
     ParallelBailoutUnsupported,
+    ParallelBailoutUnsupportedVM,
     ParallelBailoutUnsupportedStringComparison,
-    ParallelBailoutUnsupportedSparseArray,
     ParallelBailoutRequestedGC,
     ParallelBailoutRequestedZoneGC,
 };
 
 struct ParallelBailoutTrace {
     JSScript *script;
     jsbytecode *bytecode;
 };
@@ -266,19 +266,23 @@ struct ParallelBailoutRecord {
     // but for now we gather at most a single frame.
     static const uint32_t MaxDepth = 1;
     uint32_t depth;
     ParallelBailoutTrace trace[MaxDepth];
 
     void init(JSContext *cx);
     void reset(JSContext *cx);
     void setCause(ParallelBailoutCause cause,
-                  JSScript *outermostScript,   // inliner (if applicable)
-                  JSScript *currentScript,     // inlinee (if applicable)
-                  jsbytecode *currentPc);
+                  JSScript *outermostScript = nullptr,   // inliner (if applicable)
+                  JSScript *currentScript = nullptr,     // inlinee (if applicable)
+                  jsbytecode *currentPc = nullptr);
+    void updateCause(ParallelBailoutCause cause,
+                     JSScript *outermostScript,
+                     JSScript *currentScript,
+                     jsbytecode *currentPc);
     void addTrace(JSScript *script,
                   jsbytecode *pc);
 };
 
 struct ForkJoinShared;
 
 class ForkJoinSlice : public ThreadSafeContext
 {
@@ -310,16 +314,28 @@ class ForkJoinSlice : public ThreadSafeC
     // |TriggerCompartmentGC()| as appropriate once the parallel
     // section is complete. This is done because those routines do
     // various preparations that are not thread-safe, and because the
     // full set of arenas is not available until the end of the
     // parallel section.
     void requestGC(JS::gcreason::Reason reason);
     void requestZoneGC(JS::Zone *zone, JS::gcreason::Reason reason);
 
+    // Set the fatal flag for the next abort. Used to distinguish retry or
+    // fatal aborts from VM functions.
+    bool setPendingAbortFatal(ParallelBailoutCause cause);
+
+    // Reports an unsupported operation, returning false if we are reporting
+    // an error. Otherwise drop the warning on the floor.
+    bool reportError(ParallelBailoutCause cause, unsigned report) {
+        if (report & JSREPORT_ERROR)
+            return setPendingAbortFatal(cause);
+        return true;
+    }
+
     // During the parallel phase, this method should be invoked
     // periodically, for example on every backedge, similar to the
     // interrupt check.  If it returns false, then the parallel phase
     // has been aborted and so you should bailout.  The function may
     // also rendesvous to perform GC or do other similar things.
     //
     // This function is guaranteed to have no effect if both
     // runtime()->interrupt is zero.  Ion-generated code takes
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -609,17 +609,17 @@ ScriptFrameIter::Data::Data(JSContext *c
   : perThread_(perThread),
     cx_(cx),
     savedOption_(savedOption),
     contextOption_(contextOption),
     pc_(nullptr),
     interpFrames_(nullptr),
     activations_(cx->runtime())
 #ifdef JS_ION
-  , ionFrames_((uint8_t *)nullptr)
+  , ionFrames_((uint8_t *)nullptr, SequentialExecution)
 #endif
 {
 }
 
 ScriptFrameIter::Data::Data(const ScriptFrameIter::Data &other)
   : perThread_(other.perThread_),
     cx_(other.cx_),
     savedOption_(other.savedOption_),
@@ -1331,16 +1331,42 @@ jit::JitActivation::setActive(JSContext 
         prevIonJSContext_ = cx->mainThread().ionJSContext;
         cx->mainThread().ionJSContext = cx;
     } else {
         cx->mainThread().ionTop = prevIonTop_;
         cx->mainThread().ionJSContext = prevIonJSContext_;
     }
 }
 
+ForkJoinActivation::ForkJoinActivation(JSContext *cx)
+  : Activation(cx, ForkJoin),
+    prevIonTop_(cx->mainThread().ionTop)
+{
+    // Note: we do not allow GC during parallel sections.
+    // Moreover, we do not wish to worry about making
+    // write barriers thread-safe.  Therefore, we guarantee
+    // that there is no incremental GC in progress and force
+    // a minor GC to ensure no cross-generation pointers get
+    // created:
+
+    if (JS::IsIncrementalGCInProgress(cx->runtime())) {
+        JS::PrepareForIncrementalGC(cx->runtime());
+        JS::FinishIncrementalGC(cx->runtime(), JS::gcreason::API);
+    }
+
+    MinorGC(cx->runtime(), JS::gcreason::API);
+
+    cx->runtime()->gcHelperThread.waitBackgroundSweepEnd();
+}
+
+ForkJoinActivation::~ForkJoinActivation()
+{
+    cx_->mainThread().ionTop = prevIonTop_;
+}
+
 InterpreterFrameIterator &
 InterpreterFrameIterator::operator++()
 {
     JS_ASSERT(!done());
     if (fp_ != activation_->entry_) {
         pc_ = fp_->prevpc();
         sp_ = fp_->prevsp();
         fp_ = fp_->prev();
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1170,16 +1170,17 @@ struct DefaultHasher<AbstractFramePtr> {
     static bool match(const AbstractFramePtr &k, const Lookup &l) {
         return k == l;
     }
 };
 
 /*****************************************************************************/
 
 class InterpreterActivation;
+class ForkJoinActivation;
 
 namespace jit {
     class JitActivation;
 };
 
 class Activation
 {
   protected:
@@ -1188,17 +1189,17 @@ class Activation
     Activation *prev_;
 
     // Counter incremented by JS_SaveFrameChain on the top-most activation and
     // decremented by JS_RestoreFrameChain. If > 0, ScriptFrameIter should stop
     // iterating when it reaches this activation (if GO_THROUGH_SAVED is not
     // set).
     size_t savedFrameChain_;
 
-    enum Kind { Interpreter, Jit };
+    enum Kind { Interpreter, Jit, ForkJoin };
     Kind kind_;
 
     inline Activation(JSContext *cx, Kind kind_);
     inline ~Activation();
 
   public:
     JSContext *cx() const {
         return cx_;
@@ -1211,25 +1212,32 @@ class Activation
     }
 
     bool isInterpreter() const {
         return kind_ == Interpreter;
     }
     bool isJit() const {
         return kind_ == Jit;
     }
+    bool isForkJoin() const {
+        return kind_ == ForkJoin;
+    }
 
     InterpreterActivation *asInterpreter() const {
         JS_ASSERT(isInterpreter());
         return (InterpreterActivation *)this;
     }
     jit::JitActivation *asJit() const {
         JS_ASSERT(isJit());
         return (jit::JitActivation *)this;
     }
+    ForkJoinActivation *asForkJoin() const {
+        JS_ASSERT(isForkJoin());
+        return (ForkJoinActivation *)this;
+    }
 
     void saveFrameChain() {
         savedFrameChain_++;
     }
     void restoreFrameChain() {
         JS_ASSERT(savedFrameChain_ > 0);
         savedFrameChain_--;
     }
@@ -1387,16 +1395,25 @@ class JitActivationIterator : public Act
     }
 
     // Returns the bottom and top addresses of the current JitActivation.
     void jitStackRange(uintptr_t *&min, uintptr_t *&end);
 };
 
 } // namespace jit
 
+class ForkJoinActivation : public Activation
+{
+    uint8_t *prevIonTop_;
+
+  public:
+    ForkJoinActivation(JSContext *cx);
+    ~ForkJoinActivation();
+};
+
 // Iterates over the frames of a single InterpreterActivation.
 class InterpreterFrameIterator
 {
     InterpreterActivation *activation_;
     StackFrame *fp_;
     jsbytecode *pc_;
     Value *sp_;
 
--- a/layout/media/Makefile.in
+++ b/layout/media/Makefile.in
@@ -101,40 +101,19 @@ SHARED_LIBRARY_LIBS 	+= \
 SHARED_LIBRARY_LIBS 	+= \
 	$(DEPTH)/gfx/2d/$(LIB_PREFIX)gfx2d.$(LIB_SUFFIX) \
 	$(NULL)
 
 ifdef MOZ_ENABLE_SKIA
 SHARED_LIBRARY_LIBS += $(MOZ_SKIA_LIBS)
 endif
 
-ifdef MOZ_WEBRTC
-ifndef MOZ_WEBRTC_IN_LIBXUL
-DEFINES += -DMOZ_WEBRTC_GKMEDIA=1
-include $(topsrcdir)/media/webrtc/shared_libs.mk
-SHARED_LIBRARY_LIBS += $(WEBRTC_LIBS)
-endif
-endif
-
 ifeq (WINNT,$(OS_TARGET))
 EXTRA_DSO_LDOPTS = $(MOZALLOC_LIB) $(NSPR_LIBS)
 OS_LIBS += $(call EXPAND_LIBNAME,usp10 ole32)
-
-ifdef MOZ_WEBRTC
-EXTRA_DSO_LDOPTS += \
-  -LIBPATH:"$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)" \
-  $(NULL)
-OS_LIBS += $(call EXPAND_LIBNAME,secur32 crypt32 iphlpapi strmiids dmoguids wmcodecdspuuid amstrmid msdmo wininet)
-ifdef _MSC_VER
-OS_LIBS += $(call EXPAND_LIBNAME,delayimp)
-EXTRA_DSO_LDOPTS += \
-  -DELAYLOAD:msdmo.dll \
-  $(NULL)
-endif
-endif
 DEFFILE = symbols.def
 endif
 
 include $(topsrcdir)/config/rules.mk
 
 ifeq (WINNT,$(OS_TARGET))
 symbols.def: symbols.def.in $(GLOBAL_DEPS)
 	$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(ACDEFINES) $< > $@
--- a/layout/media/moz.build
+++ b/layout/media/moz.build
@@ -3,8 +3,9 @@
 # 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/.
 
 MODULE = 'layout'
 
 LIBRARY_NAME = 'gkmedias'
 
+DIRS += ['webrtc']
--- a/layout/media/symbols.def.in
+++ b/layout/media/symbols.def.in
@@ -160,31 +160,16 @@ opus_encode_float
 ShInitialize
 ShFinalize
 ShGetObjectCode
 ShDestruct
 ShGetInfoLog
 ShCompile
 ShGetInfo
 ShConstructCompiler
-#ifdef MOZ_WEBRTC_GKMEDIA
-#ifdef HAVE_64BIT_OS
-?GetInterface@ViERender@webrtc@@SAPEAV12@PEAVVideoEngine@2@@Z
-?GetInterface@ViECapture@webrtc@@SAPEAV12@PEAVVideoEngine@2@@Z
-?GetInterface@ViEBase@webrtc@@SAPEAV12@PEAVVideoEngine@2@@Z
-?Create@VideoEngine@webrtc@@SAPEAV12@XZ
-?Delete@VideoEngine@webrtc@@SA_NAEAPEAV12@@Z
-#else
-?GetInterface@ViERender@webrtc@@SAPAV12@PAVVideoEngine@2@@Z
-?GetInterface@ViECapture@webrtc@@SAPAV12@PAVVideoEngine@2@@Z
-?GetInterface@ViEBase@webrtc@@SAPAV12@PAVVideoEngine@2@@Z
-?Create@VideoEngine@webrtc@@SAPAV12@XZ
-?Delete@VideoEngine@webrtc@@SA_NAAPAV12@@Z
-#endif
-#endif
 ShGetActiveAttrib
 ShGetActiveUniform
 #ifndef MOZ_NATIVE_PNG
 MOZ_APNG_get_first_frame_is_hidden
 MOZ_APNG_get_next_frame_blend_op
 MOZ_APNG_get_next_frame_delay_den
 MOZ_APNG_get_next_frame_delay_num
 MOZ_APNG_get_next_frame_dispose_op
rename from media/webrtc/shared_libs.mk
rename to layout/media/webrtc/Makefile.in
--- a/media/webrtc/shared_libs.mk
+++ b/layout/media/webrtc/Makefile.in
@@ -1,14 +1,14 @@
 # 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/.
 
 # shared libs for webrtc
-WEBRTC_LIBS = \
+SHARED_LIBRARY_LIBS = \
   $(call EXPAND_LIBNAME_PATH,common_video,$(DEPTH)/media/webrtc/trunk/webrtc/common_video/common_video_common_video) \
   $(call EXPAND_LIBNAME_PATH,common_audio,$(DEPTH)/media/webrtc/trunk/webrtc/common_audio/common_audio_common_audio) \
   $(call EXPAND_LIBNAME_PATH,video_capture_module,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_video_capture_module) \
   $(call EXPAND_LIBNAME_PATH,webrtc_utility,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_webrtc_utility) \
   $(call EXPAND_LIBNAME_PATH,audio_coding_module,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_audio_coding_module) \
   $(call EXPAND_LIBNAME_PATH,CNG,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_CNG) \
   $(call EXPAND_LIBNAME_PATH,G711,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_G711) \
   $(call EXPAND_LIBNAME_PATH,PCM16B,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_PCM16B) \
@@ -33,34 +33,34 @@ WEBRTC_LIBS = \
   $(call EXPAND_LIBNAME_PATH,audio_processing,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_audio_processing) \
   $(call EXPAND_LIBNAME_PATH,yuv,$(DEPTH)/media/webrtc/trunk/third_party/libyuv/libyuv_libyuv) \
   $(call EXPAND_LIBNAME_PATH,nicer,$(DEPTH)/media/mtransport/third_party/nICEr/nicer_nicer) \
   $(call EXPAND_LIBNAME_PATH,nrappkit,$(DEPTH)/media/mtransport/third_party/nrappkit/nrappkit_nrappkit) \
   $(NULL)
 
 # if we're on an intel arch, we want SSE2 optimizations
 ifneq (,$(INTEL_ARCHITECTURE))
-WEBRTC_LIBS += \
+SHARED_LIBRARY_LIBS += \
   $(call EXPAND_LIBNAME_PATH,video_processing_sse2,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_video_processing_sse2) \
   $(call EXPAND_LIBNAME_PATH,audio_processing_sse2,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_audio_processing_sse2) \
   $(call EXPAND_LIBNAME_PATH,common_audio_sse2,$(DEPTH)/media/webrtc/trunk/webrtc/common_audio/common_audio_common_audio_sse2) \
   $(NULL)
 endif
 
 ifeq ($(CPU_ARCH), arm)
 ifeq (Android,$(OS_TARGET))
 # NEON detection on WebRTC is Android only. If WebRTC supports Linux/arm etc,
 # we should remove OS check
 # extra ARM libs
-WEBRTC_LIBS += \
+SHARED_LIBRARY_LIBS += \
   $(call EXPAND_LIBNAME_PATH,cpu_features_android,$(DEPTH)/media/webrtc/trunk/webrtc/system_wrappers/source/system_wrappers_cpu_features_android) \
   $(NULL)
 # neon for ARM
 ifeq ($(BUILD_ARM_NEON),1)
-WEBRTC_LIBS += \
+SHARED_LIBRARY_LIBS += \
   $(call EXPAND_LIBNAME_PATH,common_audio_neon,$(DEPTH)/media/webrtc/trunk/webrtc/common_audio/common_audio_common_audio_neon) \
   $(call EXPAND_LIBNAME_PATH,audio_processing_neon,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_audio_processing_neon) \
   $(NULL)
 endif
 endif
 endif
 
 
new file mode 100644
--- /dev/null
+++ b/layout/media/webrtc/moz.build
@@ -0,0 +1,7 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+LIBRARY_NAME = 'webrtc'
--- a/layout/reftests/scoped-style/reftest.list
+++ b/layout/reftests/scoped-style/reftest.list
@@ -15,16 +15,18 @@
 == scoped-style-015.html scoped-style-015-ref.html
 == scoped-style-016.html scoped-style-016-ref.html
 == scoped-style-017.html scoped-style-017-ref.html
 == scoped-style-018.html scoped-style-018-ref.html
 == scoped-style-019.svg scoped-style-019-ref.svg
 == scoped-style-020.html scoped-style-020-ref.html
 == scoped-style-021.html scoped-style-021-ref.html
 == scoped-style-022.html scoped-style-022-ref.html
+== scoped-style-023.html scoped-style-023-ref.html
+== scoped-style-024.html scoped-style-024-ref.html
 == scoped-style-important-001.html scoped-style-important-001-ref.html
 == scoped-style-important-002.html scoped-style-important-002-ref.html
 == scoped-style-important-003.html scoped-style-important-003-ref.html
 == scoped-style-important-004.html scoped-style-important-004-ref.html
 == scoped-style-important-005.html scoped-style-important-005-ref.html
 == scoped-style-important-006.html scoped-style-important-006-ref.html
 == scoped-style-important-007.html scoped-style-important-007-ref.html
 == scoped-style-dynamic-001.html scoped-style-dynamic-001-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/scoped-style/scoped-style-023-ref.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<body>
+  <p><span style="color: green">First line</span><br><span style="color: blue">Second line</span></p>
+</body>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/scoped-style/scoped-style-023.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<body>
+  <style scoped>
+    p::first-line { color: green; }
+    span { color: blue; }
+  </style>
+  <p>First line<br><span>Second line</span></p>
+</body>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/scoped-style/scoped-style-024-ref.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<body>
+  <p style="color: green">Hello.</p>
+</body>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/scoped-style/scoped-style-024.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<body>
+  <style scoped>
+    p[data-test] { color: green; }
+  </style>
+  <p>Hello.</p>
+  <script>
+    document.body.offsetHeight;
+    document.querySelector("p").setAttribute("data-test", "");
+  </script>
+</body>
--- a/layout/style/nsRuleProcessorData.h
+++ b/layout/style/nsRuleProcessorData.h
@@ -168,19 +168,43 @@ struct MOZ_STACK_CLASS TreeMatchContext 
       return false;
     }
     if (mCurrentStyleScope == aElement) {
       mCurrentStyleScope = nullptr;
     }
     return true;
   }
 
+#ifdef DEBUG
+  void AssertHasAllStyleScopes(mozilla::dom::Element* aElement)
+  {
+    int32_t i = mStyleScopes.Length() - 1;
+    nsINode* node = aElement->GetParentNode();
+    while (node && i != -1) {
+      if (node->IsScopedStyleRoot()) {
+        MOZ_ASSERT(mStyleScopes[i] == node);
+        --i;
+      }
+      node = node->GetParentNode();
+    }
+    while (node) {
+      MOZ_ASSERT(!node->IsScopedStyleRoot());
+      node = node->GetParentNode();
+    }
+    MOZ_ASSERT(i == -1);
+  }
+#endif
+
   bool SetStyleScopeForSelectorMatching(mozilla::dom::Element* aSubject,
                                         mozilla::dom::Element* aScope)
   {
+#ifdef DEBUG
+    AssertHasAllStyleScopes(aSubject);
+#endif
+
     mForScopedStyle = !!aScope;
     if (!aScope) {
       // This is not for a scoped style sheet; return true, as we want
       // selector matching to proceed.
       mCurrentStyleScope = nullptr;
       return true;
     }
     if (aScope == aSubject) {
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -1152,22 +1152,31 @@ nsStyleSet::WalkRuleProcessors(nsIStyleR
   if (mRuleProcessors[eStyleAttrSheet])
     (*aFunc)(mRuleProcessors[eStyleAttrSheet], aData);
   if (mRuleProcessors[eOverrideSheet])
     (*aFunc)(mRuleProcessors[eOverrideSheet], aData);
   (*aFunc)(mRuleProcessors[eAnimationSheet], aData);
   (*aFunc)(mRuleProcessors[eTransitionSheet], aData);
 }
 
+static void
+InitAncestorsIfInStyleScope(TreeMatchContext& aTreeContext, Element* aElement)
+{
+  if (aElement->IsElementInStyleScope()) {
+    aTreeContext.InitAncestors(aElement->GetParentElement());
+  }
+}
+
 already_AddRefed<nsStyleContext>
 nsStyleSet::ResolveStyleFor(Element* aElement,
                             nsStyleContext* aParentContext)
 {
   TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
                                aElement->OwnerDoc());
+  InitAncestorsIfInStyleScope(treeContext, aElement);
   return ResolveStyleFor(aElement, aParentContext, treeContext);
 }
 
 already_AddRefed<nsStyleContext>
 nsStyleSet::ResolveStyleFor(Element* aElement,
                             nsStyleContext* aParentContext,
                             TreeMatchContext& aTreeMatchContext)
 {
@@ -1332,16 +1341,17 @@ nsStyleSet::ResolvePseudoElementStyle(El
 
   NS_ASSERTION(aType < nsCSSPseudoElements::ePseudo_PseudoElementCount,
                "must have pseudo element type");
   NS_ASSERTION(aParentElement, "Must have parent element");
 
   nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
   TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
                                aParentElement->OwnerDoc());
+  InitAncestorsIfInStyleScope(treeContext, aParentElement);
   PseudoElementRuleProcessorData data(PresContext(), aParentElement,
                                       &ruleWalker, aType, treeContext);
   WalkRestrictionRule(aType, &ruleWalker);
   FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
             aParentElement, &ruleWalker);
 
   nsRuleNode *ruleNode = ruleWalker.CurrentNode();
   nsRuleNode *visitedRuleNode = nullptr;
@@ -1375,16 +1385,17 @@ nsStyleSet::ResolvePseudoElementStyle(El
 
 already_AddRefed<nsStyleContext>
 nsStyleSet::ProbePseudoElementStyle(Element* aParentElement,
                                     nsCSSPseudoElements::Type aType,
                                     nsStyleContext* aParentContext)
 {
   TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
                                aParentElement->OwnerDoc());
+  InitAncestorsIfInStyleScope(treeContext, aParentElement);
   return ProbePseudoElementStyle(aParentElement, aType, aParentContext,
                                  treeContext);
 }
 
 already_AddRefed<nsStyleContext>
 nsStyleSet::ProbePseudoElementStyle(Element* aParentElement,
                                     nsCSSPseudoElements::Type aType,
                                     nsStyleContext* aParentContext,
@@ -1513,16 +1524,17 @@ nsStyleSet::ResolveXULTreePseudoStyle(El
 
   NS_ASSERTION(aPseudoTag, "must have pseudo tag");
   NS_ASSERTION(nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag),
                "Unexpected pseudo");
 
   nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
   TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
                                aParentElement->OwnerDoc());
+  InitAncestorsIfInStyleScope(treeContext, aParentElement);
   XULTreeRuleProcessorData data(PresContext(), aParentElement, &ruleWalker,
                                 aPseudoTag, aComparator, treeContext);
   FileRules(EnumRulesMatching<XULTreeRuleProcessorData>, &data, aParentElement,
             &ruleWalker);
 
   nsRuleNode *ruleNode = ruleWalker.CurrentNode();
   nsRuleNode *visitedRuleNode = nullptr;
 
@@ -1875,16 +1887,17 @@ nsStyleSet::HasDocumentStateDependentSty
                                            nsIContent*    aContent,
                                            nsEventStates  aStateMask)
 {
   if (!aContent || !aContent->IsElement())
     return false;
 
   TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
                                aContent->OwnerDoc());
+  InitAncestorsIfInStyleScope(treeContext, aContent->AsElement());
   StatefulData data(aPresContext, aContent->AsElement(), aStateMask,
                     treeContext);
   WalkRuleProcessors(SheetHasDocumentStateStyle, &data, true);
   return data.mHint != 0;
 }
 
 static bool SheetHasStatefulStyle(nsIStyleRuleProcessor* aProcessor,
                                     void *aData)
@@ -1898,16 +1911,17 @@ static bool SheetHasStatefulStyle(nsISty
 // Test if style is dependent on content state
 nsRestyleHint
 nsStyleSet::HasStateDependentStyle(nsPresContext*       aPresContext,
                                    Element*             aElement,
                                    nsEventStates        aStateMask)
 {
   TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
                                aElement->OwnerDoc());
+  InitAncestorsIfInStyleScope(treeContext, aElement);
   StatefulData data(aPresContext, aElement, aStateMask, treeContext);
   WalkRuleProcessors(SheetHasStatefulStyle, &data, false);
   return data.mHint;
 }
 
 struct MOZ_STACK_CLASS AttributeData : public AttributeRuleProcessorData {
   AttributeData(nsPresContext* aPresContext,
                 Element* aElement, nsIAtom* aAttribute, int32_t aModType,
@@ -1933,16 +1947,17 @@ nsRestyleHint
 nsStyleSet::HasAttributeDependentStyle(nsPresContext* aPresContext,
                                        Element*       aElement,
                                        nsIAtom*       aAttribute,
                                        int32_t        aModType,
                                        bool           aAttrHasChanged)
 {
   TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
                                aElement->OwnerDoc());
+  InitAncestorsIfInStyleScope(treeContext, aElement);
   AttributeData data(aPresContext, aElement, aAttribute,
                      aModType, aAttrHasChanged, treeContext);
   WalkRuleProcessors(SheetHasAttributeStyle, &data, false);
   return data.mHint;
 }
 
 bool
 nsStyleSet::MediumFeaturesChanged(nsPresContext* aPresContext)
--- a/media/webrtc/signaling/test/Makefile.in
+++ b/media/webrtc/signaling/test/Makefile.in
@@ -6,16 +6,17 @@ LIBS = \
   $(XPCOM_LIBS) \
   $(NSPR_LIBS) \
   $(NSS_LIBS) \
   $(REALTIME_LIBS) \
   $(DEPTH)/xpcom/glue/$(LIB_PREFIX)xpcomglue_s.$(LIB_SUFFIX) \
   $(DEPTH)/media/mtransport/standalone/$(LIB_PREFIX)mtransport_s.$(LIB_SUFFIX) \
   $(DEPTH)/media/webrtc/signalingtest/signaling_ecc/$(LIB_PREFIX)ecc.$(LIB_SUFFIX) \
   $(DEPTH)/media/webrtc/signalingtest/signaling_sipcc/$(LIB_PREFIX)sipcc.$(LIB_SUFFIX) \
+  $(DEPTH)/layout/media/webrtc/$(LIB_PREFIX)webrtc.$(LIB_SUFFIX) \
   $(DEPTH)/layout/media/$(LIB_PREFIX)gkmedias.$(LIB_SUFFIX) \
   $(DEPTH)/media/webrtc/trunk/testing/gtest_gtest/$(LIB_PREFIX)gtest.$(LIB_SUFFIX) \
   $(DEPTH)/netwerk/srtp/src/$(LIB_PREFIX)nksrtp_s.$(LIB_SUFFIX) \
   $(NULL)
 
 ifdef MOZ_CUBEB
 ifdef MOZ_ALSA
 LIBS += \
--- a/media/webrtc/webrtc_config.gypi
+++ b/media/webrtc/webrtc_config.gypi
@@ -36,17 +36,17 @@
       }],
     ],
 # (for vp8) chromium sets to 0 also
     'use_temporal_layers': 0,
 # Creates AEC internal sample dump files in current directory
 #    'aec_debug_dump': 1,
 
     # codec enable/disables:
-    # Note: if you change one here, you must modify shared_libs.mk!
+    # Note: if you change one here, you must modify layout/media/webrtc/Makefile.in!
     'include_g711': 1,
     'include_opus': 1,
     'include_g722': 0,
     'include_ilbc': 0,
     'include_isac': 0,
     'include_pcm16b': 1,
   }
 }
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -308,22 +308,16 @@ FENNEC_PP_JAVA_FILES := \
   widget/GeckoRelativeLayout.java \
   widget/GeckoTextSwitcher.java \
   widget/GeckoTextView.java \
   SysInfo.java \
   WebApp.java \
   WebApps.java \
   $(NULL)
 
-FENNEC_PP_XML_FILES = \
-  res/xml/preferences.xml \
-  res/xml/preferences_customize.xml \
-  res/xml/searchable.xml \
-  $(NULL)
-
 ifneq (,$(findstring -march=armv7,$(OS_CFLAGS)))
 MIN_CPU_VERSION=7
 else
 MIN_CPU_VERSION=5
 endif
 
 MOZ_APP_BUILDID=$(shell cat $(DEPTH)/config/buildid)
 
@@ -353,16 +347,18 @@ endif
 DEFINES += \
   -DMANGLED_ANDROID_PACKAGE_NAME=$(subst fennec,f3nn3c,$(ANDROID_PACKAGE_NAME)) \
   -DANDROID_PACKAGE_NAME=$(ANDROID_PACKAGE_NAME) \
   -DANDROID_CPU_ARCH=$(ANDROID_CPU_ARCH) \
   -DANDROID_VERSION_CODE=$(ANDROID_VERSION_CODE) \
   -DCPU_ARCH=$(CPU_ARCH) \
   -DGRE_MILESTONE=$(GRE_MILESTONE) \
   -DMOZILLA_OFFICIAL=$(MOZILLA_OFFICIAL) \
+  -DMOZ_ANDROID_SHARED_ID="$(MOZ_ANDROID_SHARED_ID)" \
+  -DMOZ_ANDROID_SHARED_ACCOUNT_TYPE="$(MOZ_ANDROID_SHARED_ACCOUNT_TYPE)" \
   -DMOZ_APP_ABI=$(TARGET_XPCOM_ABI) \
   -DMOZ_APP_BASENAME=$(MOZ_APP_BASENAME) \
   -DMOZ_APP_BUILDID=$(MOZ_APP_BUILDID) \
   -DMOZ_APP_DISPLAYNAME="$(MOZ_APP_DISPLAYNAME)" \
   -DMOZ_APP_ID=$(MOZ_APP_ID) \
   -DMOZ_APP_NAME=$(MOZ_APP_NAME) \
   -DMOZ_APP_VENDOR=$(MOZ_APP_VENDOR) \
   -DMOZ_APP_VERSION=$(MOZ_APP_VERSION) \
@@ -389,66 +385,38 @@ GARBAGE += \
   AndroidManifest.xml  \
   classes.dex  \
   $(MOZGLUE_PP_JAVA_FILES) \
   $(FENNEC_PP_JAVA_FILES) \
   $(SYNC_PP_JAVA_FILES) \
   gecko.ap_  \
   res/values/strings.xml \
   R.java \
-  $(FENNEC_PP_XML_FILES) \
-  $(SYNC_PP_RES_XML) \
   package-name.txt \
   fennec_ids.txt \
   Manifest.java \
   javah.out \
   jni-stubs.inc \
   GeneratedJNIWrappers.cpp \
   GeneratedJNIWrappers.h \
   $(NULL)
 
 GARBAGE_DIRS += classes db jars res sync services
 
-MOZ_ANDROID_SHARED_ID = "$(ANDROID_PACKAGE_NAME).sharedID"
-MOZ_ANDROID_SHARED_ACCOUNT_TYPE = "$(ANDROID_PACKAGE_NAME)_sync"
-
 # Bug 567884 - Need a way to find appropriate icons during packaging
 ifeq ($(MOZ_APP_NAME),fennec)
 ICON_PATH = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/fennec_48x48.png
 ICON_PATH_HDPI = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/fennec_72x72.png
 ICON_PATH_XHDPI = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/fennec_96x96.png
 ICON_PATH_XXHDPI = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/fennec_144x144.png
-
-# we released these builds to the public with shared IDs and need to keep them
-ifeq (org.mozilla.firefox,$(ANDROID_PACKAGE_NAME))
-MOZ_ANDROID_SHARED_ID = "org.mozilla.firefox.sharedID"
-MOZ_ANDROID_SHARED_ACCOUNT_TYPE = "org.mozilla.firefox_sync"
-else ifeq (org.mozilla.firefox_beta,$(ANDROID_PACKAGE_NAME))
-MOZ_ANDROID_SHARED_ID = "org.mozilla.firefox.sharedID"
-MOZ_ANDROID_SHARED_ACCOUNT_TYPE = "org.mozilla.firefox_sync"
-else ifeq (org.mozilla.fennec_aurora,$(ANDROID_PACKAGE_NAME))
-MOZ_ANDROID_SHARED_ID = "org.mozilla.fennec.sharedID"
-MOZ_ANDROID_SHARED_ACCOUNT_TYPE = "org.mozilla.fennec_sync"
-else ifeq (org.mozilla.fennec,$(ANDROID_PACKAGE_NAME))
-MOZ_ANDROID_SHARED_ID = "org.mozilla.fennec.sharedID"
-MOZ_ANDROID_SHARED_ACCOUNT_TYPE = "org.mozilla.fennec_sync"
-endif
-
 else
 ICON_PATH = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/icon48.png
 ICON_PATH_HDPI = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/icon64.png
 endif
 
-ifdef MOZ_ANDROID_SHARED_ID
-DEFINES += -DMOZ_ANDROID_SHARED_ID="$(MOZ_ANDROID_SHARED_ID)"
-endif
-ifdef MOZ_ANDROID_SHARED_ACCOUNT_TYPE
-DEFINES += -DMOZ_ANDROID_SHARED_ACCOUNT_TYPE="$(MOZ_ANDROID_SHARED_ACCOUNT_TYPE)"
-endif
-
 RES_LAYOUT = \
   $(SYNC_RES_LAYOUT) \
   res/layout/arrow_popup.xml \
   res/layout/autocomplete_list.xml \
   res/layout/autocomplete_list_item.xml \
   res/layout/bookmark_edit.xml \
   res/layout/bookmark_folder_row.xml \
   res/layout/bookmark_item_row.xml \
@@ -593,21 +561,24 @@ RES_VALUES_V14 = \
   res/values-v14/styles.xml \
   $(NULL)
 
 RES_VALUES_V16 = \
   res/values-v16/styles.xml \
   $(NULL)
 
 RES_XML = \
+  res/xml/preferences.xml \
+  res/xml/preferences_customize.xml \
   res/xml/preferences_display.xml \
   res/xml/preferences_search.xml \
   res/xml/preferences_privacy.xml \
   res/xml/preferences_vendor.xml \
   res/xml/preferences_devtools.xml \
+  res/xml/searchable.xml \
   $(SYNC_RES_XML) \
   $(NULL)
 
 RES_XML_V11 = \
   res/xml-v11/preferences_customize.xml \
   res/xml-v11/preference_headers.xml \
   res/xml-v11/preferences_customize_tablet.xml \
   res/xml-v11/preferences.xml \
@@ -1328,26 +1299,16 @@ jni-stubs.inc: jars/gecko-browser.jar ja
 	$(PYTHON) $(topsrcdir)/mobile/android/base/jni-generator.py javah.out $@
 
 ANNOTATION_PROCESSOR_JAR_FILES := $(DEPTH)/build/annotationProcessors/annotationProcessors.jar
 
 GeneratedJNIWrappers.cpp: $(ANNOTATION_PROCESSOR_JAR_FILES)
 GeneratedJNIWrappers.cpp: $(ALL_JARS)
 	$(JAVA) -classpath $(JAVA_BOOTCLASSPATH):$(ANNOTATION_PROCESSOR_JAR_FILES) org.mozilla.gecko.annotationProcessors.AnnotationProcessor $(ALL_JARS)
 
-PP_RES_XML= \
-  $(SYNC_PP_RES_XML) \
-  $(FENNEC_PP_XML_FILES) \
-  $(NULL)
-
-# This is kinda awful; if any of the source files change, we remake them all.
-$(PP_RES_XML): $(patsubst res/%,$(srcdir)/resources/%.in,$(PP_RES_XML))
-	$(PYTHON) $(topsrcdir)/config/Preprocessor.py \
-             $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $(subst res/,$(srcdir)/resources/,$@).in > $@
-
 # AndroidManifest.xml includes these files, so they need to be marked as dependencies.
 SERVICES_MANIFEST_FRAGMENTS = $(wildcard $(topsrcdir)/mobile/android/services/manifests/*.in)
 
 android-tgts = \
   AndroidManifest.xml \
   $(MOZGLUE_PP_JAVA_FILES) \
   $(FENNEC_PP_JAVA_FILES) \
   $(SYNC_PP_JAVA_FILES) \
@@ -1402,17 +1363,16 @@ all_resources = \
   res/drawable-mdpi/icon.png \
   res/drawable-hdpi/icon.png \
   res/drawable-xhdpi/icon.png \
   res/drawable-xxhdpi/icon.png \
   res/values/strings.xml \
   $(MULTILOCALE_STRINGS_XML_FILES) \
   AndroidManifest.xml \
   $(RESOURCES) \
-  $(PP_RES_XML) \
   $(NULL)
 
 R.java: $(all_resources)
 	$(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -J . --custom-package org.mozilla.gecko --non-constant-id
 
 gecko.ap_: $(all_resources)
 	$(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar  -S res -F $@
 
--- a/mobile/android/base/android-services-files.mk
+++ b/mobile/android/base/android-services-files.mk
@@ -338,22 +338,19 @@ SYNC_RES_VALUES_V11 := \
   res/values-v11/sync_styles.xml \
   $(NULL)
 
 SYNC_RES_VALUES_LARGE_V11 := \
   res/values-large-v11/sync_styles.xml \
   $(NULL)
 
 SYNC_RES_XML := \
-  $(NULL)
-
-SYNC_PP_RES_XML := \
+  res/xml/sync_authenticator.xml \
   res/xml/sync_syncadapter.xml \
   res/xml/sync_options.xml \
-  res/xml/sync_authenticator.xml \
   $(NULL)
 
 SYNC_THIRDPARTY_JAVA_FILES := \
   httpclientandroidlib/androidextra/HttpClientAndroidLog.java \
   httpclientandroidlib/annotation/GuardedBy.java \
   httpclientandroidlib/annotation/Immutable.java \
   httpclientandroidlib/annotation/NotThreadSafe.java \
   httpclientandroidlib/annotation/ThreadSafe.java \
--- a/mobile/android/base/home/BrowserSearch.java
+++ b/mobile/android/base/home/BrowserSearch.java
@@ -211,18 +211,20 @@ public class BrowserSearch extends HomeF
     }
 
     @Override
     public void onDestroyView() {
         super.onDestroyView();
 
         unregisterEventListener("SearchEngines:Data");
 
+        mList.setAdapter(null);
+        mList = null;
+
         mView = null;
-        mList = null;
         mSuggestionsOptInPrompt = null;
         mSuggestClient = null;
     }
 
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
         mList.setTag(HomePager.LIST_TAG_BROWSER_SEARCH);
--- a/mobile/android/base/locales/Makefile.in
+++ b/mobile/android/base/locales/Makefile.in
@@ -54,20 +54,24 @@ strings-xml-preqs =\
   $(strings-xml-in) \
   $(BRANDPATH) \
   $(STRINGSPATH) \
   $(SYNCSTRINGSPATH) \
   $(BOOKMARKSPATH) \
   $(if $(IS_LANGUAGE_REPACK),FORCE) \
   $(NULL)
 
+$(if $(MOZ_ANDROID_SHARED_ACCOUNT_TYPE),,$(error Missing MOZ_ANDROID_SHARED_ACCOUNT_TYPE))
+
 $(dir-strings-xml)/strings.xml: $(strings-xml-preqs)
 	$(NSINSTALL) -D $(dir-strings-xml)
 	$(TOUCH) $(call mkdir_deps,$(dir-strings-xml))
 	$(PYTHON) $(topsrcdir)/config/Preprocessor.py \
       $(DEFINES) \
+	  -DANDROID_PACKAGE_NAME=$(ANDROID_PACKAGE_NAME) \
+	  -DBOOKMARKSPATH="$(BOOKMARKSPATH)" \
 	  -DBRANDPATH="$(BRANDPATH)" \
+	  -DMOZ_ANDROID_SHARED_ACCOUNT_TYPE=$(MOZ_ANDROID_SHARED_ACCOUNT_TYPE) \
+	  -DMOZ_APP_DISPLAYNAME="@MOZ_APP_DISPLAYNAME@" \
 	  -DSTRINGSPATH="$(STRINGSPATH)" \
 	  -DSYNCSTRINGSPATH="$(SYNCSTRINGSPATH)" \
-	  -DBOOKMARKSPATH="$(BOOKMARKSPATH)" \
-	  -DMOZ_APP_DISPLAYNAME="@MOZ_APP_DISPLAYNAME@" \
       $< \
 	  > $@
rename from mobile/android/base/resources/xml/preferences.xml.in
rename to mobile/android/base/resources/xml/preferences.xml
--- a/mobile/android/base/resources/xml/preferences.xml.in
+++ b/mobile/android/base/resources/xml/preferences.xml
@@ -1,9 +1,8 @@
-#filter substitution
 <?xml version="1.0" encoding="utf-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/. -->
 
 <!-- Preferences screen for pre-v11 Android devices that do not support
      PreferenceFragment or ActionBar. Preference changes here should be mirrored
      to xml-v11/preferences.xml. -->
@@ -13,56 +12,56 @@
                   android:enabled="false">
 
     <org.mozilla.gecko.SyncPreference android:key="android.not_a_preference.sync"
                                       android:title="@string/pref_sync"
                                       android:persistent="false" />
 
     <PreferenceScreen android:title="@string/pref_category_customize" >
         <intent android:action="android.intent.action.VIEW"
-                android:targetPackage="@ANDROID_PACKAGE_NAME@"
+                android:targetPackage="@string/android_package_name"
                 android:targetClass="org.mozilla.gecko.GeckoPreferences" >
             <extra
                 android:name="resource"
                 android:value="preferences_customize" />
         </intent>
     </PreferenceScreen>
 
     <PreferenceScreen android:title="@string/pref_category_display" >
         <intent android:action="android.intent.action.VIEW"
-                android:targetPackage="@ANDROID_PACKAGE_NAME@"
+                android:targetPackage="@string/android_package_name"
                 android:targetClass="org.mozilla.gecko.GeckoPreferences" >
             <extra
                 android:name="resource"
                 android:value="preferences_display" />
         </intent>
     </PreferenceScreen>
 
     <PreferenceScreen android:title="@string/pref_category_privacy_short" >
         <intent android:action="android.intent.action.VIEW"
-                android:targetPackage="@ANDROID_PACKAGE_NAME@"
+                android:targetPackage="@string/android_package_name"
                 android:targetClass="org.mozilla.gecko.GeckoPreferences" >
             <extra
                 android:name="resource"
                 android:value="preferences_privacy" />
         </intent>
     </PreferenceScreen>
 
     <PreferenceScreen android:title="@string/pref_category_vendor">
         <intent android:action="android.intent.action.VIEW"
-                android:targetPackage="@ANDROID_PACKAGE_NAME@"
+                android:targetPackage="@string/android_package_name"
                 android:targetClass="org.mozilla.gecko.GeckoPreferences" >
             <extra
                 android:name="resource"
                 android:value="preferences_vendor" />
         </intent>
     </PreferenceScreen>
     <PreferenceScreen android:title="@string/pref_category_devtools">
         <intent android:action="android.intent.action.VIEW"
-                android:targetPackage="@ANDROID_PACKAGE_NAME@"
+                android:targetPackage="@string/android_package_name"
                 android:targetClass="org.mozilla.gecko.GeckoPreferences" >
             <extra
                 android:name="resource"
                 android:value="preferences_devtools" />
         </intent>
     </PreferenceScreen>
 
 </PreferenceScreen>
rename from mobile/android/base/resources/xml/preferences_customize.xml.in
rename to mobile/android/base/resources/xml/preferences_customize.xml
--- a/mobile/android/base/resources/xml/preferences_customize.xml.in
+++ b/mobile/android/base/resources/xml/preferences_customize.xml
@@ -1,20 +1,19 @@
-#filter substitution
 <?xml version="1.0" encoding="utf-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/. -->
 
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
                   xmlns:gecko="http://schemas.android.com/apk/res-auto"
                   android:enabled="false">
     <PreferenceScreen android:title="@string/pref_category_search" >
         <intent android:action="android.intent.action.VIEW"
-                android:targetPackage="@ANDROID_PACKAGE_NAME@"
+                android:targetPackage="@string/android_package_name"
                 android:targetClass="org.mozilla.gecko.GeckoPreferences" >
             <extra
                 android:name="resource"
                 android:value="preferences_search" />
         </intent>
     </PreferenceScreen>
 
     <org.mozilla.gecko.AndroidImportPreference
rename from mobile/android/base/resources/xml/searchable.xml.in
rename to mobile/android/base/resources/xml/searchable.xml
--- a/mobile/android/base/resources/xml/searchable.xml.in
+++ b/mobile/android/base/resources/xml/searchable.xml
@@ -1,8 +1,7 @@
-#filter substitution
 <?xml version="1.0" encoding="utf-8"?>
 <searchable xmlns:android="http://schemas.android.com/apk/res/android"
             android:label="@string/moz_app_displayname"
-            android:searchSuggestAuthority="@ANDROID_PACKAGE_NAME@.db.browser"
+            android:searchSuggestAuthority="@string/content_authority_db_browser"
             android:searchSuggestIntentAction="android.intent.action.SEARCH"
             android:searchSettingsDescription="@string/searchable_description"
             android:includeInGlobalSearch="true"/>
rename from mobile/android/base/resources/xml/sync_authenticator.xml.in
rename to mobile/android/base/resources/xml/sync_authenticator.xml
--- a/mobile/android/base/resources/xml/sync_authenticator.xml.in
+++ b/mobile/android/base/resources/xml/sync_authenticator.xml
@@ -1,12 +1,11 @@
-#filter substitution
 <?xml version="1.0" encoding="utf-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/. -->
 
 <account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
-    android:accountType="@MOZ_ANDROID_SHARED_ACCOUNT_TYPE@"
+    android:accountType="@string/moz_android_shared_account_type"
     android:icon="@drawable/icon"
     android:smallIcon="@drawable/icon"
     android:label="@string/sync_account_label"
     android:accountPreferences="@xml/sync_options" />
rename from mobile/android/base/resources/xml/sync_options.xml.in
rename to mobile/android/base/resources/xml/sync_options.xml
--- a/mobile/android/base/resources/xml/sync_options.xml.in
+++ b/mobile/android/base/resources/xml/sync_options.xml
@@ -1,32 +1,31 @@
-#filter substitution
 <?xml version="1.0" encoding="UTF-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/. -->
 
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
   <PreferenceCategory
     android:title="@string/sync_settings_options" />
   <PreferenceScreen
     android:key="sync_options"
     android:title="@string/sync_title_pair"
     android:summary="@string/sync_settings_summary_pair">
     <intent
       android:action="android.intent.action.MAIN"
-      android:targetPackage="@ANDROID_PACKAGE_NAME@"
+      android:targetPackage="@string/android_package_name"
       android:targetClass="org.mozilla.gecko.sync.setup.activities.SetupSyncActivity">
       <extra
         android:name="isSetup"
         android:value="false" />
     </intent>
   </PreferenceScreen>
   <PreferenceScreen
     android:key="sync_configure_engines"
     android:title="@string/sync_configure_engines_title">
     <intent
       android:action="android.intent.action.MAIN"
-      android:targetPackage="@ANDROID_PACKAGE_NAME@"
+      android:targetPackage="@string/android_package_name"
       android:targetClass="org.mozilla.gecko.sync.config.activities.SelectEnginesActivity">
     </intent>
   </PreferenceScreen>
 </PreferenceScreen>
rename from mobile/android/base/resources/xml/sync_syncadapter.xml.in
rename to mobile/android/base/resources/xml/sync_syncadapter.xml
--- a/mobile/android/base/resources/xml/sync_syncadapter.xml.in
+++ b/mobile/android/base/resources/xml/sync_syncadapter.xml
@@ -1,12 +1,11 @@
-#filter substitution
 <?xml version="1.0" encoding="utf-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/. -->
 
 <sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
-    android:contentAuthority="@ANDROID_PACKAGE_NAME@.db.browser"
-    android:accountType="@MOZ_ANDROID_SHARED_ACCOUNT_TYPE@"
+    android:contentAuthority="@string/content_authority_db_browser"
+    android:accountType="@string/moz_android_shared_account_type"
     android:supportsUploading="true"
     android:userVisible="true"
 />
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -14,16 +14,19 @@
 <!ENTITY formatS1 "&#037;1&#036;s">
 <!ENTITY formatS2 "&#037;2&#036;s">
 <!ENTITY formatD "&#037;d">
 ]>
 
 #includesubst @BOOKMARKSPATH@
 <resources>
   <string name="moz_app_displayname">@MOZ_APP_DISPLAYNAME@</string>
+  <string name="android_package_name">@ANDROID_PACKAGE_NAME@</string>
+  <string name="content_authority_db_browser">@ANDROID_PACKAGE_NAME@.db.browser</string>
+  <string name="moz_android_shared_account_type">@MOZ_ANDROID_SHARED_ACCOUNT_TYPE@</string>
 #include ../services/strings.xml.in
   <string name="no_space_to_start_error">&no_space_to_start_error;</string>
   <string name="error_loading_file">&error_loading_file;</string>
 
   <string name="bookmarks_title">&bookmarks_title;</string>
   <string name="history_title">&history_title;</string>
   <string name="reading_list_title">&reading_list_title;</string>
 
new file mode 100644
--- /dev/null
+++ b/mobile/android/defs.mk
@@ -0,0 +1,18 @@
+MOZ_ANDROID_SHARED_ID = "$(ANDROID_PACKAGE_NAME).sharedID"
+MOZ_ANDROID_SHARED_ACCOUNT_TYPE = "$(ANDROID_PACKAGE_NAME)_sync"
+
+# We released these builds to the public with shared IDs and need to
+# keep them consistent.
+ifeq (org.mozilla.firefox,$(ANDROID_PACKAGE_NAME))
+MOZ_ANDROID_SHARED_ID = "org.mozilla.firefox.sharedID"
+MOZ_ANDROID_SHARED_ACCOUNT_TYPE = "org.mozilla.firefox_sync"
+else ifeq (org.mozilla.firefox_beta,$(ANDROID_PACKAGE_NAME))
+MOZ_ANDROID_SHARED_ID = "org.mozilla.firefox.sharedID"
+MOZ_ANDROID_SHARED_ACCOUNT_TYPE = "org.mozilla.firefox_sync"
+else ifeq (org.mozilla.fennec_aurora,$(ANDROID_PACKAGE_NAME))
+MOZ_ANDROID_SHARED_ID = "org.mozilla.fennec.sharedID"
+MOZ_ANDROID_SHARED_ACCOUNT_TYPE = "org.mozilla.fennec_sync"
+else ifeq (org.mozilla.fennec,$(ANDROID_PACKAGE_NAME))
+MOZ_ANDROID_SHARED_ID = "org.mozilla.fennec.sharedID"
+MOZ_ANDROID_SHARED_ACCOUNT_TYPE = "org.mozilla.fennec_sync"
+endif
--- a/mobile/android/tests/background/junit3/src/common/TestUtils.java
+++ b/mobile/android/tests/background/junit3/src/common/TestUtils.java
@@ -1,13 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.gecko.background.common;
 
+import java.io.File;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
 import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
@@ -72,9 +74,86 @@ public class TestUtils extends AndroidSy
 
   public void testGetStagesToSyncFromBundle() {
     final String[] all = new String[] { "other1", "other2", "skip1", "skip2", "sync1", "sync2" };
     assertStagesFromBundle(all, null, null, all);
     assertStagesFromBundle(all, new String[] { "sync1" }, null, new String[] { "sync1" });
     assertStagesFromBundle(all, null, new String[] { "skip1", "skip2" }, new String[] { "other1", "other2", "sync1", "sync2" });
     assertStagesFromBundle(all, new String[] { "sync1", "sync2" }, new String[] { "skip1", "skip2" }, new String[] { "sync1", "sync2" });
   }
+
+  public static void deleteDirectoryRecursively(final File dir) throws IOException {
+    if (!dir.isDirectory()) {
+      throw new IllegalStateException("Given directory, " + dir + ", is not a directory!");
+    }
+
+    for (File f : dir.listFiles()) {
+      if (f.isDirectory()) {
+        deleteDirectoryRecursively(f);
+      } else if (!f.delete()) {
+        // Since this method is for testing, we assume we should be able to do this.
+        throw new IOException("Could not delete file, " + f.getAbsolutePath() + ". Permissions?");
+      }
+    }
+
+    if (!dir.delete()) {
+      throw new IOException("Could not delete dir, " + dir.getAbsolutePath() + ".");
+    }
+  }
+
+  public void testDeleteDirectory() throws Exception {
+    final String TEST_DIR = getApplicationContext().getCacheDir().getAbsolutePath() +
+        "-testDeleteDirectory-" + System.currentTimeMillis();
+
+    // Non-existent directory.
+    final File nonexistent = new File("nonexistentDirectory"); // Hopefully. ;)
+    assertFalse(nonexistent.exists());
+    try {
+      deleteDirectoryRecursively(nonexistent);
+      fail("deleteDirectoryRecursively on a nonexistent directory should throw Exception");
+    } catch (IllegalStateException e) { }
+
+    // Empty dir.
+    File dir = mkdir(TEST_DIR);
+    deleteDirectoryRecursively(dir);
+    assertFalse(dir.exists());
+
+    // Filled dir.
+    dir = mkdir(TEST_DIR);
+    populateDir(dir);
+    deleteDirectoryRecursively(dir);
+    assertFalse(dir.exists());
+
+    // Filled dir with empty dir.
+    dir = mkdir(TEST_DIR);
+    populateDir(dir);
+    File subDir = new File(TEST_DIR + File.separator + "subDir");
+    assertTrue(subDir.mkdir());
+    deleteDirectoryRecursively(dir);
+    assertFalse(subDir.exists()); // For short-circuiting errors.
+    assertFalse(dir.exists());
+
+    // Filled dir with filled dir.
+    dir = mkdir(TEST_DIR);
+    populateDir(dir);
+    subDir = new File(TEST_DIR + File.separator + "subDir");
+    assertTrue(subDir.mkdir());
+    populateDir(subDir);
+    deleteDirectoryRecursively(dir);
+    assertFalse(subDir.exists()); // For short-circuiting errors.
+    assertFalse(dir.exists());
+  }
+
+  private File mkdir(final String name) {
+    final File dir = new File(name);
+    assertTrue(dir.mkdir());
+    return dir;
+  }
+
+  private void populateDir(final File dir) throws IOException {
+    assertTrue(dir.isDirectory());
+    final String dirPath = dir.getAbsolutePath();
+    for (int i = 0; i < 3; i++) {
+      final File f = new File(dirPath + File.separator + i);
+      assertTrue(f.createNewFile()); // Throws IOException if file could not be created.
+    }
+  }
 }
--- a/mobile/android/tests/background/junit3/src/helpers/FakeProfileTestCase.java
+++ b/mobile/android/tests/background/junit3/src/helpers/FakeProfileTestCase.java
@@ -4,16 +4,18 @@
 package org.mozilla.gecko.background.helpers;
 
 import java.io.File;
 
 import android.app.Activity;
 import android.content.Context;
 import android.test.ActivityInstrumentationTestCase2;
 
+import org.mozilla.gecko.background.common.TestUtils;
+
 public abstract class FakeProfileTestCase extends ActivityInstrumentationTestCase2<Activity> {
 
   protected Context context;
   protected File fakeProfileDirectory;
 
   public FakeProfileTestCase() {
     super(Activity.class);
   }
@@ -21,23 +23,22 @@ public abstract class FakeProfileTestCas
   protected abstract String getCacheSuffix();
 
   @Override
   protected void setUp() throws Exception {
     super.setUp();
     context = getInstrumentation().getTargetContext();
     File cache = context.getCacheDir();
     fakeProfileDirectory = new File(cache.getAbsolutePath() + getCacheSuffix());
+    if (fakeProfileDirectory.exists()) {
+      TestUtils.deleteDirectoryRecursively(fakeProfileDirectory);
+    }
     if (!fakeProfileDirectory.mkdir()) {
       throw new IllegalStateException("Could not create temporary directory.");
     }
   }
 
   @Override
   protected void tearDown() throws Exception {
-    // We don't check return values.
-    for (File child : fakeProfileDirectory.listFiles()) {
-      child.delete();
-    }
-    fakeProfileDirectory.delete();
+    TestUtils.deleteDirectoryRecursively(fakeProfileDirectory);
     super.tearDown();
   }
 }
--- a/python/mozbuild/mozbuild/backend/recursivemake.py
+++ b/python/mozbuild/mozbuild/backend/recursivemake.py
@@ -439,30 +439,40 @@ class RecursiveMakeBackend(CommonBackend
         # Skip static dirs during export traversal, or build everything in
         # parallel when enabled.
         def export_filter(current, subdirs):
             if self._parallel_export:
                 return parallel_filter(current, subdirs)
             return current, subdirs.parallel, \
                 subdirs.dirs + subdirs.tests + subdirs.tools
 
-        # Skip tools dirs during libs traversal
+        # Skip tools dirs during libs traversal. Because of bug 925236 and
+        # possible other unknown race conditions, don't parallelize the libs
+        # tier.
         def libs_filter(current, subdirs):
             if current in self._may_skip[tier]:
                 current = None
+            return current, [], subdirs.parallel + \
+                subdirs.static + subdirs.dirs + subdirs.tests
+
+        # Because of bug 925236 and possible other unknown race conditions,
+        # don't parallelize the tools tier.
+        def tools_filter(current, subdirs):
+            if current in self._may_skip[tier]:
+                current = None
             return current, subdirs.parallel, \
-                subdirs.static + subdirs.dirs + subdirs.tests
+                subdirs.static + subdirs.dirs + subdirs.tests + subdirs.tools
 
         # compile, binaries and tools tiers use the same traversal as export
         filters = {
             'export': export_filter,
             'compile': parallel_filter,
             'binaries': parallel_filter,
             'libs': libs_filter,
-            'tools': parallel_filter,
+            'tools': tools_filter,
         }
 
         root_deps_mk = Makefile()
 
         # Fill the dependencies for traversal of each tier.
         for tier, filter in filters.items():
             main, all_deps = \
                 self._traversal.compute_dependencies(filter)
--- a/testing/mochitest/runtests.py
+++ b/testing/mochitest/runtests.py
@@ -359,17 +359,17 @@ class MochitestUtilsMixin(object):
       # Bug 883865 - add this functionality into manifestDestiny
       with open('tests.json', 'w') as manifestFile:
         manifestFile.write(json.dumps({'tests': paths}))
       options.manifestFile = 'tests.json'
 
     testHost = "http://mochi.test:8888"
     testURL = ("/").join([testHost, self.TEST_PATH, options.testPath])
     if os.path.isfile(os.path.join(self.oldcwd, os.path.dirname(__file__), self.TEST_PATH, options.testPath)) and options.repeat > 0:
-       testURL = ("/").join([testHost, self.PLAIN_LOOP_PATH])
+       testURL = ("/").join([testHost, self.TEST_PATH, os.path.dirname(options.testPath)])
     if options.chrome or options.a11y:
        testURL = ("/").join([testHost, self.CHROME_PATH])
     elif options.browserChrome:
       testURL = "about:blank"
     elif options.ipcplugins:
       testURL = ("/").join([testHost, self.TEST_PATH, "dom/plugins/test"])
     return testURL
 
--- a/toolkit/library/Makefile.in
+++ b/toolkit/library/Makefile.in
@@ -406,33 +406,32 @@ endif
 
 EXTRA_DSO_LDOPTS += $(call EXPAND_LIBNAME_PATH,gkmedias,$(DIST)/lib)
 
 ifdef MOZ_WEBRTC
 ifdef MOZ_PEERCONNECTION
 COMPONENT_LIBS += peerconnection
 endif
 ifdef MOZ_WEBRTC_SIGNALING
-EXTRA_DSO_LDOPTS += \
+SHARED_LIBRARY_LIBS += \
   $(DEPTH)/media/mtransport/build/$(LIB_PREFIX)mtransport.$(LIB_SUFFIX) \
   $(DEPTH)/media/webrtc/signaling/signaling_ecc/$(LIB_PREFIX)ecc.$(LIB_SUFFIX) \
   $(DEPTH)/media/webrtc/signaling/signaling_sipcc/$(LIB_PREFIX)sipcc.$(LIB_SUFFIX) \
   $(NULL)
 endif
-ifdef MOZ_WEBRTC_IN_LIBXUL
-include $(topsrcdir)/media/webrtc/shared_libs.mk
-EXTRA_DSO_LDOPTS += $(WEBRTC_LIBS)
+
+SHARED_LIBRARY_LIBS += $(call EXPAND_LIBNAME_PATH,webrtc,$(DEPTH)/layout/media/webrtc)
+
 ifeq (WINNT,$(OS_TARGET))
 EXTRA_DSO_LDOPTS += \
   -LIBPATH:"$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)" \
   $(NULL)
 OS_LIBS += $(call EXPAND_LIBNAME,secur32 crypt32 iphlpapi strmiids dmoguids wmcodecdspuuid amstrmid msdmo wininet)
 endif
 endif
-endif
 
 
 ifdef MOZ_CUBEB
 ifdef MOZ_ALSA
 EXTRA_DSO_LDOPTS += $(MOZ_ALSA_LIBS)
 endif
 ifdef MOZ_PULSEAUDIO
 EXTRA_DSO_LDOPTS += $(MOZ_PULSEAUDIO_LIBS)
@@ -580,17 +579,17 @@ endif
 EXTRA_DSO_LDOPTS += -DELAYLOAD:API-MS-WIN-CORE-WINRT-L$(CRTEXPDLLVERSION).DLL
 EXTRA_DSO_LDOPTS += -DELAYLOAD:API-MS-WIN-CORE-WINRT-STRING-L$(CRTEXPDLLVERSION).DLL
 EXTRA_DSO_LDOPTS += -DELAYLOAD:uiautomationcore.dll
 endif
 
 ifdef ACCESSIBILITY
 EXTRA_DSO_LDOPTS += -DELAYLOAD:oleacc.dll
 endif
-ifdef MOZ_WEBRTC_IN_LIBXUL
+ifdef MOZ_WEBRTC
 EXTRA_DSO_LDOPTS += -DELAYLOAD:msdmo.dll
 endif
 endif
 ifdef MOZ_GAMEPAD
 ifndef GNU_CC
 DXSDK := $(subst \,/,$(MOZ_DIRECTX_SDK_PATH))/Lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)
 OS_LIBS += \
   "$(DXSDK)/dxguid.lib" \
--- a/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_cache.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_cache.js
@@ -401,18 +401,28 @@ const WITH_EXTENSION_CACHE = [{
   },
   screenshots:            [{ get url () { return get_subfile_uri(ADDON_IDS[2], "preview.png"); } }],
   sourceURI:              NetUtil.newURI(ADDON_FILES[2]).spec
 }];
 
 
 /*
  * Trigger an AddonManager background update check
+ *
+ * @param  aCallback
+ *         Callback to call once the background update is complete
  */
-function trigger_background_update() {
+function trigger_background_update(aCallback) {
+  Services.obs.addObserver({
+    observe: function(aSubject, aTopic, aData) {
+      Services.obs.removeObserver(this, "addons-background-update-complete");
+      do_execute_soon(aCallback);
+    }
+  }, "addons-background-update-complete", false);
+
   gInternalManager.notify(null);
 }
 
 /*
  * Check whether or not the add-ons database exists
  *
  * @param  aExpectedExists
  *         Whether or not the database is expected to exist
@@ -692,31 +702,25 @@ function run_test_12() {
 }
 
 // Tests that a background update with caching disabled deletes the add-ons
 // database, and that XPI add-ons still do not use any of repository properties
 function run_test_13() {
   check_database_exists(true);
   Services.prefs.setCharPref(PREF_GETADDONS_BYIDS_PERF, GETADDONS_EMPTY);
 
-  Services.obs.addObserver({
-    observe: function(aSubject, aTopic, aData) {
-      Services.obs.removeObserver(this, "addons-background-update-complete");
-
-      // Database should have been deleted with the background update.
-      check_database_exists(false);
+  trigger_background_update(function() {
+    // Database should have been deleted
+    check_database_exists(false);
 
-      AddonManager.getAddonsByIDs(ADDON_IDS, function(aAddons) {
-        check_results(aAddons, WITHOUT_CACHE);
-        do_execute_soon(run_test_14);
-      });
-    }
-  }, "addons-background-update-complete", false);
-
-  trigger_background_update();
+    AddonManager.getAddonsByIDs(ADDON_IDS, function(aAddons) {
+      check_results(aAddons, WITHOUT_CACHE);
+      do_execute_soon(run_test_14);
+    });
+  });
 }
 
 // Tests that the XPI add-ons have the correct properties if caching is
 // enabled but has no information
 function run_test_14() {
   Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true);
 
   waitForFlushedData(function() {
@@ -731,24 +735,22 @@ function run_test_14() {
   trigger_background_update();
 }
 
 // Tests that the XPI add-ons correctly use the repository properties when
 // caching is enabled and the repository information is available
 function run_test_15() {
   Services.prefs.setCharPref(PREF_GETADDONS_BYIDS_PERF, GETADDONS_RESULTS);
 
-  waitForFlushedData(function() {
+  trigger_background_update(function() {
     AddonManager.getAddonsByIDs(ADDON_IDS, function(aAddons) {
       check_results(aAddons, WITH_CACHE);
       do_execute_soon(run_test_16);
     });
   });
-
-  trigger_background_update();
 }
 
 // Tests that restarting the manager does not change the checked properties
 // on the XPI add-ons (repository properties still exist and are still properly
 // used)
 function run_test_16() {
   restartManager();
 
@@ -757,18 +759,16 @@ function run_test_16() {
     do_execute_soon(run_test_17);
   });
 }
 
 // Tests that setting a list of types to cache works
 function run_test_17() {
   Services.prefs.setCharPref(PREF_GETADDONS_CACHE_TYPES, "foo,bar,extension,baz");
 
-  waitForFlushedData(function() {
+  trigger_background_update(function() {
     AddonManager.getAddonsByIDs(ADDON_IDS, function(aAddons) {
       check_results(aAddons, WITH_EXTENSION_CACHE);
       end_test();
     });
   });
-
-  trigger_background_update();
 }