Commit 848a0cc0 authored by barraclough@apple.com's avatar barraclough@apple.com
Browse files

Bug 58154 - Add support for comparison operators to the DFG JIT.

Reviewed by Oliver Hunt.

Add support for <, <=, ==, ===, and also !.  Add support for all corresponding
bytecode ops, including the not- and -null forms.  Initially add functionally
correct support, we'll revisit the performance.

* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::ByteCodeParser):
(JSC::DFG::ByteCodeParser::constantNull):
(JSC::DFG::ByteCodeParser::parse):
    - Add support for parsing of bytecode opcodes, 
* dfg/DFGJITCodeGenerator.h:
(JSC::DFG::JITCodeGenerator::callOperation):
    - Add new operation call types, return bool values.
* dfg/DFGNode.h:
    - Add new node types.
* dfg/DFGNonSpeculativeJIT.cpp:
(JSC::DFG::NonSpeculativeJIT::compile):
    - Add code generation for new nodes.
* dfg/DFGOperations.cpp:
(JSC::DFG::operationCompareLess):
(JSC::DFG::operationCompareLessEq):
(JSC::DFG::operationCompareEq):
(JSC::DFG::operationCompareStrictEq):
(JSC::DFG::dfgConvertJSValueToBoolean):
* dfg/DFGOperations.h:
    - Add operation callbacks to implement new ops.
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compile):
    - Add code generation for new nodes.
* jit/JITOpcodes.cpp:
(JSC::JIT::privateCompileCTIMachineTrampolines):
    - Switched to a simpler <0 check, rather than relying on an internal value in JSImmediate.
* jit/JITPropertyAccess.cpp:
(JSC::JIT::privateCompilePatchGetArrayLength):
    - Switched to a simpler <0 check, rather than relying on an internal value in JSImmediate.
* runtime/JSImmediate.h:
    - Make tag values public, rather than relying on a friend - this matches JSVALUE32_64.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@83337 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 26a12535
