Bug 853555 - Avoid using `a[i] = b` until we are sure that `i` is defined on `a` r=till
authorNicholas D. Matsakis <nmatsakis@mozilla.com>
Wed, 27 Mar 2013 20:01:52 -0400
changeset 126486 e3e6a4b4502851cd0aa8018d04593bc40abd82c4
parent 126485 40b1eec8a12a38689abe843fe42e98b8d08baa1f
child 126487 01de5071069b45c4d351a87d8cc8738f5b2e310f
push id24485
push userryanvm@gmail.com
push dateThu, 28 Mar 2013 12:31:20 +0000
treeherdermozilla-central@293498096b28 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
bugs853555
milestone22.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
Bug 853555 - Avoid using `a[i] = b` until we are sure that `i` is defined on `a` r=till Bug 853555 - Propagate type constraints for UnsafeSetElement in jsinfer r=jandem
js/src/builtin/ParallelArray.js
js/src/jsinfer.cpp
--- a/js/src/builtin/ParallelArray.js
+++ b/js/src/builtin/ParallelArray.js
@@ -98,17 +98,17 @@ function ComputeIndices(shape, index1d) 
   var result = [];
   for (var i = 0; i < l; i++) {
     // Obtain product of all higher dimensions.
     // So if i == 0 and shape is [A,B,C,D], yields BCD.
     var stride = products[l - i - 1];
 
     // Compute how many steps of width stride we could take.
     var index = (index1d / stride) | 0;
-    result[i] = index;
+    ARRAY_PUSH(result, index);
 
     // Adjust remaining indices for smaller dimensions.
     index1d -= (index * stride);
   }
 
   return result;
 }
 
