Commit 5139edc1 authored by barraclough@apple.com's avatar barraclough@apple.com

Mapping booleans the same way as integers

https://bugs.webkit.org/show_bug.cgi?id=56913

Patch by Zoltan Herczeg <zherczeg@webkit.org> on 2011-04-07
Reviewed by Gavin Barraclough.

Instead of having a seperate tag field for booleans,
the logical values are stored in the payload field
(for JSValue32_64 representation).

1.007x speedup on SunSpider.

* jit/JIT.h:
* jit/JITInlineMethods.h:
(JSC::JIT::emitStoreBool):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_instanceof):
(JSC::JIT::emit_op_not):
(JSC::JIT::emit_op_jfalse):
(JSC::JIT::emitSlow_op_jfalse):
(JSC::JIT::emit_op_jtrue):
(JSC::JIT::emitSlow_op_jtrue):
(JSC::JIT::emit_op_jeq_null):
(JSC::JIT::emit_op_jneq_null):
(JSC::JIT::emit_op_eq):
(JSC::JIT::emitSlow_op_eq):
(JSC::JIT::emit_op_neq):
(JSC::JIT::emitSlow_op_neq):
(JSC::JIT::compileOpStrictEq):
(JSC::JIT::emit_op_eq_null):
(JSC::JIT::emit_op_neq_null):
* jit/JSInterfaceJIT.h:
* runtime/JSValue.h:
(JSC::JSValue::JSValue):
(JSC::JSValue::isTrue):
(JSC::JSValue::isFalse):
(JSC::JSValue::getBoolean):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@83230 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent d5a6064e
2011-04-07 Zoltan Herczeg <zherczeg@webkit.org>
Reviewed by Gavin Barraclough.
Mapping booleans the same way as integers
https://bugs.webkit.org/show_bug.cgi?id=56913
Instead of having a seperate tag field for booleans,
the logical values are stored in the payload field
(for JSValue32_64 representation).
1.007x speedup on SunSpider.
* jit/JIT.h:
* jit/JITInlineMethods.h:
(JSC::JIT::emitStoreBool):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_instanceof):
(JSC::JIT::emit_op_not):
(JSC::JIT::emit_op_jfalse):
(JSC::JIT::emitSlow_op_jfalse):
(JSC::JIT::emit_op_jtrue):
(JSC::JIT::emitSlow_op_jtrue):
(JSC::JIT::emit_op_jeq_null):
(JSC::JIT::emit_op_jneq_null):
(JSC::JIT::emit_op_eq):
(JSC::JIT::emitSlow_op_eq):
(JSC::JIT::emit_op_neq):
(JSC::JIT::emitSlow_op_neq):
(JSC::JIT::compileOpStrictEq):
(JSC::JIT::emit_op_eq_null):
(JSC::JIT::emit_op_neq_null):
* jit/JSInterfaceJIT.h:
* runtime/JSValue.h:
(JSC::JSValue::JSValue):
(JSC::JSValue::isTrue):
(JSC::JSValue::isFalse):
(JSC::JSValue::getBoolean):
2011-04-07 Eric Seidel <eric@webkit.org>
Reviewed by Adam Barth.
......
......@@ -311,7 +311,7 @@ namespace JSC {
void emitStoreInt32(unsigned index, RegisterID payload, bool indexIsInt32 = false);
void emitStoreInt32(unsigned index, TrustedImm32 payload, bool indexIsInt32 = false);
void emitStoreCell(unsigned index, RegisterID payload, bool indexIsCell = false);
void emitStoreBool(unsigned index, RegisterID tag, bool indexIsBool = false);
void emitStoreBool(unsigned index, RegisterID payload, bool indexIsBool = false);
void emitStoreDouble(unsigned index, FPRegisterID value);
bool isLabeled(unsigned bytecodeOffset);
......
......@@ -453,11 +453,11 @@ inline void JIT::emitStoreCell(unsigned index, RegisterID payload, bool indexIsC
store32(TrustedImm32(JSValue::CellTag), tagFor(index, callFrameRegister));
}
inline void JIT::emitStoreBool(unsigned index, RegisterID tag, bool indexIsBool)
inline void JIT::emitStoreBool(unsigned index, RegisterID payload, bool indexIsBool)
{
store32(payload, payloadFor(index, callFrameRegister));
if (!indexIsBool)
store32(TrustedImm32(0), payloadFor(index, callFrameRegister));
store32(tag, tagFor(index, callFrameRegister));
store32(TrustedImm32(JSValue::BooleanTag), tagFor(index, callFrameRegister));
}
inline void JIT::emitStoreDouble(unsigned index, FPRegisterID value)
......
......@@ -553,7 +553,7 @@ void JIT::emit_op_instanceof(Instruction* currentInstruction)
// Optimistically load the result true, and start looping.
// Initially, regT1 still contains proto and regT2 still contains value.
// As we loop regT2 will be updated with its prototype, recursively walking the prototype chain.
move(TrustedImm32(JSValue::TrueTag), regT0);
move(TrustedImm32(1), regT0);
Label loop(this);
// Load the prototype of the cell in regT2. If this is equal to regT1 - WIN!
......@@ -564,7 +564,7 @@ void JIT::emit_op_instanceof(Instruction* currentInstruction)
branchTest32(NonZero, regT2).linkTo(loop, this);
// We get here either by dropping out of the loop, or if value was not an Object. Result is false.
move(TrustedImm32(JSValue::FalseTag), regT0);
move(TrustedImm32(0), regT0);
// isInstance jumps right down to here, to skip setting the result to false (it has already set true).
isInstance.link(this);
......@@ -829,9 +829,9 @@ void JIT::emit_op_not(Instruction* currentInstruction)
emitLoadTag(src, regT0);
xor32(TrustedImm32(JSValue::FalseTag), regT0);
addSlowCase(branchTest32(NonZero, regT0, TrustedImm32(~1)));
xor32(TrustedImm32(JSValue::TrueTag), regT0);
emitLoad(src, regT1, regT0);
addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::BooleanTag)));
xor32(TrustedImm32(1), regT0);
emitStoreBool(dst, regT0, (dst == src));
}
......@@ -855,25 +855,9 @@ void JIT::emit_op_jfalse(Instruction* currentInstruction)
emitLoad(cond, regT1, regT0);
Jump isTrue = branch32(Equal, regT1, TrustedImm32(JSValue::TrueTag));
addJump(branch32(Equal, regT1, TrustedImm32(JSValue::FalseTag)), target);
Jump isNotInteger = branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag));
Jump isTrue2 = branch32(NotEqual, regT0, TrustedImm32(0));
addJump(jump(), target);
if (supportsFloatingPoint()) {
isNotInteger.link(this);
addSlowCase(branch32(Above, regT1, TrustedImm32(JSValue::LowestTag)));
emitLoadDouble(cond, fpRegT0);
addJump(branchDoubleZeroOrNaN(fpRegT0, fpRegT1), target);
} else
addSlowCase(isNotInteger);
isTrue.link(this);
isTrue2.link(this);
ASSERT((JSValue::BooleanTag + 1 == JSValue::Int32Tag) && !(JSValue::Int32Tag + 1));
addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::BooleanTag)));
addJump(branchTest32(Zero, regT0), target);
}
void JIT::emitSlow_op_jfalse(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
......@@ -882,6 +866,18 @@ void JIT::emitSlow_op_jfalse(Instruction* currentInstruction, Vector<SlowCaseEnt
unsigned target = currentInstruction[2].u.operand;
linkSlowCase(iter);
if (supportsFloatingPoint()) {
// regT1 contains the tag from the hot path.
Jump notNumber = branch32(Above, regT1, Imm32(JSValue::LowestTag));
emitLoadDouble(cond, fpRegT0);
emitJumpSlowToHot(branchDoubleZeroOrNaN(fpRegT0, fpRegT1), target);
emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jfalse));
notNumber.link(this);
}
JITStubCall stubCall(this, cti_op_jtrue);
stubCall.addArgument(cond);
stubCall.call();
......@@ -895,25 +891,9 @@ void JIT::emit_op_jtrue(Instruction* currentInstruction)
emitLoad(cond, regT1, regT0);
Jump isFalse = branch32(Equal, regT1, TrustedImm32(JSValue::FalseTag));
addJump(branch32(Equal, regT1, TrustedImm32(JSValue::TrueTag)), target);
Jump isNotInteger = branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag));
Jump isFalse2 = branch32(Equal, regT0, TrustedImm32(0));
addJump(jump(), target);
if (supportsFloatingPoint()) {
isNotInteger.link(this);
addSlowCase(branch32(Above, regT1, TrustedImm32(JSValue::LowestTag)));
emitLoadDouble(cond, fpRegT0);
addJump(branchDoubleNonZero(fpRegT0, fpRegT1), target);
} else
addSlowCase(isNotInteger);
isFalse.link(this);
isFalse2.link(this);
ASSERT((JSValue::BooleanTag + 1 == JSValue::Int32Tag) && !(JSValue::Int32Tag + 1));
addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::BooleanTag)));
addJump(branchTest32(NonZero, regT0), target);
}
void JIT::emitSlow_op_jtrue(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
......@@ -922,6 +902,18 @@ void JIT::emitSlow_op_jtrue(Instruction* currentInstruction, Vector<SlowCaseEntr
unsigned target = currentInstruction[2].u.operand;
linkSlowCase(iter);
if (supportsFloatingPoint()) {
// regT1 contains the tag from the hot path.
Jump notNumber = branch32(Above, regT1, Imm32(JSValue::LowestTag));
emitLoadDouble(cond, fpRegT0);
emitJumpSlowToHot(branchDoubleNonZero(fpRegT0, fpRegT1), target);
emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jtrue));
notNumber.link(this);
}
JITStubCall stubCall(this, cti_op_jtrue);
stubCall.addArgument(cond);
stubCall.call();
......@@ -946,8 +938,9 @@ void JIT::emit_op_jeq_null(Instruction* currentInstruction)
// Now handle the immediate cases - undefined & null
isImmediate.link(this);
ASSERT((JSValue::UndefinedTag + 1 == JSValue::NullTag) && !(JSValue::NullTag + 1));
addJump(branch32(AboveOrEqual, regT1, TrustedImm32(JSValue::UndefinedTag)), target);
ASSERT((JSValue::UndefinedTag + 1 == JSValue::NullTag) && (JSValue::NullTag & 0x1));
or32(TrustedImm32(1), regT1);
addJump(branch32(Equal, regT1, TrustedImm32(JSValue::NullTag)), target);
wasNotImmediate.link(this);
}
......@@ -970,8 +963,9 @@ void JIT::emit_op_jneq_null(Instruction* currentInstruction)
// Now handle the immediate cases - undefined & null
isImmediate.link(this);
ASSERT((JSValue::UndefinedTag + 1 == JSValue::NullTag) && !(JSValue::NullTag + 1));
addJump(branch32(Below, regT1, TrustedImm32(JSValue::UndefinedTag)), target);
ASSERT((JSValue::UndefinedTag + 1 == JSValue::NullTag) && (JSValue::NullTag & 0x1));
or32(TrustedImm32(1), regT1);
addJump(branch32(NotEqual, regT1, TrustedImm32(JSValue::NullTag)), target);
wasNotImmediate.link(this);
}
......@@ -1012,8 +1006,7 @@ void JIT::emit_op_eq(Instruction* currentInstruction)
addSlowCase(branch32(Equal, regT1, TrustedImm32(JSValue::CellTag)));
addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::LowestTag)));
set8Compare32(Equal, regT0, regT2, regT0);
or32(TrustedImm32(JSValue::FalseTag), regT0);
set32Compare32(Equal, regT0, regT2, regT0);
emitStoreBool(dst, regT0);
}
......@@ -1049,7 +1042,6 @@ void JIT::emitSlow_op_eq(Instruction* currentInstruction, Vector<SlowCaseEntry>:
stubCallEq.call(regT0);
storeResult.link(this);
or32(TrustedImm32(JSValue::FalseTag), regT0);
emitStoreBool(dst, regT0);
}
......@@ -1064,8 +1056,7 @@ void JIT::emit_op_neq(Instruction* currentInstruction)
addSlowCase(branch32(Equal, regT1, TrustedImm32(JSValue::CellTag)));
addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::LowestTag)));
set8Compare32(NotEqual, regT0, regT2, regT0);
or32(TrustedImm32(JSValue::FalseTag), regT0);
set32Compare32(NotEqual, regT0, regT2, regT0);
emitStoreBool(dst, regT0);
}
......@@ -1100,7 +1091,6 @@ void JIT::emitSlow_op_neq(Instruction* currentInstruction, Vector<SlowCaseEntry>
storeResult.link(this);
xor32(TrustedImm32(0x1), regT0);
or32(TrustedImm32(JSValue::FalseTag), regT0);
emitStoreBool(dst, regT0);
}
......@@ -1121,11 +1111,9 @@ void JIT::compileOpStrictEq(Instruction* currentInstruction, CompileOpStrictEqTy
addSlowCase(branch32(AboveOrEqual, regT2, TrustedImm32(JSValue::CellTag)));
if (type == OpStrictEq)
set8Compare32(Equal, regT0, regT1, regT0);
set32Compare32(Equal, regT0, regT1, regT0);
else
set8Compare32(NotEqual, regT0, regT1, regT0);
or32(TrustedImm32(JSValue::FalseTag), regT0);
set32Compare32(NotEqual, regT0, regT1, regT0);
emitStoreBool(dst, regT0);
}
......@@ -1185,14 +1173,12 @@ void JIT::emit_op_eq_null(Instruction* currentInstruction)
isImmediate.link(this);
set8Compare32(Equal, regT1, TrustedImm32(JSValue::NullTag), regT2);
set8Compare32(Equal, regT1, TrustedImm32(JSValue::UndefinedTag), regT1);
set32Compare32(Equal, regT1, TrustedImm32(JSValue::NullTag), regT2);
set32Compare32(Equal, regT1, TrustedImm32(JSValue::UndefinedTag), regT1);
or32(regT2, regT1);
wasNotImmediate.link(this);
or32(TrustedImm32(JSValue::FalseTag), regT1);
emitStoreBool(dst, regT1);
}
......@@ -1211,14 +1197,12 @@ void JIT::emit_op_neq_null(Instruction* currentInstruction)
isImmediate.link(this);
set8Compare32(NotEqual, regT1, TrustedImm32(JSValue::NullTag), regT2);
set8Compare32(NotEqual, regT1, TrustedImm32(JSValue::UndefinedTag), regT1);
set32Compare32(NotEqual, regT1, TrustedImm32(JSValue::NullTag), regT2);
set32Compare32(NotEqual, regT1, TrustedImm32(JSValue::UndefinedTag), regT1);
and32(regT2, regT1);
wasNotImmediate.link(this);
or32(TrustedImm32(JSValue::FalseTag), regT1);
emitStoreBool(dst, regT1);
}
......
......@@ -160,7 +160,7 @@ namespace JSC {
#if USE(JSVALUE32_64)
// Can't just propogate JSValue::Int32Tag as visual studio doesn't like it
static const unsigned Int32Tag = 0xfffffffd;
static const unsigned Int32Tag = 0xffffffff;
COMPILE_ASSERT(Int32Tag == JSValue::Int32Tag, Int32Tag_out_of_sync);
#else
static const unsigned Int32Tag = JSImmediate::TagTypeNumber >> 32;
......
......@@ -268,18 +268,17 @@ namespace JSC {
*
* For JSValues that do not contain a double value, the high 32 bits contain the tag
* values listed in the enums below, which all correspond to NaN-space. In the case of
* cell and integer values the lower 32 bits (the 'payload') contain the pointer or
* integer value; in the case of all other tags the payload is 0.
* cell, integer and bool values the lower 32 bits (the 'payload') contain the pointer
* integer or boolean value; in the case of all other tags the payload is 0.
*/
enum { NullTag = 0xffffffff };
enum { UndefinedTag = 0xfffffffe };
enum { Int32Tag = 0xfffffffd };
enum { CellTag = 0xfffffffc };
enum { TrueTag = 0xfffffffb };
enum { FalseTag = 0xfffffffa };
enum { EmptyValueTag = 0xfffffff9 };
enum { DeletedValueTag = 0xfffffff8 };
enum { Int32Tag = 0xffffffff };
enum { BooleanTag = 0xfffffffe };
enum { NullTag = 0xfffffffd };
enum { UndefinedTag = 0xfffffffc };
enum { CellTag = 0xfffffffb };
enum { EmptyValueTag = 0xfffffffa };
enum { DeletedValueTag = 0xfffffff9 };
enum { LowestTag = DeletedValueTag };
uint32_t tag() const;
......@@ -443,13 +442,13 @@ namespace JSC {
inline JSValue::JSValue(JSTrueTag)
{
u.asBits.tag = TrueTag;
u.asBits.payload = 0;
u.asBits.tag = BooleanTag;
u.asBits.payload = 1;
}
inline JSValue::JSValue(JSFalseTag)
{
u.asBits.tag = FalseTag;
u.asBits.tag = BooleanTag;
u.asBits.payload = 0;
}
......@@ -536,12 +535,12 @@ namespace JSC {
inline bool JSValue::isTrue() const
{
return tag() == TrueTag;
return tag() == BooleanTag && payload();
}
inline bool JSValue::isFalse() const
{
return tag() == FalseTag;
return tag() == BooleanTag && !payload();
}
inline uint32_t JSValue::tag() const
......@@ -691,7 +690,7 @@ namespace JSC {
inline bool JSValue::getBoolean() const
{
ASSERT(isBoolean());
return tag() == TrueTag;
return payload();
}
inline double JSValue::uncheckedGetNumber() 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