Bug 977853 -- If we have observed ints and are reading from a ConvertToDoubles array, skip the barrier and just assume we will see both ints + doubles r=jandem
authorNicholas D. Matsakis <nmatsakis@mozilla.com>
Thu, 27 Feb 2014 17:43:18 -0500
changeset 191884 6f9de0cc867b54e6ab091196c29dcc9d4cebbcdf
parent 191883 7e40555e25f7db773925d361d0478eb0c953e09c
child 191885 861f6c26ef3a1eaf4881c41ae23b406637fc6760
push id474
push userasasaki@mozilla.com
push dateMon, 02 Jun 2014 21:01:02 +0000
treeherdermozilla-release@967f4cf1b31c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs977853
milestone30.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 977853 -- If we have observed ints and are reading from a ConvertToDoubles array, skip the barrier and just assume we will see both ints + doubles r=jandem
js/src/jit-test/tests/parallel/bug977853-convert-doubles.js
js/src/jit/IonBuilder.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/parallel/bug977853-convert-doubles.js
@@ -0,0 +1,63 @@
+// Bug 977853 -- Pared down version of script exhibiting negative
+// interaction with convert to doubles optimization. See bug for gory
+// details.
+
+if (!getBuildConfiguration().parallelJS)
+  quit();
+
+load(libdir + "parallelarray-helpers.js")
+
+var numIters = 5;
+var golden_output;
+
+function PJS_div4(v, s)
+{
+  return [ v[0]/s, v[1]/s, v[2]/s, v[3]/s ];
+}
+
+function PJS_normalized(v)
+{
+  var d = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+  d = d > 0.0 ? d : 1.0;
+  var result = [ v[0]/d, v[1]/d, v[2]/d, 1.0 ];
+  return result;
+}
+
+// This is the elemental function passed to mapPar
+function PJS_displace(p)
+{
+  var position = [p[0], p[1], p[2], 1.0];
+  var normal = position;
+  var roughness = 0.025 / 0.35;
+  normal = PJS_normalized(PJS_div4(normal, roughness));
+  return null;
+}
+var NUM_VERTEX_COMPONENTS = 3;
+var initPos, nVertices;
+var userData = {
+  nVertices : 25, //2880,
+  initPos : [],
+};
+function setup() {
+  for(var k = 0; k < NUM_VERTEX_COMPONENTS*userData.nVertices; k++) {
+    userData.initPos[k] = k/1000;
+  }
+  nVertices	= userData.nVertices;
+  initPos		= new Array(nVertices);
+  for(var i=0, j=0; i<nVertices; i++, j+=NUM_VERTEX_COMPONENTS) {
+	initPos[i] = [userData.initPos[j],
+				  userData.initPos[j+1],
+				  userData.initPos[j+2]];
+  }
+}
+function SimulatePJS() {
+  var curPosAndNor;
+
+  // Measure Parallel Execution
+  assertParallelExecSucceeds(
+    function(m) { return initPos.mapPar(PJS_displace, m); },
+    function() { });
+}
+var start_time, elapsed_parallel = 0, elapsed_sequential = 0;
+setup();
+SimulatePJS();
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -7154,16 +7154,46 @@ IonBuilder::jsop_getelem_dense(MDefiniti
         current->add(load);
 
         // If maybeUndefined was true, the typeset must have undefined, and
         // then either additional types or a barrier. This means we should
         // never have a typed version of LoadElementHole.
         JS_ASSERT(knownType == JSVAL_TYPE_UNKNOWN);
     }
 
+    // If the array is being converted to doubles, but we've observed
+    // just int, substitute a type set of int+double into the observed
+    // type set. The reason for this is that, in the
+    // interpreter+baseline, such arrays may consist of mixed
+    // ints/doubles, but when we enter ion code, we will be coercing
+    // all inputs to doubles. Therefore, the type barrier checking for
+    // just int is highly likely (*almost* guaranteed) to fail sooner
+    // or later. Essentially, by eagerly coercing to double, ion is
+    // making the observed types outdated. To compensate for this, we
+    // substitute a broader observed type set consisting of both ints
+    // and doubles. There is perhaps a tradeoff here, so we limit this
+    // optimization to parallel code, where it is needed to prevent
+    // perpetual bailouts in some extreme cases. (Bug 977853)
+    //
+    // NB: we have not added a MConvertElementsToDoubles MIR, so we
+    // cannot *assume* the result is a double.
+    if (executionMode == ParallelExecution &&
+        barrier &&
+        types->getKnownTypeTag() == JSVAL_TYPE_INT32 &&
+        objTypes &&
+        objTypes->convertDoubleElements(constraints()) == types::TemporaryTypeSet::AlwaysConvertToDoubles)
+    {
+        // Note: double implies int32 as well for typesets
+        types = alloc_->lifoAlloc()->new_<types::TemporaryTypeSet>(types::Type::DoubleType());
+        if (!types)
+            return false;
+
+        barrier = false; // Don't need a barrier anymore
+    }
+
     if (knownType != JSVAL_TYPE_UNKNOWN)
         load->setResultType(MIRTypeFromValueType(knownType));
 
     current->push(load);
     return pushTypeBarrier(load, types, barrier);
 }
 
 MInstruction *