Commit 560dde7c authored by barraclough@apple.com's avatar barraclough@apple.com

Bug 58263 - Use EncodedValueDescriptor on both JSVALUE32_64, JSVALUE64

Reviewed by Sam Weinig.

The JSJITInterface already uses EncodedValueDescriptor to access the tag/payload
separately on JSVALUE64, even though EncodedValueDescriptor is not used in
JSVALUE64's implementation of JSValue. Remove the separate definition for m_ptr
on X86_64. Using the union allows us to remove a layer of makeImmediate()/
immedaiteValue() methods.

* dfg/DFGNonSpeculativeJIT.cpp:
(JSC::DFG::NonSpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* jit/JITInlineMethods.h:
(JSC::JIT::emitTagAsBoolImmediate):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_not):
(JSC::JIT::emit_op_jeq_null):
(JSC::JIT::emit_op_jneq_null):
(JSC::JIT::emit_op_get_pnames):
(JSC::JIT::emit_op_eq_null):
(JSC::JIT::emit_op_neq_null):
(JSC::JIT::emitSlow_op_not):
* runtime/JSCell.h:
* runtime/JSValue.h:
* runtime/JSValueInlineMethods.h:
(JSC::JSValue::encode):
(JSC::JSValue::decode):
(JSC::JSValue::operator==):
(JSC::JSValue::operator!=):
(JSC::JSValue::JSValue):
(JSC::JSValue::operator bool):
(JSC::JSValue::asInt32):
(JSC::JSValue::isUndefinedOrNull):
(JSC::JSValue::isBoolean):
(JSC::JSValue::isCell):
(JSC::JSValue::isInt32):
(JSC::JSValue::asDouble):
(JSC::JSValue::isNumber):
(JSC::JSValue::asCell):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@83517 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 0ea3dedd
2011-04-11 Gavin Barraclough <barraclough@apple.com>
Reviewed by Sam Weinig.
Bug 58263 - Use EncodedValueDescriptor on both JSVALUE32_64, JSVALUE64
The JSJITInterface already uses EncodedValueDescriptor to access the tag/payload
separately on JSVALUE64, even though EncodedValueDescriptor is not used in
JSVALUE64's implementation of JSValue. Remove the separate definition for m_ptr
on X86_64. Using the union allows us to remove a layer of makeImmediate()/
immedaiteValue() methods.
* dfg/DFGNonSpeculativeJIT.cpp:
(JSC::DFG::NonSpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* jit/JITInlineMethods.h:
(JSC::JIT::emitTagAsBoolImmediate):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_not):
(JSC::JIT::emit_op_jeq_null):
(JSC::JIT::emit_op_jneq_null):
(JSC::JIT::emit_op_get_pnames):
(JSC::JIT::emit_op_eq_null):
(JSC::JIT::emit_op_neq_null):
(JSC::JIT::emitSlow_op_not):
* runtime/JSCell.h:
* runtime/JSValue.h:
* runtime/JSValueInlineMethods.h:
(JSC::JSValue::encode):
(JSC::JSValue::decode):
(JSC::JSValue::operator==):
(JSC::JSValue::operator!=):
(JSC::JSValue::JSValue):
(JSC::JSValue::operator bool):
(JSC::JSValue::asInt32):
(JSC::JSValue::isUndefinedOrNull):
(JSC::JSValue::isBoolean):
(JSC::JSValue::isCell):
(JSC::JSValue::isInt32):
(JSC::JSValue::asDouble):
(JSC::JSValue::isNumber):
(JSC::JSValue::asCell):
2011-04-11 Geoffrey Garen <ggaren@apple.com>
Try to fix a few builds.
......
......@@ -455,7 +455,7 @@ void NonSpeculativeJIT::compile(SpeculationCheckIndexIterator& checkIterator, No
callOperation(dfgConvertJSValueToBoolean, result.gpr(), arg1GPR);
// If we add a DataFormatBool, we should use it here.
m_jit.xor32(TrustedImm32(FullTagTypeTrue), result.registerID());
m_jit.xor32(TrustedImm32(ValueTrue), result.registerID());
jsValueResult(result.gpr(), m_compileIndex);
break;
}
......@@ -469,7 +469,7 @@ void NonSpeculativeJIT::compile(SpeculationCheckIndexIterator& checkIterator, No
GPRResult result(this);
callOperation(operationCompareLess, result.gpr(), arg1GPR, arg2GPR);
m_jit.or32(TrustedImm32(FullTagTypeFalse), result.registerID());
m_jit.or32(TrustedImm32(ValueFalse), result.registerID());
jsValueResult(result.gpr(), m_compileIndex);
break;
......@@ -484,7 +484,7 @@ void NonSpeculativeJIT::compile(SpeculationCheckIndexIterator& checkIterator, No
GPRResult result(this);
callOperation(operationCompareLessEq, result.gpr(), arg1GPR, arg2GPR);
m_jit.or32(TrustedImm32(FullTagTypeFalse), result.registerID());
m_jit.or32(TrustedImm32(ValueFalse), result.registerID());
jsValueResult(result.gpr(), m_compileIndex);
break;
......@@ -499,7 +499,7 @@ void NonSpeculativeJIT::compile(SpeculationCheckIndexIterator& checkIterator, No
GPRResult result(this);
callOperation(operationCompareEq, result.gpr(), arg1GPR, arg2GPR);
m_jit.or32(TrustedImm32(FullTagTypeFalse), result.registerID());
m_jit.or32(TrustedImm32(ValueFalse), result.registerID());
jsValueResult(result.gpr(), m_compileIndex);
break;
......@@ -514,7 +514,7 @@ void NonSpeculativeJIT::compile(SpeculationCheckIndexIterator& checkIterator, No
GPRResult result(this);
callOperation(operationCompareStrictEq, result.gpr(), arg1GPR, arg2GPR);
m_jit.or32(TrustedImm32(FullTagTypeFalse), result.registerID());
m_jit.or32(TrustedImm32(ValueFalse), result.registerID());
jsValueResult(result.gpr(), m_compileIndex);
break;
......
......@@ -439,9 +439,9 @@ bool SpeculativeJIT::compile(Node& node)
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>(FullTagTypeFalse)), result.registerID());
m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), result.registerID());
speculationCheck(m_jit.branchTestPtr(JITCompiler::NonZero, result.registerID(), TrustedImm32(static_cast<int32_t>(~1))));
m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(FullTagTypeTrue)), result.registerID());
m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueTrue)), result.registerID());
// If we add a DataFormatBool, we should use it here.
jsValueResult(result.gpr(), m_compileIndex);
......@@ -456,7 +456,7 @@ bool SpeculativeJIT::compile(Node& node)
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(FullTagTypeFalse), result.registerID());
m_jit.or32(TrustedImm32(ValueFalse), result.registerID());
jsValueResult(result.gpr(), m_compileIndex);
break;
}
......@@ -469,7 +469,7 @@ bool SpeculativeJIT::compile(Node& node)
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(FullTagTypeFalse), result.registerID());
m_jit.or32(TrustedImm32(ValueFalse), result.registerID());
jsValueResult(result.gpr(), m_compileIndex);
break;
}
......@@ -482,7 +482,7 @@ bool SpeculativeJIT::compile(Node& node)
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(FullTagTypeFalse), result.registerID());
m_jit.or32(TrustedImm32(ValueFalse), result.registerID());
jsValueResult(result.gpr(), m_compileIndex);
break;
}
......@@ -495,7 +495,7 @@ bool SpeculativeJIT::compile(Node& node)
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(FullTagTypeFalse), result.registerID());
m_jit.or32(TrustedImm32(ValueFalse), result.registerID());
jsValueResult(result.gpr(), m_compileIndex);
break;
}
......
......@@ -845,7 +845,7 @@ ALWAYS_INLINE void JIT::emitFastArithIntToImmNoCheck(RegisterID src, RegisterID
ALWAYS_INLINE void JIT::emitTagAsBoolImmediate(RegisterID reg)
{
or32(TrustedImm32(static_cast<int32_t>(FullTagTypeFalse)), reg);
or32(TrustedImm32(static_cast<int32_t>(ValueFalse)), reg);
}
#endif // USE(JSVALUE32_64)
......
......@@ -699,9 +699,9 @@ void JIT::emit_op_not(Instruction* currentInstruction)
// Invert against JSValue(false); if the value was tagged as a boolean, then all bits will be
// clear other than the low bit (which will be 0 or 1 for false or true inputs respectively).
// Then invert against JSValue(true), which will add the tag back in, and flip the low bit.
xorPtr(TrustedImm32(static_cast<int32_t>(FullTagTypeFalse)), regT0);
xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), regT0);
addSlowCase(branchTestPtr(NonZero, regT0, TrustedImm32(static_cast<int32_t>(~1))));
xorPtr(TrustedImm32(static_cast<int32_t>(FullTagTypeTrue)), regT0);
xorPtr(TrustedImm32(static_cast<int32_t>(ValueTrue)), regT0);
emitPutVirtualRegister(currentInstruction[1].u.operand);
}
......@@ -736,7 +736,7 @@ void JIT::emit_op_jeq_null(Instruction* currentInstruction)
// Now handle the immediate cases - undefined & null
isImmediate.link(this);
andPtr(TrustedImm32(~ExtendedTagBitUndefined), regT0);
andPtr(TrustedImm32(~TagBitUndefined), regT0);
addJump(branchPtr(Equal, regT0, TrustedImmPtr(JSValue::encode(jsNull()))), target);
wasNotImmediate.link(this);
......@@ -757,7 +757,7 @@ void JIT::emit_op_jneq_null(Instruction* currentInstruction)
// Now handle the immediate cases - undefined & null
isImmediate.link(this);
andPtr(TrustedImm32(~ExtendedTagBitUndefined), regT0);
andPtr(TrustedImm32(~TagBitUndefined), regT0);
addJump(branchPtr(NotEqual, regT0, TrustedImmPtr(JSValue::encode(jsNull()))), target);
wasNotImmediate.link(this);
......@@ -914,8 +914,8 @@ void JIT::emit_op_get_pnames(Instruction* currentInstruction)
isNotObject.link(this);
move(regT0, regT1);
and32(TrustedImm32(~ExtendedTagBitUndefined), regT1);
addJump(branch32(Equal, regT1, TrustedImm32(FullTagTypeNull)), breakTarget);
and32(TrustedImm32(~TagBitUndefined), regT1);
addJump(branch32(Equal, regT1, TrustedImm32(ValueNull)), breakTarget);
JITStubCall toObjectStubCall(this, cti_to_object);
toObjectStubCall.addArgument(regT0);
......@@ -1168,8 +1168,8 @@ void JIT::emit_op_eq_null(Instruction* currentInstruction)
isImmediate.link(this);
andPtr(TrustedImm32(~ExtendedTagBitUndefined), regT0);
setPtr(Equal, regT0, TrustedImm32(FullTagTypeNull), regT0);
andPtr(TrustedImm32(~TagBitUndefined), regT0);
setPtr(Equal, regT0, TrustedImm32(ValueNull), regT0);
wasNotImmediate.link(this);
......@@ -1193,8 +1193,8 @@ void JIT::emit_op_neq_null(Instruction* currentInstruction)
isImmediate.link(this);
andPtr(TrustedImm32(~ExtendedTagBitUndefined), regT0);
setPtr(NotEqual, regT0, TrustedImm32(FullTagTypeNull), regT0);
andPtr(TrustedImm32(~TagBitUndefined), regT0);
setPtr(NotEqual, regT0, TrustedImm32(ValueNull), regT0);
wasNotImmediate.link(this);
......@@ -1379,7 +1379,7 @@ void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCas
void JIT::emitSlow_op_not(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
linkSlowCase(iter);
xorPtr(TrustedImm32(static_cast<int32_t>(FullTagTypeFalse)), regT0);
xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), regT0);
JITStubCall stubCall(this, cti_op_not);
stubCall.addArgument(regT0);
stubCall.call(currentInstruction[1].u.operand);
......
......@@ -242,14 +242,6 @@ namespace JSC {
return false;
}
#if USE(JSVALUE64)
ALWAYS_INLINE JSCell* JSValue::asCell() const
{
ASSERT(isCell());
return m_ptr;
}
#endif // USE(JSVALUE64)
inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
{
return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue();
......
......@@ -64,7 +64,7 @@ namespace JSC {
#endif
union EncodedValueDescriptor {
EncodedJSValue asEncodedJSValue;
int64_t asInt64;
#if USE(JSVALUE32_64)
double asDouble;
#elif USE(JSVALUE64)
......@@ -106,8 +106,8 @@ namespace JSC {
friend class SpecializedThunkJIT;
public:
static EncodedJSValue encode(JSValue value);
static JSValue decode(EncodedJSValue ptr);
static EncodedJSValue encode(JSValue);
static JSValue decode(EncodedJSValue);
enum JSNullTag { JSNull };
enum JSUndefinedTag { JSUndefined };
......@@ -280,8 +280,6 @@ namespace JSC {
uint32_t tag() const;
int32_t payload() const;
EncodedValueDescriptor u;
#elif USE(JSVALUE64)
/*
* On 64-bit platforms USE(JSVALUE64) should be defined, and we use a NaN-encoded
......@@ -327,7 +325,7 @@ namespace JSC {
* These values have the following properties:
* - Bit 1 (TagBitTypeOther) is set for all four values, allowing real pointers to be
* quickly distinguished from all immediate values, including these invalid pointers.
* - With bit 3 is masked out (ExtendedTagBitUndefined) Undefined and Null share the
* - With bit 3 is masked out (TagBitUndefined) Undefined and Null share the
* same value, allowing null & undefined to be quickly detected.
*
* No valid JSValue will have the bit pattern 0x0, this is used to represent array
......@@ -336,30 +334,36 @@ namespace JSC {
// These values are #defines since using static const integers here is a ~1% regression!
// 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.
#define TagTypeNumber 0xffff000000000000ll
// This value is 2^48, used to encode doubles such that the encoded value will begin
// with a 16-bit pattern within the range 0x0001..0xFFFE.
#define DoubleEncodeOffset 0x1000000000000ll
// The second bit set indicates an immediate other than a number (bool, null, undefined).
// 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.
#define TagTypeNumber 0xffff000000000000ll
// All non-numeric (bool, null, undefined) immediates have bit 2 set.
#define TagBitTypeOther 0x2ll
#define TagBitBool 0x4ll
#define TagBitUndefined 0x8ll
// Combined integer value for non-numeric immediates.
#define ValueFalse (TagBitTypeOther | TagBitBool | false)
#define ValueTrue (TagBitTypeOther | TagBitBool | true)
#define ValueUndefined (TagBitTypeOther | TagBitUndefined)
#define ValueNull (TagBitTypeOther)
// TagMask is used to check for all types of immediate values (either number or 'other').
#define TagMask (TagTypeNumber | TagBitTypeOther)
#define ExtendedTagBitBool 0x4ll
#define ExtendedTagBitUndefined 0x8ll
#define FullTagTypeFalse (TagBitTypeOther | ExtendedTagBitBool | false)
#define FullTagTypeTrue (TagBitTypeOther | ExtendedTagBitBool | true)
#define FullTagTypeUndefined (TagBitTypeOther | ExtendedTagBitUndefined)
#define FullTagTypeNull (TagBitTypeOther)
static JSValue makeImmediate(intptr_t value);
intptr_t immediateValue() const;
JSCell* m_ptr;
// These special values are never visible to JavaScript code; Empty is used to represent
// Array holes, and for uninitialized JSValues. Deleted is used in hash table code.
// These values would map to cell types in the JSValue encoding, but not valid GC cell
// pointer should have either of these values (Empty is null, deleted is at an invalid
// alignment for a GC cell, and in the zero page).
#define ValueEmpty 0x0ll
#define ValueDeleted 0x4ll
#endif
EncodedValueDescriptor u;
};
#if USE(JSVALUE32_64)
......
......@@ -173,16 +173,15 @@ namespace JSC {
}
#if USE(JSVALUE32_64)
// JSValue member functions.
inline EncodedJSValue JSValue::encode(JSValue value)
{
return value.u.asEncodedJSValue;
return value.u.asInt64;
}
inline JSValue JSValue::decode(EncodedJSValue encodedJSValue)
{
JSValue v;
v.u.asEncodedJSValue = encodedJSValue;
v.u.asInt64 = encodedJSValue;
return v;
}
......@@ -254,12 +253,12 @@ namespace JSC {
inline bool JSValue::operator==(const JSValue& other) const
{
return u.asEncodedJSValue == other.u.asEncodedJSValue;
return u.asInt64 == other.u.asInt64;
}
inline bool JSValue::operator!=(const JSValue& other) const
{
return u.asEncodedJSValue != other.u.asEncodedJSValue;
return u.asInt64 != other.u.asInt64;
}
inline bool JSValue::isUndefined() const
......@@ -362,7 +361,7 @@ namespace JSC {
// JSValue member functions.
inline EncodedJSValue JSValue::encode(JSValue value)
{
return reinterpret_cast<EncodedJSValue>(value.m_ptr);
return value.u.ptr;
}
inline JSValue JSValue::decode(EncodedJSValue ptr)
......@@ -370,39 +369,29 @@ namespace JSC {
return JSValue(reinterpret_cast<JSCell*>(ptr));
}
inline JSValue JSValue::makeImmediate(intptr_t value)
{
return JSValue(reinterpret_cast<JSCell*>(value));
}
inline intptr_t JSValue::immediateValue() const
{
return reinterpret_cast<intptr_t>(m_ptr);
}
// 0x0 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x0, which is in the (invalid) zero page.
inline JSValue::JSValue()
: m_ptr(0)
{
u.asInt64 = ValueEmpty;
}
// 0x4 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x4, which is in the (invalid) zero page.
inline JSValue::JSValue(HashTableDeletedValueTag)
: m_ptr(reinterpret_cast<JSCell*>(0x4))
{
u.asInt64 = ValueDeleted;
}
inline JSValue::JSValue(JSCell* ptr)
: m_ptr(ptr)
{
u.ptr = ptr;
#if ENABLE(JSC_ZOMBIES)
ASSERT(!isZombie());
#endif
}
inline JSValue::JSValue(const JSCell* ptr)
: m_ptr(const_cast<JSCell*>(ptr))
{
u.ptr = const_cast<JSCell*>(ptr);
#if ENABLE(JSC_ZOMBIES)
ASSERT(!isZombie());
#endif
......@@ -410,17 +399,17 @@ namespace JSC {
inline JSValue::operator bool() const
{
return m_ptr;
return u.ptr;
}
inline bool JSValue::operator==(const JSValue& other) const
{
return m_ptr == other.m_ptr;
return u.ptr == other.u.ptr;
}
inline bool JSValue::operator!=(const JSValue& other) const
{
return m_ptr != other.m_ptr;
return u.ptr != other.u.ptr;
}
inline bool JSValue::isUndefined() const
......@@ -452,7 +441,7 @@ namespace JSC {
inline int32_t JSValue::asInt32() const
{
ASSERT(isInt32());
return static_cast<int32_t>(immediateValue());
return static_cast<int32_t>(u.asInt64);
}
inline bool JSValue::isDouble() const
......@@ -462,43 +451,43 @@ namespace JSC {
inline JSValue::JSValue(JSNullTag)
{
*this = JSValue::makeImmediate(FullTagTypeNull);
u.asInt64 = ValueNull;
}
inline JSValue::JSValue(JSUndefinedTag)
{
*this = JSValue::makeImmediate(FullTagTypeUndefined);
u.asInt64 = ValueUndefined;
}
inline JSValue::JSValue(JSTrueTag)
{
*this = JSValue::makeImmediate(FullTagTypeTrue);
u.asInt64 = ValueTrue;
}
inline JSValue::JSValue(JSFalseTag)
{
*this = JSValue::makeImmediate(FullTagTypeFalse);
u.asInt64 = ValueFalse;
}
inline bool JSValue::isUndefinedOrNull() const
{
// Undefined and null share the same value, bar the 'undefined' bit in the extended tag.
return (immediateValue() & ~ExtendedTagBitUndefined) == FullTagTypeNull;
return (u.asInt64 & ~TagBitUndefined) == ValueNull;
}
inline bool JSValue::isBoolean() const
{
return (immediateValue() & ~1) == FullTagTypeFalse;
return (u.asInt64 & ~1) == ValueFalse;
}
inline bool JSValue::isCell() const
{
return !(immediateValue() & TagMask);
return !(u.asInt64 & TagMask);
}
inline bool JSValue::isInt32() const
{
return (immediateValue() & TagTypeNumber) == TagTypeNumber;
return (u.asInt64 & TagTypeNumber) == TagTypeNumber;
}
inline intptr_t reinterpretDoubleToIntptr(double value)
......@@ -512,22 +501,28 @@ namespace JSC {
ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d)
{
*this = makeImmediate(reinterpretDoubleToIntptr(d) + DoubleEncodeOffset);
u.asInt64 = reinterpretDoubleToIntptr(d) + DoubleEncodeOffset;
}
inline JSValue::JSValue(int i)
{
*this = makeImmediate(static_cast<intptr_t>(static_cast<uint32_t>(i)) | TagTypeNumber);
u.asInt64 = TagTypeNumber | static_cast<uint32_t>(i);
}
inline double JSValue::asDouble() const
{
return reinterpretIntptrToDouble(immediateValue() - DoubleEncodeOffset);
return reinterpretIntptrToDouble(u.asInt64 - DoubleEncodeOffset);
}
inline bool JSValue::isNumber() const
{
return immediateValue() & TagTypeNumber;
return u.asInt64 & TagTypeNumber;
}
ALWAYS_INLINE JSCell* JSValue::asCell() const
{
ASSERT(isCell());
return u.ptr;
}
#endif // USE(JSVALUE64)
......
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