Commit 71a0340c authored by ggaren@apple.com's avatar ggaren@apple.com

Take one branch instead of two to test for JSValue().

        
Patch by Geoffrey Garen <ggaren@apple.com> on 2009-10-01
Reviewed by Sam Weinig.

1.1% SunSpider speedup.

* jit/JITCall.cpp:
(JSC::JIT::compileOpCall):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_to_jsnumber):
(JSC::JIT::emit_op_create_arguments):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emitSlow_op_get_by_val):
(JSC::JIT::emit_op_put_by_val): Test for the empty value tag, instead
of testing for the cell tag with a 0 payload.

* runtime/JSValue.cpp:
(JSC::JSValue::description): Added support for dumping the new empty value,
and deleted values, in debug builds.

* runtime/JSValue.h:
(JSC::JSValue::JSValue()): Construct JSValue() with the empty value tag.

(JSC::JSValue::JSValue(JSCell*)): Convert null pointer to the empty value
tag, to avoid having two different c++ versions of null / empty.

(JSC::JSValue::operator bool): Test for the empty value tag, instead
of testing for the cell tag with a 0 payload.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@49004 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent c20916e7
2009-10-01 Geoffrey Garen <ggaren@apple.com>
Reviewed by Sam Weinig.
Take one branch instead of two to test for JSValue().
1.1% SunSpider speedup.
* jit/JITCall.cpp:
(JSC::JIT::compileOpCall):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_to_jsnumber):
(JSC::JIT::emit_op_create_arguments):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emitSlow_op_get_by_val):
(JSC::JIT::emit_op_put_by_val): Test for the empty value tag, instead
of testing for the cell tag with a 0 payload.
* runtime/JSValue.cpp:
(JSC::JSValue::description): Added support for dumping the new empty value,
and deleted values, in debug builds.
* runtime/JSValue.h:
(JSC::JSValue::JSValue()): Construct JSValue() with the empty value tag.
(JSC::JSValue::JSValue(JSCell*)): Convert null pointer to the empty value
tag, to avoid having two different c++ versions of null / empty.
(JSC::JSValue::operator bool): Test for the empty value tag, instead
of testing for the cell tag with a 0 payload.
2009-10-01 Yongjun Zhang <yongjun.zhang@nokia.com>
Reviewed by Darin Adler.
......
......@@ -236,16 +236,14 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned)
int argCount = instruction[3].u.operand;
int registerOffset = instruction[4].u.operand;
Jump wasEval1;
Jump wasEval2;
Jump wasEval;
if (opcodeID == op_call_eval) {
JITStubCall stubCall(this, cti_op_call_eval);
stubCall.addArgument(callee);
stubCall.addArgument(JIT::Imm32(registerOffset));
stubCall.addArgument(JIT::Imm32(argCount));
stubCall.call();
wasEval1 = branchTest32(NonZero, regT0);
wasEval2 = branch32(NotEqual, regT1, Imm32(JSValue::CellTag));
wasEval = branch32(Equal, regT1, Imm32(JSValue::EmptyValueTag));
}
emitLoad(callee, regT1, regT2);
......@@ -271,10 +269,8 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned)
emitNakedCall(m_globalData->jitStubs.ctiVirtualCall());
if (opcodeID == op_call_eval) {
wasEval1.link(this);
wasEval2.link(this);
}
if (opcodeID == op_call_eval)
wasEval.link(this);
emitStore(dst, regT1, regT0);;
......@@ -306,16 +302,14 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned ca
int argCount = instruction[3].u.operand;
int registerOffset = instruction[4].u.operand;
Jump wasEval1;
Jump wasEval2;
Jump wasEval;
if (opcodeID == op_call_eval) {
JITStubCall stubCall(this, cti_op_call_eval);
stubCall.addArgument(callee);
stubCall.addArgument(JIT::Imm32(registerOffset));
stubCall.addArgument(JIT::Imm32(argCount));
stubCall.call();
wasEval1 = branchTest32(NonZero, regT0);
wasEval2 = branch32(NotEqual, regT1, Imm32(JSValue::CellTag));
wasEval = branch32(NotEqual, regT1, Imm32(JSValue::EmptyValueTag));
}
emitLoad(callee, regT1, regT0);
......@@ -359,10 +353,8 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned ca
// Call to the callee
m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall();
if (opcodeID == op_call_eval) {
wasEval1.link(this);
wasEval2.link(this);
}
if (opcodeID == op_call_eval)
wasEval.link(this);
// Put the return value in dst. In the interpreter, op_ret does this.
emitStore(dst, regT1, regT0);
......
......@@ -248,10 +248,8 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable
addPtr(Imm32(NativeCallFrameSize - sizeof(NativeFunctionCalleeSignature)), stackPointerRegister);
// Check for an exception
// FIXME: Maybe we can optimize this comparison to JSValue().
move(ImmPtr(&globalData->exception), regT2);
Jump sawException1 = branch32(NotEqual, tagFor(0, regT2), Imm32(JSValue::CellTag));
Jump sawException2 = branch32(NonZero, payloadFor(0, regT2), Imm32(0));
Jump sawException = branch32(NotEqual, tagFor(0, regT2), Imm32(JSValue::EmptyValueTag));
// Grab the return address.
emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT3);
......@@ -264,8 +262,7 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable
ret();
// Handle an exception
sawException1.link(this);
sawException2.link(this);
sawException.link(this);
// Grab the return address.
emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1);
move(ImmPtr(&globalData->exceptionLocation), regT2);
......@@ -1237,7 +1234,7 @@ void JIT::emit_op_to_jsnumber(Instruction* currentInstruction)
emitLoad(src, regT1, regT0);
Jump isInt32 = branch32(Equal, regT1, Imm32(JSValue::Int32Tag));
addSlowCase(branch32(AboveOrEqual, regT1, Imm32(JSValue::DeletedValueTag)));
addSlowCase(branch32(AboveOrEqual, regT1, Imm32(JSValue::EmptyValueTag)));
isInt32.link(this);
if (src != dst)
......@@ -1381,8 +1378,7 @@ void JIT::emit_op_enter_with_activation(Instruction* currentInstruction)
void JIT::emit_op_create_arguments(Instruction*)
{
Jump argsNotCell = branch32(NotEqual, tagFor(RegisterFile::ArgumentsRegister, callFrameRegister), Imm32(JSValue::CellTag));
Jump argsNotNull = branchTestPtr(NonZero, payloadFor(RegisterFile::ArgumentsRegister, callFrameRegister));
Jump argsCreated = branch32(NotEqual, tagFor(RegisterFile::ArgumentsRegister, callFrameRegister), Imm32(JSValue::EmptyValueTag));
// If we get here the arguments pointer is a null cell - i.e. arguments need lazy creation.
if (m_codeBlock->m_numParameters == 1)
......@@ -1390,8 +1386,7 @@ void JIT::emit_op_create_arguments(Instruction*)
else
JITStubCall(this, cti_op_create_arguments).call();
argsNotCell.link(this);
argsNotNull.link(this);
argsCreated.link(this);
}
void JIT::emit_op_init_arguments(Instruction*)
......
......@@ -310,12 +310,8 @@ void JIT::emitSlow_op_get_by_val(Instruction* currentInstruction, Vector<SlowCas
// Missed the fast region, but it is still in the vector.
load32(BaseIndex(regT0, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + 4), regT1); // tag
load32(BaseIndex(regT0, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), regT0); // payload
branch32(Equal, regT1, Imm32(JSValue::EmptyValueTag)).linkTo(callGetByValJITStub, this);
// FIXME: Maybe we can optimize this comparison to JSValue().
Jump skip = branch32(NotEqual, regT0, Imm32(0));
branch32(Equal, regT1, Imm32(JSValue::CellTag), callGetByValJITStub);
skip.link(this);
emitStore(dst, regT1, regT0);
}
......@@ -333,15 +329,13 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction)
loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT3);
Jump inFastVector = branch32(Below, regT2, Address(regT0, OBJECT_OFFSETOF(JSArray, m_fastAccessCutoff)));
// Check if the access is within the vector.
addSlowCase(branch32(AboveOrEqual, regT2, Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_vectorLength))));
// This is a write to the slow part of the vector; first, we have to check if this would be the first write to this location.
// FIXME: should be able to handle initial write to array; increment the the number of items in the array, and potentially update fast access cutoff.
Jump skip = branch32(NotEqual, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + 4), Imm32(JSValue::CellTag));
addSlowCase(branch32(Equal, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), Imm32(0)));
skip.link(this);
addSlowCase(branch32(Equal, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + 4), Imm32(JSValue::EmptyValueTag)));
inFastVector.link(this);
......
......@@ -122,9 +122,13 @@ char* JSValue::description()
snprintf(description, size, "False");
else if (isNull())
snprintf(description, size, "Null");
else {
ASSERT(isUndefined());
else if (isUndefined())
snprintf(description, size, "Undefined");
else if (tag() == EmptyValueTag)
snprintf(description, size, "<JSValue()>");
else {
ASSERT(tag() == DeletedValueTag);
snprintf(description, size, "<HashTableDeletedValue>");
}
return description;
......
......@@ -213,7 +213,8 @@ namespace JSC {
enum { FalseTag = 0xfffffffc };
enum { NullTag = 0xfffffffb };
enum { UndefinedTag = 0xfffffffa };
enum { DeletedValueTag = 0xfffffff9 };
enum { EmptyValueTag = 0xfffffff9 };
enum { DeletedValueTag = 0xfffffff8 };
enum { LowestTag = DeletedValueTag };
......@@ -427,7 +428,7 @@ namespace JSC {
inline JSValue::JSValue()
{
u.asBits.tag = CellTag;
u.asBits.tag = EmptyValueTag;
u.asBits.payload = 0;
}
......@@ -463,19 +464,26 @@ namespace JSC {
inline JSValue::JSValue(JSCell* ptr)
{
u.asBits.tag = CellTag;
if (ptr)
u.asBits.tag = CellTag;
else
u.asBits.tag = EmptyValueTag;
u.asBits.payload = reinterpret_cast<int32_t>(ptr);
}
inline JSValue::JSValue(const JSCell* ptr)
{
u.asBits.tag = CellTag;
if (ptr)
u.asBits.tag = CellTag;
else
u.asBits.tag = EmptyValueTag;
u.asBits.payload = reinterpret_cast<int32_t>(const_cast<JSCell*>(ptr));
}
inline JSValue::operator bool() const
{
return u.asBits.payload || tag() != CellTag;
ASSERT(tag() != DeletedValueTag);
return tag() != EmptyValueTag;
}
inline bool JSValue::operator==(const JSValue& other) const
......
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