2012-02-01 Filip Pizlo <fpizlo@apple.com>
+ DFG should fold double-to-int conversions
+ https://bugs.webkit.org/show_bug.cgi?id=77532
+
+ Reviewed by Oliver Hunt.
+
+ Performance neutral on major benchmarks. But it makes calling V8's
+ Math.random() 4x faster.
+
+ * bytecode/CodeBlock.cpp:
+ (JSC):
+ (JSC::CodeBlock::addOrFindConstant):
+ * bytecode/CodeBlock.h:
+ (JSC::CodeBlock::addConstant):
+ (CodeBlock):
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::execute):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::toInt32):
+ (ByteCodeParser):
+ (JSC::DFG::ByteCodeParser::getJSConstantForValue):
+ (JSC::DFG::ByteCodeParser::isInt32Constant):
+ * dfg/DFGGraph.h:
+ (JSC::DFG::Graph::addShouldSpeculateInteger):
+ (Graph):
+ (JSC::DFG::Graph::addImmediateShouldSpeculateInteger):
+ * dfg/DFGPropagator.cpp:
+ (JSC::DFG::Propagator::propagateNodePredictions):
+ (JSC::DFG::Propagator::doRoundOfDoubleVoting):
+ (JSC::DFG::Propagator::fixupNode):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileAdd):
+ (DFG):
+ (JSC::DFG::SpeculativeJIT::compileArithSub):
+ * dfg/DFGSpeculativeJIT.h:
+ (JSC::DFG::SpeculativeJIT::valueOfNumberConstantAsInt32):
+ (SpeculativeJIT):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * runtime/JSValueInlineMethods.h:
+ (JSC::JSValue::asDouble):
+
+2012-02-01 Filip Pizlo <fpizlo@apple.com>
+
DFG graph dump for GetScopedVar should show the correct prediction
https://bugs.webkit.org/show_bug.cgi?id=77530
callFrame->uncheckedR(activationRegister()) = JSValue(activation);
callFrame->setScopeChain(callFrame->scopeChain()->push(activation));
}
+
+unsigned CodeBlock::addOrFindConstant(JSValue v)
+{
+ unsigned numberOfConstants = numberOfConstantRegisters();
+ for (unsigned i = 0; i < numberOfConstants; ++i) {
+ if (getConstant(FirstConstantRegisterIndex + i) == v)
+ return i;
+ }
+ return addConstant(v);
+}
#if ENABLE(JIT)
void CodeBlock::unlinkCalls()
Identifier& identifier(int index) { return m_identifiers[index]; }
size_t numberOfConstantRegisters() const { return m_constantRegisters.size(); }
- void addConstant(JSValue v)
+ unsigned addConstant(JSValue v)
{
+ unsigned result = m_constantRegisters.size();
m_constantRegisters.append(WriteBarrier<Unknown>());
m_constantRegisters.last().set(m_globalObject->globalData(), m_ownerExecutable.get(), v);
+ return result;
}
+ unsigned addOrFindConstant(JSValue);
WriteBarrier<Unknown>& constantRegister(int index) { return m_constantRegisters[index - FirstConstantRegisterIndex]; }
ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index >= FirstConstantRegisterIndex; }
ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].get(); }
case ValueAdd:
case ArithAdd: {
- if (Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child2()]) && node.canSpeculateInteger()) {
+ if (m_graph.addShouldSpeculateInteger(node, m_codeBlock)) {
forNode(node.child1()).filter(PredictInt32);
forNode(node.child2()).filter(PredictInt32);
forNode(nodeIndex).set(PredictInt32);
break;
}
- case ArithSub:
+ case ArithSub: {
+ if (m_graph.addShouldSpeculateInteger(node, m_codeBlock)) {
+ forNode(node.child1()).filter(PredictInt32);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+ }
+ forNode(node.child1()).filter(PredictNumber);
+ forNode(node.child2()).filter(PredictNumber);
+ forNode(nodeIndex).set(PredictDouble);
+ break;
+ }
+
case ArithMul:
case ArithDiv:
case ArithMin:
JSValue v = valueOfJSConstant(index);
if (v.isInt32())
return getJSConstant(node.constantNumber());
- // FIXME: We could convert the double ToInteger at this point.
+ if (v.isNumber())
+ return getJSConstantForValue(JSValue(JSC::toInt32(v.asNumber())));
}
return addToGraph(ValueToInt32, index);
return addToGraph(ValueToNumber, OpInfo(NodeUseBottom), index);
}
+
+ NodeIndex getJSConstantForValue(JSValue constantValue)
+ {
+ unsigned constantIndex = m_codeBlock->addOrFindConstant(constantValue);
+ if (constantIndex >= m_constants.size())
+ m_constants.append(ConstantRecord());
+
+ ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters());
+
+ return getJSConstant(constantIndex);
+ }
NodeIndex getJSConstant(unsigned constant)
{
{
return isJSConstant(nodeIndex) && valueOfJSConstant(nodeIndex).isInt32();
}
- bool isSmallInt32Constant(NodeIndex nodeIndex)
- {
- if (!isJSConstant(nodeIndex))
- return false;
- JSValue value = valueOfJSConstant(nodeIndex);
- if (!value.isInt32())
- return false;
- int32_t intValue = value.asInt32();
- return intValue >= -5 && intValue <= 5;
- }
// Convenience methods for getting constant values.
JSValue valueOfJSConstant(NodeIndex index)
{
ASSERT(isInt32Constant(nodeIndex));
return valueOfJSConstant(nodeIndex).asInt32();
}
-
+
// This method returns a JSConstant with the value 'undefined'.
NodeIndex constantUndefined()
{
return predictionFromValue(node.valueOfJSConstant(codeBlock));
}
+ bool addShouldSpeculateInteger(Node& add, CodeBlock* codeBlock)
+ {
+ ASSERT(add.op == ValueAdd || add.op == ArithAdd || add.op == ArithSub);
+
+ Node& left = at(add.child1());
+ Node& right = at(add.child2());
+
+ if (left.hasConstant())
+ return addImmediateShouldSpeculateInteger(codeBlock, add, right, left);
+ if (right.hasConstant())
+ return addImmediateShouldSpeculateInteger(codeBlock, add, left, right);
+
+ return Node::shouldSpeculateInteger(left, right) && add.canSpeculateInteger();
+ }
+
+ bool addShouldSpeculateInteger(NodeIndex nodeIndex, CodeBlock* codeBlock)
+ {
+ return addShouldSpeculateInteger(at(nodeIndex), codeBlock);
+ }
+
// Helper methods to check nodes for constants.
bool isConstant(NodeIndex nodeIndex)
{
unsigned m_parameterSlots;
private:
+ bool addImmediateShouldSpeculateInteger(CodeBlock* codeBlock, Node& add, Node& variable, Node& immediate)
+ {
+ ASSERT(immediate.hasConstant());
+
+ JSValue immediateValue = immediate.valueOfJSConstant(codeBlock);
+ if (!immediateValue.isNumber())
+ return false;
+
+ if (!variable.shouldSpeculateInteger())
+ return false;
+
+ if (immediateValue.isInt32())
+ return add.canSpeculateInteger();
+
+ double doubleImmediate = immediateValue.asDouble();
+ const double twoToThe48 = 281474976710656.0;
+ if (doubleImmediate < -twoToThe48 || doubleImmediate > twoToThe48)
+ return false;
+
+ return nodeCanTruncateInteger(add.arithNodeFlags());
+ }
+
// When a node's refCount goes from 0 to 1, it must (logically) recursively ref all of its children, and vice versa.
void refChildren(NodeIndex);
void derefChildren(NodeIndex);
if (left && right) {
if (isNumberPrediction(left) && isNumberPrediction(right)) {
- if (isInt32Prediction(mergePredictions(left, right)) && nodeCanSpeculateInteger(node.arithNodeFlags()))
+ if (m_graph.addShouldSpeculateInteger(node, m_codeBlock))
changed |= mergePrediction(PredictInt32);
else
changed |= mergePrediction(PredictDouble);
}
case ArithAdd:
- case ArithSub:
+ case ArithSub: {
+ PredictedType left = m_graph[node.child1()].prediction();
+ PredictedType right = m_graph[node.child2()].prediction();
+
+ if (left && right) {
+ if (m_graph.addShouldSpeculateInteger(node, m_codeBlock))
+ changed |= mergePrediction(PredictInt32);
+ else
+ changed |= mergePrediction(PredictDouble);
+ }
+ break;
+ }
+
case ArithMul:
case ArithMin:
case ArithMax:
switch (node.op) {
case ValueAdd:
case ArithAdd:
- case ArithSub:
+ case ArithSub: {
+ PredictedType left = m_graph[node.child1()].prediction();
+ PredictedType right = m_graph[node.child2()].prediction();
+
+ VariableAccessData::Ballot ballot;
+
+ if (isNumberPrediction(left) && isNumberPrediction(right)
+ && !m_graph.addShouldSpeculateInteger(node, m_codeBlock))
+ ballot = VariableAccessData::VoteDouble;
+ else
+ ballot = VariableAccessData::VoteValue;
+
+ vote(node.child1(), ballot);
+ vote(node.child2(), ballot);
+ break;
+ }
+
case ArithMul:
case ArithMin:
case ArithMax:
#endif
switch (op) {
- case ValueAdd: {
- if (!nodeCanSpeculateInteger(node.arithNodeFlags())) {
- toDouble(node.child1());
- toDouble(node.child2());
- break;
- }
-
+ case ValueAdd:
+ case ArithAdd:
+ case ArithSub: {
PredictedType left = m_graph[node.child1()].prediction();
PredictedType right = m_graph[node.child2()].prediction();
if (left && right
&& isNumberPrediction(left) && isNumberPrediction(right)
- && ((left & PredictDouble) || (right & PredictDouble))) {
+ && !m_graph.addShouldSpeculateInteger(node, m_codeBlock)) {
toDouble(node.child1());
toDouble(node.child2());
}
break;
}
- case ArithAdd:
- case ArithSub:
case ArithMul:
case ArithMin:
case ArithMax:
#endif
}
+void SpeculativeJIT::compileAdd(Node& node)
+{
+ if (m_jit.graph().addShouldSpeculateInteger(node, m_jit.codeBlock())) {
+ if (isNumberConstant(node.child1())) {
+ int32_t imm1 = valueOfNumberConstantAsInt32(node.child1());
+ SpeculateIntegerOperand op2(this, node.child2());
+ GPRTemporary result(this);
+
+ if (nodeCanTruncateInteger(node.arithNodeFlags())) {
+ m_jit.move(op2.gpr(), result.gpr());
+ m_jit.add32(Imm32(imm1), result.gpr());
+ } else
+ speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchAdd32(MacroAssembler::Overflow, op2.gpr(), Imm32(imm1), result.gpr()));
+
+ integerResult(result.gpr(), m_compileIndex);
+ return;
+ }
+
+ if (isNumberConstant(node.child2())) {
+ SpeculateIntegerOperand op1(this, node.child1());
+ int32_t imm2 = valueOfNumberConstantAsInt32(node.child2());
+ GPRTemporary result(this);
+
+ if (nodeCanTruncateInteger(node.arithNodeFlags())) {
+ m_jit.move(op1.gpr(), result.gpr());
+ m_jit.add32(Imm32(imm2), result.gpr());
+ } else
+ speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchAdd32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr()));
+
+ integerResult(result.gpr(), m_compileIndex);
+ return;
+ }
+
+ SpeculateIntegerOperand op1(this, node.child1());
+ SpeculateIntegerOperand op2(this, node.child2());
+ GPRTemporary result(this, op1, op2);
+
+ GPRReg gpr1 = op1.gpr();
+ GPRReg gpr2 = op2.gpr();
+ GPRReg gprResult = result.gpr();
+
+ if (nodeCanTruncateInteger(node.arithNodeFlags())) {
+ if (gpr1 == gprResult)
+ m_jit.add32(gpr2, gprResult);
+ else {
+ m_jit.move(gpr2, gprResult);
+ m_jit.add32(gpr1, gprResult);
+ }
+ } else {
+ MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, gpr1, gpr2, gprResult);
+
+ if (gpr1 == gprResult)
+ speculationCheck(Overflow, JSValueRegs(), NoNode, check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr2));
+ else if (gpr2 == gprResult)
+ speculationCheck(Overflow, JSValueRegs(), NoNode, check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr1));
+ else
+ speculationCheck(Overflow, JSValueRegs(), NoNode, check);
+ }
+
+ integerResult(gprResult, m_compileIndex);
+ return;
+ }
+
+ if (Node::shouldSpeculateNumber(at(node.child1()), at(node.child2()))) {
+ SpeculateDoubleOperand op1(this, node.child1());
+ SpeculateDoubleOperand op2(this, node.child2());
+ FPRTemporary result(this, op1, op2);
+
+ FPRReg reg1 = op1.fpr();
+ FPRReg reg2 = op2.fpr();
+ m_jit.addDouble(reg1, reg2, result.fpr());
+
+ doubleResult(result.fpr(), m_compileIndex);
+ return;
+ }
+
+ ASSERT(node.op == ValueAdd);
+ compileValueAdd(node);
+}
+
+void SpeculativeJIT::compileArithSub(Node& node)
+{
+ if (m_jit.graph().addShouldSpeculateInteger(node, m_jit.codeBlock())) {
+ if (isNumberConstant(node.child2())) {
+ SpeculateIntegerOperand op1(this, node.child1());
+ int32_t imm2 = valueOfNumberConstantAsInt32(node.child2());
+ GPRTemporary result(this);
+
+ if (nodeCanTruncateInteger(node.arithNodeFlags())) {
+ m_jit.move(op1.gpr(), result.gpr());
+ m_jit.sub32(Imm32(imm2), result.gpr());
+ } else
+ speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr()));
+
+ integerResult(result.gpr(), m_compileIndex);
+ return;
+ }
+
+ if (isNumberConstant(node.child1())) {
+ int32_t imm1 = valueOfNumberConstantAsInt32(node.child1());
+ SpeculateIntegerOperand op2(this, node.child2());
+ GPRTemporary result(this);
+
+ m_jit.move(Imm32(imm1), result.gpr());
+ if (nodeCanTruncateInteger(node.arithNodeFlags()))
+ m_jit.sub32(op2.gpr(), result.gpr());
+ else
+ speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchSub32(MacroAssembler::Overflow, op2.gpr(), result.gpr()));
+
+ integerResult(result.gpr(), m_compileIndex);
+ return;
+ }
+
+ SpeculateIntegerOperand op1(this, node.child1());
+ SpeculateIntegerOperand op2(this, node.child2());
+ GPRTemporary result(this);
+
+ if (nodeCanTruncateInteger(node.arithNodeFlags())) {
+ m_jit.move(op1.gpr(), result.gpr());
+ m_jit.sub32(op2.gpr(), result.gpr());
+ } else
+ speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), op2.gpr(), result.gpr()));
+
+ integerResult(result.gpr(), m_compileIndex);
+ return;
+ }
+
+ SpeculateDoubleOperand op1(this, node.child1());
+ SpeculateDoubleOperand op2(this, node.child2());
+ FPRTemporary result(this, op1);
+
+ FPRReg reg1 = op1.fpr();
+ FPRReg reg2 = op2.fpr();
+ m_jit.subDouble(reg1, reg2, result.fpr());
+
+ doubleResult(result.fpr(), m_compileIndex);
+}
+
void SpeculativeJIT::compileArithMul(Node& node)
{
if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) {
bool isFunctionConstant(NodeIndex nodeIndex) { return m_jit.isFunctionConstant(nodeIndex); }
int32_t valueOfInt32Constant(NodeIndex nodeIndex) { return m_jit.valueOfInt32Constant(nodeIndex); }
double valueOfNumberConstant(NodeIndex nodeIndex) { return m_jit.valueOfNumberConstant(nodeIndex); }
+ int32_t valueOfNumberConstantAsInt32(NodeIndex nodeIndex)
+ {
+ if (isInt32Constant(nodeIndex))
+ return valueOfInt32Constant(nodeIndex);
+ return JSC::toInt32(valueOfNumberConstant(nodeIndex));
+ }
#if USE(JSVALUE32_64)
void* addressOfDoubleConstant(NodeIndex nodeIndex) { return m_jit.addressOfDoubleConstant(nodeIndex); }
#endif
void compileUInt32ToNumber(Node&);
void compileGetByValOnByteArray(Node&);
void compilePutByValForByteArray(GPRReg base, GPRReg property, Node&);
+ void compileAdd(Node&);
+ void compileArithSub(Node&);
void compileArithMul(Node&);
void compileArithMod(Node&);
void compileSoftModulo(Node&);
}
case ValueAdd:
- case ArithAdd: {
- if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) {
- if (isInt32Constant(node.child1())) {
- int32_t imm1 = valueOfInt32Constant(node.child1());
- SpeculateIntegerOperand op2(this, node.child2());
- GPRTemporary result(this);
-
- if (nodeCanTruncateInteger(node.arithNodeFlags())) {
- m_jit.move(op2.gpr(), result.gpr());
- m_jit.add32(Imm32(imm1), result.gpr());
- } else
- speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchAdd32(MacroAssembler::Overflow, op2.gpr(), Imm32(imm1), result.gpr()));
-
- integerResult(result.gpr(), m_compileIndex);
- break;
- }
-
- if (isInt32Constant(node.child2())) {
- SpeculateIntegerOperand op1(this, node.child1());
- int32_t imm2 = valueOfInt32Constant(node.child2());
- GPRTemporary result(this);
-
- if (nodeCanTruncateInteger(node.arithNodeFlags())) {
- m_jit.move(op1.gpr(), result.gpr());
- m_jit.add32(Imm32(imm2), result.gpr());
- } else
- speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchAdd32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr()));
-
- integerResult(result.gpr(), m_compileIndex);
- break;
- }
-
- SpeculateIntegerOperand op1(this, node.child1());
- SpeculateIntegerOperand op2(this, node.child2());
- GPRTemporary result(this, op1, op2);
-
- GPRReg gpr1 = op1.gpr();
- GPRReg gpr2 = op2.gpr();
- GPRReg gprResult = result.gpr();
-
- if (nodeCanTruncateInteger(node.arithNodeFlags())) {
- if (gpr1 == gprResult)
- m_jit.add32(gpr2, gprResult);
- else {
- m_jit.move(gpr2, gprResult);
- m_jit.add32(gpr1, gprResult);
- }
- } else {
- MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, gpr1, gpr2, gprResult);
-
- if (gpr1 == gprResult)
- speculationCheck(Overflow, JSValueRegs(), NoNode, check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr2));
- else if (gpr2 == gprResult)
- speculationCheck(Overflow, JSValueRegs(), NoNode, check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr1));
- else
- speculationCheck(Overflow, JSValueRegs(), NoNode, check);
- }
-
- integerResult(gprResult, m_compileIndex);
- break;
- }
-
- if (Node::shouldSpeculateNumber(at(node.child1()), at(node.child2()))) {
- SpeculateDoubleOperand op1(this, node.child1());
- SpeculateDoubleOperand op2(this, node.child2());
- FPRTemporary result(this, op1, op2);
-
- FPRReg reg1 = op1.fpr();
- FPRReg reg2 = op2.fpr();
- m_jit.addDouble(reg1, reg2, result.fpr());
-
- doubleResult(result.fpr(), m_compileIndex);
- break;
- }
-
- ASSERT(op == ValueAdd);
- compileValueAdd(node);
+ case ArithAdd:
+ compileAdd(node);
break;
- }
- case ArithSub: {
- if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) {
- if (isInt32Constant(node.child2())) {
- SpeculateIntegerOperand op1(this, node.child1());
- int32_t imm2 = valueOfInt32Constant(node.child2());
- GPRTemporary result(this);
-
- if (nodeCanTruncateInteger(node.arithNodeFlags())) {
- m_jit.move(op1.gpr(), result.gpr());
- m_jit.sub32(Imm32(imm2), result.gpr());
- } else
- speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr()));
-
- integerResult(result.gpr(), m_compileIndex);
- break;
- }
-
- SpeculateIntegerOperand op1(this, node.child1());
- SpeculateIntegerOperand op2(this, node.child2());
- GPRTemporary result(this);
-
- if (nodeCanTruncateInteger(node.arithNodeFlags())) {
- m_jit.move(op1.gpr(), result.gpr());
- m_jit.sub32(op2.gpr(), result.gpr());
- } else
- speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), op2.gpr(), result.gpr()));
-
- integerResult(result.gpr(), m_compileIndex);
- break;
- }
-
- SpeculateDoubleOperand op1(this, node.child1());
- SpeculateDoubleOperand op2(this, node.child2());
- FPRTemporary result(this, op1);
-
- FPRReg reg1 = op1.fpr();
- FPRReg reg2 = op2.fpr();
- m_jit.subDouble(reg1, reg2, result.fpr());
-
- doubleResult(result.fpr(), m_compileIndex);
+ case ArithSub:
+ compileArithSub(node);
break;
- }
- case ArithMul: {
+ case ArithMul:
compileArithMul(node);
break;
- }
case ArithDiv: {
if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) {
}
case ValueAdd:
- case ArithAdd: {
- if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) {
- if (isInt32Constant(node.child1())) {
- int32_t imm1 = valueOfInt32Constant(node.child1());
- SpeculateIntegerOperand op2(this, node.child2());
- GPRTemporary result(this);
-
- if (nodeCanTruncateInteger(node.arithNodeFlags())) {
- m_jit.move(op2.gpr(), result.gpr());
- m_jit.add32(Imm32(imm1), result.gpr());
- } else
- speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchAdd32(MacroAssembler::Overflow, op2.gpr(), Imm32(imm1), result.gpr()));
-
- integerResult(result.gpr(), m_compileIndex);
- break;
- }
-
- if (isInt32Constant(node.child2())) {
- SpeculateIntegerOperand op1(this, node.child1());
- int32_t imm2 = valueOfInt32Constant(node.child2());
- GPRTemporary result(this);
-
- if (nodeCanTruncateInteger(node.arithNodeFlags())) {
- m_jit.move(op1.gpr(), result.gpr());
- m_jit.add32(Imm32(imm2), result.gpr());
- } else
- speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchAdd32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr()));
-
- integerResult(result.gpr(), m_compileIndex);
- break;
- }
-
- SpeculateIntegerOperand op1(this, node.child1());
- SpeculateIntegerOperand op2(this, node.child2());
- GPRTemporary result(this, op1, op2);
-
- GPRReg gpr1 = op1.gpr();
- GPRReg gpr2 = op2.gpr();
- GPRReg gprResult = result.gpr();
-
- if (nodeCanTruncateInteger(node.arithNodeFlags())) {
- if (gpr1 == gprResult)
- m_jit.add32(gpr2, gprResult);
- else {
- m_jit.move(gpr2, gprResult);
- m_jit.add32(gpr1, gprResult);
- }
- } else {
- MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, gpr1, gpr2, gprResult);
-
- if (gpr1 == gprResult)
- speculationCheck(Overflow, JSValueRegs(), NoNode, check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr2));
- else if (gpr2 == gprResult)
- speculationCheck(Overflow, JSValueRegs(), NoNode, check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr1));
- else
- speculationCheck(Overflow, JSValueRegs(), NoNode, check);
- }
-
- integerResult(gprResult, m_compileIndex);
- break;
- }
-
- if (Node::shouldSpeculateNumber(at(node.child1()), at(node.child2()))) {
- SpeculateDoubleOperand op1(this, node.child1());
- SpeculateDoubleOperand op2(this, node.child2());
- FPRTemporary result(this, op1, op2);
-
- FPRReg reg1 = op1.fpr();
- FPRReg reg2 = op2.fpr();
- m_jit.addDouble(reg1, reg2, result.fpr());
-
- doubleResult(result.fpr(), m_compileIndex);
- break;
- }
-
- ASSERT(op == ValueAdd);
- compileValueAdd(node);
+ case ArithAdd:
+ compileAdd(node);
break;
- }
-
- case ArithSub: {
- if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) {
- if (isInt32Constant(node.child2())) {
- SpeculateIntegerOperand op1(this, node.child1());
- int32_t imm2 = valueOfInt32Constant(node.child2());
- GPRTemporary result(this);
-
- if (nodeCanTruncateInteger(node.arithNodeFlags())) {
- m_jit.move(op1.gpr(), result.gpr());
- m_jit.sub32(Imm32(imm2), result.gpr());
- } else
- speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr()));
-
- integerResult(result.gpr(), m_compileIndex);
- break;
- }
-
- SpeculateIntegerOperand op1(this, node.child1());
- SpeculateIntegerOperand op2(this, node.child2());
- GPRTemporary result(this);
-
- if (nodeCanTruncateInteger(node.arithNodeFlags())) {
- m_jit.move(op1.gpr(), result.gpr());
- m_jit.sub32(op2.gpr(), result.gpr());
- } else
- speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), op2.gpr(), result.gpr()));
- integerResult(result.gpr(), m_compileIndex);
- break;
- }
-
- SpeculateDoubleOperand op1(this, node.child1());
- SpeculateDoubleOperand op2(this, node.child2());
- FPRTemporary result(this, op1);
-
- FPRReg reg1 = op1.fpr();
- FPRReg reg2 = op2.fpr();
- m_jit.subDouble(reg1, reg2, result.fpr());
-
- doubleResult(result.fpr(), m_compileIndex);
+ case ArithSub:
+ compileArithSub(node);
break;
- }
- case ArithMul: {
+ case ArithMul:
compileArithMul(node);
break;
- }
case ArithDiv: {
if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) {
inline double JSValue::asDouble() const
{
+ ASSERT(isDouble());
return reinterpretIntptrToDouble(u.asInt64 - DoubleEncodeOffset);
}