@@ -148,17 +148,17 @@ function ParallelArrayConstructEmpty() {
 function ParallelArrayConstructFromArray(buffer) {
   var buffer = ToObject(buffer);
   var length = buffer.length >>> 0;
   if (length !== buffer.length)
     ThrowError(JSMSG_PAR_ARRAY_BAD_ARG, "");
 
   var buffer1 = [];
   for (var i = 0; i < length; i++)
-    buffer1[i] = buffer[i];
+    ARRAY_PUSH(buffer1, buffer[i]);
 
   this.buffer = buffer1;
   this.offset = 0;
   this.shape = [length];
   this.get = ParallelArrayGet1;
 }
 
 /**
@@ -203,17 +203,17 @@ function ParallelArrayConstructFromCompr
     ThrowError(JSMSG_PAR_ARRAY_BAD_ARG, "");
   } else {
     var shape1 = [];
     for (var i = 0, l = shape.length; i < l; i++) {
       var s0 = shape[i];
       var s1 = s0 >>> 0;
       if (s1 !== s0)
         ThrowError(JSMSG_PAR_ARRAY_BAD_ARG, "");
-      shape1[i] = s1;
+      ARRAY_PUSH(shape1, s1);
     }
     ParallelArrayBuild(self, shape1, func, mode);
   }
 }
 
 /**
  * Internal function used when constructing new parallel arrays. The
  * NewParallelArray() intrinsic takes a ctor function which it invokes
@@ -394,17 +394,18 @@ function ParallelArrayMap(func, mode) {
     ParallelDo(mapSlice, CheckParallel(mode));
     return NewParallelArray(ParallelArrayView, [length], buffer, 0);
   }
 
   // Sequential fallback:
   ASSERT_SEQUENTIAL_IS_OK(mode);
   for (var i = 0; i < length; i++) {
     // Note: Unlike JS arrays, parallel arrays cannot have holes.
-    buffer[i] = func(self.get(i), i, self);
+    var v = func(self.get(i), i, self);
+    UnsafeSetElement(buffer, i, v);
   }
   return NewParallelArray(ParallelArrayView, [length], buffer, 0);
 
   function mapSlice(sliceId, numSlices, warmup) {
     var chunkPos = info[SLICE_POS(sliceId)];
     var chunkEnd = info[SLICE_END(sliceId)];
 
     if (warmup && chunkEnd > chunkPos + 1)
@@ -535,19 +536,22 @@ function ParallelArrayScan(func, mode) {
       break parallel;
     var info = ComputeAllSliceBounds(chunks, numSlices);
 
     // Scan slices individually (see comment on phase1()).
     ParallelDo(phase1, CheckParallel(mode));
 
     // Compute intermediates array (see comment on phase2()).
     var intermediates = [];
-    var accumulator = intermediates[0] = buffer[finalElement(0)];
-    for (var i = 1; i < numSlices - 1; i++)
-      accumulator = intermediates[i] = func(accumulator, buffer[finalElement(i)]);
+    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);
+    }
 
     // Reset the current position information for each slice, but
     // convert from chunks to indices (see comment on phase2()).
     for (var i = 0; i < numSlices; i++) {
       info[SLICE_POS(i)] = info[SLICE_START(i)] << CHUNK_SHIFT;
       info[SLICE_END(i)] = info[SLICE_END(i)] << CHUNK_SHIFT;
     }
     info[SLICE_END(numSlices - 1)] = std_Math_min(info[SLICE_END(numSlices - 1)], length);
@@ -802,23 +806,25 @@ function ParallelArrayScatter(targets, d
   }
 
 
   function parDivideOutputRange() {
     var chunks = ComputeNumChunks(targetsLength);
     var numSlices = ParallelSlices();
     var checkpoints = NewDenseArray(numSlices);
     for (var i = 0; i < numSlices; i++)
-      checkpoints[i] = 0;
+      UnsafeSetElement(checkpoints, i, 0);
 
     var buffer = NewDenseArray(length);
     var conflicts = NewDenseArray(length);
 
-    for (var i = 0; i < length; i++)
-      buffer[i] = defaultValue;
+    for (var i = 0; i < length; i++) {
+      UnsafeSetElement(buffer, i, defaultValue);
+      UnsafeSetElement(conflicts, i, false);
+    }
 
     ParallelDo(fill, CheckParallel(mode));
     return NewParallelArray(ParallelArrayView, [length], buffer, 0);
 
     function fill(sliceId, numSlices, warmup) {
       var indexPos = checkpoints[sliceId];
       var indexEnd = targetsLength;
       if (warmup)
@@ -849,20 +855,24 @@ function ParallelArrayScatter(targets, d
     // before. Therefore, we must proceed not by chunks but rather by
     // individual indices.
     var numSlices = ParallelSlices();
     var info = ComputeAllSliceBounds(targetsLength, numSlices);
 
     // FIXME(bug 844890): Use typed arrays here.
     var localBuffers = NewDenseArray(numSlices);
     for (var i = 0; i < numSlices; i++)
-        localBuffers[i] = NewDenseArray(length);
+      UnsafeSetElement(localBuffers, i, NewDenseArray(length));
     var localConflicts = NewDenseArray(numSlices);
-    for (var i = 0; i < numSlices; i++)
-        localConflicts[i] = NewDenseArray(length);
+    for (var i = 0; i < numSlices; i++) {
+      var conflicts_i = NewDenseArray(length);
+      for (var j = 0; j < length; j++)
+        UnsafeSetElement(conflicts_i, j, false);
+      UnsafeSetElement(localConflicts, i, conflicts_i);
+    }
 
     // Initialize the 0th buffer, which will become the output. For
     // the other buffers, we track which parts have been written to
     // using the conflict buffer so they do not need to be
     // initialized.
     var outputBuffer = localBuffers[0];
     for (var i = 0; i < length; i++)
       UnsafeSetElement(outputBuffer, i, defaultValue);
@@ -915,18 +925,20 @@ function ParallelArrayScatter(targets, d
       }
     }
   }
 
   function seq() {
     var buffer = NewDenseArray(length);
     var conflicts = NewDenseArray(length);
 
-    for (var i = 0; i < length; i++)
-      buffer[i] = defaultValue;
+    for (var i = 0; i < length; i++) {
+      UnsafeSetElement(buffer, i, defaultValue);
+      UnsafeSetElement(conflicts, i, false);
+    }
 
     for (var i = 0; i < targetsLength; i++) {
       var x = self.get(i);
       var t = targets[i];
       checkTarget(i, t);
       if (conflicts[t])
         x = collide(x, buffer[t]);
 
@@ -975,40 +987,40 @@ function ParallelArrayFilter(func, mode)
     // |survivors| containing a bitset for each chunk, 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.
     //
     // FIXME(bug 844890): Use typed arrays here.
     var counts = NewDenseArray(numSlices);
     for (var i = 0; i < numSlices; i++)
-      counts[i] = 0;
+      UnsafeSetElement(counts, i, 0);
     var survivors = NewDenseArray(chunks);
     ParallelDo(findSurvivorsInSlice, CheckParallel(mode));
 
     // 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)
       ParallelDo(copySurvivorsInSlice, CheckParallel(mode));
 
     return NewParallelArray(ParallelArrayView, [count], buffer, 0);
   }
 
   // Sequential fallback:
   ASSERT_SEQUENTIAL_IS_OK(mode);
-  var buffer = [], count = 0;
+  var buffer = [];
   for (var i = 0; i < length; i++) {
     var elem = self.get(i);
     if (func(elem, i, self))
-      buffer[count++] = elem;
+      ARRAY_PUSH(buffer, elem);
   }
-  return NewParallelArray(ParallelArrayView, [count], buffer, 0);
+  return NewParallelArray(ParallelArrayView, [buffer.length], buffer, 0);
 
   /**
    * As described above, our goal is to determine which items we
    * will preserve from a given slice. We do this one chunk at a
    * time. When we finish a chunk, we record our current count and
    * the next chunk sliceId, lest we should bail.
    */
   function findSurvivorsInSlice(sliceId, numSlices, warmup) {
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -1394,16 +1394,27 @@ TypeConstraintCall::newType(JSContext *c
 
             if (native == js::array_push) {
                 for (size_t i = 0; i < callsite->argumentCount; i++) {
                     callsite->thisTypes->addSetProperty(cx, script, pc,
                                                         callsite->argumentTypes[i], JSID_VOID);
                 }
             }
 
+            if (native == intrinsic_UnsafeSetElement) {
+                // UnsafeSetElement(arr0, idx0, elem0, ..., arrN, idxN, elemN)
+                // is (basically) equivalent to arri[idxi] = elemi for i = 0...N
+                JS_ASSERT((callsite->argumentCount % 3) == 0);
+                for (size_t i = 0; i < callsite->argumentCount; i += 3) {
+                    StackTypeSet *arr = callsite->argumentTypes[i];
+                    StackTypeSet *elem = callsite->argumentTypes[i+2];
+                    arr->addSetProperty(cx, script, pc, elem, JSID_VOID);
+                }
+            }
+
             if (native == js::array_pop || native == js::array_shift)
                 callsite->thisTypes->addGetProperty(cx, script, pc, callsite->returnTypes, JSID_VOID);
 
             if (native == js_Array) {
                 TypeObject *res = TypeScript::InitObject(cx, script, pc, JSProto_Array);
                 if (!res)
                     return;