Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (199791 => 199792)
--- trunk/Source/_javascript_Core/ChangeLog 2016-04-20 22:03:09 UTC (rev 199791)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-04-20 22:24:32 UTC (rev 199792)
@@ -1,3 +1,30 @@
+2016-04-20 Benjamin Poulain <bpoul...@apple.com>
+
+ [JSC] Add register reuse for ArithAdd of an Int32 and constant in DFG
+ https://bugs.webkit.org/show_bug.cgi?id=155164
+
+ Reviewed by Mark Lam.
+
+ Every "inc" in loop was looking like this:
+ move rX, rY
+ inc rY
+ jo 0x230f4a200580
+
+ This patch add register Reuse to that case to remove
+ the extra "move".
+
+ * dfg/DFGOSRExit.h:
+ (JSC::DFG::SpeculationRecovery::SpeculationRecovery):
+ (JSC::DFG::SpeculationRecovery::immediate):
+ * dfg/DFGOSRExitCompiler32_64.cpp:
+ (JSC::DFG::OSRExitCompiler::compileExit):
+ * dfg/DFGOSRExitCompiler64.cpp:
+ (JSC::DFG::OSRExitCompiler::compileExit):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileArithAdd):
+ * tests/stress/arith-add-with-constant-overflow.js: Added.
+ (opaqueAdd):
+
2016-04-20 Saam barati <sbar...@apple.com>
We don't need a manual stack for an RAII object when the machine's stack will do just fine
Modified: trunk/Source/_javascript_Core/assembler/MacroAssembler.h (199791 => 199792)
--- trunk/Source/_javascript_Core/assembler/MacroAssembler.h 2016-04-20 22:03:09 UTC (rev 199791)
+++ trunk/Source/_javascript_Core/assembler/MacroAssembler.h 2016-04-20 22:24:32 UTC (rev 199792)
@@ -1694,16 +1694,20 @@
Jump branchAdd32(ResultCondition cond, RegisterID src, Imm32 imm, RegisterID dest)
{
- if (src == dest)
- ASSERT(haveScratchRegisterForBlinding());
-
if (shouldBlind(imm)) {
- if (src == dest) {
- move(src, scratchRegisterForBlinding());
- src = ""
+ if (src != dest || haveScratchRegisterForBlinding()) {
+ if (src == dest) {
+ move(src, scratchRegisterForBlinding());
+ src = ""
+ }
+ loadXorBlindedConstant(xorBlindConstant(imm), dest);
+ return branchAdd32(cond, src, dest);
}
- loadXorBlindedConstant(xorBlindConstant(imm), dest);
- return branchAdd32(cond, src, dest);
+ // If we don't have a scratch register available for use, we'll just
+ // place a random number of nops.
+ uint32_t nopCount = random() & 3;
+ while (nopCount--)
+ nop();
}
return branchAdd32(cond, src, imm.asTrustedImm32(), dest);
}
Modified: trunk/Source/_javascript_Core/dfg/DFGOSRExit.h (199791 => 199792)
--- trunk/Source/_javascript_Core/dfg/DFGOSRExit.h 2016-04-20 22:03:09 UTC (rev 199791)
+++ trunk/Source/_javascript_Core/dfg/DFGOSRExit.h 2016-04-20 22:24:32 UTC (rev 199792)
@@ -48,8 +48,9 @@
// This enum describes the types of additional recovery that
// may need be performed should a speculation check fail.
-enum SpeculationRecoveryType {
+enum SpeculationRecoveryType : uint8_t {
SpeculativeAdd,
+ SpeculativeAddImmediate,
BooleanSpeculationCheck
};
@@ -60,22 +61,36 @@
class SpeculationRecovery {
public:
SpeculationRecovery(SpeculationRecoveryType type, GPRReg dest, GPRReg src)
- : m_type(type)
+ : m_src(src)
, m_dest(dest)
- , m_src(src)
+ , m_type(type)
{
+ ASSERT(m_type == SpeculativeAdd || m_type == BooleanSpeculationCheck);
}
+ SpeculationRecovery(SpeculationRecoveryType type, GPRReg dest, int32_t immediate)
+ : m_immediate(immediate)
+ , m_dest(dest)
+ , m_type(type)
+ {
+ ASSERT(m_type == SpeculativeAddImmediate);
+ }
+
SpeculationRecoveryType type() { return m_type; }
GPRReg dest() { return m_dest; }
GPRReg src() { return m_src; }
+ int32_t immediate() { return m_immediate; }
private:
+ // different recovery types may required different additional information here.
+ union {
+ GPRReg m_src;
+ int32_t m_immediate;
+ };
+ GPRReg m_dest;
+
// Indicates the type of additional recovery to be performed.
SpeculationRecoveryType m_type;
- // different recovery types may required different additional information here.
- GPRReg m_dest;
- GPRReg m_src;
};
// === OSRExit ===
Modified: trunk/Source/_javascript_Core/dfg/DFGOSRExitCompiler32_64.cpp (199791 => 199792)
--- trunk/Source/_javascript_Core/dfg/DFGOSRExitCompiler32_64.cpp 2016-04-20 22:03:09 UTC (rev 199791)
+++ trunk/Source/_javascript_Core/dfg/DFGOSRExitCompiler32_64.cpp 2016-04-20 22:24:32 UTC (rev 199792)
@@ -56,6 +56,10 @@
case SpeculativeAdd:
m_jit.sub32(recovery->src(), recovery->dest());
break;
+
+ case SpeculativeAddImmediate:
+ m_jit.sub32(AssemblyHelpers::Imm32(recovery->immediate()), recovery->dest());
+ break;
case BooleanSpeculationCheck:
break;
Modified: trunk/Source/_javascript_Core/dfg/DFGOSRExitCompiler64.cpp (199791 => 199792)
--- trunk/Source/_javascript_Core/dfg/DFGOSRExitCompiler64.cpp 2016-04-20 22:03:09 UTC (rev 199791)
+++ trunk/Source/_javascript_Core/dfg/DFGOSRExitCompiler64.cpp 2016-04-20 22:24:32 UTC (rev 199792)
@@ -61,6 +61,11 @@
m_jit.sub32(recovery->src(), recovery->dest());
m_jit.or64(GPRInfo::tagTypeNumberRegister, recovery->dest());
break;
+
+ case SpeculativeAddImmediate:
+ m_jit.sub32(AssemblyHelpers::Imm32(recovery->immediate()), recovery->dest());
+ m_jit.or64(GPRInfo::tagTypeNumberRegister, recovery->dest());
+ break;
case BooleanSpeculationCheck:
m_jit.xor64(AssemblyHelpers::TrustedImm32(static_cast<int32_t>(ValueFalse)), recovery->dest());
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (199791 => 199792)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2016-04-20 22:03:09 UTC (rev 199791)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2016-04-20 22:24:32 UTC (rev 199792)
@@ -3496,19 +3496,26 @@
if (node->child2()->isInt32Constant()) {
SpeculateInt32Operand op1(this, node->child1());
+ GPRTemporary result(this, Reuse, op1);
+
+ GPRReg gpr1 = op1.gpr();
int32_t imm2 = node->child2()->asInt32();
+ GPRReg gprResult = result.gpr();
if (!shouldCheckOverflow(node->arithMode())) {
- GPRTemporary result(this, Reuse, op1);
- m_jit.add32(Imm32(imm2), op1.gpr(), result.gpr());
- int32Result(result.gpr(), node);
+ m_jit.add32(Imm32(imm2), gpr1, gprResult);
+ int32Result(gprResult, node);
return;
}
- GPRTemporary result(this);
- speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchAdd32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr()));
+ MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, gpr1, Imm32(imm2), gprResult);
+ if (gpr1 == gprResult) {
+ speculationCheck(Overflow, JSValueRegs(), 0, check,
+ SpeculationRecovery(SpeculativeAddImmediate, gpr1, imm2));
+ } else
+ speculationCheck(Overflow, JSValueRegs(), 0, check);
- int32Result(result.gpr(), node);
+ int32Result(gprResult, node);
return;
}
Added: trunk/Source/_javascript_Core/tests/stress/arith-add-with-constant-overflow.js (0 => 199792)
--- trunk/Source/_javascript_Core/tests/stress/arith-add-with-constant-overflow.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/arith-add-with-constant-overflow.js 2016-04-20 22:24:32 UTC (rev 199792)
@@ -0,0 +1,21 @@
+function opaqueAdd(a)
+{
+ return a + 42;
+}
+noInline(opaqueAdd);
+
+// Warm up.
+for (let i = 0; i < 1e4; ++i) {
+ let result = opaqueAdd(5);
+ if (result !== 47)
+ throw "Invalid opaqueAdd(5) at i = " + i;
+}
+
+// Overflow.
+for (let i = 0; i < 1e3; ++i) {
+ for (let j = -50; j < 50; ++j) {
+ let result = opaqueAdd(2147483647 + j);
+ if (result !== 2147483689 + j)
+ throw "Invalid opaqueAdd(" + 2147483647 + j + ") at i = " + i + " j = " + j;
+ }
+}