2011-04-08 Gavin Barraclough <barraclough@apple.com>
Reviewed by Oliver Hunt.
Bug 58154 - Add support for comparison operators to the DFG JIT.
Add support for <, <=, ==, ===, and also !. Add support for all corresponding
bytecode ops, including the not- and -null forms. Initially add functionally
correct support, we'll revisit the performance.
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::ByteCodeParser):
(JSC::DFG::ByteCodeParser::constantNull):
(JSC::DFG::ByteCodeParser::parse):
- Add support for parsing of bytecode opcodes,
* dfg/DFGJITCodeGenerator.h:
(JSC::DFG::JITCodeGenerator::callOperation):
- Add new operation call types, return bool values.
* dfg/DFGNode.h:
- Add new node types.
* dfg/DFGNonSpeculativeJIT.cpp:
(JSC::DFG::NonSpeculativeJIT::compile):
- Add code generation for new nodes.
* dfg/DFGOperations.cpp:
(JSC::DFG::operationCompareLess):
(JSC::DFG::operationCompareLessEq):
(JSC::DFG::operationCompareEq):
(JSC::DFG::operationCompareStrictEq):
(JSC::DFG::dfgConvertJSValueToBoolean):
* dfg/DFGOperations.h:
- Add operation callbacks to implement new ops.
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compile):
- Add code generation for new nodes.
* jit/JITOpcodes.cpp:
(JSC::JIT::privateCompileCTIMachineTrampolines):
- Switched to a simpler <0 check, rather than relying on an internal value in JSImmediate.
* jit/JITPropertyAccess.cpp:
(JSC::JIT::privateCompilePatchGetArrayLength):
- Switched to a simpler <0 check, rather than relying on an internal value in JSImmediate.
* runtime/JSImmediate.h:
- Make tag values public, rather than relying on a friend - this matches JSVALUE32_64.
2011-04-07 Anna Cavender <annacc@chromium.org>
Reviewed by Eric Carlson.
......
......@@ -44,8 +44,9 @@ public:
, m_codeBlock(codeBlock)
, m_graph(graph)
, m_currentIndex(0)
, m_noArithmetic(true)
, m_regressionGuard(false)
, m_constantUndefined(UINT_MAX)
, m_constantNull(UINT_MAX)
, m_constant1(UINT_MAX)
{
unsigned numberOfConstants = codeBlock->numberOfConstantRegisters();
......@@ -327,6 +328,31 @@ private:
return getJSConstant(m_constantUndefined);
}
// This method returns a JSConstant with the value 'null'.
NodeIndex constantNull()
{
// Has m_constantNull been set up yet?
if (m_constantNull == UINT_MAX) {
// Search the constant pool for null, if we find it, we can just reuse this!
unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters();
for (m_constantNull = 0; m_constantNull < numberOfConstants; ++m_constantNull) {
JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNull);
if (testMe.isNull())
return getJSConstant(m_constantNull);
}
// Add null to the CodeBlock's constants, and add a corresponding slot in m_constantRecords.
ASSERT(m_constantRecords.size() == numberOfConstants);
m_codeBlock->addConstant(jsNull());
m_constantRecords.append(ConstantRecord());
ASSERT(m_constantRecords.size() == m_codeBlock->numberOfConstantRegisters());
}
// m_constantNull must refer to an entry in the CodeBlock's constant pool that has the value 'null'.
ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNull).isNull());
return getJSConstant(m_constantNull);
}
// This method returns a DoubleConstant with the value 1.
NodeIndex one()
{
......@@ -383,7 +409,7 @@ private:
unsigned m_currentIndex;
// FIXME: used to temporarily disable arithmetic, until we fix associated performance regressions.
bool m_noArithmetic;
bool m_regressionGuard;
// We use these values during code generation, and to avoid the need for
// special handling we make sure they are available as constants in the
......@@ -391,6 +417,7 @@ private:
// UINT_MAX, and lazily updated to hold an index into the CodeBlock's
// constant pool, as necessary.
unsigned m_constantUndefined;
unsigned m_constantNull;
unsigned m_constant1;
// A constant in the constant pool may be represented by more than one
......@@ -561,7 +588,7 @@ bool ByteCodeParser::parse()
// === Arithmetic operations ===
case op_add: {
m_noArithmetic = false;
m_regressionGuard = true;
NodeIndex op1 = get(currentInstruction[2].u.operand);
NodeIndex op2 = get(currentInstruction[3].u.operand);
// If both operands can statically be determined to the numbers, then this is an arithmetic add.
......@@ -574,7 +601,7 @@ bool ByteCodeParser::parse()
}
case op_sub: {
m_noArithmetic = false;
m_regressionGuard = true;
NodeIndex op1 = getToNumber(currentInstruction[2].u.operand);
NodeIndex op2 = getToNumber(currentInstruction[3].u.operand);
set(currentInstruction[1].u.operand, addToGraph(ArithSub, op1, op2));
......@@ -582,7 +609,7 @@ bool ByteCodeParser::parse()
}
case op_mul: {
m_noArithmetic = false;
m_regressionGuard = true;
NodeIndex op1 = getToNumber(currentInstruction[2].u.operand);
NodeIndex op2 = getToNumber(currentInstruction[3].u.operand);
set(currentInstruction[1].u.operand, addToGraph(ArithMul, op1, op2));
......@@ -590,7 +617,7 @@ bool ByteCodeParser::parse()
}
case op_mod: {
m_noArithmetic = false;
m_regressionGuard = true;
NodeIndex op1 = getToNumber(currentInstruction[2].u.operand);
NodeIndex op2 = getToNumber(currentInstruction[3].u.operand);
set(currentInstruction[1].u.operand, addToGraph(ArithMod, op1, op2));
......@@ -598,7 +625,7 @@ bool ByteCodeParser::parse()
}
case op_div: {
m_noArithmetic = false;
m_regressionGuard = true;
NodeIndex op1 = getToNumber(currentInstruction[2].u.operand);
NodeIndex op2 = getToNumber(currentInstruction[3].u.operand);
set(currentInstruction[1].u.operand, addToGraph(ArithDiv, op1, op2));
......@@ -613,6 +640,75 @@ bool ByteCodeParser::parse()
NEXT_OPCODE(op_mov);
}
case op_not: {
m_regressionGuard = true;
NodeIndex value = get(currentInstruction[2].u.operand);
set(currentInstruction[1].u.operand, addToGraph(LogicalNot, value));
NEXT_OPCODE(op_not);
}
case op_less: {
m_regressionGuard = true;
NodeIndex op1 = get(currentInstruction[2].u.operand);
NodeIndex op2 = get(currentInstruction[3].u.operand);
set(currentInstruction[1].u.operand, addToGraph(CompareLess, op1, op2));
NEXT_OPCODE(op_less);
}
case op_lesseq: {
m_regressionGuard = true;
NodeIndex op1 = get(currentInstruction[2].u.operand);
NodeIndex op2 = get(currentInstruction[3].u.operand);
set(currentInstruction[1].u.operand, addToGraph(CompareLessEq, op1, op2));
NEXT_OPCODE(op_lesseq);
}
case op_eq: {
m_regressionGuard = true;
NodeIndex op1 = get(currentInstruction[2].u.operand);
NodeIndex op2 = get(currentInstruction[3].u.operand);
set(currentInstruction[1].u.operand, addToGraph(CompareEq, op1, op2));
NEXT_OPCODE(op_eq);
}
case op_eq_null: {
m_regressionGuard = true;
NodeIndex value = get(currentInstruction[2].u.operand);
set(currentInstruction[1].u.operand, addToGraph(CompareEq, value, constantNull()));
NEXT_OPCODE(op_eq_null);
}
case op_stricteq: {
m_regressionGuard = true;
NodeIndex op1 = get(currentInstruction[2].u.operand);
NodeIndex op2 = get(currentInstruction[3].u.operand);
set(currentInstruction[1].u.operand, addToGraph(CompareStrictEq, op1, op2));
NEXT_OPCODE(op_stricteq);
}
case op_neq: {
m_regressionGuard = true;
NodeIndex op1 = get(currentInstruction[2].u.operand);
NodeIndex op2 = get(currentInstruction[3].u.operand);
set(currentInstruction[1].u.operand, addToGraph(LogicalNot, addToGraph(CompareEq, op1, op2)));
NEXT_OPCODE(op_neq);
}
case op_neq_null: {
m_regressionGuard = true;
NodeIndex value = get(currentInstruction[2].u.operand);
set(currentInstruction[1].u.operand, addToGraph(LogicalNot, addToGraph(CompareEq, value, constantNull())));
NEXT_OPCODE(op_neq_null);
}
case op_nstricteq: {
m_regressionGuard = true;
NodeIndex op1 = get(currentInstruction[2].u.operand);
NodeIndex op2 = get(currentInstruction[3].u.operand);
set(currentInstruction[1].u.operand, addToGraph(LogicalNot, addToGraph(CompareStrictEq, op1, op2)));
NEXT_OPCODE(op_nstricteq);
}
// === Property access operations ===
case op_get_by_val: {
......@@ -685,10 +781,10 @@ bool ByteCodeParser::parse()
m_currentIndex += OPCODE_LENGTH(op_ret);
#if ENABLE(DFG_JIT_RESTRICTIONS)
// FIXME: temporarily disabling the DFG JIT for functions containing arithmetic.
return m_noArithmetic;
#else
return true;
if (m_regressionGuard)
return false
#endif
return true;
}
default:
......
......@@ -607,6 +607,26 @@ protected:
appendCallWithExceptionCheck(operation);
m_jit.move(JITCompiler::returnValueRegister, JITCompiler::gprToRegisterID(result));
}
void callOperation(Z_DFGOperation_EJ operation, GPRReg result, GPRReg arg1)
{
ASSERT(isFlushed());
m_jit.move(JITCompiler::gprToRegisterID(arg1), JITCompiler::argumentRegister1);
m_jit.move(JITCompiler::callFrameRegister, JITCompiler::argumentRegister0);
appendCallWithExceptionCheck(operation);
m_jit.move(JITCompiler::returnValueRegister, JITCompiler::gprToRegisterID(result));
}
void callOperation(Z_DFGOperation_EJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
{
ASSERT(isFlushed());
setupStubArguments(arg1, arg2);
m_jit.move(JITCompiler::callFrameRegister, JITCompiler::argumentRegister0);
appendCallWithExceptionCheck(operation);
m_jit.move(JITCompiler::returnValueRegister, JITCompiler::gprToRegisterID(result));
}
void callOperation(J_DFGOperation_EJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
{
ASSERT(isFlushed());
......
......@@ -115,6 +115,15 @@ typedef uint32_t ExceptionInfo;
macro(GetGlobalVar, NodeResultJS | NodeMustGenerate) \
macro(PutGlobalVar, NodeMustGenerate) \
\
/* Nodes for comparison operations. */\
macro(CompareLess, NodeResultJS | NodeMustGenerate) \
macro(CompareLessEq, NodeResultJS | NodeMustGenerate) \
macro(CompareEq, NodeResultJS | NodeMustGenerate) \
macro(CompareStrictEq, NodeResultJS) \
\
/* Nodes for misc operations. */\
macro(LogicalNot, NodeResultJS) \
\
macro(Return, NodeMustGenerate)
// This enum generates a monotonically increasing id for all Node types,
......
......@@ -446,6 +446,80 @@ void NonSpeculativeJIT::compile(SpeculationCheckIndexIterator& checkIterator, No
break;
}
case LogicalNot: {
JSValueOperand arg1(this, node.child1);
GPRReg arg1GPR = arg1.gpr();
flushRegisters();
GPRResult result(this);
callOperation(dfgConvertJSValueToBoolean, result.gpr(), arg1GPR);
// If we add a DataFormatBool, we should use it here.
m_jit.xor32(TrustedImm32(JSImmediate::FullTagTypeTrue), result.registerID());
jsValueResult(result.gpr(), m_compileIndex);
break;
}
case CompareLess: {
JSValueOperand arg1(this, node.child1);
JSValueOperand arg2(this, node.child2);
GPRReg arg1GPR = arg1.gpr();
GPRReg arg2GPR = arg2.gpr();
flushRegisters();
GPRResult result(this);
callOperation(operationCompareLess, result.gpr(), arg1GPR, arg2GPR);
m_jit.or32(TrustedImm32(JSImmediate::FullTagTypeFalse), result.registerID());
jsValueResult(result.gpr(), m_compileIndex);
break;
}
case CompareLessEq: {
JSValueOperand arg1(this, node.child1);
JSValueOperand arg2(this, node.child2);
GPRReg arg1GPR = arg1.gpr();
GPRReg arg2GPR = arg2.gpr();
flushRegisters();
GPRResult result(this);
callOperation(operationCompareLessEq, result.gpr(), arg1GPR, arg2GPR);
m_jit.or32(TrustedImm32(JSImmediate::FullTagTypeFalse), result.registerID());
jsValueResult(result.gpr(), m_compileIndex);
break;
}
case CompareEq: {
JSValueOperand arg1(this, node.child1);
JSValueOperand arg2(this, node.child2);
GPRReg arg1GPR = arg1.gpr();
GPRReg arg2GPR = arg2.gpr();
flushRegisters();
GPRResult result(this);
callOperation(operationCompareEq, result.gpr(), arg1GPR, arg2GPR);
m_jit.or32(TrustedImm32(JSImmediate::FullTagTypeFalse), result.registerID());
jsValueResult(result.gpr(), m_compileIndex);
break;
}
case CompareStrictEq: {
JSValueOperand arg1(this, node.child1);
JSValueOperand arg2(this, node.child2);
GPRReg arg1GPR = arg1.gpr();
GPRReg arg2GPR = arg2.gpr();
flushRegisters();
GPRResult result(this);
callOperation(operationCompareStrictEq, result.gpr(), arg1GPR, arg2GPR);
m_jit.or32(TrustedImm32(JSImmediate::FullTagTypeFalse), result.registerID());
jsValueResult(result.gpr(), m_compileIndex);
break;
}
case GetByVal: {
JSValueOperand arg1(this, node.child1);
JSValueOperand arg2(this, node.child2);
......
......@@ -192,6 +192,26 @@ void operationPutByIdDirectNonStrict(ExecState* exec, EncodedJSValue encodedValu
JSValue::decode(encodedBase).putDirect(exec, *identifier, JSValue::decode(encodedValue), slot);
}
bool operationCompareLess(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
{
return jsLess(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
}
bool operationCompareLessEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
{
return jsLessEq(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
}
bool operationCompareEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
{
return JSValue::equal(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
}
bool operationCompareStrictEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
{
return JSValue::strictEqual(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
}
DFGHandler lookupExceptionHandler(ExecState* exec, ReturnAddressPtr faultLocation)
{
JSValue exceptionValue = exec->exception();
......@@ -215,6 +235,11 @@ int32_t dfgConvertJSValueToInt32(ExecState* exec, EncodedJSValue value)
return JSValue::decode(value).toInt32(exec);
}
bool dfgConvertJSValueToBoolean(ExecState* exec, EncodedJSValue encodedOp)
{
return JSValue::decode(encodedOp).toBoolean(exec);
}
} } // namespace JSC::DFG
#endif
......@@ -42,6 +42,8 @@ typedef EncodedJSValue (*J_DFGOperation_EJJ)(ExecState*, EncodedJSValue, Encoded
typedef EncodedJSValue (*J_DFGOperation_EJ)(ExecState*, EncodedJSValue);
typedef EncodedJSValue (*J_DFGOperation_EJP)(ExecState*, EncodedJSValue, void*);
typedef EncodedJSValue (*J_DFGOperation_EJI)(ExecState*, EncodedJSValue, Identifier*);
typedef bool (*Z_DFGOperation_EJ)(ExecState*, EncodedJSValue);
typedef bool (*Z_DFGOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
typedef void (*V_DFGOperation_EJJJ)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue);
typedef void (*V_DFGOperation_EJJP)(ExecState*, EncodedJSValue, EncodedJSValue, void*);
typedef void (*V_DFGOperation_EJJI)(ExecState*, EncodedJSValue, EncodedJSValue, Identifier*);
......@@ -58,6 +60,10 @@ void operationPutByIdStrict(ExecState*, EncodedJSValue encodedValue, EncodedJSVa
void operationPutByIdNonStrict(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier*);
void operationPutByIdDirectStrict(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier*);
void operationPutByIdDirectNonStrict(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier*);
bool operationCompareLess(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
bool operationCompareLessEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
bool operationCompareEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
bool operationCompareStrictEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
// This method is used to lookup an exception hander, keyed by faultLocation, which is
// the return location from one of the calls out to one of the helper operations above.
......@@ -73,9 +79,10 @@ struct DFGHandler {
};
DFGHandler lookupExceptionHandler(ExecState*, ReturnAddressPtr faultLocation);
// These operations implement the implicitly called ToInt32 and ToNumber conversions from ES5.
// These operations implement the implicitly called ToInt32, ToNumber, and ToBoolean conversions from ES5.
double dfgConvertJSValueToNumber(ExecState*, EncodedJSValue);
int32_t dfgConvertJSValueToInt32(ExecState*, EncodedJSValue);
bool dfgConvertJSValueToBoolean(ExecState*, EncodedJSValue);
} } // namespace JSC::DFG
......
......@@ -434,6 +434,72 @@ bool SpeculativeJIT::compile(Node& node)
break;
}
case LogicalNot: {
JSValueOperand value(this, node.child1);
GPRTemporary result(this); // FIXME: We could reuse, but on speculation fail would need recovery to restore tag (akin to add).
m_jit.move(value.registerID(), result.registerID());
m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(JSImmediate::FullTagTypeFalse)), result.registerID());
speculationCheck(m_jit.branchTestPtr(JITCompiler::NonZero, result.registerID(), TrustedImm32(static_cast<int32_t>(~1))));
m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(JSImmediate::FullTagTypeTrue)), result.registerID());
// If we add a DataFormatBool, we should use it here.
jsValueResult(result.gpr(), m_compileIndex);
break;
}
case CompareLess: {
SpeculateIntegerOperand op1(this, node.child1);
SpeculateIntegerOperand op2(this, node.child2);
GPRTemporary result(this, op1, op2);
m_jit.set32Compare32(JITCompiler::LessThan, op1.registerID(), op2.registerID(), result.registerID());
// If we add a DataFormatBool, we should use it here.
m_jit.or32(TrustedImm32(JSImmediate::FullTagTypeFalse), result.registerID());
jsValueResult(result.gpr(), m_compileIndex);
break;
}
case CompareLessEq: {
SpeculateIntegerOperand op1(this, node.child1);
SpeculateIntegerOperand op2(this, node.child2);
GPRTemporary result(this, op1, op2);
m_jit.set32Compare32(JITCompiler::LessThanOrEqual, op1.registerID(), op2.registerID(), result.registerID());
// If we add a DataFormatBool, we should use it here.
m_jit.or32(TrustedImm32(JSImmediate::FullTagTypeFalse), result.registerID());
jsValueResult(result.gpr(), m_compileIndex);
break;
}
case CompareEq: {
SpeculateIntegerOperand op1(this, node.child1);
SpeculateIntegerOperand op2(this, node.child2);
GPRTemporary result(this, op1, op2);
m_jit.set32Compare32(JITCompiler::Equal, op1.registerID(), op2.registerID(), result.registerID());
// If we add a DataFormatBool, we should use it here.
m_jit.or32(TrustedImm32(JSImmediate::FullTagTypeFalse), result.registerID());
jsValueResult(result.gpr(), m_compileIndex);
break;
}
case CompareStrictEq: {
SpeculateIntegerOperand op1(this, node.child1);
SpeculateIntegerOperand op2(this, node.child2);
GPRTemporary result(this, op1, op2);
m_jit.set32Compare32(JITCompiler::Equal, op1.registerID(), op2.registerID(), result.registerID());
// If we add a DataFormatBool, we should use it here.
m_jit.or32(TrustedImm32(JSImmediate::FullTagTypeFalse), result.registerID());
jsValueResult(result.gpr(), m_compileIndex);
break;
}
case GetByVal: {
NodeIndex alias = node.child3;
if (alias != NoNode) {
......
......@@ -57,7 +57,7 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable
// Checks out okay! - get the length from the Ustring.
load32(Address(regT0, OBJECT_OFFSETOF(JSString, m_length)), regT0);
Jump string_failureCases3 = branch32(Above, regT0, TrustedImm32(JSImmediate::maxImmediateInt));
Jump string_failureCases3 = branch32(LessThan, regT0, TrustedImm32(0));
// regT0 contains a 64 bit value (is positive, is zero extended) so we don't need sign extend here.
emitFastArithIntToImmNoCheck(regT0, regT0);
......
......@@ -697,7 +697,7 @@ void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress)
// Checks out okay! - get the length from the storage
loadPtr(Address(regT0, JSArray::storageOffset()), regT3);
load32(Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length)), regT2);
Jump failureCases2 = branch32(Above, regT2, TrustedImm32(JSImmediate::maxImmediateInt));
Jump failureCases2 = branch32(LessThan, regT2, TrustedImm32(0));
emitFastArithIntToImmNoCheck(regT2, regT0);
Jump success = jump();
......
......@@ -105,11 +105,7 @@ namespace JSC {
*/
class JSImmediate {
private:
friend class JIT;
friend class JSValue;
friend class JSInterfaceJIT;
friend class SpecializedThunkJIT;
friend JSValue jsNumber(ExecState* exec, double d);
friend JSValue jsNumber(ExecState*, char i);
friend JSValue jsNumber(ExecState*, unsigned char i);
......@@ -131,6 +127,7 @@ namespace JSC {
friend JSValue jsNumber(JSGlobalData* globalData, long long i);
friend JSValue jsNumber(JSGlobalData* globalData, unsigned long long i);
public:
// If all bits in the mask are set, this indicates an integer number,
// if any but not all are set this value is a double precision number.
static const intptr_t TagTypeNumber = 0xffff000000000000ll;
......@@ -150,6 +147,7 @@ namespace JSC {
static const intptr_t FullTagTypeUndefined = TagBitTypeOther | ExtendedTagBitUndefined;
static const intptr_t FullTagTypeNull = TagBitTypeOther;
private:
static ALWAYS_INLINE bool isImmediate(JSValue v)
{
return rawValue(v) & TagMask;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment