mirror of
https://github.com/Samsung/escargot.git
synced 2026-06-22 10:01:50 +00:00
wip
Signed-off-by: Seonghyun Kim <sh8281.kim@samsung.com>
This commit is contained in:
parent
c100122bf4
commit
5575cad622
17 changed files with 355 additions and 534 deletions
|
|
@ -1238,7 +1238,7 @@ static Value builtinArrayIncludes(ExecutionState& state, Value thisValue, size_t
|
|||
// Let elementK be the result of ? Get(O, ! ToString(k)).
|
||||
Value elementK = O->get(state, ObjectPropertyName(state, Value(doubleK))).value(state, O);
|
||||
// If SameValueZero(searchElement, elementK) is true, return true.
|
||||
if (elementK.equalsToByTheSameValueZeroAlgorithm(state, searchElement)) {
|
||||
if (elementK.equalsToByTheSameValueZeroAlgorithm(searchElement)) {
|
||||
return Value(true);
|
||||
}
|
||||
// Increase k by 1.
|
||||
|
|
|
|||
|
|
@ -596,7 +596,7 @@ static Value builtinObjectIs(ExecutionState& state, Value thisValue, size_t argc
|
|||
// 19.1.2.10 Object.is ( value1, value2 )
|
||||
|
||||
// Return SameValue(value1, value2).
|
||||
return Value(argv[0].equalsToByTheSameValueAlgorithm(state, argv[1]));
|
||||
return Value(argv[0].equalsToByTheSameValueAlgorithm(argv[1]));
|
||||
}
|
||||
|
||||
static Value builtinObjectKeys(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
|
|
|
|||
|
|
@ -227,13 +227,13 @@ static Value builtinRegExpSearch(ExecutionState& state, Value thisValue, size_t
|
|||
RESOLVE_THIS_BINDING_TO_OBJECT(rx, Object, search);
|
||||
String* s = argv[0].toString(state);
|
||||
Value previousLastIndex = rx->get(state, ObjectPropertyName(state.context()->staticStrings().lastIndex)).value(state, thisValue);
|
||||
if (!previousLastIndex.equalsToByTheSameValueAlgorithm(state, Value(0))) {
|
||||
if (!previousLastIndex.equalsToByTheSameValueAlgorithm(Value(0))) {
|
||||
rx->setThrowsException(state, ObjectPropertyName(state.context()->staticStrings().lastIndex), Value(0), thisValue);
|
||||
}
|
||||
Value result = regExpExec(state, rx, s);
|
||||
|
||||
Value currentLastIndex = rx->get(state, ObjectPropertyName(state.context()->staticStrings().lastIndex)).value(state, thisValue);
|
||||
if (!previousLastIndex.equalsToByTheSameValueAlgorithm(state, currentLastIndex)) {
|
||||
if (!previousLastIndex.equalsToByTheSameValueAlgorithm(currentLastIndex)) {
|
||||
rx->setThrowsException(state, ObjectPropertyName(state.context()->staticStrings().lastIndex), previousLastIndex, thisValue);
|
||||
}
|
||||
if (result.isNull()) {
|
||||
|
|
|
|||
|
|
@ -658,7 +658,7 @@ static Value builtinTypedArrayIncludes(ExecutionState& state, Value thisValue, s
|
|||
// Let elementK be the result of ? Get(O, ! ToString(k)).
|
||||
Value elementK = O->getIndexedProperty(state, Value(k)).value(state, O);
|
||||
// If SameValueZero(searchElement, elementK) is true, return true.
|
||||
if (elementK.equalsToByTheSameValueZeroAlgorithm(state, searchElement)) {
|
||||
if (elementK.equalsToByTheSameValueZeroAlgorithm(searchElement)) {
|
||||
return Value(true);
|
||||
}
|
||||
// Increase k by 1.
|
||||
|
|
|
|||
|
|
@ -57,21 +57,13 @@ void getNextValidInValueVector(GC_word* ptr, GC_word* end, GC_word** next_ptr, G
|
|||
{
|
||||
while (ptr < end) {
|
||||
Value* current = (Value*)ptr;
|
||||
if (current->isPointerValue()) {
|
||||
#ifdef ESCARGOT_32
|
||||
*next_ptr = ptr + 2;
|
||||
#else
|
||||
if (current->isHeapValue()) {
|
||||
*next_ptr = ptr + 1;
|
||||
#endif
|
||||
*from = ptr;
|
||||
*to = (GC_word*)current->asPointerValue();
|
||||
*to = (GC_word*)current->asRawData();
|
||||
return;
|
||||
}
|
||||
#ifdef ESCARGOT_32
|
||||
ptr = ptr + 2;
|
||||
#else
|
||||
ptr = ptr + 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
*next_ptr = end;
|
||||
|
|
@ -353,13 +345,13 @@ template <>
|
|||
Value* CustomAllocator<Value>::allocate(size_type GC_n, const void*)
|
||||
{
|
||||
// Un-comment this to use default allocator
|
||||
// return (Value*)GC_MALLOC(sizeof(Value) * GC_n);
|
||||
int kind = s_gcKinds[HeapObjectKind::ValueVectorKind];
|
||||
size_t size = sizeof(Value) * GC_n;
|
||||
return (Value*)GC_MALLOC(sizeof(Value) * GC_n);
|
||||
// int kind = s_gcKinds[HeapObjectKind::ValueVectorKind];
|
||||
// size_t size = sizeof(Value) * GC_n;
|
||||
|
||||
Value* ret;
|
||||
ret = (Value*)GC_GENERIC_MALLOC(size, kind);
|
||||
return ret;
|
||||
// Value* ret;
|
||||
// ret = (Value*)GC_GENERIC_MALLOC(size, kind);
|
||||
// return ret;
|
||||
}
|
||||
|
||||
template <>
|
||||
|
|
|
|||
|
|
@ -492,7 +492,11 @@ Value ByteCodeInterpreter::interpret(ExecutionState* state, ByteCodeBlock* byteC
|
|||
if (LIKELY(arr->isFastModeArray())) {
|
||||
uint32_t idx = property.tryToUseAsIndexProperty(*state);
|
||||
if (LIKELY(idx < arr->arrayLength(*state))) {
|
||||
registerFile[code->m_storeRegisterIndex] = arr->m_fastModeData[idx].toValue<true>();
|
||||
if (UNLIKELY(arr->m_fastModeData[idx].isEmpty())) {
|
||||
registerFile[code->m_storeRegisterIndex] = Value();
|
||||
} else {
|
||||
registerFile[code->m_storeRegisterIndex] = arr->m_fastModeData[idx];
|
||||
}
|
||||
ADD_PROGRAM_COUNTER(GetObject);
|
||||
NEXT_INSTRUCTION();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,8 +50,10 @@ public:
|
|||
}
|
||||
} else {
|
||||
ASSERT(m_value.asPointerValue()->isBigInt());
|
||||
codeBlock->m_otherLiteralData.pushBack(m_value.asPointerValue()->asBigInt());
|
||||
codeBlock->m_otherLiteralData.pushBack(m_value.asPointerValue());
|
||||
}
|
||||
} else if (m_value.isHeapValue()) {
|
||||
codeBlock->m_otherLiteralData.pushBack(reinterpret_cast<void*>(m_value.asRawData()));
|
||||
}
|
||||
if (dstRegister < REGULAR_REGISTER_LIMIT + VARIABLE_LIMIT) {
|
||||
codeBlock->pushCode(LoadLiteral(ByteCodeLOC(m_loc.index), dstRegister, m_value), context, this);
|
||||
|
|
|
|||
|
|
@ -1078,6 +1078,10 @@ public:
|
|||
// raw = this->getTokenRaw(token);
|
||||
if (builder.isNodeGenerator()) {
|
||||
auto d = token->valueNumberLiteral(this->scanner);
|
||||
if (d.first.asRawData() == 0) {
|
||||
puts("123");
|
||||
token->valueNumberLiteral(this->scanner);
|
||||
}
|
||||
if (LIKELY(!d.second)) {
|
||||
if (minus) {
|
||||
d.first = Value(-d.first.asNumber());
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class PointerValue;
|
|||
|
||||
#ifdef ESCARGOT_32
|
||||
COMPILE_ASSERT(sizeof(EncodedValueData) == 4, "");
|
||||
COMPILE_ASSERT(sizeof(Value) == 8, "");
|
||||
COMPILE_ASSERT(sizeof(Value) == 4, "");
|
||||
#else
|
||||
COMPILE_ASSERT(sizeof(EncodedValueData) == 8, "");
|
||||
#endif
|
||||
|
|
@ -99,85 +99,103 @@ private:
|
|||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
namespace EncodedValueImpl {
|
||||
class EncodedValue {
|
||||
public:
|
||||
enum ForceUninitializedTag { ForceUninitialized };
|
||||
enum EmptyValueInitTag { EmptyValue };
|
||||
COMPILE_ASSERT(EncodedValue::EmptyValue == 0, "");
|
||||
friend class EncodedSmallValue;
|
||||
|
||||
const int kApiAlignSize = 4;
|
||||
const int kApiIntSize = sizeof(int);
|
||||
const int kApiInt64Size = sizeof(int64_t);
|
||||
EncodedValue(const Value& v = Value())
|
||||
: m_value(v)
|
||||
{
|
||||
}
|
||||
|
||||
// Tag information for small immediate. Other values are heap objects.
|
||||
const int kSmiTag = 1;
|
||||
const int kSmiTagSize = 1;
|
||||
const intptr_t kSmiTagMask = (1 << kSmiTagSize) - 1;
|
||||
explicit EncodedValue(PointerValue* v)
|
||||
: m_value(v)
|
||||
{
|
||||
}
|
||||
|
||||
template <size_t ptr_size>
|
||||
struct SmiTagging;
|
||||
static EncodedValue fromPayload(const void* p)
|
||||
{
|
||||
return Value(Value::FromPayload, reinterpret_cast<intptr_t>(p));
|
||||
}
|
||||
|
||||
template <int kSmiShiftSize>
|
||||
inline int32_t IntToSmiT(int value)
|
||||
{
|
||||
int smi_shift_bits = kSmiTagSize + kSmiShiftSize;
|
||||
uintptr_t tagged_value = (static_cast<uintptr_t>(value) << smi_shift_bits) | kSmiTag;
|
||||
return (int32_t)(tagged_value);
|
||||
}
|
||||
explicit EncodedValue(const uint32_t from)
|
||||
: m_value(Value(from))
|
||||
{
|
||||
}
|
||||
|
||||
// Smi constants for 32-bit systems.
|
||||
template <>
|
||||
struct SmiTagging<4> {
|
||||
enum {
|
||||
kSmiShiftSize = 0,
|
||||
kSmiValueSize = 31
|
||||
};
|
||||
static int SmiShiftSize()
|
||||
EncodedValue(ForceUninitializedTag)
|
||||
{
|
||||
return kSmiShiftSize;
|
||||
}
|
||||
static int SmiValueSize()
|
||||
|
||||
EncodedValue(EmptyValueInitTag)
|
||||
{
|
||||
return kSmiValueSize;
|
||||
m_value = Value(Value::EmptyValue);
|
||||
}
|
||||
inline static int SmiToInt(intptr_t value)
|
||||
|
||||
const EncodedValue& operator=(PointerValue* from)
|
||||
{
|
||||
int shift_bits = kSmiTagSize + kSmiShiftSize;
|
||||
// Throw away top 32 bits and shift down (requires >> to be sign extending).
|
||||
return static_cast<int>(value >> shift_bits);
|
||||
ASSERT(from);
|
||||
m_value = Value(from);
|
||||
return *this;
|
||||
}
|
||||
inline static int32_t IntToSmi(int value)
|
||||
|
||||
bool operator==(const EncodedValue& other) const
|
||||
{
|
||||
return IntToSmiT<kSmiShiftSize>(value);
|
||||
return Value(m_value) == Value(other);
|
||||
}
|
||||
inline static bool IsValidSmi(intptr_t value)
|
||||
|
||||
bool isStoredInHeap() const
|
||||
{
|
||||
// To be representable as an tagged small integer, the two
|
||||
// most-significant bits of 'value' must be either 00 or 11 due to
|
||||
// sign-extension. To check this we add 01 to the two
|
||||
// most-significant bits, and check if the most-significant bit is 0
|
||||
//
|
||||
// CAUTION: The original code below:
|
||||
// bool result = ((value + 0x40000000) & 0x80000000) == 0;
|
||||
// may lead to incorrect results according to the C language spec, and
|
||||
// in fact doesn't work correctly with gcc4.1.1 in some cases: The
|
||||
// compiler may produce undefined results in case of signed integer
|
||||
// overflow. The computation must be done w/ unsigned ints.
|
||||
return static_cast<uintptr_t>(value + 0x40000000U) < 0x80000000U;
|
||||
return m_value.isHeapValue();
|
||||
}
|
||||
|
||||
intptr_t payload() const
|
||||
{
|
||||
return m_value.asRawData();
|
||||
}
|
||||
|
||||
bool isEmpty() const
|
||||
{
|
||||
return m_value.isEmpty();
|
||||
}
|
||||
|
||||
bool isInt32()
|
||||
{
|
||||
return m_value.isInt32();
|
||||
}
|
||||
|
||||
bool isUInt32()
|
||||
{
|
||||
return m_value.isUInt32();
|
||||
}
|
||||
|
||||
int32_t asInt32()
|
||||
{
|
||||
return m_value.asInt32();
|
||||
}
|
||||
|
||||
uint32_t asUInt32()
|
||||
{
|
||||
return m_value.asUInt32();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE operator Value&()
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE operator const Value&() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
private:
|
||||
Value m_value;
|
||||
};
|
||||
|
||||
|
||||
typedef SmiTagging<kApiAlignSize> PlatformSmiTagging;
|
||||
const int kSmiShiftSize = PlatformSmiTagging::kSmiShiftSize;
|
||||
const int kSmiValueSize = PlatformSmiTagging::kSmiValueSize;
|
||||
|
||||
#if defined(ESCARGOT_64) && defined(ESCARGOT_USE_32BIT_IN_64BIT)
|
||||
#define HAS_SMI_TAG(value) \
|
||||
((static_cast<intptr_t>((long int)value) & ::Escargot::EncodedValueImpl::kSmiTagMask) == ::Escargot::EncodedValueImpl::kSmiTag)
|
||||
#else
|
||||
#define HAS_SMI_TAG(value) \
|
||||
((static_cast<intptr_t>(value) & ::Escargot::EncodedValueImpl::kSmiTagMask) == ::Escargot::EncodedValueImpl::kSmiTag)
|
||||
#endif
|
||||
} // namespace EncodedValueImpl
|
||||
|
||||
|
||||
/*
|
||||
// EncodedValue turns int, double values into pointer or odd value
|
||||
// so there is no conservative gc leak(there is no even value looks like pointer without pointers)
|
||||
// developers should use this class if want to save some Value on Heap
|
||||
|
|
@ -423,6 +441,7 @@ protected:
|
|||
private:
|
||||
EncodedValueData m_data;
|
||||
};
|
||||
*/
|
||||
|
||||
#if defined(ESCARGOT_64) && defined(ESCARGOT_USE_32BIT_IN_64BIT)
|
||||
class EncodedSmallValue {
|
||||
|
|
|
|||
|
|
@ -38,14 +38,16 @@ public:
|
|||
RELEASE_ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
Object* m_object;
|
||||
uint32_t m_arrayLength;
|
||||
size_t m_index;
|
||||
EncodedValueTightVector m_keys;
|
||||
|
||||
protected:
|
||||
EnumerateObject(Object* obj)
|
||||
: m_index(0)
|
||||
, m_object(obj)
|
||||
: m_object(obj)
|
||||
, m_arrayLength(0)
|
||||
, m_index(0)
|
||||
{
|
||||
ASSERT(!!m_object);
|
||||
}
|
||||
|
|
@ -54,9 +56,6 @@ protected:
|
|||
|
||||
virtual void executeEnumeration(ExecutionState& state, EncodedValueTightVector& keys) = 0;
|
||||
virtual bool checkIfModified(ExecutionState& state);
|
||||
|
||||
Object* m_object;
|
||||
uint32_t m_arrayLength;
|
||||
};
|
||||
|
||||
// enumerate object for destruction operation e.g. var obj = { a, ...b };
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ bool MapObject::deleteOperation(ExecutionState& state, const Value& key)
|
|||
if (existingKey.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (existingKey.equalsToByTheSameValueZeroAlgorithm(state, key)) {
|
||||
if (existingKey.equalsToByTheSameValueZeroAlgorithm(key)) {
|
||||
m_storage[i] = std::make_pair(Value(Value::EmptyValue), Value(Value::EmptyValue));
|
||||
return true;
|
||||
}
|
||||
|
|
@ -90,7 +90,7 @@ Value MapObject::get(ExecutionState& state, const Value& key)
|
|||
if (existingKey.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (existingKey.equalsToByTheSameValueZeroAlgorithm(state, key)) {
|
||||
if (existingKey.equalsToByTheSameValueZeroAlgorithm(key)) {
|
||||
return m_storage[i].second;
|
||||
}
|
||||
}
|
||||
|
|
@ -104,7 +104,7 @@ bool MapObject::has(ExecutionState& state, const Value& key)
|
|||
if (existingKey.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (existingKey.equalsToByTheSameValueZeroAlgorithm(state, key)) {
|
||||
if (existingKey.equalsToByTheSameValueZeroAlgorithm(key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -118,7 +118,7 @@ void MapObject::set(ExecutionState& state, const Value& key, const Value& value)
|
|||
if (existingKey.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (existingKey.equalsToByTheSameValueZeroAlgorithm(state, key)) {
|
||||
if (existingKey.equalsToByTheSameValueZeroAlgorithm(key)) {
|
||||
m_storage[i].second = value;
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ bool ModuleNamespaceObject::defineOwnProperty(ExecutionState& state, const Objec
|
|||
}
|
||||
// If Desc.[[Value]] is present, return SameValue(Desc.[[Value]], current.[[Value]]).
|
||||
if (desc.isValuePresent()) {
|
||||
return desc.value().equalsToByTheSameValueAlgorithm(state, current.value(state, this));
|
||||
return desc.value().equalsToByTheSameValueAlgorithm(current.value(state, this));
|
||||
}
|
||||
// Return true.
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -809,7 +809,7 @@ bool Object::defineOwnPropertyMethod(ExecutionState& state, const ObjectProperty
|
|||
}
|
||||
// If the [[Writable]] field of current is false, then
|
||||
// Reject, if the [[Value]] field of Desc is present and SameValue(Desc.[[Value]], current.[[Value]]) is false.
|
||||
if (!item->m_descriptor.isWritable() && desc.isValuePresent() && !desc.value().equalsToByTheSameValueAlgorithm(state, getOwnDataPropertyUtilForObject(state, idx, this))) {
|
||||
if (!item->m_descriptor.isWritable() && desc.isValuePresent() && !desc.value().equalsToByTheSameValueAlgorithm(getOwnDataPropertyUtilForObject(state, idx, this))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1471,7 +1471,7 @@ bool Object::isCompatiblePropertyDescriptor(ExecutionState& state, bool extensib
|
|||
// ii. If the [[Writable]] field of current is false, then
|
||||
if (!current.isWritable()) {
|
||||
// 1. Return false, if the [[Value]] field of Desc is present and SameValue(Desc.[[Value]], current.[[Value]]) is false.
|
||||
if (desc.isValuePresent() && !desc.value().equalsToByTheSameValueAlgorithm(state, current.value(state, Value()))) {
|
||||
if (desc.isValuePresent() && !desc.value().equalsToByTheSameValueAlgorithm(current.value(state, Value()))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ bool SetObject::deleteOperation(ExecutionState& state, const Value& key)
|
|||
if (existingKey.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (existingKey.equalsToByTheSameValueZeroAlgorithm(state, key)) {
|
||||
if (existingKey.equalsToByTheSameValueZeroAlgorithm(key)) {
|
||||
m_storage[i] = Value(Value::EmptyValue);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -77,7 +77,7 @@ void SetObject::add(ExecutionState& state, const Value& key)
|
|||
if (existingKey.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (existingKey.equalsToByTheSameValueZeroAlgorithm(state, key)) {
|
||||
if (existingKey.equalsToByTheSameValueZeroAlgorithm(key)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -97,7 +97,7 @@ bool SetObject::has(ExecutionState& state, const Value& key)
|
|||
if (existingKey.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (existingKey.equalsToByTheSameValueZeroAlgorithm(state, key)) {
|
||||
if (existingKey.equalsToByTheSameValueZeroAlgorithm(key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ bool Value::abstractEqualsToSlowCase(ExecutionState& state, const Value& val) co
|
|||
|
||||
return a == b;
|
||||
} else {
|
||||
if (u.asInt64 == val.u.asInt64) {
|
||||
if (m_data.payload == val.m_data.payload) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -443,9 +443,9 @@ bool Value::equalsToSlowCase(ExecutionState& state, const Value& val) const
|
|||
return a == b;
|
||||
}
|
||||
|
||||
return u.asInt64 == val.u.asInt64;
|
||||
return m_data.payload == val.m_data.payload;
|
||||
} else {
|
||||
if (u.asInt64 == val.u.asInt64) {
|
||||
if (m_data.payload == val.m_data.payload) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -470,7 +470,7 @@ bool Value::equalsToSlowCase(ExecutionState& state, const Value& val) const
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Value::equalsToByTheSameValueAlgorithm(ExecutionState& ec, const Value& val) const
|
||||
bool Value::equalsToByTheSameValueAlgorithm(const Value& val) const
|
||||
{
|
||||
if (!val.isPointerValue()) {
|
||||
if (isNumber() && val.isNumber()) {
|
||||
|
|
@ -489,9 +489,9 @@ bool Value::equalsToByTheSameValueAlgorithm(ExecutionState& ec, const Value& val
|
|||
return a == b && std::signbit(a) == std::signbit(b);
|
||||
}
|
||||
|
||||
return u.asInt64 == val.u.asInt64;
|
||||
return m_data.payload == val.m_data.payload;
|
||||
} else {
|
||||
if (u.asInt64 == val.u.asInt64) {
|
||||
if (m_data.payload == val.m_data.payload) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -518,7 +518,7 @@ bool Value::equalsToByTheSameValueAlgorithm(ExecutionState& ec, const Value& val
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Value::equalsToByTheSameValueZeroAlgorithm(ExecutionState& ec, const Value& val) const
|
||||
bool Value::equalsToByTheSameValueZeroAlgorithm(const Value& val) const
|
||||
{
|
||||
if (LIKELY(!val.isPointerValue())) {
|
||||
if (isNumber() && val.isNumber()) {
|
||||
|
|
@ -532,9 +532,9 @@ bool Value::equalsToByTheSameValueZeroAlgorithm(ExecutionState& ec, const Value&
|
|||
return a == b;
|
||||
}
|
||||
|
||||
return u.asInt64 == val.u.asInt64;
|
||||
return m_data.payload == val.m_data.payload;
|
||||
} else {
|
||||
if (u.asInt64 == val.u.asInt64) {
|
||||
if (m_data.payload == val.m_data.payload) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,96 @@
|
|||
|
||||
namespace Escargot {
|
||||
|
||||
namespace EncodedValueImpl {
|
||||
|
||||
const int kApiAlignSize = 4;
|
||||
const int kApiIntSize = sizeof(int);
|
||||
const int kApiInt64Size = sizeof(int64_t);
|
||||
|
||||
// Tag information for small immediate. Other values are heap objects.
|
||||
const int kSmiTag = 1;
|
||||
const int kSmiTagSize = 1;
|
||||
const intptr_t kSmiTagMask = (1 << kSmiTagSize) - 1;
|
||||
|
||||
template <size_t ptr_size>
|
||||
struct SmiTagging;
|
||||
|
||||
template <int kSmiShiftSize>
|
||||
inline int32_t IntToSmiT(int value)
|
||||
{
|
||||
int smi_shift_bits = kSmiTagSize + kSmiShiftSize;
|
||||
uintptr_t tagged_value = (static_cast<uintptr_t>(value) << smi_shift_bits) | kSmiTag;
|
||||
return (int32_t)(tagged_value);
|
||||
}
|
||||
|
||||
// Smi constants for 32-bit systems.
|
||||
template <>
|
||||
struct SmiTagging<4> {
|
||||
enum {
|
||||
kSmiShiftSize = 0,
|
||||
kSmiValueSize = 31
|
||||
};
|
||||
static int SmiShiftSize()
|
||||
{
|
||||
return kSmiShiftSize;
|
||||
}
|
||||
static int SmiValueSize()
|
||||
{
|
||||
return kSmiValueSize;
|
||||
}
|
||||
inline static int SmiToInt(intptr_t value)
|
||||
{
|
||||
int shift_bits = kSmiTagSize + kSmiShiftSize;
|
||||
// Throw away top 32 bits and shift down (requires >> to be sign extending).
|
||||
return static_cast<int>(value >> shift_bits);
|
||||
}
|
||||
inline static int32_t IntToSmi(int value)
|
||||
{
|
||||
return IntToSmiT<kSmiShiftSize>(value);
|
||||
}
|
||||
inline static bool IsValidSmi(intptr_t value)
|
||||
{
|
||||
// To be representable as an tagged small integer, the two
|
||||
// most-significant bits of 'value' must be either 00 or 11 due to
|
||||
// sign-extension. To check this we add 01 to the two
|
||||
// most-significant bits, and check if the most-significant bit is 0
|
||||
//
|
||||
// CAUTION: The original code below:
|
||||
// bool result = ((value + 0x40000000) & 0x80000000) == 0;
|
||||
// may lead to incorrect results according to the C language spec, and
|
||||
// in fact doesn't work correctly with gcc4.1.1 in some cases: The
|
||||
// compiler may produce undefined results in case of signed integer
|
||||
// overflow. The computation must be done w/ unsigned ints.
|
||||
return static_cast<uintptr_t>(value + 0x40000000U) < 0x80000000U;
|
||||
}
|
||||
};
|
||||
|
||||
typedef SmiTagging<kApiAlignSize> PlatformSmiTagging;
|
||||
const int kSmiShiftSize = PlatformSmiTagging::kSmiShiftSize;
|
||||
const int kSmiValueSize = PlatformSmiTagging::kSmiValueSize;
|
||||
|
||||
#if defined(ESCARGOT_64) && defined(ESCARGOT_USE_32BIT_IN_64BIT)
|
||||
#define HAS_SMI_TAG(value) \
|
||||
((static_cast<intptr_t>((long int)value) & ::Escargot::EncodedValueImpl::kSmiTagMask) == ::Escargot::EncodedValueImpl::kSmiTag)
|
||||
#else
|
||||
#define HAS_SMI_TAG(value) \
|
||||
((static_cast<intptr_t>(value) & ::Escargot::EncodedValueImpl::kSmiTagMask) == ::Escargot::EncodedValueImpl::kSmiTag)
|
||||
#endif
|
||||
} // namespace EncodedValueImpl
|
||||
|
||||
struct ValueData {
|
||||
intptr_t payload;
|
||||
ValueData()
|
||||
: payload(0)
|
||||
{
|
||||
}
|
||||
|
||||
explicit ValueData(void* ptr)
|
||||
: payload((intptr_t)ptr)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class PointerValue;
|
||||
class ExecutionState;
|
||||
class Object;
|
||||
|
|
@ -131,6 +221,10 @@ public:
|
|||
explicit Value(TrueInitTag);
|
||||
explicit Value(FalseInitTag);
|
||||
explicit Value(FromPayloadTag, intptr_t ptr);
|
||||
|
||||
explicit Value(PointerValue* ptr);
|
||||
Value(const PointerValue* ptr);
|
||||
/*
|
||||
#ifdef ESCARGOT_64
|
||||
explicit Value(PointerValue* ptr);
|
||||
Value(const PointerValue* ptr);
|
||||
|
|
@ -145,7 +239,7 @@ public:
|
|||
Value(const String* ptr);
|
||||
explicit Value(FromTagTag, uint32_t tag);
|
||||
#endif
|
||||
|
||||
*/
|
||||
// Numbers
|
||||
Value(EncodeAsDoubleTag, const double&);
|
||||
explicit Value(const double&);
|
||||
|
|
@ -175,7 +269,7 @@ public:
|
|||
double asDouble() const;
|
||||
bool asBoolean() const;
|
||||
double asNumber() const;
|
||||
uint64_t asRawData() const;
|
||||
intptr_t asRawData() const;
|
||||
inline PointerValue* asPointerValue() const;
|
||||
inline Object* asObject() const;
|
||||
inline FunctionObject* asFunction() const;
|
||||
|
|
@ -202,6 +296,7 @@ public:
|
|||
inline bool isPrimitive() const;
|
||||
bool isGetterSetter() const;
|
||||
bool isCustomGetterSetter() const;
|
||||
inline bool isHeapValue() const;
|
||||
inline bool isPointerValue() const;
|
||||
bool isObject() const;
|
||||
bool isCallable() const;
|
||||
|
|
@ -250,39 +345,20 @@ public:
|
|||
bool abstractEqualsToSlowCase(ExecutionState& ec, const Value& val) const;
|
||||
inline bool equalsTo(ExecutionState& ec, const Value& val) const;
|
||||
bool equalsToSlowCase(ExecutionState& ec, const Value& val) const;
|
||||
bool equalsToByTheSameValueAlgorithm(ExecutionState& ec, const Value& val) const;
|
||||
bool equalsToByTheSameValueZeroAlgorithm(ExecutionState& ec, const Value& val) const;
|
||||
bool equalsToByTheSameValueAlgorithm(const Value& val) const;
|
||||
bool equalsToByTheSameValueZeroAlgorithm(const Value& val) const;
|
||||
bool instanceOf(ExecutionState& ec, const Value& other) const;
|
||||
|
||||
|
||||
#ifdef ESCARGOT_32
|
||||
uint32_t tag() const;
|
||||
#elif ESCARGOT_64
|
||||
// These values are #defines since using static const integers here is a ~1% regression!
|
||||
|
||||
// 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
|
||||
// DoubleEncodeOffset assumes that double value will begin with 0x0000..0xFFFD,
|
||||
// but there can be invalid inputs start with 0xFFFE or 0xFFFF.
|
||||
// So it is used to filter those values.
|
||||
#define DoubleInvalidBeginning 0xfffe000000000000ll
|
||||
// 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
|
||||
|
||||
// TagMask is used to check for all types of immediate values (either number or 'other').
|
||||
#define TagMask (TagTypeNumber | TagBitTypeOther)
|
||||
#endif
|
||||
|
||||
intptr_t payload() const;
|
||||
static constexpr double maximumLength();
|
||||
|
||||
static bool isInt32ConvertibleDouble(const double& d);
|
||||
static bool isInt32ConvertibleDouble(const double& d, int32_t& asInt32);
|
||||
|
||||
private:
|
||||
ValueDescriptor u;
|
||||
const uint8_t readPointerValueTag() const
|
||||
{
|
||||
return *(reinterpret_cast<size_t*>(m_data.payload) + 1);
|
||||
}
|
||||
ValueData m_data;
|
||||
double toNumberSlowCase(ExecutionState& ec) const; // $7.1.3 ToNumber
|
||||
std::pair<Value, bool> toNumericSlowCase(ExecutionState& ec) const;
|
||||
String* toStringSlowCase(ExecutionState& ec) const; // $7.1.12 ToString
|
||||
|
|
|
|||
|
|
@ -50,436 +50,243 @@ constexpr double Value::maximumLength()
|
|||
return 9007199254740991.0;
|
||||
}
|
||||
|
||||
#pragma pack(push, 1)
|
||||
// NumberInEncodedValue stores its tag in `this + sizeof(size_t)`
|
||||
// the location is same with PointerValues
|
||||
// store double
|
||||
class DoubleInValue : public gc {
|
||||
public:
|
||||
explicit DoubleInValue(const double& v)
|
||||
#ifdef ESCARGOT_32
|
||||
{
|
||||
m_buffer[1] = POINTER_VALUE_NUMBER_TAG_IN_DATA;
|
||||
setValue(v);
|
||||
}
|
||||
#else
|
||||
: m_value(v)
|
||||
, m_typeTag(POINTER_VALUE_NUMBER_TAG_IN_DATA)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
void* operator new(size_t size)
|
||||
{
|
||||
return GC_MALLOC_ATOMIC(size);
|
||||
}
|
||||
void* operator new[](size_t size) = delete;
|
||||
|
||||
double value() const
|
||||
{
|
||||
#ifdef ESCARGOT_32
|
||||
double ret;
|
||||
uint32_t* buf = reinterpret_cast<uint32_t*>(&ret);
|
||||
buf[0] = m_buffer[0];
|
||||
buf[1] = m_buffer[2];
|
||||
return ret;
|
||||
#else
|
||||
return m_value;
|
||||
#endif
|
||||
}
|
||||
|
||||
void setValue(const double& v)
|
||||
{
|
||||
#ifdef ESCARGOT_32
|
||||
const uint32_t* buf = reinterpret_cast<const uint32_t*>(&v);
|
||||
m_buffer[0] = buf[0];
|
||||
m_buffer[2] = buf[1];
|
||||
#else
|
||||
m_value = v;
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef ESCARGOT_32
|
||||
uint32_t m_buffer[3];
|
||||
#else
|
||||
double m_value;
|
||||
size_t m_typeTag;
|
||||
#endif
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
// ==============================================================================
|
||||
// ===32-bit architecture========================================================
|
||||
// ==============================================================================
|
||||
|
||||
#ifdef ESCARGOT_32
|
||||
|
||||
inline Value::Value(ForceUninitializedTag)
|
||||
{
|
||||
}
|
||||
|
||||
inline Value::Value()
|
||||
{
|
||||
u.asBits.tag = UndefinedTag;
|
||||
u.asBits.payload = 0;
|
||||
}
|
||||
|
||||
inline Value::Value(NullInitTag)
|
||||
{
|
||||
u.asBits.tag = NullTag;
|
||||
u.asBits.payload = 0;
|
||||
}
|
||||
|
||||
inline Value::Value(UndefinedInitTag)
|
||||
{
|
||||
u.asBits.tag = UndefinedTag;
|
||||
u.asBits.payload = 0;
|
||||
}
|
||||
|
||||
inline Value::Value(EmptyValueInitTag)
|
||||
{
|
||||
u.asBits.tag = EmptyValueTag;
|
||||
u.asBits.payload = 0;
|
||||
}
|
||||
|
||||
inline Value::Value(TrueInitTag)
|
||||
{
|
||||
u.asBits.tag = BooleanTrueTag;
|
||||
u.asBits.payload = 0;
|
||||
}
|
||||
|
||||
inline Value::Value(FalseInitTag)
|
||||
{
|
||||
u.asBits.tag = BooleanFalseTag;
|
||||
u.asBits.payload = 0;
|
||||
}
|
||||
|
||||
inline Value::Value(bool b)
|
||||
{
|
||||
u.asBits.tag = BooleanFalseTag ^ (((uint32_t)b) << TagTypeShift);
|
||||
u.asBits.payload = 0;
|
||||
}
|
||||
|
||||
inline Value::Value(FromPayloadTag, intptr_t ptr)
|
||||
{
|
||||
u.asBits.tag = OtherPointerTag;
|
||||
#if defined(COMPILER_MSVC)
|
||||
u.asBits.payload = (int32_t)(ptr);
|
||||
#else
|
||||
u.asBits.payload = reinterpret_cast<int32_t>(ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline Value::Value(PointerValue* ptr)
|
||||
{
|
||||
// other type of PointerValue(Object) has pointer in first data area
|
||||
if (ptr->getTypeTag() & (POINTER_VALUE_NOT_OBJECT_TAG_IN_DATA)) {
|
||||
u.asBits.tag = OtherPointerTag;
|
||||
} else {
|
||||
u.asBits.tag = ObjectPointerTag;
|
||||
}
|
||||
u.asBits.payload = reinterpret_cast<int32_t>(const_cast<PointerValue*>(ptr));
|
||||
}
|
||||
|
||||
inline Value::Value(const PointerValue* ptr)
|
||||
{
|
||||
if (ptr->isObject()) {
|
||||
u.asBits.tag = ObjectPointerTag;
|
||||
} else {
|
||||
u.asBits.tag = OtherPointerTag;
|
||||
}
|
||||
u.asBits.payload = reinterpret_cast<int32_t>(const_cast<PointerValue*>(ptr));
|
||||
}
|
||||
|
||||
inline Value::Value(const PointerValue* ptr, FromNonObjectPointerTag)
|
||||
{
|
||||
ASSERT(!ptr->isObject());
|
||||
u.asBits.tag = OtherPointerTag;
|
||||
u.asBits.payload = reinterpret_cast<int32_t>(const_cast<PointerValue*>(ptr));
|
||||
}
|
||||
|
||||
inline Value::Value(String* ptr)
|
||||
{
|
||||
ASSERT(ptr != NULL);
|
||||
u.asBits.tag = OtherPointerTag;
|
||||
u.asBits.payload = reinterpret_cast<int32_t>(ptr);
|
||||
}
|
||||
|
||||
inline Value::Value(const String* ptr)
|
||||
{
|
||||
ASSERT(ptr != NULL);
|
||||
u.asBits.tag = OtherPointerTag;
|
||||
u.asBits.payload = reinterpret_cast<int32_t>(const_cast<String*>(ptr));
|
||||
}
|
||||
|
||||
inline Value::Value(Object* ptr)
|
||||
{
|
||||
u.asBits.tag = ObjectPointerTag;
|
||||
u.asBits.payload = reinterpret_cast<int32_t>(const_cast<Object*>(ptr));
|
||||
}
|
||||
|
||||
inline Value::Value(const Object* ptr)
|
||||
{
|
||||
u.asBits.tag = ObjectPointerTag;
|
||||
u.asBits.payload = reinterpret_cast<int32_t>(const_cast<Object*>(ptr));
|
||||
}
|
||||
|
||||
inline Value::Value(FromTagTag, uint32_t tag)
|
||||
{
|
||||
ASSERT(tag == BooleanFalseTag || tag == BooleanTrueTag || tag == NullTag
|
||||
|| tag == UndefinedTag || tag == EmptyValueTag);
|
||||
|
||||
u.asBits.tag = tag;
|
||||
u.asBits.payload = 0;
|
||||
}
|
||||
|
||||
inline Value::Value(EncodeAsDoubleTag, const double& d)
|
||||
{
|
||||
u.asDouble = d;
|
||||
}
|
||||
|
||||
inline Value::Value(int i)
|
||||
{
|
||||
u.asBits.tag = Int32Tag;
|
||||
u.asBits.payload = i;
|
||||
}
|
||||
|
||||
inline bool Value::operator==(const Value& other) const
|
||||
{
|
||||
return u.asInt64 == other.u.asInt64;
|
||||
}
|
||||
|
||||
inline bool Value::operator!=(const Value& other) const
|
||||
{
|
||||
return u.asInt64 != other.u.asInt64;
|
||||
}
|
||||
|
||||
inline uint32_t Value::tag() const
|
||||
{
|
||||
return u.asBits.tag;
|
||||
}
|
||||
|
||||
inline int32_t Value::payload() const
|
||||
{
|
||||
return u.asBits.payload;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE bool Value::isInt32() const
|
||||
{
|
||||
return tag() == Int32Tag;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE bool Value::isDouble() const
|
||||
{
|
||||
return tag() < LowestTag;
|
||||
}
|
||||
|
||||
inline int32_t Value::asInt32() const
|
||||
{
|
||||
ASSERT(isInt32());
|
||||
return u.asBits.payload;
|
||||
}
|
||||
|
||||
inline bool Value::asBoolean() const
|
||||
{
|
||||
ASSERT(isBoolean());
|
||||
return u.asBits.tag == BooleanTrueTag;
|
||||
}
|
||||
|
||||
inline double Value::asDouble() const
|
||||
{
|
||||
ASSERT(isDouble());
|
||||
return u.asDouble;
|
||||
}
|
||||
|
||||
inline bool Value::isEmpty() const
|
||||
{
|
||||
return tag() == EmptyValueTag;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE bool Value::isNumber() const
|
||||
{
|
||||
return isInt32() || isDouble();
|
||||
}
|
||||
|
||||
inline bool Value::isPointerValue() const
|
||||
{
|
||||
return (tag() == ObjectPointerTag) || (tag() == OtherPointerTag);
|
||||
}
|
||||
|
||||
inline bool Value::isUndefined() const
|
||||
{
|
||||
return tag() == UndefinedTag;
|
||||
}
|
||||
|
||||
inline bool Value::isNull() const
|
||||
{
|
||||
return tag() == NullTag;
|
||||
}
|
||||
|
||||
inline bool Value::isBoolean() const
|
||||
{
|
||||
/* BooleanTrueTag and BooleanFalseTag are inverted values
|
||||
of ValueTrue and ValueFalse respectively. */
|
||||
COMPILE_ASSERT(BooleanFalseTag == (BooleanTrueTag | (1 << TagTypeShift)), "");
|
||||
|
||||
return (tag() | (1 << TagTypeShift)) == BooleanFalseTag;
|
||||
}
|
||||
|
||||
inline bool Value::isTrue() const
|
||||
{
|
||||
return tag() == BooleanTrueTag;
|
||||
}
|
||||
|
||||
inline bool Value::isFalse() const
|
||||
{
|
||||
return tag() == BooleanFalseTag;
|
||||
}
|
||||
|
||||
inline PointerValue* Value::asPointerValue() const
|
||||
{
|
||||
ASSERT(isPointerValue());
|
||||
return reinterpret_cast<PointerValue*>(u.asBits.payload);
|
||||
}
|
||||
|
||||
inline bool Value::isString() const
|
||||
{
|
||||
return tag() == OtherPointerTag && asPointerValue()->isString();
|
||||
}
|
||||
|
||||
inline bool Value::isSymbol() const
|
||||
{
|
||||
return tag() == OtherPointerTag && asPointerValue()->isSymbol();
|
||||
}
|
||||
|
||||
inline bool Value::isBigInt() const
|
||||
{
|
||||
return tag() == OtherPointerTag && asPointerValue()->isBigInt();
|
||||
}
|
||||
|
||||
inline String* Value::asString() const
|
||||
{
|
||||
ASSERT(isString());
|
||||
return asPointerValue()->asString();
|
||||
}
|
||||
|
||||
inline Symbol* Value::asSymbol() const
|
||||
{
|
||||
ASSERT(isSymbol());
|
||||
return asPointerValue()->asSymbol();
|
||||
}
|
||||
|
||||
inline BigInt* Value::asBigInt() const
|
||||
{
|
||||
ASSERT(isBigInt());
|
||||
return asPointerValue()->asBigInt();
|
||||
}
|
||||
|
||||
inline bool Value::isObject() const
|
||||
{
|
||||
return tag() == ObjectPointerTag;
|
||||
}
|
||||
|
||||
inline Object* Value::asObject() const
|
||||
{
|
||||
return asPointerValue()->asObject();
|
||||
}
|
||||
|
||||
inline bool Value::isFunction() const
|
||||
{
|
||||
return isObject() && asPointerValue()->isFunctionObject();
|
||||
}
|
||||
|
||||
inline bool Value::isExtendedNativeFunctionObject() const
|
||||
{
|
||||
return isObject() && asPointerValue()->isExtendedNativeFunctionObject();
|
||||
}
|
||||
|
||||
inline FunctionObject* Value::asFunction() const
|
||||
{
|
||||
return asPointerValue()->asFunctionObject();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// ==============================================================================
|
||||
// ===64-bit architecture========================================================
|
||||
// ==============================================================================
|
||||
|
||||
#endif
|
||||
|
||||
inline Value::Value()
|
||||
{
|
||||
u.asInt64 = ValueUndefined;
|
||||
}
|
||||
// ==============================================================================
|
||||
// ===common architecture========================================================
|
||||
// ==============================================================================
|
||||
|
||||
inline Value::Value(ForceUninitializedTag)
|
||||
{
|
||||
}
|
||||
|
||||
inline Value::Value()
|
||||
{
|
||||
m_data.payload = ValueUndefined;
|
||||
}
|
||||
|
||||
inline Value::Value(NullInitTag)
|
||||
{
|
||||
u.asInt64 = ValueNull;
|
||||
m_data.payload = ValueNull;
|
||||
}
|
||||
|
||||
inline Value::Value(UndefinedInitTag)
|
||||
{
|
||||
u.asInt64 = ValueUndefined;
|
||||
m_data.payload = ValueUndefined;
|
||||
}
|
||||
|
||||
inline Value::Value(EmptyValueInitTag)
|
||||
{
|
||||
u.asInt64 = ValueEmpty;
|
||||
m_data.payload = ValueEmpty;
|
||||
}
|
||||
|
||||
inline Value::Value(TrueInitTag)
|
||||
{
|
||||
u.asInt64 = ValueTrue;
|
||||
m_data.payload = ValueTrue;
|
||||
}
|
||||
|
||||
inline Value::Value(FalseInitTag)
|
||||
{
|
||||
u.asInt64 = ValueFalse;
|
||||
}
|
||||
|
||||
inline Value::Value(FromPayloadTag, intptr_t ptr)
|
||||
{
|
||||
u.ptr = (PointerValue*)ptr;
|
||||
m_data.payload = ValueFalse;
|
||||
}
|
||||
|
||||
inline Value::Value(bool b)
|
||||
{
|
||||
u.asInt64 = (TagBitTypeOther | (b << TagTypeShift));
|
||||
m_data.payload = b ? ValueTrue : ValueFalse;
|
||||
}
|
||||
|
||||
inline Value::Value(FromPayloadTag, intptr_t ptr)
|
||||
{
|
||||
m_data.payload = ptr;
|
||||
}
|
||||
|
||||
inline Value::Value(PointerValue* ptr)
|
||||
{
|
||||
u.ptr = ptr;
|
||||
m_data.payload = reinterpret_cast<intptr_t>(ptr);
|
||||
}
|
||||
|
||||
inline Value::Value(const PointerValue* ptr)
|
||||
{
|
||||
u.ptr = const_cast<PointerValue*>(ptr);
|
||||
}
|
||||
|
||||
inline int64_t reinterpretDoubleToInt64(double value)
|
||||
{
|
||||
return bitwise_cast<int64_t>(value);
|
||||
}
|
||||
inline double reinterpretInt64ToDouble(int64_t value)
|
||||
{
|
||||
return bitwise_cast<double>(value);
|
||||
}
|
||||
|
||||
inline Value::Value(EncodeAsDoubleTag, const double& d)
|
||||
{
|
||||
u.asInt64 = reinterpretDoubleToInt64(d) + DoubleEncodeOffset;
|
||||
m_data.payload = reinterpret_cast<intptr_t>(ptr);
|
||||
}
|
||||
|
||||
inline Value::Value(int i)
|
||||
{
|
||||
u.asInt64 = TagTypeNumber | static_cast<uint32_t>(i);
|
||||
if (LIKELY(EncodedValueImpl::PlatformSmiTagging::IsValidSmi(i))) {
|
||||
m_data.payload = EncodedValueImpl::PlatformSmiTagging::IntToSmi(i);
|
||||
} else {
|
||||
*this = Value(Value::EncodeAsDouble, static_cast<double>(i));
|
||||
}
|
||||
}
|
||||
|
||||
inline Value::Value(EncodeAsDoubleTag, const double& v)
|
||||
{
|
||||
m_data.payload = reinterpret_cast<intptr_t>(new DoubleInValue(v));
|
||||
}
|
||||
|
||||
inline intptr_t Value::asRawData() const
|
||||
{
|
||||
return m_data.payload;
|
||||
}
|
||||
|
||||
inline bool Value::operator==(const Value& other) const
|
||||
{
|
||||
return u.asInt64 == other.u.asInt64;
|
||||
return equalsToByTheSameValueAlgorithm(other);
|
||||
}
|
||||
|
||||
inline bool Value::operator!=(const Value& other) const
|
||||
{
|
||||
return u.asInt64 != other.u.asInt64;
|
||||
return !equalsToByTheSameValueAlgorithm(other);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE bool Value::isInt32() const
|
||||
{
|
||||
#ifdef ESCARGOT_LITTLE_ENDIAN
|
||||
ASSERT(sizeof(short) == 2);
|
||||
unsigned short* firstByte = (unsigned short*)&u.asInt64;
|
||||
return firstByte[3] == 0xffff;
|
||||
#else
|
||||
return (u.asInt64 & TagTypeNumber) == TagTypeNumber;
|
||||
#endif
|
||||
return HAS_SMI_TAG(m_data.payload);
|
||||
}
|
||||
|
||||
inline bool Value::isDouble() const
|
||||
ALWAYS_INLINE bool Value::isDouble() const
|
||||
{
|
||||
return isNumber() && !isInt32();
|
||||
return isHeapValue() && readPointerValueTag() == POINTER_VALUE_NUMBER_TAG_IN_DATA;
|
||||
}
|
||||
|
||||
inline int32_t Value::asInt32() const
|
||||
{
|
||||
ASSERT(isInt32());
|
||||
return static_cast<int32_t>(u.asInt64);
|
||||
return EncodedValueImpl::PlatformSmiTagging::SmiToInt(m_data.payload);
|
||||
}
|
||||
|
||||
inline bool Value::asBoolean() const
|
||||
{
|
||||
ASSERT(isBoolean());
|
||||
return u.asInt64 == ValueTrue;
|
||||
return m_data.payload == ValueTrue;
|
||||
}
|
||||
|
||||
inline double Value::asDouble() const
|
||||
{
|
||||
ASSERT(isDouble());
|
||||
return reinterpretInt64ToDouble(u.asInt64 - DoubleEncodeOffset);
|
||||
return reinterpret_cast<DoubleInValue*>(m_data.payload)->value();
|
||||
}
|
||||
|
||||
inline bool Value::isEmpty() const
|
||||
{
|
||||
return u.asInt64 == ValueEmpty;
|
||||
return m_data.payload == ValueEmpty;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE bool Value::isNumber() const
|
||||
{
|
||||
#ifdef ESCARGOT_LITTLE_ENDIAN
|
||||
ASSERT(sizeof(short) == 2);
|
||||
unsigned short* firstByte = (unsigned short*)&u.asInt64;
|
||||
return firstByte[3];
|
||||
#else
|
||||
return u.asInt64 & TagTypeNumber;
|
||||
#endif
|
||||
return isInt32() || isDouble();
|
||||
}
|
||||
|
||||
inline bool Value::isHeapValue() const
|
||||
{
|
||||
return !(m_data.payload & (EncodedValueImpl::kSmiTagMask | TagBitTypeOther));
|
||||
}
|
||||
|
||||
inline bool Value::isPointerValue() const
|
||||
{
|
||||
return isHeapValue() && readPointerValueTag() != POINTER_VALUE_NUMBER_TAG_IN_DATA;
|
||||
}
|
||||
|
||||
inline bool Value::isUndefined() const
|
||||
{
|
||||
return m_data.payload == ValueUndefined;
|
||||
}
|
||||
|
||||
inline bool Value::isNull() const
|
||||
{
|
||||
return m_data.payload == ValueNull;
|
||||
}
|
||||
|
||||
inline bool Value::isBoolean() const
|
||||
{
|
||||
return (m_data.payload | (1 << TagTypeShift)) == ValueTrue;
|
||||
}
|
||||
|
||||
inline bool Value::isTrue() const
|
||||
{
|
||||
return m_data.payload == ValueTrue;
|
||||
}
|
||||
|
||||
inline bool Value::isFalse() const
|
||||
{
|
||||
return m_data.payload == ValueFalse;
|
||||
}
|
||||
|
||||
inline PointerValue* Value::asPointerValue() const
|
||||
{
|
||||
ASSERT(isPointerValue());
|
||||
return reinterpret_cast<PointerValue*>(m_data.payload);
|
||||
}
|
||||
|
||||
inline bool Value::isString() const
|
||||
|
|
@ -515,47 +322,14 @@ inline BigInt* Value::asBigInt() const
|
|||
return asPointerValue()->asBigInt();
|
||||
}
|
||||
|
||||
inline bool Value::isPointerValue() const
|
||||
{
|
||||
return !(u.asInt64 & TagMask);
|
||||
}
|
||||
|
||||
inline bool Value::isUndefined() const
|
||||
{
|
||||
return u.asInt64 == ValueUndefined;
|
||||
}
|
||||
|
||||
inline bool Value::isNull() const
|
||||
{
|
||||
return u.asInt64 == ValueNull;
|
||||
}
|
||||
|
||||
inline bool Value::isBoolean() const
|
||||
{
|
||||
COMPILE_ASSERT(ValueTrue == (ValueFalse | (1 << TagTypeShift)), "");
|
||||
|
||||
return (u.asInt64 | (1 << TagTypeShift)) == ValueTrue;
|
||||
}
|
||||
|
||||
inline bool Value::isTrue() const
|
||||
{
|
||||
return u.asInt64 == ValueTrue;
|
||||
}
|
||||
|
||||
inline bool Value::isFalse() const
|
||||
{
|
||||
return u.asInt64 == ValueFalse;
|
||||
}
|
||||
|
||||
inline PointerValue* Value::asPointerValue() const
|
||||
{
|
||||
ASSERT(isPointerValue());
|
||||
return u.ptr;
|
||||
}
|
||||
|
||||
inline bool Value::isObject() const
|
||||
{
|
||||
return isPointerValue() && asPointerValue()->isObject();
|
||||
if (LIKELY(isHeapValue())) {
|
||||
if (LIKELY(!(readPointerValueTag() & POINTER_VALUE_NOT_OBJECT_TAG_IN_DATA))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline Object* Value::asObject() const
|
||||
|
|
@ -568,27 +342,16 @@ inline bool Value::isFunction() const
|
|||
return isPointerValue() && asPointerValue()->isFunctionObject();
|
||||
}
|
||||
|
||||
inline bool Value::isExtendedNativeFunctionObject() const
|
||||
{
|
||||
return isPointerValue() && asPointerValue()->isExtendedNativeFunctionObject();
|
||||
}
|
||||
|
||||
inline FunctionObject* Value::asFunction() const
|
||||
{
|
||||
return asPointerValue()->asFunctionObject();
|
||||
}
|
||||
|
||||
inline ExtendedNativeFunctionObject* Value::asExtendedNativeFunctionObject() const
|
||||
{
|
||||
return asPointerValue()->asExtendedNativeFunctionObject();
|
||||
}
|
||||
|
||||
inline intptr_t Value::payload() const
|
||||
{
|
||||
return u.asInt64;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// ==============================================================================
|
||||
// ===common architecture========================================================
|
||||
// ==============================================================================
|
||||
|
||||
ALWAYS_INLINE bool Value::isInt32ConvertibleDouble(const double& d)
|
||||
{
|
||||
int32_t asInt32 = static_cast<int32_t>(d);
|
||||
|
|
@ -614,12 +377,6 @@ inline Value::Value(const double& d)
|
|||
*this = Value(asInt32);
|
||||
return;
|
||||
}
|
||||
#ifdef ESCARGOT_64
|
||||
if (UNLIKELY((bitwise_cast<int64_t>(d) & DoubleInvalidBeginning) == DoubleInvalidBeginning)) {
|
||||
*this = Value(EncodeAsDouble, std::numeric_limits<double>::quiet_NaN());
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
*this = Value(EncodeAsDouble, d);
|
||||
}
|
||||
|
||||
|
|
@ -712,11 +469,7 @@ ALWAYS_INLINE double Value::asNumber() const
|
|||
|
||||
inline bool Value::isPrimitive() const
|
||||
{
|
||||
#ifdef ESCARGOT_32
|
||||
return tag() != ObjectPointerTag;
|
||||
#else
|
||||
return isUndefined() || isNull() || isNumber() || isString() || isBoolean() || isSymbol() || isBigInt();
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool Value::isCallable() const
|
||||
|
|
@ -730,21 +483,10 @@ inline bool Value::isCallable() const
|
|||
// https://www.ecma-international.org/ecma-262/6.0/#sec-tonumber
|
||||
inline double Value::toNumber(ExecutionState& state) const
|
||||
{
|
||||
#ifdef ESCARGOT_64
|
||||
auto n = u.asInt64 & TagTypeNumber;
|
||||
if (LIKELY(n)) {
|
||||
if (n == TagTypeNumber) {
|
||||
return FastI2D(asInt32());
|
||||
} else {
|
||||
return asDouble();
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (LIKELY(isInt32()))
|
||||
return FastI2D(asInt32());
|
||||
else if (isDouble())
|
||||
return asDouble();
|
||||
#endif
|
||||
else if (isUndefined())
|
||||
return std::numeric_limits<double>::quiet_NaN();
|
||||
else if (isNull())
|
||||
|
|
@ -758,20 +500,11 @@ inline double Value::toNumber(ExecutionState& state) const
|
|||
|
||||
inline std::pair<Value, bool> Value::toNumeric(ExecutionState& state) const // <Value, isBigInt>
|
||||
{
|
||||
// fast path
|
||||
#ifdef ESCARGOT_64
|
||||
auto n = u.asInt64 & TagTypeNumber;
|
||||
if (LIKELY(n)) {
|
||||
return std::make_pair(*this, false);
|
||||
}
|
||||
#else
|
||||
if (LIKELY(isInt32())) {
|
||||
return std::make_pair(*this, false);
|
||||
} else if (isDouble()) {
|
||||
return std::make_pair(*this, false);
|
||||
}
|
||||
#endif
|
||||
else if (isUndefined()) {
|
||||
} else if (isUndefined()) {
|
||||
return std::make_pair(Value(std::numeric_limits<double>::quiet_NaN()), false);
|
||||
} else if (isNull()) {
|
||||
return std::make_pair(Value(0), false);
|
||||
|
|
@ -803,11 +536,7 @@ inline Value Value::toPrimitive(ExecutionState& ec, PrimitiveTypeHint preferredT
|
|||
inline bool Value::abstractEqualsTo(ExecutionState& state, const Value& val) const
|
||||
{
|
||||
if (isInt32() && val.isInt32()) {
|
||||
#ifdef ESCARGOT_64
|
||||
return u.asInt64 == val.u.asInt64;
|
||||
#else
|
||||
return u.asBits.payload == val.u.asBits.payload;
|
||||
#endif
|
||||
return m_data.payload == val.m_data.payload;
|
||||
} else {
|
||||
return abstractEqualsToSlowCase(state, val);
|
||||
}
|
||||
|
|
@ -816,11 +545,7 @@ inline bool Value::abstractEqualsTo(ExecutionState& state, const Value& val) con
|
|||
inline bool Value::equalsTo(ExecutionState& state, const Value& val) const
|
||||
{
|
||||
if (isInt32() && val.isInt32()) {
|
||||
#ifdef ESCARGOT_64
|
||||
return u.asInt64 == val.u.asInt64;
|
||||
#else
|
||||
return u.asBits.payload == val.u.asBits.payload;
|
||||
#endif
|
||||
return m_data.payload == val.m_data.payload;
|
||||
} else {
|
||||
return equalsToSlowCase(state, val);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue