Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (192530 => 192531)
--- trunk/Source/_javascript_Core/ChangeLog 2015-11-17 21:45:32 UTC (rev 192530)
+++ trunk/Source/_javascript_Core/ChangeLog 2015-11-17 21:55:33 UTC (rev 192531)
@@ -1,3 +1,65 @@
+2015-11-17 Mark Lam <mark....@apple.com>
+
+ Use the JITAddGenerator snippet in the DFG.
+ https://bugs.webkit.org/show_bug.cgi?id=151266
+
+ Reviewed by Geoffrey Garen.
+
+ No tests added because the op_add.js stress test already tests for correctness
+ (using the LLINT as a reference).
+
+ Performance-wise, the difference from the pre-existing DFG implementation is
+ insignificant (at least as measured on x86 and x86_64). We're moving forward
+ with adopting this implementation because it unifies the 32-bit and 64-bit
+ implementations, as well as lays ground work for a repatching inline cache
+ implementation of op_add later.
+
+ * dfg/DFGAbstractValue.cpp:
+ (JSC::DFG::AbstractValue::resultType):
+ - Made an assertion less restrictive. For ValueAdd operands, the DFG thinks that
+ the operand can also be empty (though we should never see this in practice).
+
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ - Add fallback to unused type operands.
+
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileValueAdd):
+ - Introduce a common function to compile the ValueAdd node.
+
+ * dfg/DFGSpeculativeJIT.h:
+ (JSC::DFG::JSValueOperand::JSValueOperand):
+ - Add the forwarding constructor so that we can use Optional<JSValueOperand>.
+
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ - Changed to use the common compileValueAdd().
+
+ * jit/AssemblyHelpers.h:
+ (JSC::AssemblyHelpers::moveValue):
+ - Similar to moveTrustedValue() but used for untrusted constants.
+
+ * jit/JITAddGenerator.cpp:
+ (JSC::JITAddGenerator::generateFastPath):
+ * jit/JITAddGenerator.h:
+ (JSC::JITAddGenerator::JITAddGenerator):
+ - Updated to take the left or right operand as a constant. This is necessary
+ because the client should not be making assumptions about whether the snippet
+ will determine the operation to be commutative or not. Instead, the client
+ should just pass in the operands and let the snippet do any operand order
+ swapping if necessary.
+
+ * jit/JITArithmetic.cpp:
+ (JSC::JIT::emit_op_add):
+ - Updated to use the new JITAddGenerator interface.
+
+ * tests/stress/op_add.js:
+ (stringifyIfNeeded):
+ (runTest):
+ - Made test output more clear about when string results are expected.
+
2015-11-17 Filip Pizlo <fpi...@apple.com>
It's best for the DFG to always have some guess of basic block frequency
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractValue.cpp (192530 => 192531)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractValue.cpp 2015-11-17 21:45:32 UTC (rev 192530)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractValue.cpp 2015-11-17 21:55:33 UTC (rev 192531)
@@ -499,7 +499,7 @@
ResultType AbstractValue::resultType() const
{
- ASSERT(isType(SpecHeapTop));
+ ASSERT(isType(SpecBytecodeTop));
if (isType(SpecBoolean))
return ResultType::booleanType();
if (isType(SpecInt32))
Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (192530 => 192531)
--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2015-11-17 21:45:32 UTC (rev 192530)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2015-11-17 21:55:33 UTC (rev 192531)
@@ -155,8 +155,9 @@
if (attemptToMakeFastStringAdd(node))
break;
- // We could attempt to turn this into a StrCat here. But for now, that wouldn't
- // significantly reduce the number of branches required.
+ fixEdge<UntypedUse>(node->child1());
+ fixEdge<UntypedUse>(node->child2());
+ node->setResult(NodeResultJS);
break;
}
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (192530 => 192531)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2015-11-17 21:45:32 UTC (rev 192530)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2015-11-17 21:55:33 UTC (rev 192531)
@@ -38,6 +38,7 @@
#include "DFGSaneStringGetByValSlowPathGenerator.h"
#include "DFGSlowPathGenerator.h"
#include "DirectArguments.h"
+#include "JITAddGenerator.h"
#include "JITSubGenerator.h"
#include "JSArrowFunction.h"
#include "JSCInlines.h"
@@ -2782,6 +2783,127 @@
blessedBooleanResult(scratchReg, node);
}
+void SpeculativeJIT::compileValueAdd(Node* node)
+{
+ if (isKnownNotNumber(node->child1().node()) || isKnownNotNumber(node->child2().node())) {
+ JSValueOperand left(this, node->child1());
+ JSValueOperand right(this, node->child2());
+ JSValueRegs leftRegs = left.jsValueRegs();
+ JSValueRegs rightRegs = right.jsValueRegs();
+#if USE(JSVALUE64)
+ GPRTemporary result(this);
+ JSValueRegs resultRegs = JSValueRegs(result.gpr());
+#else
+ GPRTemporary resultTag(this);
+ GPRTemporary resultPayload(this);
+ JSValueRegs resultRegs = JSValueRegs(resultPayload.gpr(), resultTag.gpr());
+#endif
+ flushRegisters();
+ callOperation(operationValueAddNotNumber, resultRegs, leftRegs, rightRegs);
+ m_jit.exceptionCheck();
+
+ jsValueResult(resultRegs, node);
+ return;
+ }
+
+ bool leftIsConstInt32 = node->child1()->isInt32Constant();
+ bool rightIsConstInt32 = node->child2()->isInt32Constant();
+
+ // The DFG does not always fold the sum of 2 constant int operands together.
+ if (leftIsConstInt32 && rightIsConstInt32) {
+#if USE(JSVALUE64)
+ GPRTemporary result(this);
+ JSValueRegs resultRegs = JSValueRegs(result.gpr());
+#else
+ GPRTemporary resultTag(this);
+ GPRTemporary resultPayload(this);
+ JSValueRegs resultRegs = JSValueRegs(resultPayload.gpr(), resultTag.gpr());
+#endif
+ int64_t leftConst = node->child1()->asInt32();
+ int64_t rightConst = node->child2()->asInt32();
+ int64_t resultConst = leftConst + rightConst;
+ m_jit.moveValue(JSValue(resultConst), resultRegs);
+ jsValueResult(resultRegs, node);
+ return;
+ }
+
+ Optional<JSValueOperand> left;
+ Optional<JSValueOperand> right;
+
+ JSValueRegs leftRegs;
+ JSValueRegs rightRegs;
+
+ FPRTemporary leftNumber(this);
+ FPRTemporary rightNumber(this);
+ FPRReg leftFPR = leftNumber.fpr();
+ FPRReg rightFPR = rightNumber.fpr();
+
+#if USE(JSVALUE64)
+ GPRTemporary result(this);
+ JSValueRegs resultRegs = JSValueRegs(result.gpr());
+ GPRTemporary scratch(this);
+ GPRReg scratchGPR = scratch.gpr();
+ FPRReg scratchFPR = InvalidFPRReg;
+#else
+ GPRTemporary resultTag(this);
+ GPRTemporary resultPayload(this);
+ JSValueRegs resultRegs = JSValueRegs(resultPayload.gpr(), resultTag.gpr());
+ GPRReg scratchGPR = resultTag.gpr();
+ FPRTemporary fprScratch(this);
+ FPRReg scratchFPR = fprScratch.fpr();
+#endif
+
+ ResultType leftType = m_state.forNode(node->child1()).resultType();
+ ResultType rightType = m_state.forNode(node->child2()).resultType();
+ int32_t leftConstInt32 = 0;
+ int32_t rightConstInt32 = 0;
+
+ ASSERT(!leftIsConstInt32 || !rightIsConstInt32);
+
+ if (leftIsConstInt32) {
+ leftConstInt32 = node->child1()->asInt32();
+ right = JSValueOperand(this, node->child2());
+ rightRegs = right->jsValueRegs();
+ } else if (rightIsConstInt32) {
+ left = JSValueOperand(this, node->child1());
+ leftRegs = left->jsValueRegs();
+ rightConstInt32 = node->child2()->asInt32();
+ } else {
+ left = JSValueOperand(this, node->child1());
+ leftRegs = left->jsValueRegs();
+ right = JSValueOperand(this, node->child2());
+ rightRegs = right->jsValueRegs();
+ }
+
+ JITAddGenerator gen(resultRegs, leftRegs, rightRegs, leftType, rightType,
+ leftIsConstInt32, rightIsConstInt32, leftConstInt32, rightConstInt32,
+ leftFPR, rightFPR, scratchGPR, scratchFPR);
+ gen.generateFastPath(m_jit);
+
+ gen.slowPathJumpList().link(&m_jit);
+
+ silentSpillAllRegisters(resultRegs);
+
+ if (leftIsConstInt32) {
+ leftRegs = resultRegs;
+ int64_t leftConst = node->child1()->asInt32();
+ m_jit.moveValue(JSValue(leftConst), leftRegs);
+ } else if (rightIsConstInt32) {
+ rightRegs = resultRegs;
+ int64_t rightConst = node->child2()->asInt32();
+ m_jit.moveValue(JSValue(rightConst), rightRegs);
+ }
+
+ callOperation(operationValueAdd, resultRegs, leftRegs, rightRegs);
+
+ silentFillAllRegisters(resultRegs);
+ m_jit.exceptionCheck();
+
+ gen.endJumpList().link(&m_jit);
+ jsValueResult(resultRegs, node);
+ return;
+}
+
void SpeculativeJIT::compileArithAdd(Node* node)
{
switch (node->binaryUseKind()) {
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (192530 => 192531)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2015-11-17 21:45:32 UTC (rev 192530)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2015-11-17 21:55:33 UTC (rev 192531)
@@ -2207,6 +2207,7 @@
void compileValueToInt32(Node*);
void compileUInt32ToNumber(Node*);
void compileDoubleAsInt32(Node*);
+ void compileValueAdd(Node*);
void compileArithAdd(Node*);
void compileMakeRope(Node*);
void compileArithClz32(Node*);
@@ -2552,6 +2553,32 @@
#endif
}
+ explicit JSValueOperand(JSValueOperand&& other)
+ : m_jit(other.m_jit)
+ , m_edge(other.m_edge)
+ {
+#if USE(JSVALUE64)
+ m_gprOrInvalid = other.m_gprOrInvalid;
+#elif USE(JSVALUE32_64)
+ m_register.pair.tagGPR = InvalidGPRReg;
+ m_register.pair.payloadGPR = InvalidGPRReg;
+ m_isDouble = other.m_isDouble;
+
+ if (m_edge) {
+ if (m_isDouble)
+ m_register.fpr = other.m_register.fpr;
+ else
+ m_register.pair = other.m_register.pair;
+ }
+#endif
+ other.m_edge = Edge();
+#if USE(JSVALUE64)
+ other.m_gprOrInvalid = InvalidGPRReg;
+#elif USE(JSVALUE32_64)
+ other.m_isDouble = false;
+#endif
+ }
+
~JSValueOperand()
{
if (!m_edge)
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (192530 => 192531)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2015-11-17 21:45:32 UTC (rev 192530)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2015-11-17 21:55:33 UTC (rev 192531)
@@ -2134,29 +2134,10 @@
compileValueRep(node);
break;
}
-
- case ValueAdd: {
- JSValueOperand op1(this, node->child1());
- JSValueOperand op2(this, node->child2());
-
- GPRReg op1TagGPR = op1.tagGPR();
- GPRReg op1PayloadGPR = op1.payloadGPR();
- GPRReg op2TagGPR = op2.tagGPR();
- GPRReg op2PayloadGPR = op2.payloadGPR();
-
- flushRegisters();
-
- GPRFlushedCallResult2 resultTag(this);
- GPRFlushedCallResult resultPayload(this);
- if (isKnownNotNumber(node->child1().node()) || isKnownNotNumber(node->child2().node()))
- callOperation(operationValueAddNotNumber, resultTag.gpr(), resultPayload.gpr(), op1TagGPR, op1PayloadGPR, op2TagGPR, op2PayloadGPR);
- else
- callOperation(operationValueAdd, resultTag.gpr(), resultPayload.gpr(), op1TagGPR, op1PayloadGPR, op2TagGPR, op2PayloadGPR);
- m_jit.exceptionCheck();
-
- jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
+
+ case ValueAdd:
+ compileValueAdd(node);
break;
- }
case StrCat: {
JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (192530 => 192531)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2015-11-17 21:45:32 UTC (rev 192530)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2015-11-17 21:55:33 UTC (rev 192531)
@@ -2268,27 +2268,11 @@
}
break;
}
-
- case ValueAdd: {
- JSValueOperand op1(this, node->child1());
- JSValueOperand op2(this, node->child2());
-
- GPRReg op1GPR = op1.gpr();
- GPRReg op2GPR = op2.gpr();
-
- flushRegisters();
-
- GPRFlushedCallResult result(this);
- if (isKnownNotNumber(node->child1().node()) || isKnownNotNumber(node->child2().node()))
- callOperation(operationValueAddNotNumber, result.gpr(), op1GPR, op2GPR);
- else
- callOperation(operationValueAdd, result.gpr(), op1GPR, op2GPR);
- m_jit.exceptionCheck();
-
- jsValueResult(result.gpr(), node);
+
+ case ValueAdd:
+ compileValueAdd(node);
break;
- }
-
+
case StrCat: {
JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
JSValueOperand op2(this, node->child2(), ManualOperandSpeculation);
Modified: trunk/Source/_javascript_Core/jit/AssemblyHelpers.h (192530 => 192531)
--- trunk/Source/_javascript_Core/jit/AssemblyHelpers.h 2015-11-17 21:45:32 UTC (rev 192530)
+++ trunk/Source/_javascript_Core/jit/AssemblyHelpers.h 2015-11-17 21:55:33 UTC (rev 192531)
@@ -148,7 +148,17 @@
}
#endif
}
-
+
+ void moveValue(JSValue value, JSValueRegs regs)
+ {
+#if USE(JSVALUE64)
+ move(Imm64(JSValue::encode(value)), regs.gpr());
+#else
+ move(Imm32(value.tag()), regs.tagGPR());
+ move(Imm32(value.payload()), regs.payloadGPR());
+#endif
+ }
+
void moveTrustedValue(JSValue value, JSValueRegs regs)
{
#if USE(JSVALUE64)
Modified: trunk/Source/_javascript_Core/jit/JITAddGenerator.cpp (192530 => 192531)
--- trunk/Source/_javascript_Core/jit/JITAddGenerator.cpp 2015-11-17 21:45:32 UTC (rev 192530)
+++ trunk/Source/_javascript_Core/jit/JITAddGenerator.cpp 2015-11-17 21:55:33 UTC (rev 192531)
@@ -35,22 +35,38 @@
ASSERT(m_scratchGPR != InvalidGPRReg);
ASSERT(m_scratchGPR != m_left.payloadGPR());
ASSERT(m_scratchGPR != m_right.payloadGPR());
-#if ENABLE(JSVALUE32_64)
- ASSERT(m_scratchGPR != m_left.tagGPR());x
+#if USE(JSVALUE32_64)
+ ASSERT(m_scratchGPR != m_left.tagGPR());
ASSERT(m_scratchGPR != m_right.tagGPR());
ASSERT(m_scratchFPR != InvalidFPRReg);
#endif
+ ASSERT(!m_leftIsConstInt32 || !m_rightIsConstInt32);
+
if (!m_leftType.mightBeNumber() || !m_rightType.mightBeNumber()) {
m_slowPathJumpList.append(jit.jump());
return;
}
- if (m_operandsConstness == RightIsConstInt32) {
+ if (m_leftIsConstInt32 || m_rightIsConstInt32) {
+ JSValueRegs var;
+ ResultType varType = ResultType::unknownType();
+ int32_t constInt32;
+
+ if (m_leftIsConstInt32) {
+ var = m_right;
+ varType = m_rightType;
+ constInt32 = m_leftConstInt32;
+ } else {
+ var = m_left;
+ varType = m_leftType;
+ constInt32 = m_rightConstInt32;
+ }
+
// Try to do intVar + intConstant.
- CCallHelpers::Jump notInt32 = jit.branchIfNotInt32(m_left);
+ CCallHelpers::Jump notInt32 = jit.branchIfNotInt32(var);
- m_slowPathJumpList.append(jit.branchAdd32(CCallHelpers::Overflow, m_left.payloadGPR(), CCallHelpers::Imm32(m_rightConstInt32), m_scratchGPR));
+ m_slowPathJumpList.append(jit.branchAdd32(CCallHelpers::Overflow, var.payloadGPR(), CCallHelpers::Imm32(constInt32), m_scratchGPR));
jit.boxInt32(m_scratchGPR, m_result);
m_endJumpList.append(jit.jump());
@@ -62,18 +78,18 @@
// Try to do doubleVar + double(intConstant).
notInt32.link(&jit);
- if (!m_leftType.definitelyIsNumber())
- m_slowPathJumpList.append(jit.branchIfNotNumber(m_left, m_scratchGPR));
+ if (!varType.definitelyIsNumber())
+ m_slowPathJumpList.append(jit.branchIfNotNumber(var, m_scratchGPR));
- jit.unboxDoubleNonDestructive(m_left, m_leftFPR, m_scratchGPR, m_scratchFPR);
+ jit.unboxDoubleNonDestructive(var, m_leftFPR, m_scratchGPR, m_scratchFPR);
- jit.move(CCallHelpers::Imm32(m_rightConstInt32), m_scratchGPR);
+ jit.move(CCallHelpers::Imm32(constInt32), m_scratchGPR);
jit.convertInt32ToDouble(m_scratchGPR, m_rightFPR);
// Fall thru to doubleVar + doubleVar.
} else {
- ASSERT(m_operandsConstness == NeitherAreConstInt32);
+ ASSERT(!m_leftIsConstInt32 && !m_rightIsConstInt32);
CCallHelpers::Jump leftNotInt;
CCallHelpers::Jump rightNotInt;
Modified: trunk/Source/_javascript_Core/jit/JITAddGenerator.h (192530 => 192531)
--- trunk/Source/_javascript_Core/jit/JITAddGenerator.h 2015-11-17 21:45:32 UTC (rev 192530)
+++ trunk/Source/_javascript_Core/jit/JITAddGenerator.h 2015-11-17 21:55:33 UTC (rev 192531)
@@ -35,36 +35,26 @@
class JITAddGenerator {
public:
- enum OperandsConstness {
- NeitherAreConstInt32,
-
- // Since addition is commutative, it doesn't matter which operand we make the
- // ConstInt32. Let's always put the const in the right, and the variable operand
- // in the left.
- RightIsConstInt32,
-
- // We choose not to implement any optimization for the case where both operands
- // are ConstInt32 here. The client may choose to do that optimzation and not
- // invoke this snippet generator, or may load both operands into registers
- // and pass them as variables to the snippet generator instead.
- };
-
JITAddGenerator(JSValueRegs result, JSValueRegs left, JSValueRegs right,
- OperandsConstness operandsConstness, int32_t rightConstInt32,
- ResultType leftType, ResultType rightType, FPRReg leftFPR, FPRReg rightFPR,
+ ResultType leftType, ResultType rightType, bool leftIsConstInt32, bool rightIsConstInt32,
+ int32_t leftConstInt32, int32_t rightConstInt32, FPRReg leftFPR, FPRReg rightFPR,
GPRReg scratchGPR, FPRReg scratchFPR)
: m_result(result)
, m_left(left)
, m_right(right)
- , m_operandsConstness(operandsConstness)
- , m_rightConstInt32(rightConstInt32)
, m_leftType(leftType)
, m_rightType(rightType)
+ , m_leftIsConstInt32(leftIsConstInt32)
+ , m_rightIsConstInt32(rightIsConstInt32)
+ , m_leftConstInt32(leftConstInt32)
+ , m_rightConstInt32(rightConstInt32)
, m_leftFPR(leftFPR)
, m_rightFPR(rightFPR)
, m_scratchGPR(scratchGPR)
, m_scratchFPR(scratchFPR)
- { }
+ {
+ ASSERT(!leftIsConstInt32 || !rightIsConstInt32);
+ }
void generateFastPath(CCallHelpers&);
@@ -75,10 +65,12 @@
JSValueRegs m_result;
JSValueRegs m_left;
JSValueRegs m_right;
- OperandsConstness m_operandsConstness;
- int32_t m_rightConstInt32;
ResultType m_leftType;
ResultType m_rightType;
+ bool m_leftIsConstInt32;
+ bool m_rightIsConstInt32;
+ int32_t m_leftConstInt32;
+ int32_t m_rightConstInt32;
FPRReg m_leftFPR;
FPRReg m_rightFPR;
GPRReg m_scratchGPR;
Modified: trunk/Source/_javascript_Core/jit/JITArithmetic.cpp (192530 => 192531)
--- trunk/Source/_javascript_Core/jit/JITArithmetic.cpp 2015-11-17 21:45:32 UTC (rev 192530)
+++ trunk/Source/_javascript_Core/jit/JITArithmetic.cpp 2015-11-17 21:55:33 UTC (rev 192531)
@@ -934,34 +934,26 @@
bool leftIsConstInt32 = isOperandConstantInt(op1);
bool rightIsConstInt32 = isOperandConstantInt(op2);
- JITAddGenerator::OperandsConstness operandsConstness;
- int32_t rightConstInt32 = 0;
ResultType leftType = types.first();
ResultType rightType = types.second();
+ int32_t leftConstInt32 = 0;
+ int32_t rightConstInt32 = 0;
ASSERT(!leftIsConstInt32 || !rightIsConstInt32);
if (leftIsConstInt32) {
- // JITAddGenerator expects the const value in the right operand.
- // Let's swap the operands.
- operandsConstness = JITAddGenerator::RightIsConstInt32;
- rightConstInt32 = getOperandConstantInt(op1);
- rightType = types.first();
- emitGetVirtualRegister(op2, leftRegs);
- leftType = types.second();
+ leftConstInt32 = getOperandConstantInt(op1);
+ emitGetVirtualRegister(op2, rightRegs);
} else if (rightIsConstInt32) {
- operandsConstness = JITAddGenerator::RightIsConstInt32;
- rightConstInt32 = getOperandConstantInt(op2);
emitGetVirtualRegister(op1, leftRegs);
+ rightConstInt32 = getOperandConstantInt(op2);
} else {
- operandsConstness = JITAddGenerator::NeitherAreConstInt32;
emitGetVirtualRegister(op1, leftRegs);
emitGetVirtualRegister(op2, rightRegs);
}
- JITAddGenerator gen(resultRegs, leftRegs, rightRegs,
- operandsConstness, rightConstInt32,
- leftType, rightType,
+ JITAddGenerator gen(resultRegs, leftRegs, rightRegs, leftType, rightType,
+ leftIsConstInt32, rightIsConstInt32, leftConstInt32, rightConstInt32,
fpRegT0, fpRegT1, scratchGPR, scratchFPR);
gen.generateFastPath(*this);
Modified: trunk/Source/_javascript_Core/tests/stress/op_add.js (192530 => 192531)
--- trunk/Source/_javascript_Core/tests/stress/op_add.js 2015-11-17 21:45:32 UTC (rev 192530)
+++ trunk/Source/_javascript_Core/tests/stress/op_add.js 2015-11-17 21:55:33 UTC (rev 192531)
@@ -318,6 +318,12 @@
var errorReport = "";
+function stringifyIfNeeded(x) {
+ if (typeof x == "string")
+ return '"' + x + '"';
+ return x;
+}
+
function runTest(test) {
var failedScenario = [];
var scenarios = test.scenarios;
@@ -327,7 +333,7 @@
for (var scenarioID = 0; scenarioID < scenarios.length; scenarioID++) {
var scenario = scenarios[scenarioID];
if (verbose)
- print("Testing " + test.name + ":" + scenario.name + " on iteration " + i + ": expecting " + scenario.expected);
+ print("Testing " + test.name + ":" + scenario.name + " on iteration " + i + ": expecting " + stringifyIfNeeded(scenario.expected));
var result = testFunc(scenario.x, scenario.y);
if (result == scenario.expected)
@@ -335,7 +341,8 @@
if (Number.isNaN(result) && Number.isNaN(scenario.expected))
continue;
if (!failedScenario[scenarioID]) {
- errorReport += "FAIL: " + test.name + ":" + scenario.name + " started failing on iteration " + i + ": expected " + scenario.expected + ", actual " + result + "\n";
+ errorReport += "FAIL: " + test.name + ":" + scenario.name + " started failing on iteration " + i
+ + ": expected " + stringifyIfNeeded(scenario.expected) + ", actual " + stringifyIfNeeded(result) + "\n";
if (abortOnFirstFail)
throw errorReport;
failedScenario[scenarioID] = scenario;