Bug 1008636 - Disable automatic truncation for Asm.JS. r=sunfish
authorNicolas B. Pierron <nicolas.b.pierron@mozilla.com>
Wed, 14 May 2014 15:39:37 -0700
changeset 202539 32a8e28507e635790e7fbbb044b10fc96ec02643
parent 202538 2430884972b68062a91c892efad998251ba2cf1e
child 202540 8c234572141a2593807d8ff5960f6c7789305da7
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssunfish
bugs1008636
milestone32.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 1008636 - Disable automatic truncation for Asm.JS. r=sunfish
js/src/jit-test/tests/asm.js/bug1008636.js
js/src/jit/Ion.cpp
js/src/jit/IonOptimizationLevels.cpp
js/src/jit/IonOptimizationLevels.h
js/src/jit/RangeAnalysis.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/asm.js/bug1008636.js
@@ -0,0 +1,12 @@
+// |jit-test| error:TypeError
+// stdlib is undefined
+
+(function(stdlib, n, heap) {
+    "use asm"
+    var Int16ArrayView = new stdlib.Int16Array(heap)
+    function f() {
+        var x = 4.
+        Int16ArrayView[~~((1 ? .0 : .9) % x) >> 1] = 0
+        u(x)
+    }
+})()
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -1472,23 +1472,25 @@ OptimizeMIR(MIRGenerator *mir)
                 IonSpewPass("UCE After RA");
                 AssertExtendedGraphCoherency(graph);
 
                 if (mir->shouldCancel("UCE After RA"))
                     return false;
             }
         }
 
-        if (!r.truncate())
-            return false;
-        IonSpewPass("Truncate Doubles");
-        AssertExtendedGraphCoherency(graph);
-
-        if (mir->shouldCancel("Truncate Doubles"))
-            return false;
+        if (mir->optimizationInfo().autoTruncateEnabled()) {
+            if (!r.truncate())
+                return false;
+            IonSpewPass("Truncate Doubles");
+            AssertExtendedGraphCoherency(graph);
+
+            if (mir->shouldCancel("Truncate Doubles"))
+                return false;
+        }
     }
 
     if (mir->optimizationInfo().eaaEnabled()) {
         AutoTraceLog log(logger, TraceLogger::EffectiveAddressAnalysis);
         EffectiveAddressAnalysis eaa(graph);
         if (!eaa.analyze())
             return false;
         IonSpewPass("Effective Address Analysis");
--- a/js/src/jit/IonOptimizationLevels.cpp
+++ b/js/src/jit/IonOptimizationLevels.cpp
@@ -28,16 +28,17 @@ OptimizationInfo::initNormalOptimization
     eliminateRedundantChecks_ = true;
     inlineInterpreted_ = true;
     inlineNative_ = true;
     gvn_ = true;
     gvnKind_ = GVN_Optimistic;
     licm_ = true;
     uce_ = true;
     rangeAnalysis_ = true;
+    autoTruncate_ = true;
     registerAllocator_ = RegisterAllocator_LSRA;
 
     inlineMaxTotalBytecodeLength_ = 1000;
     inliningMaxCallerBytecodeLength_ = 10000;
     maxInlineDepth_ = 3;
     smallFunctionMaxInlineDepth_ = 10;
     usesBeforeCompile_ = 1000;
     usesBeforeInliningFactor_ = 0.125;
@@ -50,16 +51,17 @@ OptimizationInfo::initAsmjsOptimizationI
     // Disables some passes that don't work well with asmjs.
 
     // Take normal option values for not specified values.
     initNormalOptimizationInfo();
 
     level_ = Optimization_AsmJS;
     edgeCaseAnalysis_ = false;
     eliminateRedundantChecks_ = false;
+    autoTruncate_ = false;
     registerAllocator_ = RegisterAllocator_Backtracking;
 }
 
 uint32_t
 OptimizationInfo::usesBeforeCompile(JSScript *script, jsbytecode *pc) const
 {
     JS_ASSERT(pc == nullptr || pc == script->code() || JSOp(*pc) == JSOP_LOOPENTRY);
 
--- a/js/src/jit/IonOptimizationLevels.h
+++ b/js/src/jit/IonOptimizationLevels.h
@@ -73,16 +73,19 @@ class OptimizationInfo
     bool licm_;
 
     // Toggles whether Unreachable Code Elimination is performed.
     bool uce_;
 
     // Toggles whether Range Analysis is used.
     bool rangeAnalysis_;
 
+    // Toggles whether Truncation based on Range Analysis is used.
+    bool autoTruncate_;
+
     // Describes which register allocator to use.
     IonRegisterAllocator registerAllocator_;
 
     // The maximum total bytecode size of an inline call site.
     uint32_t inlineMaxTotalBytecodeLength_;
 
     // The maximum bytecode length the caller may have,
     // before we stop inlining large functions in that caller.
@@ -138,16 +141,20 @@ class OptimizationInfo
     bool uceEnabled() const {
         return uce_ && !js_JitOptions.disableUce;
     }
 
     bool rangeAnalysisEnabled() const {
         return rangeAnalysis_ && !js_JitOptions.disableRangeAnalysis;
     }
 
+    bool autoTruncateEnabled() const {
+        return autoTruncate_ && rangeAnalysisEnabled();
+    }
+
     bool eaaEnabled() const {
         return eaa_ && !js_JitOptions.disableEaa;
     }
 
     bool edgeCaseAnalysisEnabled() const {
         return edgeCaseAnalysis_ && !js_JitOptions.disableEdgeCaseAnalysis;
     }
 
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -2525,16 +2525,22 @@ AdjustTruncatedInputs(TempAllocator &all
 //
 // We iterate backward because it is likely that a truncated operation truncates
 // some of its operands.
 bool
 RangeAnalysis::truncate()
 {
     IonSpew(IonSpew_Range, "Do range-base truncation (backward loop)");
 
+    // Automatic truncation is disabled for AsmJS because the truncation logic
+    // is based on IonMonkey which assumes that we can bailout if the truncation
+    // logic fails. As AsmJS code has no bailout mechanism, it is safer to avoid
+    // any automatic truncations.
+    MOZ_ASSERT(!mir->compilingAsmJS());
+
     Vector<MInstruction *, 16, SystemAllocPolicy> worklist;
     Vector<MBinaryBitwiseInstruction *, 16, SystemAllocPolicy> bitops;
 
     for (PostorderIterator block(graph_.poBegin()); block != graph_.poEnd(); block++) {
         for (MInstructionReverseIterator iter(block->rbegin()); iter != block->rend(); iter++) {
             if (iter->type() == MIRType_None)
                 continue;