Title: [215531] trunk
Revision
215531
Author
[email protected]
Date
2017-04-19 14:51:52 -0700 (Wed, 19 Apr 2017)

Log Message

B3StackmapSpecial should handle when stackmap values are not recoverable from a Def'ed arg.
https://bugs.webkit.org/show_bug.cgi?id=170973
<rdar://problem/30318657>

Reviewed by Filip Pizlo.

JSTests:

* stress/regress-170973.js: Added.

Source/_javascript_Core:

In the event of an arithmetic overflow on a binary sub instruction (where the
result register is same as one of the operand registers), the CheckSub FTL
operation will try to recover the original value in the clobbered result register.

This recover is done by adding the other operand value to the result register.
However, this recovery method only works if the width of the original value in
the result register is less or equal to the width of the expected result.  If the
width of the original operand value (e.g. a JSInt32) is wider than the result
(e.g. a machine Int32), then the sub operation would have zero extended the
result and cleared the upper 32-bits of the result register.  Recovery by adding
back the other operand will not restore the JSValue tag in the upper word.

This poses a problem if the stackmap value for the operand relies on that same
clobbered register.

The fix is to detect this potential scenario (i.e. width of the Def's arg < width
of a stackmap value).  If this condition is detected, we'll declare the stackmap
value to be LateColdUse to ensure that the register allocator gives it a
different register if needed so that it's not dependent on the clobbered register.

* b3/B3CheckSpecial.cpp:
(JSC::B3::CheckSpecial::forEachArg):
* b3/B3PatchpointSpecial.cpp:
(JSC::B3::PatchpointSpecial::forEachArg):
* b3/B3StackmapSpecial.cpp:
(JSC::B3::StackmapSpecial::forEachArgImpl):
* b3/B3StackmapSpecial.h:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (215530 => 215531)


--- trunk/JSTests/ChangeLog	2017-04-19 21:30:05 UTC (rev 215530)
+++ trunk/JSTests/ChangeLog	2017-04-19 21:51:52 UTC (rev 215531)
@@ -1,3 +1,13 @@
+2017-04-19  Mark Lam  <[email protected]>
+
+        B3StackmapSpecial should handle when stackmap values are not recoverable from a Def'ed arg.
+        https://bugs.webkit.org/show_bug.cgi?id=170973
+        <rdar://problem/30318657>
+
+        Reviewed by Filip Pizlo.
+
+        * stress/regress-170973.js: Added.
+
 2017-04-19  JF Bastien  <[email protected]>
 
         WebAssembly: limit slow memories

Added: trunk/JSTests/stress/regress-170973.js (0 => 215531)


--- trunk/JSTests/stress/regress-170973.js	                        (rev 0)
+++ trunk/JSTests/stress/regress-170973.js	2017-04-19 21:51:52 UTC (rev 215531)
@@ -0,0 +1,16 @@
+// This test passes if it does not crash.
+
+function test(i0, i1) {
+    i0 = i0|0;
+    i1 = i1|0;
+    if (i1 & 1)
+        i1 = (((i0 ? i1 : i1)-i0) ? false : 0);
+}
+noInline(test);
+
+for (var k = 0; k < 200; ++k) {
+    if (k < 100)
+        test(0, 0x80000001);
+    else
+        test(0x800, 0x80000001);
+}

Modified: trunk/Source/_javascript_Core/ChangeLog (215530 => 215531)


--- trunk/Source/_javascript_Core/ChangeLog	2017-04-19 21:30:05 UTC (rev 215530)
+++ trunk/Source/_javascript_Core/ChangeLog	2017-04-19 21:51:52 UTC (rev 215531)
@@ -1,3 +1,39 @@
+2017-04-19  Mark Lam  <[email protected]>
+
+        B3StackmapSpecial should handle when stackmap values are not recoverable from a Def'ed arg.
+        https://bugs.webkit.org/show_bug.cgi?id=170973
+        <rdar://problem/30318657>
+
+        Reviewed by Filip Pizlo.
+
+        In the event of an arithmetic overflow on a binary sub instruction (where the
+        result register is same as one of the operand registers), the CheckSub FTL
+        operation will try to recover the original value in the clobbered result register.
+
+        This recover is done by adding the other operand value to the result register.
+        However, this recovery method only works if the width of the original value in
+        the result register is less or equal to the width of the expected result.  If the
+        width of the original operand value (e.g. a JSInt32) is wider than the result
+        (e.g. a machine Int32), then the sub operation would have zero extended the
+        result and cleared the upper 32-bits of the result register.  Recovery by adding
+        back the other operand will not restore the JSValue tag in the upper word.
+
+        This poses a problem if the stackmap value for the operand relies on that same
+        clobbered register.
+
+        The fix is to detect this potential scenario (i.e. width of the Def's arg < width
+        of a stackmap value).  If this condition is detected, we'll declare the stackmap
+        value to be LateColdUse to ensure that the register allocator gives it a
+        different register if needed so that it's not dependent on the clobbered register.
+
+        * b3/B3CheckSpecial.cpp:
+        (JSC::B3::CheckSpecial::forEachArg):
+        * b3/B3PatchpointSpecial.cpp:
+        (JSC::B3::PatchpointSpecial::forEachArg):
+        * b3/B3StackmapSpecial.cpp:
+        (JSC::B3::StackmapSpecial::forEachArgImpl):
+        * b3/B3StackmapSpecial.h:
+
 2017-04-19  JF Bastien  <[email protected]>
 
         Unreviewed, rolling out r215520.

Modified: trunk/Source/_javascript_Core/b3/B3CheckSpecial.cpp (215530 => 215531)


--- trunk/Source/_javascript_Core/b3/B3CheckSpecial.cpp	2017-04-19 21:30:05 UTC (rev 215530)
+++ trunk/Source/_javascript_Core/b3/B3CheckSpecial.cpp	2017-04-19 21:51:52 UTC (rev 215531)
@@ -108,9 +108,14 @@
 
 void CheckSpecial::forEachArg(Inst& inst, const ScopedLambda<Inst::EachArgCallback>& callback)
 {
+    std::optional<Width> optionalDefArgWidth;
     Inst hidden = hiddenBranch(inst);
     hidden.forEachArg(
         [&] (Arg& arg, Arg::Role role, Bank bank, Width width) {
+            if (Arg::isAnyDef(role)) {
+                ASSERT(!optionalDefArgWidth); // There can only be one Def'ed arg.
+                optionalDefArgWidth = width;
+            }
             unsigned index = &arg - &hidden.args[0];
             callback(inst.args[1 + index], role, bank, width);
         });
@@ -118,7 +123,7 @@
     std::optional<unsigned> firstRecoverableIndex;
     if (m_checkKind.opcode == BranchAdd32 || m_checkKind.opcode == BranchAdd64)
         firstRecoverableIndex = 1;
-    forEachArgImpl(numB3Args(inst), m_numCheckArgs + 1, inst, m_stackmapRole, firstRecoverableIndex, callback);
+    forEachArgImpl(numB3Args(inst), m_numCheckArgs + 1, inst, m_stackmapRole, firstRecoverableIndex, callback, optionalDefArgWidth);
 }
 
 bool CheckSpecial::isValid(Inst& inst)

Modified: trunk/Source/_javascript_Core/b3/B3PatchpointSpecial.cpp (215530 => 215531)


--- trunk/Source/_javascript_Core/b3/B3PatchpointSpecial.cpp	2017-04-19 21:30:05 UTC (rev 215530)
+++ trunk/Source/_javascript_Core/b3/B3PatchpointSpecial.cpp	2017-04-19 21:51:52 UTC (rev 215531)
@@ -59,7 +59,7 @@
         callback(inst.args[argIndex++], role, inst.origin->resultBank(), inst.origin->resultWidth());
     }
 
-    forEachArgImpl(0, argIndex, inst, SameAsRep, std::nullopt, callback);
+    forEachArgImpl(0, argIndex, inst, SameAsRep, std::nullopt, callback, std::nullopt);
     argIndex += inst.origin->numChildren();
 
     for (unsigned i = patchpoint->numGPScratchRegisters; i--;)

Modified: trunk/Source/_javascript_Core/b3/B3StackmapSpecial.cpp (215530 => 215531)


--- trunk/Source/_javascript_Core/b3/B3StackmapSpecial.cpp	2017-04-19 21:30:05 UTC (rev 215530)
+++ trunk/Source/_javascript_Core/b3/B3StackmapSpecial.cpp	2017-04-19 21:51:52 UTC (rev 215531)
@@ -74,7 +74,7 @@
 void StackmapSpecial::forEachArgImpl(
     unsigned numIgnoredB3Args, unsigned numIgnoredAirArgs,
     Inst& inst, RoleMode roleMode, std::optional<unsigned> firstRecoverableIndex,
-    const ScopedLambda<Inst::EachArgCallback>& callback)
+    const ScopedLambda<Inst::EachArgCallback>& callback, std::optional<Width> optionalDefArgWidth)
 {
     StackmapValue* value = inst.origin->as<StackmapValue>();
     ASSERT(value);
@@ -83,7 +83,8 @@
     ASSERT(inst.args.size() >= numIgnoredAirArgs);
     ASSERT(value->children().size() >= numIgnoredB3Args);
     ASSERT(inst.args.size() - numIgnoredAirArgs >= value->children().size() - numIgnoredB3Args);
-    
+    ASSERT(inst.args[0].kind() == Arg::Kind::Special);
+
     for (unsigned i = 0; i < value->children().size() - numIgnoredB3Args; ++i) {
         Arg& arg = inst.args[i + numIgnoredAirArgs];
         ConstrainedValue child = value->constrainedChild(i + numIgnoredB3Args);
@@ -120,6 +121,16 @@
                 RELEASE_ASSERT_NOT_REACHED();
                 break;
             }
+
+            // If the Def'ed arg has a smaller width than the a stackmap value, then we may not
+            // be able to recover the stackmap value. So, force LateColdUse to preserve the
+            // original stackmap value across the Special operation.
+            if (!Arg::isLateUse(role) && optionalDefArgWidth && *optionalDefArgWidth < child.value()->resultWidth()) {
+                if (Arg::isWarmUse(role))
+                    role = Arg::LateUse;
+                else
+                    role = Arg::LateColdUse;
+            }
             break;
         case ForceLateUse:
             role = Arg::LateColdUse;

Modified: trunk/Source/_javascript_Core/b3/B3StackmapSpecial.h (215530 => 215531)


--- trunk/Source/_javascript_Core/b3/B3StackmapSpecial.h	2017-04-19 21:30:05 UTC (rev 215530)
+++ trunk/Source/_javascript_Core/b3/B3StackmapSpecial.h	2017-04-19 21:51:52 UTC (rev 215531)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -60,8 +60,8 @@
     void forEachArgImpl(
         unsigned numIgnoredB3Args, unsigned numIgnoredAirArgs,
         Air::Inst&, RoleMode, std::optional<unsigned> firstRecoverableIndex,
-        const ScopedLambda<Air::Inst::EachArgCallback>&);
-    
+        const ScopedLambda<Air::Inst::EachArgCallback>&, std::optional<Width> optionalDefArgWidth);
+
     bool isValidImpl(
         unsigned numIgnoredB3Args, unsigned numIgnoredAirArgs,
         Air::Inst&);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to