Bug 1118084 - Remove self-hosted and user-exposed PJS methods. (r=lth)
authorShu-yu Guo <shu@rfrn.org>
Fri, 09 Jan 2015 00:06:03 -0800
changeset 222905 68d1c3fd25f1fbbb5b8910a41ff0a691c0eae371
parent 222904 5f8dbb4956752d9759c92ac84b37c79d046805d2
child 222906 46c80c517631bd66053a9a84f8419329f7891935
push id10731
push usercbook@mozilla.com
push dateFri, 09 Jan 2015 14:51:37 +0000
treeherderfx-team@e6756043d930 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslth
bugs1118084
milestone37.0a1
Bug 1118084 - Remove self-hosted and user-exposed PJS methods. (r=lth)
js/src/Makefile.in
js/src/builtin/Array.js
js/src/builtin/ParallelUtilities.js
js/src/builtin/TestingFunctions.cpp
js/src/builtin/TypedObject.cpp
js/src/builtin/TypedObject.js
js/src/builtin/Utilities.js
js/src/jit-test/tests/ion/inlining/TypedObject-TypeDescrIsSizedArrayType.js
js/src/js.msg
js/src/jsarray.cpp
js/src/tests/ecma_7/TypedObject/method_scatter.js
js/src/vm/SelfHosting.cpp
js/src/vm/Xdr.h
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -308,17 +308,16 @@ ifdef HAVE_DTRACE
 endif
 
 # Prepare self-hosted JS code for embedding
 export:: selfhosting
 selfhosting:: selfhosted.out.h
 
 selfhosting_srcs := \
   $(srcdir)/builtin/Utilities.js \
-  $(srcdir)/builtin/ParallelUtilities.js \
   $(srcdir)/builtin/Array.js \
   $(srcdir)/builtin/Date.js \
   $(srcdir)/builtin/Error.js \
   $(srcdir)/builtin/Generator.js \
   $(srcdir)/builtin/Intl.js \
   $(srcdir)/builtin/IntlData.js \
   $(srcdir)/builtin/Iterator.js \
   $(srcdir)/builtin/Map.js \
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -777,531 +777,8 @@ function ArrayFrom(arrayLike, mapfn=unde
             _DefineDataProperty(A, k, mappedValue, attrs);
         }
     }
 
     // Steps 8.g.iv.1-3 and 18-20 are the same.
     A.length = k;
     return A;
 }
-
-#ifdef ENABLE_PARALLEL_JS
-
-/*
- * Strawman spec:
- *   http://wiki.ecmascript.org/doku.php?id=strawman:data_parallelism
- */
-
-/**
- * Creates a new array by applying |func(e, i, self)| for each element |e|
- * with index |i|.
- */
-function ArrayMapPar(func, mode) {
-  if (!IsCallable(func))
-    ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, func));
-
-  var self = ToObject(this);
-  var length = self.length;
-  var buffer = NewDenseArray(length);
-
-  parallel: for (;;) {
-    // Avoid parallel compilation if we are already nested in another
-    // parallel section or the user told us not to parallelize. The
-    // use of a for (;;) loop is working around some ion limitations:
-    //
-    // - Breaking out of named blocks does not currently work (bug 684384);
-    // - Unreachable Code Elim. can't properly handle if (a && b) (bug 669796)
-    if (ShouldForceSequential())
-      break parallel;
-    if (!TRY_PARALLEL(mode))
-      break parallel;
-
-    var slicesInfo = ComputeSlicesInfo(length);
-    ForkJoin(mapThread, 0, slicesInfo.count, ForkJoinMode(mode), buffer);
-    return buffer;
-  }
-
-  // Sequential fallback:
-  ASSERT_SEQUENTIAL_IS_OK(mode);
-  for (var i = 0; i < length; i++)
-    UnsafePutElements(buffer, i, func(self[i], i, self));
-  return buffer;
-
-  function mapThread(workerId, sliceStart, sliceEnd) {
-    var sliceShift = slicesInfo.shift;
-    var sliceId;
-    while (GET_SLICE(sliceStart, sliceEnd, sliceId)) {
-      var indexStart = SLICE_START_INDEX(sliceShift, sliceId);
-      var indexEnd = SLICE_END_INDEX(sliceShift, indexStart, length);
-      for (var i = indexStart; i < indexEnd; i++)
-        UnsafePutElements(buffer, i, func(self[i], i, self));
-    }
-    return sliceId;
-  }
-}
-
-/**
- * Reduces the elements in an array in parallel. Order is not fixed and |func|
- * is assumed to be associative.
- */
-function ArrayReducePar(func, mode) {
-  if (!IsCallable(func))
-    ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, func));
-
-  var self = ToObject(this);
-  var length = self.length;
-
-  if (length === 0)
-    ThrowError(JSMSG_EMPTY_ARRAY_REDUCE);
-
-  parallel: for (;;) { // see ArrayMapPar() to explain why for(;;) etc
-    if (ShouldForceSequential())
-      break parallel;
-    if (!TRY_PARALLEL(mode))
-      break parallel;
-
-    var slicesInfo = ComputeSlicesInfo(length);
-    var numSlices = slicesInfo.count;
-    var subreductions = NewDenseArray(numSlices);
-
-    ForkJoin(reduceThread, 0, numSlices, ForkJoinMode(mode), subreductions);
-
-    var accumulator = subreductions[0];
-    for (var i = 1; i < numSlices; i++)
-      accumulator = func(accumulator, subreductions[i]);
-    return accumulator;
-  }
-
-  // Sequential fallback:
-  ASSERT_SEQUENTIAL_IS_OK(mode);
-  var accumulator = self[0];
-  for (var i = 1; i < length; i++)
-    accumulator = func(accumulator, self[i]);
-  return accumulator;
-
-  function reduceThread(workerId, sliceStart, sliceEnd) {
-    var sliceShift = slicesInfo.shift;
-    var sliceId;
-    while (GET_SLICE(sliceStart, sliceEnd, sliceId)) {
-      var indexStart = SLICE_START_INDEX(sliceShift, sliceId);
-      var indexEnd = SLICE_END_INDEX(sliceShift, indexStart, length);
-      var accumulator = self[indexStart];
-      for (var i = indexStart + 1; i < indexEnd; i++)
-        accumulator = func(accumulator, self[i]);
-      UnsafePutElements(subreductions, sliceId, accumulator);
-    }
-    return sliceId;
-  }
-}
-
-/**
- * Returns an array [s_0, ..., s_N] where |s_i| is equal to the reduction (as
- * per |reduce()|) of elements |0..i|. This is the generalization of partial
- * sum.
- */
-function ArrayScanPar(func, mode) {
-  if (!IsCallable(func))
-    ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, func));
-
-  var self = ToObject(this);
-  var length = self.length;
-
-  if (length === 0)
-    ThrowError(JSMSG_EMPTY_ARRAY_REDUCE);
-
-  // We need two buffers because phase2() will read an intermediate result and
-  // write a final result; that is safe against bailout-and-restart only if
-  // the intermediate and final buffers are distinct.  (Bug 1023755)
-  // Obviously paying for a second buffer is undesirable.
-  var buffer = NewDenseArray(length);
-  var buffer2 = NewDenseArray(length);
-
-  parallel: for (;;) { // see ArrayMapPar() to explain why for(;;) etc
-    if (ShouldForceSequential())
-      break parallel;
-    if (!TRY_PARALLEL(mode))
-      break parallel;
-
-    var slicesInfo = ComputeSlicesInfo(length);
-    var numSlices = slicesInfo.count;
-
-    // Scan slices individually (see comment on phase1()).
-    ForkJoin(phase1, 0, numSlices, ForkJoinMode(mode), buffer);
-
-    // Compute intermediates array (see comment on phase2()).
-    var intermediates = [];
-    var accumulator = buffer[finalElement(0)];
-    ARRAY_PUSH(intermediates, accumulator);
-    for (var i = 1; i < numSlices - 1; i++) {
-      accumulator = func(accumulator, buffer[finalElement(i)]);
-      ARRAY_PUSH(intermediates, accumulator);
-    }
-
-    // Complete each slice using intermediates array (see comment on phase2()).
-    //
-    // Slice 0 must be handled specially - it's just a copy - since we don't
-    // have an identity value for the operation.
-    for ( var k=0, limit=finalElement(0) ; k <= limit ; k++ )
-      buffer2[k] = buffer[k];
-    ForkJoin(phase2, 1, numSlices, ForkJoinMode(mode), buffer2);
-    return buffer2;
-  }
-
-  // Sequential fallback:
-  ASSERT_SEQUENTIAL_IS_OK(mode);
-  scan(self[0], 0, length);
-  return buffer;
-
-  function scan(accumulator, start, end) {
-    UnsafePutElements(buffer, start, accumulator);
-    for (var i = start + 1; i < end; i++) {
-      accumulator = func(accumulator, self[i]);
-      UnsafePutElements(buffer, i, accumulator);
-    }
-    return accumulator;
-  }
-
-  /**
-   * In phase 1, we divide the source array into |numSlices| slices and
-   * compute scan on each slice sequentially as if it were the entire
-   * array. This function is responsible for computing one of those
-   * slices.
-   *
-   * So, if we have an array [A,B,C,D,E,F,G,H,I], |numSlices === 3|,
-   * and our function |func| is sum, then we would wind up computing a
-   * result array like:
-   *
-   *     [A, A+B, A+B+C, D, D+E, D+E+F, G, G+H, G+H+I]
-   *      ^~~~~~~~~~~~^  ^~~~~~~~~~~~^  ^~~~~~~~~~~~~^
-   *      Slice 0        Slice 1        Slice 2
-   *
-   * Read on in phase2 to see what we do next!
-   */
-  function phase1(workerId, sliceStart, sliceEnd) {
-    var sliceShift = slicesInfo.shift;
-    var sliceId;
-    while (GET_SLICE(sliceStart, sliceEnd, sliceId)) {
-      var indexStart = SLICE_START_INDEX(sliceShift, sliceId);
-      var indexEnd = SLICE_END_INDEX(sliceShift, indexStart, length);
-      scan(self[indexStart], indexStart, indexEnd);
-    }
-    return sliceId;
-  }
-
-  /**
-   * Computes the index of the final element computed by the slice |sliceId|.
-   */
-  function finalElement(sliceId) {
-    var sliceShift = slicesInfo.shift;
-    return SLICE_END_INDEX(sliceShift, SLICE_START_INDEX(sliceShift, sliceId), length) - 1;
-  }
-
-  /**
-   * After computing the phase1 results, we compute an
-   * |intermediates| array. |intermediates[i]| contains the result
-   * of reducing the final value from each preceding slice j<i with
-   * the final value of slice i. So, to continue our previous
-   * example, the intermediates array would contain:
-   *
-   *   [A+B+C, (A+B+C)+(D+E+F), ((A+B+C)+(D+E+F))+(G+H+I)]
-   *
-   * Here I have used parenthesization to make clear the order of
-   * evaluation in each case.
-   *
-   *   An aside: currently the intermediates array is computed
-   *   sequentially. In principle, we could compute it in parallel,
-   *   at the cost of doing duplicate work. This did not seem
-   *   particularly advantageous to me, particularly as the number
-   *   of slices is typically quite small (one per core), so I opted
-   *   to just compute it sequentially.
-   *
-   * Phase 2 combines the results of phase1 with the intermediates
-   * array to produce the final scan results. The idea is to
-   * reiterate over each element S[i] in the slice |sliceId|, which
-   * currently contains the result of reducing with S[0]...S[i]
-   * (where S0 is the first thing in the slice), and combine that
-   * with |intermediate[sliceId-1]|, which represents the result of
-   * reducing everything in the input array prior to the slice.
-   *
-   * To continue with our example, in phase 1 we computed slice 1 to
-   * be [D, D+E, D+E+F]. We will combine those results with
-   * |intermediates[1-1]|, which is |A+B+C|, so that the final
-   * result is [(A+B+C)+D, (A+B+C)+(D+E), (A+B+C)+(D+E+F)]. Again I
-   * am using parentheses to clarify how these results were reduced.
-   */
-  function phase2(workerId, sliceStart, sliceEnd) {
-    var sliceShift = slicesInfo.shift;
-    var sliceId;
-    while (GET_SLICE(sliceStart, sliceEnd, sliceId)) {
-      var indexPos = SLICE_START_INDEX(sliceShift, sliceId);
-      var indexEnd = SLICE_END_INDEX(sliceShift, indexPos, length);
-      var intermediate = intermediates[sliceId - 1];
-      for (; indexPos < indexEnd; indexPos++)
-        UnsafePutElements(buffer2, indexPos, func(intermediate, buffer[indexPos]));
-    }
-    return sliceId;
-  }
-}
-
-/**
- * |scatter()| redistributes the elements in the array into a new array.
- *
- * - targets: The index targets[i] indicates where the ith element
- *   should appear in the result.
- *
- * - defaultValue: what value to use for indices in the output array that
- *   are never targeted.
- *
- * - conflictFunc: The conflict function. Used to resolve what
- *   happens if two indices i and j in the source array are targeted
- *   as the same destination (i.e., targets[i] === targets[j]), then
- *   the final result is determined by applying func(targets[i],
- *   targets[j]). If no conflict function is provided, it is an error
- *   if targets[i] === targets[j].
- *
- * - length: length of the output array (if not specified, uses the
- *   length of the input).
- *
- * - mode: internal debugging specification.
- */
-function ArrayScatterPar(targets, defaultValue, conflictFunc, length, mode) {
-  if (conflictFunc && !IsCallable(conflictFunc))
-    ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(2, conflictFunc));
-
-  var self = ToObject(this);
-
-  if (length === undefined)
-    length = self.length;
-
-  var targetsLength = std_Math_min(targets.length, self.length);
-
-  if (!IS_UINT32(targetsLength) || !IS_UINT32(length))
-    ThrowError(JSMSG_BAD_ARRAY_LENGTH);
-
-  // FIXME: Bug 965609: Find a better parallel startegy for scatter.
-
-  // Sequential fallback:
-  ASSERT_SEQUENTIAL_IS_OK(mode);
-  return seq();
-
-  function seq() {
-    var buffer = NewDenseArray(length);
-    var conflicts = NewDenseArray(length);
-
-    for (var i = 0; i < length; i++) {
-      UnsafePutElements(buffer, i, defaultValue);
-      UnsafePutElements(conflicts, i, false);
-    }
-
-    for (var i = 0; i < targetsLength; i++) {
-      var x = self[i];
-      var t = checkTarget(i, targets[i]);
-      if (conflicts[t])
-        x = collide(x, buffer[t]);
-
-      UnsafePutElements(buffer, t, x, conflicts, t, true);
-    }
-
-    return buffer;
-  }
-
-  function collide(elem1, elem2) {
-    if (conflictFunc === undefined)
-      ThrowError(JSMSG_PAR_ARRAY_SCATTER_CONFLICT);
-
-    return conflictFunc(elem1, elem2);
-  }
-
-  function checkTarget(i, t) {
-    if (TO_INT32(t) !== t)
-      ThrowError(JSMSG_PAR_ARRAY_SCATTER_BAD_TARGET, i);
-
-    if (t < 0 || t >= length)
-      ThrowError(JSMSG_PAR_ARRAY_SCATTER_BOUNDS);
-
-    // It's not enough to return t, as -0 | 0 === -0.
-    return TO_INT32(t);
-  }
-}
-
-/**
- * The filter operation applied in parallel.
- */
-function ArrayFilterPar(func, mode) {
-  if (!IsCallable(func))
-    ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, func));
-
-  var self = ToObject(this);
-  var length = self.length;
-
-  parallel: for (;;) { // see ArrayMapPar() to explain why for(;;) etc
-    if (ShouldForceSequential())
-      break parallel;
-    if (!TRY_PARALLEL(mode))
-      break parallel;
-
-    var slicesInfo = ComputeSlicesInfo(length);
-
-    // Step 1. Compute which items from each slice of the result buffer should
-    // be preserved. When we're done, we have a uint8 array |survivors|
-    // containing 0 or 1 for each source element, indicating which members of
-    // the chunk survived. We also keep an array |counts| containing the total
-    // number of items that are being preserved from within one slice.
-    var numSlices = slicesInfo.count;
-    var counts = NewDenseArray(numSlices);
-    for (var i = 0; i < numSlices; i++)
-      UnsafePutElements(counts, i, 0);
-
-    var survivors = new Uint8Array(length);
-    ForkJoin(findSurvivorsThread, 0, numSlices, ForkJoinMode(mode), survivors);
-
-    // Step 2. Compress the slices into one contiguous set.
-    var count = 0;
-    for (var i = 0; i < numSlices; i++)
-      count += counts[i];
-    var buffer = NewDenseArray(count);
-    if (count > 0)
-      ForkJoin(copySurvivorsThread, 0, numSlices, ForkJoinMode(mode), buffer);
-
-    return buffer;
-  }
-
-  // Sequential fallback:
-  ASSERT_SEQUENTIAL_IS_OK(mode);
-  var buffer = [];
-  for (var i = 0; i < length; i++) {
-    var elem = self[i];
-    if (func(elem, i, self))
-      ARRAY_PUSH(buffer, elem);
-  }
-  return buffer;
-
-  /**
-   * As described above, our goal is to determine which items we will preserve
-   * from a given slice, storing "to-keep" bits into 32-bit chunks.
-   */
-  function findSurvivorsThread(workerId, sliceStart, sliceEnd) {
-    var sliceShift = slicesInfo.shift;
-    var sliceId;
-    while (GET_SLICE(sliceStart, sliceEnd, sliceId)) {
-      var count = 0;
-      var indexStart = SLICE_START_INDEX(sliceShift, sliceId);
-      var indexEnd = SLICE_END_INDEX(sliceShift, indexStart, length);
-      for (var indexPos = indexStart; indexPos < indexEnd; indexPos++) {
-        var keep = !!func(self[indexPos], indexPos, self);
-        UnsafePutElements(survivors, indexPos, keep);
-        count += keep;
-      }
-      UnsafePutElements(counts, sliceId, count);
-    }
-    return sliceId;
-  }
-
-  /**
-   * Copies the survivors from this slice into the correct position. Note
-   * that this is an idempotent operation that does not invoke user
-   * code. Therefore, we don't expect bailouts and make an effort to proceed
-   * chunk by chunk or avoid duplicating work.
-   */
-  function copySurvivorsThread(workerId, sliceStart, sliceEnd) {
-    var sliceShift = slicesInfo.shift;
-    var sliceId;
-    while (GET_SLICE(sliceStart, sliceEnd, sliceId)) {
-      // Total up the items preserved by previous slices.
-      var total = 0;
-      for (var i = 0; i < sliceId + 1; i++)
-        total += counts[i];
-
-      // Are we done?
-      var count = total - counts[sliceId];
-      if (count === total)
-        continue;
-
-      var indexStart = SLICE_START_INDEX(sliceShift, sliceId);
-      var indexEnd = SLICE_END_INDEX(sliceShift, indexStart, length);
-      for (var indexPos = indexStart; indexPos < indexEnd; indexPos++) {
-        if (survivors[indexPos]) {
-          UnsafePutElements(buffer, count++, self[indexPos]);
-          if (count == total)
-            break;
-        }
-      }
-    }
-
-    return sliceId;
-  }
-}
-
-/**
- * "Comprehension form": This is the function invoked for
- * |Array.{build,buildPar}(len, fn)| It creates a new array with length |len|
- * where index |i| is equal to |fn(i)|.
- *
- * The final |mode| argument is an internal argument used only during our
- * unit-testing.
- */
-function ArrayStaticBuild(length, func) {
-  if (!IS_UINT32(length))
-    ThrowError(JSMSG_BAD_ARRAY_LENGTH);
-  if (!IsCallable(func))
-    ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(1, func));
-
-  var buffer = NewDenseArray(length);
-
-  for (var i = 0; i < length; i++)
-    UnsafePutElements(buffer, i, func(i));
-
-  return buffer;
-}
-
-function ArrayStaticBuildPar(length, func, mode) {
-  if (!IS_UINT32(length))
-    ThrowError(JSMSG_BAD_ARRAY_LENGTH);
-  if (!IsCallable(func))
-    ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(1, func));
-
-  var buffer = NewDenseArray(length);
-
-  parallel: for (;;) {
-    if (ShouldForceSequential())
-      break parallel;
-    if (!TRY_PARALLEL(mode))
-      break parallel;
-
-    var slicesInfo = ComputeSlicesInfo(length);
-    ForkJoin(constructThread, 0, slicesInfo.count, ForkJoinMode(mode), buffer);
-    return buffer;
-  }
-
-  // Sequential fallback:
-  ASSERT_SEQUENTIAL_IS_OK(mode);
-  for (var i = 0; i < length; i++)
-    UnsafePutElements(buffer, i, func(i));
-  return buffer;
-
-  function constructThread(workerId, sliceStart, sliceEnd) {
-    var sliceShift = slicesInfo.shift;
-    var sliceId;
-    while (GET_SLICE(sliceStart, sliceEnd, sliceId)) {
-      var indexStart = SLICE_START_INDEX(sliceShift, sliceId);
-      var indexEnd = SLICE_END_INDEX(sliceShift, indexStart, length);
-      for (var i = indexStart; i < indexEnd; i++)
-        UnsafePutElements(buffer, i, func(i));
-    }
-    return sliceId;
-  }
-}
-
-/*
- * Mark the main operations as clone-at-callsite for better precision.
- * This is slightly overkill, as all that we really need is to
- * specialize to the receiver and the elemental function, but in
- * practice this is likely not so different, since element functions
- * are often used in exactly one place.
- */
-SetScriptHints(ArrayMapPar,         { cloneAtCallsite: true });
-SetScriptHints(ArrayReducePar,      { cloneAtCallsite: true });
-SetScriptHints(ArrayScanPar,        { cloneAtCallsite: true });
-SetScriptHints(ArrayScatterPar,     { cloneAtCallsite: true });
-SetScriptHints(ArrayFilterPar,      { cloneAtCallsite: true });
-SetScriptHints(ArrayStaticBuildPar, { cloneAtCallsite: true });
-
-#endif /* ENABLE_PARALLEL_JS */
deleted file mode 100644
--- a/js/src/builtin/ParallelUtilities.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/* 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 utility functions for and macros parallel operations in `Array.js`
-// and `TypedObject.js`.
-
-#ifdef ENABLE_PARALLEL_JS
-
-/* The mode asserts options object. */
-#define TRY_PARALLEL(MODE) \
-  ((!MODE || MODE.mode !== "seq"))
-#define ASSERT_SEQUENTIAL_IS_OK(MODE) \
-  do { if (MODE) AssertSequentialIsOK(MODE) } while(false)
-
-/**
- * The ParallelSpew intrinsic is only defined in debug mode, so define a dummy
- * if debug is not on.
- */
-#ifndef DEBUG
-#define ParallelSpew(args)
-#endif
-
-#define MAX_SLICE_SHIFT 6
-#define MAX_SLICE_SIZE 64
-#define MAX_SLICES_PER_WORKER 8
-
-/**
- * Macros to help compute the start and end indices of slices based on id. Use
- * with the object returned by ComputeSliceInfo.
- */
-#define SLICE_START_INDEX(shift, id) \
-    (id << shift)
-#define SLICE_END_INDEX(shift, start, length) \
-    std_Math_min(start + (1 << shift), length)
-
-/**
- * ForkJoinGetSlice acts as identity when we are not in a parallel section, so
- * pass in the next sequential value when we are in sequential mode. The
- * reason for this odd API is because intrinsics *need* to be called during
- * ForkJoin's warmup to fill the TI info.
- */
-#define GET_SLICE(sliceStart, sliceEnd, id) \
-    ((id = ForkJoinGetSlice((InParallelSection() ? -1 : sliceStart++) | 0)) < sliceEnd)
-
-/**
- * Determine the number and size of slices. The info object has the following
- * properties:
- *
- *  - shift: amount to shift by to compute indices
- *  - count: number of slices
- */
-function ComputeSlicesInfo(length) {
-  var count = length >>> MAX_SLICE_SHIFT;
-  var numWorkers = ForkJoinNumWorkers();
-  if (count < numWorkers)
-    count = numWorkers;
-  else if (count >= numWorkers * MAX_SLICES_PER_WORKER)
-    count = numWorkers * MAX_SLICES_PER_WORKER;
-
-  // Round the slice size to be a power of 2.
-  var shift = std_Math_max(std_Math_log2(length / count) | 0, 1);
-
-  // Recompute count with the rounded size.
-  count = length >>> shift;
-  if (count << shift !== length)
-    count += 1;
-
-  return { shift: shift, count: count };
-}
-
-#endif // ENABLE_PARALLEL_JS
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -164,24 +164,16 @@ GetBuildConfiguration(JSContext *cx, uns
 #ifdef JS_OOM_DO_BACKTRACES
     value = BooleanValue(true);
 #else
     value = BooleanValue(false);
 #endif
     if (!JS_SetProperty(cx, info, "oom-backtraces", value))
         return false;
 
-#ifdef ENABLE_PARALLEL_JS
-    value = BooleanValue(true);
-#else
-    value = BooleanValue(false);
-#endif
-    if (!JS_SetProperty(cx, info, "parallelJS", value))
-        return false;
-
 #ifdef ENABLE_BINARYDATA
     value = BooleanValue(true);
 #else
     value = BooleanValue(false);
 #endif
     if (!JS_SetProperty(cx, info, "binary-data", value))
         return false;
 
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -500,37 +500,30 @@ const JSPropertySpec ArrayMetaTypeDescr:
     JS_PS_END
 };
 
 const JSFunctionSpec ArrayMetaTypeDescr::typeObjectMethods[] = {
     {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"},
     JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
     {"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"},
     JS_SELF_HOSTED_FN("build",    "TypedObjectArrayTypeBuild", 3, 0),
-    JS_SELF_HOSTED_FN("buildPar", "TypedObjectArrayTypeBuildPar", 3, 0),
     JS_SELF_HOSTED_FN("from",     "TypedObjectArrayTypeFrom", 3, 0),
-    JS_SELF_HOSTED_FN("fromPar",  "TypedObjectArrayTypeFromPar", 3, 0),
     JS_FS_END
 };
 
 const JSPropertySpec ArrayMetaTypeDescr::typedObjectProperties[] = {
     JS_PS_END
 };
 
 const JSFunctionSpec ArrayMetaTypeDescr::typedObjectMethods[] = {
     {"forEach", {nullptr, nullptr}, 1, 0, "ArrayForEach"},
     {"redimension", {nullptr, nullptr}, 1, 0, "TypedObjectArrayRedimension"},
     JS_SELF_HOSTED_FN("map",        "TypedObjectArrayMap",        2, 0),
-    JS_SELF_HOSTED_FN("mapPar",     "TypedObjectArrayMapPar",     2, 0),
     JS_SELF_HOSTED_FN("reduce",     "TypedObjectArrayReduce",     2, 0),
-    JS_SELF_HOSTED_FN("reducePar",  "TypedObjectArrayReducePar",  2, 0),
-    JS_SELF_HOSTED_FN("scatter",    "TypedObjectArrayScatter",    4, 0),
-    JS_SELF_HOSTED_FN("scatterPar", "TypedObjectArrayScatterPar", 4, 0),
     JS_SELF_HOSTED_FN("filter",     "TypedObjectArrayFilter",     1, 0),
-    JS_SELF_HOSTED_FN("filterPar",  "TypedObjectArrayFilterPar",  1, 0),
     JS_FS_END
 };
 
 bool
 js::CreateUserSizeAndAlignmentProperties(JSContext *cx, HandleTypeDescr descr)
 {
     // If data is transparent, also store the public slots.
     if (descr->transparent()) {
--- a/js/src/builtin/TypedObject.js
+++ b/js/src/builtin/TypedObject.js
@@ -642,124 +642,46 @@ function TypedObjectArrayMap(a, b) {
   if (typeof a === "number" && typeof b === "function")
     return MapTypedSeqImpl(this, a, thisType, b);
   else if (typeof a === "function")
     return MapTypedSeqImpl(this, 1, thisType, a);
   ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
 }
 
 // Warning: user exposed!
-function TypedObjectArrayMapPar(a, b) {
-  // Arguments: [depth], func
-
-  // Defer to the sequential variant for error cases or
-  // when not working with typed objects.
-  if (!IsObject(this) || !ObjectIsTypedObject(this))
-    return callFunction(TypedObjectArrayMap, this, a, b);
-  var thisType = TypedObjectTypeDescr(this);
-  if (!TypeDescrIsArrayType(thisType))
-    return callFunction(TypedObjectArrayMap, this, a, b);
-
-  if (typeof a === "number" && IsCallable(b))
-    return MapTypedParImpl(this, a, thisType, b);
-  else if (IsCallable(a))
-    return MapTypedParImpl(this, 1, thisType, a);
-  return callFunction(TypedObjectArrayMap, this, a, b);
-}
-
-// Warning: user exposed!
 function TypedObjectArrayReduce(a, b) {
   // Arguments: func, [initial]
   if (!IsObject(this) || !ObjectIsTypedObject(this))
     ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
   var thisType = TypedObjectTypeDescr(this);
   if (!TypeDescrIsArrayType(thisType))
     ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
 
   if (a !== undefined && typeof a !== "function")
     ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
 
   var outputType = thisType.elementType;
   return ReduceTypedSeqImpl(this, outputType, a, b);
 }
 
 // Warning: user exposed!
-function TypedObjectArrayScatter(a, b, c, d) {
-  // Arguments: outputArrayType, indices, defaultValue, conflictFunction
-  if (!IsObject(this) || !ObjectIsTypedObject(this))
-    ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
-  var thisType = TypedObjectTypeDescr(this);
-  if (!TypeDescrIsArrayType(thisType))
-    ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
-
-  if (!IsObject(a) || !ObjectIsTypeDescr(a) || !TypeDescrIsArrayType(a))
-    ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
-
-  if (d !== undefined && typeof d !== "function")
-    ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
-
-  return ScatterTypedSeqImpl(this, a, b, c, d);
-}
-
-// Warning: user exposed!
 function TypedObjectArrayFilter(func) {
   // Arguments: predicate
   if (!IsObject(this) || !ObjectIsTypedObject(this))
     ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
   var thisType = TypedObjectTypeDescr(this);
   if (!TypeDescrIsArrayType(thisType))
     ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
 
   if (typeof func !== "function")
     ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
 
   return FilterTypedSeqImpl(this, func);
 }
 
-// placeholders
-
-// Warning: user exposed!
-function TypedObjectArrayTypeBuildPar(a,b,c) {
-  return callFunction(TypedObjectArrayTypeBuild, this, a, b, c);
-}
-
-// Warning: user exposed!
-function TypedObjectArrayTypeFromPar(a,b,c) {
-  // Arguments: arrayLike, [depth], func
-
-  // Use the sequential version for error cases or when arrayLike is
-  // not a typed object.
-  if (!IsObject(this) || !ObjectIsTypeDescr(this) || !TypeDescrIsArrayType(this))
-    return callFunction(TypedObjectArrayTypeFrom, this, a, b, c);
-  if (!IsObject(a) || !ObjectIsTypedObject(a))
-    return callFunction(TypedObjectArrayTypeFrom, this, a, b, c);
-
-  // Detect whether an explicit depth is supplied.
-  if (typeof b === "number" && IsCallable(c))
-    return MapTypedParImpl(a, b, this, c);
-  if (IsCallable(b))
-    return MapTypedParImpl(a, 1, this, b);
-  return callFunction(TypedObjectArrayTypeFrom, this, a, b, c);
-}
-
-// Warning: user exposed!
-function TypedObjectArrayReducePar(a, b) {
-  return callFunction(TypedObjectArrayReduce, this, a, b);
-}
-
-// Warning: user exposed!
-function TypedObjectArrayScatterPar(a, b, c, d) {
-  return callFunction(TypedObjectArrayScatter, this, a, b, c, d);
-}
-
-// Warning: user exposed!
-function TypedObjectArrayFilterPar(func) {
-  return callFunction(TypedObjectArrayFilter, this, func);
-}
-
 // should eventually become macros
 function NUM_BYTES(bits) {
   return (bits + 7) >> 3;
 }
 function SET_BIT(data, index) {
   var word = index >> 3;
   var mask = 1 << (index & 0x7);
   data[word] |= mask;
@@ -1020,218 +942,16 @@ function MapTypedSeqImpl(inArray, depth,
     return DoMapTypedSeqDepth1Simple(inArray, totalLength, func, result);
 
   if (depth == 1)
     return DoMapTypedSeqDepth1();
 
   return DoMapTypedSeqDepthN();
 }
 
-// Implements |map| and |from| methods for typed |inArray|.
-function MapTypedParImpl(inArray, depth, outputType, func) {
-  assert(IsObject(outputType) && ObjectIsTypeDescr(outputType),
-         "Map/From called on non-type-object outputType");
-  assert(IsObject(inArray) && ObjectIsTypedObject(inArray),
-         "Map/From called on non-object or untyped input array.");
-  assert(TypeDescrIsArrayType(outputType),
-         "Map/From called on non array-type outputType");
-  assert(typeof depth === "number",
-         "Map/From called with non-numeric depth");
-  assert(IsCallable(func),
-         "Map/From called on something not callable");
-
-  var inArrayType = TypeOfTypedObject(inArray);
-
-  if (ShouldForceSequential() ||
-      depth <= 0 ||
-      TO_INT32(depth) !== depth ||
-      !TypeDescrIsArrayType(inArrayType) ||
-      !TypeDescrIsArrayType(outputType))
-  {
-    // defer error cases to seq implementation:
-    return MapTypedSeqImpl(inArray, depth, outputType, func);
-  }
-
-  switch (depth) {
-  case 1:
-    return MapTypedParImplDepth1(inArray, inArrayType, outputType, func);
-  default:
-    return MapTypedSeqImpl(inArray, depth, outputType, func);
-  }
-}
-
-function RedirectPointer(typedObj, offset, outputIsScalar) {
-  if (!outputIsScalar || !InParallelSection()) {
-    // ^ Subtle note: always check InParallelSection() last, because
-    // otherwise the other if conditions will not execute during
-    // sequential mode and we will not gather enough type
-    // information.
-
-    // Here `typedObj` represents the input or output pointer we will
-    // pass to the user function. Ideally, we will just update the
-    // offset of `typedObj` in place so that it moves along the
-    // input/output buffer without incurring any allocation costs. But
-    // we can only do this if these changes are invisible to the user.
-    //
-    // Under normal uses, such changes *should* be invisible -- the
-    // in/out pointers are only intended to be used during the
-    // callback and then discarded, but of course in the general case
-    // nothing prevents them from escaping.
-    //
-    // However, if we are in parallel mode, we know that the pointers
-    // will not escape into global state. They could still escape by
-    // being returned into the resulting array, but even that avenue
-    // is impossible if the result array cannot contain objects.
-    //
-    // Therefore, we reuse a pointer if we are both in parallel mode
-    // and we have a transparent output type.  It'd be nice to loosen
-    // this condition later by using fancy ion optimizations that
-    // assume the value won't escape and copy it if it does. But those
-    // don't exist yet. Moreover, checking if the type is transparent
-    // is an overapproximation: users can manually declare opaque
-    // types that nonetheless only contain scalar data.
-
-    typedObj = NewDerivedTypedObject(TypedObjectTypeDescr(typedObj),
-                                     typedObj, 0);
-  }
-
-  SetTypedObjectOffset(typedObj, offset);
-  return typedObj;
-}
-SetScriptHints(RedirectPointer,         { inline: true });
-
-function MapTypedParImplDepth1(inArray, inArrayType, outArrayType, func) {
-  assert(IsObject(inArrayType) && ObjectIsTypeDescr(inArrayType) &&
-         TypeDescrIsArrayType(inArrayType),
-         "DoMapTypedParDepth1: invalid inArrayType");
-  assert(IsObject(outArrayType) && ObjectIsTypeDescr(outArrayType) &&
-         TypeDescrIsArrayType(outArrayType),
-         "DoMapTypedParDepth1: invalid outArrayType");
-  assert(IsObject(inArray) && ObjectIsTypedObject(inArray),
-         "DoMapTypedParDepth1: invalid inArray");
-
-  if (!TypedObjectIsAttached(inArray))
-    ThrowError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED);
-
-  // Determine the grain types of the input and output.
-  const inGrainType = inArrayType.elementType;
-  const outGrainType = outArrayType.elementType;
-  const inGrainTypeSize = DESCR_SIZE(inGrainType);
-  const outGrainTypeSize = DESCR_SIZE(outGrainType);
-  const inGrainTypeIsComplex = !TypeDescrIsSimpleType(inGrainType);
-  const outGrainTypeIsComplex = !TypeDescrIsSimpleType(outGrainType);
-
-  const length = inArray.length;
-  const mode = undefined;
-
-  const outArray = new outArrayType();
-  if (length === 0)
-    return outArray;
-
-  if (outArray.length != length)
-    ThrowError(JSMSG_TYPEDOBJECT_ARRAYTYPE_BAD_ARGS);
-
-  const outGrainTypeIsTransparent = ObjectIsTransparentTypedObject(outArray);
-
-  // Construct the slices and initial pointers for each worker:
-  const slicesInfo = ComputeSlicesInfo(length);
-  const numWorkers = ForkJoinNumWorkers();
-  assert(numWorkers > 0, "Should have at least the main thread");
-  const pointers = [];
-  for (var i = 0; i < numWorkers; i++) {
-    const inTypedObject = TypedObjectGetDerivedIf(inGrainType, inArray, 0,
-                                                  inGrainTypeIsComplex);
-    const outTypedObject = TypedObjectGetOpaqueIf(outGrainType, outArray, 0,
-                                                  outGrainTypeIsComplex);
-    ARRAY_PUSH(pointers, ({ inTypedObject: inTypedObject,
-                            outTypedObject: outTypedObject }));
-  }
-
-  // Below we will be adjusting offsets within the input to point at
-  // successive entries; we'll need to know the offset of inArray
-  // relative to its owner (which is often but not always 0).
-  const inBaseOffset = TypedObjectByteOffset(inArray);
-
-  ForkJoin(mapThread, 0, slicesInfo.count, ForkJoinMode(mode), outArray);
-  return outArray;
-
-  function mapThread(workerId, sliceStart, sliceEnd) {
-    assert(TO_INT32(workerId) === workerId,
-           "workerId not int: " + workerId);
-    assert(workerId < pointers.length,
-           "workerId too large: " + workerId + " >= " + pointers.length);
-
-    var pointerIndex = InParallelSection() ? workerId : 0;
-    assert(!!pointers[pointerIndex],
-          "no pointer data for workerId: " + workerId);
-
-    const { inTypedObject, outTypedObject } = pointers[pointerIndex];
-    const sliceShift = slicesInfo.shift;
-    var sliceId;
-
-    while (GET_SLICE(sliceStart, sliceEnd, sliceId)) {
-      const indexStart = SLICE_START_INDEX(sliceShift, sliceId);
-      const indexEnd = SLICE_END_INDEX(sliceShift, indexStart, length);
-
-      var inOffset = inBaseOffset + std_Math_imul(inGrainTypeSize, indexStart);
-      var outOffset = std_Math_imul(outGrainTypeSize, indexStart);
-
-      // Set the target region so that user is only permitted to write
-      // within the range set aside for this slice. This prevents user
-      // from writing to typed objects that escaped from prior slices
-      // during sequential iteration. Note that, for any particular
-      // iteration of the loop below, it's only valid to write to the
-      // memory range corresponding to the index `i` -- however, since
-      // the different iterations cannot communicate typed object
-      // pointers to one another during parallel exec, we need only
-      // fear escaped typed objects from *other* slices, so we can
-      // just set the target region once.
-      const endOffset = std_Math_imul(outGrainTypeSize, indexEnd);
-      SetForkJoinTargetRegion(outArray, outOffset, endOffset);
-
-      for (var i = indexStart; i < indexEnd; i++) {
-        var inVal = (inGrainTypeIsComplex
-                     ? RedirectPointer(inTypedObject, inOffset,
-                                       outGrainTypeIsTransparent)
-                     : inArray[i]);
-        var outVal = (outGrainTypeIsComplex
-                      ? RedirectPointer(outTypedObject, outOffset,
-                                        outGrainTypeIsTransparent)
-                      : undefined);
-        const r = func(inVal, i, inArray, outVal);
-        if (r !== undefined) {
-          if (outGrainTypeIsComplex)
-            SetTypedObjectValue(outGrainType, outArray, outOffset, r);
-          else
-            UnsafePutElements(outArray, i, r);
-        }
-        inOffset += inGrainTypeSize;
-        outOffset += outGrainTypeSize;
-
-#ifndef JSGC_FJGENERATIONAL
-        // A transparent result type cannot contain references, and
-        // hence there is no way for a pointer to a thread-local object
-        // to escape.
-        //
-        // This has been disabled for the PJS generational collector
-        // as it probably has little effect in that setting and adds
-        // per-iteration cost.
-        if (outGrainTypeIsTransparent)
-          ClearThreadLocalArenas();
-#endif
-      }
-    }
-
-    return sliceId;
-  }
-
-  return undefined;
-}
-SetScriptHints(MapTypedParImplDepth1,         { cloneAtCallsite: true });
-
 function ReduceTypedSeqImpl(array, outputType, func, initial) {
   assert(IsObject(array) && ObjectIsTypedObject(array), "Reduce called on non-object or untyped input array.");
   assert(IsObject(outputType) && ObjectIsTypeDescr(outputType), "Reduce called on non-type-object outputType");
 
   var start, value;
 
   if (initial === undefined && array.length < 1)
     // RangeError("reduce requires array of length > 0")
@@ -1263,46 +983,16 @@ function ReduceTypedSeqImpl(array, outpu
 
     for (var i = start; i < array.length; i++)
       value = func(value, array[i]);
   }
 
   return value;
 }
 
-function ScatterTypedSeqImpl(array, outputType, indices, defaultValue, conflictFunc) {
-  assert(IsObject(array) && ObjectIsTypedObject(array), "Scatter called on non-object or untyped input array.");
-  assert(IsObject(outputType) && ObjectIsTypeDescr(outputType), "Scatter called on non-type-object outputType");
-  assert(TypeDescrIsArrayType(outputType), "Scatter called on non-array type");
-  assert(conflictFunc === undefined || typeof conflictFunc === "function", "Scatter called with invalid conflictFunc");
-
-  var result = new outputType();
-  var bitvec = new Uint8Array(result.length);
-  var elemType = outputType.elementType;
-  var i, j;
-  if (defaultValue !== elemType(undefined)) {
-    for (i = 0; i < result.length; i++) {
-      result[i] = defaultValue;
-    }
-  }
-
-  for (i = 0; i < indices.length; i++) {
-    j = indices[i];
-    if (!GET_BIT(bitvec, j)) {
-      result[j] = array[i];
-      SET_BIT(bitvec, j);
-    } else if (conflictFunc === undefined) {
-      ThrowError(JSMSG_PAR_ARRAY_SCATTER_CONFLICT);
-    } else {
-      result[j] = conflictFunc(result[j], elemType(array[i]));
-    }
-  }
-  return result;
-}
-
 function FilterTypedSeqImpl(array, func) {
   assert(IsObject(array) && ObjectIsTypedObject(array), "Filter called on non-object or untyped input array.");
   assert(typeof func === "function", "Filter called with non-function predicate");
 
   var arrayType = TypeOfTypedObject(array);
   if (!TypeDescrIsArrayType(arrayType))
     ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
 
--- a/js/src/builtin/Utilities.js
+++ b/js/src/builtin/Utilities.js
@@ -102,39 +102,8 @@ function ToLength(v) {
     // Math.pow(2, 53) - 1 = 0x1fffffffffffff
     return std_Math_min(v, 0x1fffffffffffff);
 }
 
 // Spec: ECMAScript Draft, 6th edition Oct 14, 2014, 7.2.4.
 function SameValueZero(x, y) {
     return x === y || (x !== x && y !== y);
 }
-
-/********** Testing code **********/
-
-#ifdef ENABLE_PARALLEL_JS
-
-/**
- * Internal debugging tool: checks that the given `mode` permits
- * sequential execution
- */
-function AssertSequentialIsOK(mode) {
-  if (mode && mode.mode && mode.mode !== "seq" && ParallelTestsShouldPass())
-    ThrowError(JSMSG_WRONG_VALUE, "parallel execution", "sequential was forced");
-}
-
-function ForkJoinMode(mode) {
-  // WARNING: this must match the enum ForkJoinMode in ForkJoin.cpp
-  if (!mode || !mode.mode) {
-    return 0;
-  } else if (mode.mode === "compile") {
-    return 1;
-  } else if (mode.mode === "par") {
-    return 2;
-  } else if (mode.mode === "recover") {
-    return 3;
-  } else if (mode.mode === "bailout") {
-    return 4;
-  }
-  ThrowError(JSMSG_PAR_ARRAY_BAD_ARG);
-}
-
-#endif
deleted file mode 100644
--- a/js/src/jit-test/tests/ion/inlining/TypedObject-TypeDescrIsSizedArrayType.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/* -*- tab-width: 8; indent-tabs-mode: nil; js-indent-level: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* Testing TypeDescrIsSizedArrayType() is fairly straightforward:
- * it's used early in the sequential scatter() method on TypedObject
- * arrays, and is applied to the first argument (not to "this").
- *
- * Run this with IONFLAGS=logs, generate pdfs with iongraph, and then
- * try running "pdfgrep TypeDescrIsSizedArrayType func*pass00*.pdf", this
- * might net a function that is a likely candidate for manual inspection.
- *
- * (It is sometimes useful to neuter the assert() macro in the
- * self-hosted code.)
- */
-
-if (!this.TypedObject) {
-    print("No TypedObject, skipping");
-    quit();
-}
-
-var T = TypedObject;
-var IT = new T.ArrayType(T.int32, 100);
-var ix = IT.build(x => x == 0 ? 99 : x-1);  // [99, 0, 1, ..., 98]
-
-// This is a left-rotate by one place
-function check(v) {
-    return v.scatter(IT, ix);
-}
-
-function test() {
-    var w = IT.build(x => x);
-    for ( var i=0 ; i < 77 ; i++ )
-	w = check(w);
-    return w;
-}
-
-w = test();
-assertEq(w.length, 100);
-assertEq(w[0], 77);
-print("Done");
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -439,22 +439,16 @@ MSG_DEF(JSMSG_SHARED_ARRAY_BAD_OBJECT,  
 MSG_DEF(JSMSG_SHARED_ARRAY_BAD_LENGTH,  0, JSEXN_RANGEERR, "length argument out of range")
 
 // Shared typed array
 MSG_DEF(JSMSG_SHARED_TYPED_ARRAY_BAD_OBJECT,  0, JSEXN_TYPEERR, "invalid object argument")
 MSG_DEF(JSMSG_SHARED_TYPED_ARRAY_BAD_ARGS,    0, JSEXN_RANGEERR, "bad combination of offset, length, and element size")
 MSG_DEF(JSMSG_SHARED_TYPED_ARRAY_ARG_RANGE,   1, JSEXN_RANGEERR, "argument {0} out of range")
 MSG_DEF(JSMSG_SHARED_TYPED_ARRAY_BAD_LENGTH,  0, JSEXN_TYPEERR, "length argument must not be an object")
 
-// Parallel array
-MSG_DEF(JSMSG_PAR_ARRAY_BAD_ARG,       0, JSEXN_RANGEERR, "invalid parallel method argument")
-MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_BAD_TARGET, 1, JSEXN_ERR, "target for index {0} is not an integer")
-MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_BOUNDS,0, JSEXN_ERR, "index in scatter vector out of bounds")
-MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_CONFLICT, 0, JSEXN_ERR, "no conflict resolution function provided")
-
 // Reflect
 MSG_DEF(JSMSG_BAD_PARSE_NODE,          0, JSEXN_INTERNALERR, "bad parse node")
 
 // Symbol
 MSG_DEF(JSMSG_BAD_SYMBOL,              1, JSEXN_TYPEERR, "{0} is not a well-known @@-symbol")
 MSG_DEF(JSMSG_SYMBOL_TO_STRING,        0, JSEXN_TYPEERR, "can't convert symbol to string")
 MSG_DEF(JSMSG_SYMBOL_TO_NUMBER,        0, JSEXN_TYPEERR, "can't convert symbol to number")
 
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3204,25 +3204,16 @@ static const JSFunctionSpec array_method
     JS_SELF_HOSTED_FN("forEach",     "ArrayForEach",     1,0),
     JS_SELF_HOSTED_FN("map",         "ArrayMap",         1,0),
     JS_SELF_HOSTED_FN("reduce",      "ArrayReduce",      1,0),
     JS_SELF_HOSTED_FN("reduceRight", "ArrayReduceRight", 1,0),
     JS_FN("filter",             array_filter,       1,JSFUN_GENERIC_NATIVE),
     JS_SELF_HOSTED_FN("some",        "ArraySome",        1,0),
     JS_SELF_HOSTED_FN("every",       "ArrayEvery",       1,0),
 
-#ifdef ENABLE_PARALLEL_JS
-    /* Parallelizable and pure methods. */
-    JS_SELF_HOSTED_FN("mapPar",      "ArrayMapPar",      2,0),
-    JS_SELF_HOSTED_FN("reducePar",   "ArrayReducePar",   2,0),
-    JS_SELF_HOSTED_FN("scanPar",     "ArrayScanPar",     2,0),
-    JS_SELF_HOSTED_FN("scatterPar",  "ArrayScatterPar",  5,0),
-    JS_SELF_HOSTED_FN("filterPar",   "ArrayFilterPar",   2,0),
-#endif
-
     /* ES6 additions */
     JS_SELF_HOSTED_FN("find",        "ArrayFind",        1,0),
     JS_SELF_HOSTED_FN("findIndex",   "ArrayFindIndex",   1,0),
     JS_SELF_HOSTED_FN("copyWithin",  "ArrayCopyWithin",  3,0),
 
     JS_SELF_HOSTED_FN("fill",        "ArrayFill",        3,0),
 
     JS_SELF_HOSTED_SYM_FN(iterator,  "ArrayValues",      0,0),
@@ -3245,22 +3236,16 @@ static const JSFunctionSpec array_static
     JS_SELF_HOSTED_FN("map",         "ArrayStaticMap",   2,0),
     JS_SELF_HOSTED_FN("every",       "ArrayStaticEvery", 2,0),
     JS_SELF_HOSTED_FN("some",        "ArrayStaticSome",  2,0),
     JS_SELF_HOSTED_FN("reduce",      "ArrayStaticReduce", 2,0),
     JS_SELF_HOSTED_FN("reduceRight", "ArrayStaticReduceRight", 2,0),
     JS_SELF_HOSTED_FN("from",        "ArrayFrom", 3,0),
     JS_FN("of",                 array_of,           0,0),
 
-#ifdef ENABLE_PARALLEL_JS
-    JS_SELF_HOSTED_FN("build",       "ArrayStaticBuild", 2,0),
-    /* Parallelizable and pure static methods. */
-    JS_SELF_HOSTED_FN("buildPar",    "ArrayStaticBuildPar", 3,0),
-#endif
-
     JS_FS_END
 };
 
 /* ES5 15.4.2 */
 bool
 js_Array(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
deleted file mode 100644
--- a/js/src/tests/ecma_7/TypedObject/method_scatter.js
+++ /dev/null
@@ -1,95 +0,0 @@
-// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
-var BUGNUMBER = 939715;
-var summary = 'method instance.scatter';
-
-/*
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/licenses/publicdomain/
- */
-
-var ArrayType = TypedObject.ArrayType;
-var StructType = TypedObject.StructType;
-var uint8 = TypedObject.uint8;
-var uint16 = TypedObject.uint16;
-var uint32 = TypedObject.uint32;
-var uint8Clamped = TypedObject.uint8Clamped;
-var int8 = TypedObject.int8;
-var int16 = TypedObject.int16;
-var int32 = TypedObject.int32;
-var float32 = TypedObject.float32;
-var float64 = TypedObject.float64;
-
-function scatterUint8sPermute() {
-  var uint8Array = uint8.array(5);
-  var array = new uint8Array([124, 120, 122, 123, 121]);
-
-  var perm = array.scatter(uint8Array, [4, 0, 2, 3, 1]);
-  assertTypedEqual(uint8Array, perm, [120, 121, 122, 123, 124]);
-}
-
-function scatterUint8sPermuteIncomplete() {
-  var uint8Array4 = uint8.array(4);
-  var uint8Array5 = uint8.array(5);
-  var array = new uint8Array4([124, 120, 122, 123]);
-
-  var perm;
-  perm = array.scatter(uint8Array5, [4, 0, 2, 3]);
-  assertTypedEqual(uint8Array5, perm, [120,  0, 122, 123, 124]);
-
-  perm = array.scatter(uint8Array5, [4, 0, 2, 3], 77);
-  assertTypedEqual(uint8Array5, perm, [120, 77, 122, 123, 124]);
-}
-
-function scatterUint8sHistogram() {
-  var uint32Array5 = uint32.array(5);
-  var uint32Array3 = uint32.array(3);
-  var array = new uint32Array5([1, 10, 100, 1000, 10000]);
-
-  var hist = array.scatter(uint32Array3, [1, 1, 2, 1, 0], 0, (a,b) => a+b);
-  assertTypedEqual(uint32Array3, hist, [10000, 1011, 100]);
-}
-
-function scatterUint8sCollisionThrows() {
-  var uint32Array5 = uint32.array(5);
-  var uint32Array3 = uint32.array(3);
-  var array = new uint32Array5([1, 10, 100, 1000, 10000]);
-
-  var unset_nonce = new Object();
-  var unset = unset_nonce;
-  try {
-    unset = array.scatter(uint32Array3, [1, 1, 2, 1, 0], 0);
-  } catch (e) {
-    assertEq(unset, unset_nonce);
-  }
-}
-
-function scatterUint8sConflictIsAssocNonCommute() {
-  var uint32Array5 = uint32.array(5);
-  var uint32Array3 = uint32.array(3);
-  var array = new uint32Array5([1, 10, 100, 1000, 10000]);
-
-  // FIXME strawman spec says conflict must be associative, but does
-  // not dictate commutative.  Yet, strawman spec does not appear to
-  // specify operation order; must address incongruence.
-
-  var lfts = array.scatter(uint32Array3, [1, 1, 2, 1, 0], 0, (a,b) => a);
-  assertTypedEqual(uint32Array3, lfts, [10000, 1, 100]);
-  var rgts = array.scatter(uint32Array3, [1, 1, 2, 1, 0], 0, (a,b) => b);
-  assertTypedEqual(uint32Array3, rgts, [10000, 1000, 100]);
-}
-
-function runTests() {
-    print(BUGNUMBER + ": " + summary);
-
-    scatterUint8sPermute();
-    scatterUint8sPermuteIncomplete();
-    scatterUint8sHistogram();
-    scatterUint8sCollisionThrows();
-    scatterUint8sConflictIsAssocNonCommute();
-
-    if (typeof reportCompare === "function")
-        reportCompare(true, true);
-    print("Tests complete");
-}
-
-runTests();
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -299,132 +299,16 @@ intrinsic_SetScriptHints(JSContext *cx, 
         return false;
     if (ToBoolean(propv))
         funScript->setShouldInline();
 
     args.rval().setUndefined();
     return true;
 }
 
-#ifdef DEBUG
-/*
- * Dump(val): Dumps a value for debugging, even in parallel mode.
- */
-bool
-intrinsic_Dump(ThreadSafeContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    js_DumpValue(args[0]);
-    if (args[0].isObject()) {
-        fprintf(stderr, "\n");
-        js_DumpObject(&args[0].toObject());
-    }
-    args.rval().setUndefined();
-    return true;
-}
-
-JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(intrinsic_Dump_jitInfo, intrinsic_Dump_jitInfo,
-                                      intrinsic_Dump);
-
-bool
-intrinsic_ParallelSpew(ThreadSafeContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    MOZ_ASSERT(args.length() == 1);
-    MOZ_ASSERT(args[0].isString());
-
-    AutoCheckCannotGC nogc;
-    ScopedThreadSafeStringInspector inspector(args[0].toString());
-    if (!inspector.ensureChars(cx, nogc))
-        return false;
-
-    ScopedJSFreePtr<char> bytes;
-    if (inspector.hasLatin1Chars())
-        bytes = JS::CharsToNewUTF8CharsZ(cx, inspector.latin1Range()).c_str();
-    else
-        bytes = JS::CharsToNewUTF8CharsZ(cx, inspector.twoByteRange()).c_str();
-
-    parallel::Spew(parallel::SpewOps, bytes);
-
-    args.rval().setUndefined();
-    return true;
-}
-
-JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(intrinsic_ParallelSpew_jitInfo, intrinsic_ParallelSpew_jitInfo,
-                                      intrinsic_ParallelSpew);
-#endif
-
-/*
- * ForkJoin(func, sliceStart, sliceEnd, mode, updatable): Invokes |func| many times in parallel.
- *
- * If "func" will update a pre-existing object then that object /must/ be passed
- * as the object "updatable".  It is /not/ correct to pass an object that
- * references the updatable objects indirectly.
- *
- * See ForkJoin.cpp for details and ParallelArray.js for examples.
- */
-static bool
-intrinsic_ForkJoin(JSContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    return ForkJoin(cx, args);
-}
-
-/*
- * ForkJoinWorkerNumWorkers(): Returns the number of workers in the fork join
- * thread pool, including the main thread.
- */
-static bool
-intrinsic_ForkJoinNumWorkers(JSContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    args.rval().setInt32(cx->runtime()->threadPool.numWorkers());
-    return true;
-}
-
-/*
- * ForkJoinGetSlice(id): Returns the id of the next slice to be worked
- * on.
- *
- * Acts as the identity function when called from outside of a ForkJoin
- * thread. This odd API is because intrinsics must be called during the
- * parallel warm up phase to populate observed type sets, so we must call it
- * even during sequential execution. But since there is no thread pool during
- * sequential execution, the selfhosted code is responsible for computing the
- * next sequential slice id and passing it in itself.
- */
-bool
-js::intrinsic_ForkJoinGetSlice(JSContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    MOZ_ASSERT(args.length() == 1);
-    MOZ_ASSERT(args[0].isInt32());
-    args.rval().set(args[0]);
-    return true;
-}
-
-static bool
-intrinsic_ForkJoinGetSlicePar(ForkJoinContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    MOZ_ASSERT(args.length() == 1);
-    MOZ_ASSERT(args[0].isInt32());
-
-    uint16_t sliceId;
-    if (cx->getSlice(&sliceId))
-        args.rval().setInt32(sliceId);
-    else
-        args.rval().setInt32(ThreadPool::MAX_SLICE_ID);
-
-    return true;
-}
-
-JS_JITINFO_NATIVE_PARALLEL(intrinsic_ForkJoinGetSlice_jitInfo,
-                           intrinsic_ForkJoinGetSlicePar);
-
 /*
  * NewDenseArray(length): Allocates and returns a new dense array with
  * the given length where all values are initialized to holes.
  */
 bool
 js::intrinsic_NewDenseArray(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -891,69 +775,16 @@ intrinsic_IsWeakSet(JSContext *cx, unsig
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 1);
     MOZ_ASSERT(args[0].isObject());
 
     args.rval().setBoolean(args[0].toObject().is<WeakSetObject>());
     return true;
 }
 
-/*
- * ParallelTestsShouldPass(): Returns false if we are running in a
- * mode (such as --ion-eager) that is known to cause additional
- * bailouts or disqualifications for parallel array tests.
- *
- * This is needed because the parallel tests generally assert that,
- * under normal conditions, they will run without bailouts or
- * compilation failures, but this does not hold under "stress-testing"
- * conditions like --ion-eager or --no-ti.  However, running the tests
- * under those conditions HAS exposed bugs and thus we do not wish to
- * disable them entirely.  Instead, we simply disable the assertions
- * that state that no bailouts etc should occur.
- */
-static bool
-intrinsic_ParallelTestsShouldPass(JSContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    args.rval().setBoolean(ParallelTestsShouldPass(cx));
-    return true;
-}
-
-/*
- * ShouldForceSequential(): Returns true if parallel ops should take
- * the sequential fallback path.
- */
-bool
-js::intrinsic_ShouldForceSequential(JSContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    args.rval().setBoolean(cx->runtime()->forkJoinWarmup ||
-                           InParallelSection());
-    return true;
-}
-
-bool
-js::intrinsic_InParallelSection(JSContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    args.rval().setBoolean(false);
-    return true;
-}
-
-static bool
-intrinsic_InParallelSectionPar(ForkJoinContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    args.rval().setBoolean(true);
-    return true;
-}
-
-JS_JITINFO_NATIVE_PARALLEL(intrinsic_InParallelSection_jitInfo,
-                           intrinsic_InParallelSectionPar);
-
 /* These wrappers are needed in order to recognize the function
  * pointers within the JIT, and the raw js:: functions can't be used
  * directly because they take a ThreadSafeContext* argument.
  */
 bool
 js::intrinsic_ObjectIsTypedObject(JSContext *cx, unsigned argc, Value *vp)
 {
     return js::ObjectIsTypedObject(cx, argc, vp);
@@ -1154,33 +985,17 @@ static const JSFunctionSpec intrinsic_fu
 
     JS_FN("CallLegacyGeneratorMethodIfWrapped",
           CallNonGenericSelfhostedMethod<Is<LegacyGeneratorObject>>, 2, 0),
     JS_FN("CallStarGeneratorMethodIfWrapped",
           CallNonGenericSelfhostedMethod<Is<StarGeneratorObject>>, 2, 0),
 
     JS_FN("IsWeakSet",               intrinsic_IsWeakSet,               1,0),
 
-    JS_FN("ForkJoin",                intrinsic_ForkJoin,                5,0),
-    JS_FN("ForkJoinNumWorkers",      intrinsic_ForkJoinNumWorkers,      0,0),
     JS_FN("NewDenseArray",           intrinsic_NewDenseArray,           1,0),
-    JS_FN("ShouldForceSequential",   intrinsic_ShouldForceSequential,   0,0),
-    JS_FN("ParallelTestsShouldPass", intrinsic_ParallelTestsShouldPass, 0,0),
-    JS_FNINFO("ClearThreadLocalArenas",
-              intrinsic_ClearThreadLocalArenas,
-              &intrinsic_ClearThreadLocalArenasInfo, 0,0),
-    JS_FNINFO("SetForkJoinTargetRegion",
-              intrinsic_SetForkJoinTargetRegion,
-              &intrinsic_SetForkJoinTargetRegionInfo, 2, 0),
-    JS_FNINFO("ForkJoinGetSlice",
-              intrinsic_ForkJoinGetSlice,
-              &intrinsic_ForkJoinGetSlice_jitInfo, 1, 0),
-    JS_FNINFO("InParallelSection",
-              intrinsic_InParallelSection,
-              &intrinsic_InParallelSection_jitInfo, 0, 0),
 
     // See builtin/TypedObject.h for descriptors of the typedobj functions.
     JS_FN("NewOpaqueTypedObject",
           js::NewOpaqueTypedObject,
           1, 0),
     JS_FN("NewDerivedTypedObject",
           js::NewDerivedTypedObject,
           3, 0),
@@ -1259,26 +1074,16 @@ static const JSFunctionSpec intrinsic_fu
     JS_FN("intl_NumberFormat_availableLocales", intl_NumberFormat_availableLocales, 0,0),
     JS_FN("intl_numberingSystem", intl_numberingSystem, 1,0),
     JS_FN("intl_patternForSkeleton", intl_patternForSkeleton, 2,0),
 
     // See builtin/RegExp.h for descriptions of the regexp_* functions.
     JS_FN("regexp_exec_no_statics", regexp_exec_no_statics, 2,0),
     JS_FN("regexp_test_no_statics", regexp_test_no_statics, 2,0),
 
-#ifdef DEBUG
-    JS_FNINFO("Dump",
-              JSNativeThreadSafeWrapper<intrinsic_Dump>,
-              &intrinsic_Dump_jitInfo, 1,0),
-
-    JS_FNINFO("ParallelSpew",
-              JSNativeThreadSafeWrapper<intrinsic_ParallelSpew>,
-              &intrinsic_ParallelSpew_jitInfo, 1,0),
-#endif
-
     JS_FS_END
 };
 
 void
 js::FillSelfHostingCompileOptions(CompileOptions &options)
 {
     /*
      * In self-hosting mode, scripts use JSOP_GETINTRINSIC instead of
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -30,26 +30,26 @@ namespace js {
  *  https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
  *
  * === GREETINGS, FELLOW SUBTRAHEND INCREMENTER! ===
  * For the time being, please increment the subtrahend by 2 each time it
  * changes, because we have two flavors of bytecode: with JSOP_SYMBOL (in
  * Nightly) and without (all others).  FIXME: Bug 1066322 - Enable ES6 symbols
  * in all builds.
  */
-static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 224;
+static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 226;
 static_assert(XDR_BYTECODE_VERSION_SUBTRAHEND % 2 == 0, "see the comment above");
 static const uint32_t XDR_BYTECODE_VERSION =
     uint32_t(0xb973c0de - (XDR_BYTECODE_VERSION_SUBTRAHEND
 #ifdef JS_HAS_SYMBOLS
                                                            + 1
 #endif
                                                               ));
 
-static_assert(JSErr_Limit == 369,
+static_assert(JSErr_Limit == 365,
               "GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or "
               "removed MSG_DEFs from js.msg, you should increment "
               "XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's "
               "expected JSErr_Limit value.");
 
 class XDRBuffer {
   public:
     explicit XDRBuffer(JSContext *cx)