mirror of
https://github.com/Samsung/escargot.git
synced 2026-06-22 10:01:50 +00:00
Compare commits
4 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5575cad622 | ||
|
|
c100122bf4 | ||
|
|
9e667ccdd2 | ||
|
|
3631ae6097 |
20 changed files with 485 additions and 579 deletions
|
|
@ -64,13 +64,13 @@ Value builtinArrayConstructor(ExecutionState& state, Value thisValue, size_t arg
|
||||||
ArrayObject* array = new ArrayObject(state, proto, size);
|
ArrayObject* array = new ArrayObject(state, proto, size);
|
||||||
|
|
||||||
if (interpretArgumentsAsElements) {
|
if (interpretArgumentsAsElements) {
|
||||||
Value val = argv[0];
|
if (argc > 1 || !argv[0].isNumber()) {
|
||||||
if (argc > 1 || !val.isInt32()) {
|
|
||||||
if (array->isFastModeArray()) {
|
if (array->isFastModeArray()) {
|
||||||
for (size_t idx = 0; idx < argc; idx++) {
|
for (size_t idx = 0; idx < argc; idx++) {
|
||||||
array->m_fastModeData[idx] = argv[idx];
|
array->m_fastModeData[idx] = argv[idx];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
Value val = argv[0];
|
||||||
for (size_t idx = 0; idx < argc; idx++) {
|
for (size_t idx = 0; idx < argc; idx++) {
|
||||||
array->defineOwnProperty(state, ObjectPropertyName(state, idx), ObjectPropertyDescriptor(val, ObjectPropertyDescriptor::AllPresent));
|
array->defineOwnProperty(state, ObjectPropertyName(state, idx), ObjectPropertyDescriptor(val, ObjectPropertyDescriptor::AllPresent));
|
||||||
val = argv[idx + 1];
|
val = argv[idx + 1];
|
||||||
|
|
@ -1238,7 +1238,7 @@ static Value builtinArrayIncludes(ExecutionState& state, Value thisValue, size_t
|
||||||
// Let elementK be the result of ? Get(O, ! ToString(k)).
|
// Let elementK be the result of ? Get(O, ! ToString(k)).
|
||||||
Value elementK = O->get(state, ObjectPropertyName(state, Value(doubleK))).value(state, O);
|
Value elementK = O->get(state, ObjectPropertyName(state, Value(doubleK))).value(state, O);
|
||||||
// If SameValueZero(searchElement, elementK) is true, return true.
|
// If SameValueZero(searchElement, elementK) is true, return true.
|
||||||
if (elementK.equalsToByTheSameValueZeroAlgorithm(state, searchElement)) {
|
if (elementK.equalsToByTheSameValueZeroAlgorithm(searchElement)) {
|
||||||
return Value(true);
|
return Value(true);
|
||||||
}
|
}
|
||||||
// Increase k by 1.
|
// 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 )
|
// 19.1.2.10 Object.is ( value1, value2 )
|
||||||
|
|
||||||
// Return SameValue(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)
|
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);
|
RESOLVE_THIS_BINDING_TO_OBJECT(rx, Object, search);
|
||||||
String* s = argv[0].toString(state);
|
String* s = argv[0].toString(state);
|
||||||
Value previousLastIndex = rx->get(state, ObjectPropertyName(state.context()->staticStrings().lastIndex)).value(state, thisValue);
|
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);
|
rx->setThrowsException(state, ObjectPropertyName(state.context()->staticStrings().lastIndex), Value(0), thisValue);
|
||||||
}
|
}
|
||||||
Value result = regExpExec(state, rx, s);
|
Value result = regExpExec(state, rx, s);
|
||||||
|
|
||||||
Value currentLastIndex = rx->get(state, ObjectPropertyName(state.context()->staticStrings().lastIndex)).value(state, thisValue);
|
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);
|
rx->setThrowsException(state, ObjectPropertyName(state.context()->staticStrings().lastIndex), previousLastIndex, thisValue);
|
||||||
}
|
}
|
||||||
if (result.isNull()) {
|
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)).
|
// Let elementK be the result of ? Get(O, ! ToString(k)).
|
||||||
Value elementK = O->getIndexedProperty(state, Value(k)).value(state, O);
|
Value elementK = O->getIndexedProperty(state, Value(k)).value(state, O);
|
||||||
// If SameValueZero(searchElement, elementK) is true, return true.
|
// If SameValueZero(searchElement, elementK) is true, return true.
|
||||||
if (elementK.equalsToByTheSameValueZeroAlgorithm(state, searchElement)) {
|
if (elementK.equalsToByTheSameValueZeroAlgorithm(searchElement)) {
|
||||||
return Value(true);
|
return Value(true);
|
||||||
}
|
}
|
||||||
// Increase k by 1.
|
// Increase k by 1.
|
||||||
|
|
|
||||||
|
|
@ -57,21 +57,13 @@ void getNextValidInValueVector(GC_word* ptr, GC_word* end, GC_word** next_ptr, G
|
||||||
{
|
{
|
||||||
while (ptr < end) {
|
while (ptr < end) {
|
||||||
Value* current = (Value*)ptr;
|
Value* current = (Value*)ptr;
|
||||||
if (current->isPointerValue()) {
|
if (current->isHeapValue()) {
|
||||||
#ifdef ESCARGOT_32
|
|
||||||
*next_ptr = ptr + 2;
|
|
||||||
#else
|
|
||||||
*next_ptr = ptr + 1;
|
*next_ptr = ptr + 1;
|
||||||
#endif
|
|
||||||
*from = ptr;
|
*from = ptr;
|
||||||
*to = (GC_word*)current->asPointerValue();
|
*to = (GC_word*)current->asRawData();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#ifdef ESCARGOT_32
|
|
||||||
ptr = ptr + 2;
|
|
||||||
#else
|
|
||||||
ptr = ptr + 1;
|
ptr = ptr + 1;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*next_ptr = end;
|
*next_ptr = end;
|
||||||
|
|
@ -353,13 +345,13 @@ template <>
|
||||||
Value* CustomAllocator<Value>::allocate(size_type GC_n, const void*)
|
Value* CustomAllocator<Value>::allocate(size_type GC_n, const void*)
|
||||||
{
|
{
|
||||||
// Un-comment this to use default allocator
|
// Un-comment this to use default allocator
|
||||||
// return (Value*)GC_MALLOC(sizeof(Value) * GC_n);
|
return (Value*)GC_MALLOC(sizeof(Value) * GC_n);
|
||||||
int kind = s_gcKinds[HeapObjectKind::ValueVectorKind];
|
// int kind = s_gcKinds[HeapObjectKind::ValueVectorKind];
|
||||||
size_t size = sizeof(Value) * GC_n;
|
// size_t size = sizeof(Value) * GC_n;
|
||||||
|
|
||||||
Value* ret;
|
// Value* ret;
|
||||||
ret = (Value*)GC_GENERIC_MALLOC(size, kind);
|
// ret = (Value*)GC_GENERIC_MALLOC(size, kind);
|
||||||
return ret;
|
// return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
|
|
||||||
|
|
@ -246,7 +246,7 @@ Value ByteCodeInterpreter::interpret(ExecutionState* state, ByteCodeBlock* byteC
|
||||||
BinaryPlus* code = (BinaryPlus*)programCounter;
|
BinaryPlus* code = (BinaryPlus*)programCounter;
|
||||||
const Value& v0 = registerFile[code->m_srcIndex0];
|
const Value& v0 = registerFile[code->m_srcIndex0];
|
||||||
const Value& v1 = registerFile[code->m_srcIndex1];
|
const Value& v1 = registerFile[code->m_srcIndex1];
|
||||||
Value ret(Value::ForceUninitialized);
|
Value& ret = registerFile[code->m_dstIndex];
|
||||||
if (v0.isInt32() && v1.isInt32()) {
|
if (v0.isInt32() && v1.isInt32()) {
|
||||||
int32_t a = v0.asInt32();
|
int32_t a = v0.asInt32();
|
||||||
int32_t b = v1.asInt32();
|
int32_t b = v1.asInt32();
|
||||||
|
|
@ -258,11 +258,11 @@ Value ByteCodeInterpreter::interpret(ExecutionState* state, ByteCodeBlock* byteC
|
||||||
ret = Value(Value::EncodeAsDouble, (double)a + (double)b);
|
ret = Value(Value::EncodeAsDouble, (double)a + (double)b);
|
||||||
}
|
}
|
||||||
} else if (v0.isNumber() && v1.isNumber()) {
|
} else if (v0.isNumber() && v1.isNumber()) {
|
||||||
ret = Value(v0.asNumber() + v1.asNumber());
|
// most cases are double
|
||||||
|
ret = Value(Value::EncodeAsDouble, v0.asNumber() + v1.asNumber());
|
||||||
} else {
|
} else {
|
||||||
ret = plusSlowCase(*state, v0, v1);
|
ret = plusSlowCase(*state, v0, v1);
|
||||||
}
|
}
|
||||||
registerFile[code->m_dstIndex] = ret;
|
|
||||||
ADD_PROGRAM_COUNTER(BinaryPlus);
|
ADD_PROGRAM_COUNTER(BinaryPlus);
|
||||||
NEXT_INSTRUCTION();
|
NEXT_INSTRUCTION();
|
||||||
}
|
}
|
||||||
|
|
@ -273,7 +273,7 @@ Value ByteCodeInterpreter::interpret(ExecutionState* state, ByteCodeBlock* byteC
|
||||||
BinaryMinus* code = (BinaryMinus*)programCounter;
|
BinaryMinus* code = (BinaryMinus*)programCounter;
|
||||||
const Value& left = registerFile[code->m_srcIndex0];
|
const Value& left = registerFile[code->m_srcIndex0];
|
||||||
const Value& right = registerFile[code->m_srcIndex1];
|
const Value& right = registerFile[code->m_srcIndex1];
|
||||||
Value ret(Value::ForceUninitialized);
|
Value& ret = registerFile[code->m_dstIndex];
|
||||||
if (left.isInt32() && right.isInt32()) {
|
if (left.isInt32() && right.isInt32()) {
|
||||||
int32_t a = left.asInt32();
|
int32_t a = left.asInt32();
|
||||||
int32_t b = right.asInt32();
|
int32_t b = right.asInt32();
|
||||||
|
|
@ -285,11 +285,11 @@ Value ByteCodeInterpreter::interpret(ExecutionState* state, ByteCodeBlock* byteC
|
||||||
ret = Value(Value::EncodeAsDouble, (double)a - (double)b);
|
ret = Value(Value::EncodeAsDouble, (double)a - (double)b);
|
||||||
}
|
}
|
||||||
} else if (LIKELY(left.isNumber() && right.isNumber())) {
|
} else if (LIKELY(left.isNumber() && right.isNumber())) {
|
||||||
ret = Value(left.asNumber() - right.asNumber());
|
// most cases are double
|
||||||
|
ret = Value(Value::EncodeAsDouble, left.asNumber() - right.asNumber());
|
||||||
} else {
|
} else {
|
||||||
ret = minusSlowCase(*state, left, right);
|
ret = minusSlowCase(*state, left, right);
|
||||||
}
|
}
|
||||||
registerFile[code->m_dstIndex] = ret;
|
|
||||||
ADD_PROGRAM_COUNTER(BinaryMinus);
|
ADD_PROGRAM_COUNTER(BinaryMinus);
|
||||||
NEXT_INSTRUCTION();
|
NEXT_INSTRUCTION();
|
||||||
}
|
}
|
||||||
|
|
@ -300,7 +300,7 @@ Value ByteCodeInterpreter::interpret(ExecutionState* state, ByteCodeBlock* byteC
|
||||||
BinaryMultiply* code = (BinaryMultiply*)programCounter;
|
BinaryMultiply* code = (BinaryMultiply*)programCounter;
|
||||||
const Value& left = registerFile[code->m_srcIndex0];
|
const Value& left = registerFile[code->m_srcIndex0];
|
||||||
const Value& right = registerFile[code->m_srcIndex1];
|
const Value& right = registerFile[code->m_srcIndex1];
|
||||||
Value ret(Value::ForceUninitialized);
|
Value& ret = registerFile[code->m_dstIndex];
|
||||||
if (left.isInt32() && right.isInt32()) {
|
if (left.isInt32() && right.isInt32()) {
|
||||||
int32_t a = left.asInt32();
|
int32_t a = left.asInt32();
|
||||||
int32_t b = right.asInt32();
|
int32_t b = right.asInt32();
|
||||||
|
|
@ -316,11 +316,11 @@ Value ByteCodeInterpreter::interpret(ExecutionState* state, ByteCodeBlock* byteC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (LIKELY(left.isNumber() && right.isNumber())) {
|
} else if (LIKELY(left.isNumber() && right.isNumber())) {
|
||||||
|
// most cases are double
|
||||||
ret = Value(Value::EncodeAsDouble, left.asNumber() * right.asNumber());
|
ret = Value(Value::EncodeAsDouble, left.asNumber() * right.asNumber());
|
||||||
} else {
|
} else {
|
||||||
ret = multiplySlowCase(*state, left, right);
|
ret = multiplySlowCase(*state, left, right);
|
||||||
}
|
}
|
||||||
registerFile[code->m_dstIndex] = ret;
|
|
||||||
ADD_PROGRAM_COUNTER(BinaryMultiply);
|
ADD_PROGRAM_COUNTER(BinaryMultiply);
|
||||||
NEXT_INSTRUCTION();
|
NEXT_INSTRUCTION();
|
||||||
}
|
}
|
||||||
|
|
@ -331,10 +331,12 @@ Value ByteCodeInterpreter::interpret(ExecutionState* state, ByteCodeBlock* byteC
|
||||||
BinaryDivision* code = (BinaryDivision*)programCounter;
|
BinaryDivision* code = (BinaryDivision*)programCounter;
|
||||||
const Value& left = registerFile[code->m_srcIndex0];
|
const Value& left = registerFile[code->m_srcIndex0];
|
||||||
const Value& right = registerFile[code->m_srcIndex1];
|
const Value& right = registerFile[code->m_srcIndex1];
|
||||||
|
Value& ret = registerFile[code->m_dstIndex];
|
||||||
if (LIKELY(left.isNumber() && right.isNumber())) {
|
if (LIKELY(left.isNumber() && right.isNumber())) {
|
||||||
registerFile[code->m_dstIndex] = Value(left.asNumber() / right.asNumber());
|
// most cases are double
|
||||||
|
ret = Value(Value::EncodeAsDouble, left.asNumber() / right.asNumber());
|
||||||
} else {
|
} else {
|
||||||
registerFile[code->m_dstIndex] = divisionSlowCase(*state, left, right);
|
ret = divisionSlowCase(*state, left, right);
|
||||||
}
|
}
|
||||||
ADD_PROGRAM_COUNTER(BinaryDivision);
|
ADD_PROGRAM_COUNTER(BinaryDivision);
|
||||||
NEXT_INSTRUCTION();
|
NEXT_INSTRUCTION();
|
||||||
|
|
@ -490,7 +492,11 @@ Value ByteCodeInterpreter::interpret(ExecutionState* state, ByteCodeBlock* byteC
|
||||||
if (LIKELY(arr->isFastModeArray())) {
|
if (LIKELY(arr->isFastModeArray())) {
|
||||||
uint32_t idx = property.tryToUseAsIndexProperty(*state);
|
uint32_t idx = property.tryToUseAsIndexProperty(*state);
|
||||||
if (LIKELY(idx < arr->arrayLength(*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);
|
ADD_PROGRAM_COUNTER(GetObject);
|
||||||
NEXT_INSTRUCTION();
|
NEXT_INSTRUCTION();
|
||||||
}
|
}
|
||||||
|
|
@ -1633,7 +1639,7 @@ NEVER_INLINE Value ByteCodeInterpreter::multiplySlowCase(ExecutionState& state,
|
||||||
if (UNLIKELY(lnum.second)) {
|
if (UNLIKELY(lnum.second)) {
|
||||||
return Value(lnum.first.asBigInt()->multiply(state, rnum.first.asBigInt()));
|
return Value(lnum.first.asBigInt()->multiply(state, rnum.first.asBigInt()));
|
||||||
} else {
|
} else {
|
||||||
return Value(Value::EncodeAsDouble, lnum.first.asNumber() * rnum.first.asNumber());
|
return Value(lnum.first.asNumber() * rnum.first.asNumber());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1650,7 +1656,7 @@ NEVER_INLINE Value ByteCodeInterpreter::divisionSlowCase(ExecutionState& state,
|
||||||
}
|
}
|
||||||
return Value(lnum.first.asBigInt()->division(state, rnum.first.asBigInt()));
|
return Value(lnum.first.asBigInt()->division(state, rnum.first.asBigInt()));
|
||||||
} else {
|
} else {
|
||||||
return Value(Value::EncodeAsDouble, lnum.first.asNumber() / rnum.first.asNumber());
|
return Value(lnum.first.asNumber() / rnum.first.asNumber());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,10 @@ public:
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ASSERT(m_value.asPointerValue()->isBigInt());
|
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) {
|
if (dstRegister < REGULAR_REGISTER_LIMIT + VARIABLE_LIMIT) {
|
||||||
codeBlock->pushCode(LoadLiteral(ByteCodeLOC(m_loc.index), dstRegister, m_value), context, this);
|
codeBlock->pushCode(LoadLiteral(ByteCodeLOC(m_loc.index), dstRegister, m_value), context, this);
|
||||||
|
|
|
||||||
|
|
@ -1078,6 +1078,10 @@ public:
|
||||||
// raw = this->getTokenRaw(token);
|
// raw = this->getTokenRaw(token);
|
||||||
if (builder.isNodeGenerator()) {
|
if (builder.isNodeGenerator()) {
|
||||||
auto d = token->valueNumberLiteral(this->scanner);
|
auto d = token->valueNumberLiteral(this->scanner);
|
||||||
|
if (d.first.asRawData() == 0) {
|
||||||
|
puts("123");
|
||||||
|
token->valueNumberLiteral(this->scanner);
|
||||||
|
}
|
||||||
if (LIKELY(!d.second)) {
|
if (LIKELY(!d.second)) {
|
||||||
if (minus) {
|
if (minus) {
|
||||||
d.first = Value(-d.first.asNumber());
|
d.first = Value(-d.first.asNumber());
|
||||||
|
|
|
||||||
|
|
@ -335,7 +335,7 @@ void ArgumentsObject::setIndexedPropertyValueQuickly(ExecutionState& state, size
|
||||||
ASSERT(m_targetRecord != nullptr);
|
ASSERT(m_targetRecord != nullptr);
|
||||||
ArgumentsObjectNativeSetter(state, this, value, m_targetRecord, m_sourceFunctionObject->interpretedCodeBlock(), m_parameterMap[index].second);
|
ArgumentsObjectNativeSetter(state, this, value, m_targetRecord, m_sourceFunctionObject->interpretedCodeBlock(), m_parameterMap[index].second);
|
||||||
} else {
|
} else {
|
||||||
return m_parameterMap[index].first = value;
|
m_parameterMap[index].first = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,26 @@ Context::Context(VMInstance* instance)
|
||||||
ExecutionState stateForInit(this);
|
ExecutionState stateForInit(this);
|
||||||
m_globalObjectProxy = m_globalObject = new GlobalObject(stateForInit);
|
m_globalObjectProxy = m_globalObject = new GlobalObject(stateForInit);
|
||||||
m_globalObject->initializeBuiltins(stateForInit);
|
m_globalObject->initializeBuiltins(stateForInit);
|
||||||
|
|
||||||
|
#if !defined(NDEBUG)
|
||||||
|
// Int32 convertible double value test
|
||||||
|
Value v(Value::EncodeAsDouble, 2.0);
|
||||||
|
ASSERT(v.isDouble());
|
||||||
|
ASSERT(v.isNumber());
|
||||||
|
ASSERT(v.isInteger(stateForInit));
|
||||||
|
ASSERT(v.toIndex(stateForInit) == 2);
|
||||||
|
ASSERT(v.toIndex32(stateForInit) == 2);
|
||||||
|
ASSERT(v.toInt32(stateForInit) == 2);
|
||||||
|
ASSERT(v.toInteger(stateForInit) == 2);
|
||||||
|
ASSERT(v.toLength(stateForInit) == 2);
|
||||||
|
ASSERT(v.toNumber(stateForInit) == 2);
|
||||||
|
ASSERT(v.toNumeric(stateForInit).first.asDouble() == 2);
|
||||||
|
ASSERT(v.toPropertyKey(stateForInit).toIndex(stateForInit) == 2);
|
||||||
|
ASSERT(v.tryToUseAsIndex(stateForInit) == 2);
|
||||||
|
ASSERT(v.tryToUseAsIndex32(stateForInit) == 2);
|
||||||
|
ASSERT(v.equalsTo(stateForInit, Value(2)));
|
||||||
|
ASSERT(v.abstractEqualsTo(stateForInit, Value(2)));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Context::throwException(ExecutionState& state, const Value& exception)
|
void Context::throwException(ExecutionState& state, const Value& exception)
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ class PointerValue;
|
||||||
|
|
||||||
#ifdef ESCARGOT_32
|
#ifdef ESCARGOT_32
|
||||||
COMPILE_ASSERT(sizeof(EncodedValueData) == 4, "");
|
COMPILE_ASSERT(sizeof(EncodedValueData) == 4, "");
|
||||||
COMPILE_ASSERT(sizeof(Value) == 8, "");
|
COMPILE_ASSERT(sizeof(Value) == 4, "");
|
||||||
#else
|
#else
|
||||||
COMPILE_ASSERT(sizeof(EncodedValueData) == 8, "");
|
COMPILE_ASSERT(sizeof(EncodedValueData) == 8, "");
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -99,85 +99,103 @@ private:
|
||||||
};
|
};
|
||||||
#pragma pack(pop)
|
#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;
|
EncodedValue(const Value& v = Value())
|
||||||
const int kApiIntSize = sizeof(int);
|
: m_value(v)
|
||||||
const int kApiInt64Size = sizeof(int64_t);
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// Tag information for small immediate. Other values are heap objects.
|
explicit EncodedValue(PointerValue* v)
|
||||||
const int kSmiTag = 1;
|
: m_value(v)
|
||||||
const int kSmiTagSize = 1;
|
{
|
||||||
const intptr_t kSmiTagMask = (1 << kSmiTagSize) - 1;
|
}
|
||||||
|
|
||||||
template <size_t ptr_size>
|
static EncodedValue fromPayload(const void* p)
|
||||||
struct SmiTagging;
|
{
|
||||||
|
return Value(Value::FromPayload, reinterpret_cast<intptr_t>(p));
|
||||||
|
}
|
||||||
|
|
||||||
template <int kSmiShiftSize>
|
explicit EncodedValue(const uint32_t from)
|
||||||
inline int32_t IntToSmiT(int value)
|
: m_value(Value(from))
|
||||||
{
|
{
|
||||||
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.
|
EncodedValue(ForceUninitializedTag)
|
||||||
template <>
|
|
||||||
struct SmiTagging<4> {
|
|
||||||
enum {
|
|
||||||
kSmiShiftSize = 0,
|
|
||||||
kSmiValueSize = 31
|
|
||||||
};
|
|
||||||
static int SmiShiftSize()
|
|
||||||
{
|
{
|
||||||
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;
|
ASSERT(from);
|
||||||
// Throw away top 32 bits and shift down (requires >> to be sign extending).
|
m_value = Value(from);
|
||||||
return static_cast<int>(value >> shift_bits);
|
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
|
return m_value.isHeapValue();
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
// 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)
|
// 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
|
// developers should use this class if want to save some Value on Heap
|
||||||
|
|
@ -326,10 +344,11 @@ public:
|
||||||
return operator Escargot::Value().toUint32(state);
|
return operator Escargot::Value().toUint32(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator=(PointerValue* from)
|
const EncodedValue& operator=(PointerValue* from)
|
||||||
{
|
{
|
||||||
ASSERT(from);
|
ASSERT(from);
|
||||||
m_data.payload = (intptr_t)from;
|
m_data.payload = (intptr_t)from;
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const EncodedValue& other) const
|
bool operator==(const EncodedValue& other) const
|
||||||
|
|
@ -337,35 +356,39 @@ public:
|
||||||
return m_data.payload == other.payload();
|
return m_data.payload == other.payload();
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE void operator=(const Value& from)
|
ALWAYS_INLINE const EncodedValue& operator=(const Value& from)
|
||||||
{
|
{
|
||||||
if (from.isPointerValue()) {
|
if (from.isPointerValue()) {
|
||||||
#ifdef ESCARGOT_32
|
#ifdef ESCARGOT_32
|
||||||
ASSERT(!from.isEmpty());
|
ASSERT(!from.isEmpty());
|
||||||
#endif
|
#endif
|
||||||
m_data.payload = (intptr_t)from.asPointerValue();
|
m_data.payload = (intptr_t)from.asPointerValue();
|
||||||
return;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t i32;
|
int32_t i32;
|
||||||
if (from.isInt32() && EncodedValueImpl::PlatformSmiTagging::IsValidSmi(i32 = from.asInt32())) {
|
if (from.isInt32() && EncodedValueImpl::PlatformSmiTagging::IsValidSmi(i32 = from.asInt32())) {
|
||||||
m_data.payload = EncodedValueImpl::PlatformSmiTagging::IntToSmi(i32);
|
m_data.payload = EncodedValueImpl::PlatformSmiTagging::IntToSmi(i32);
|
||||||
return;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (from.isNumber()) {
|
if (from.isNumber()) {
|
||||||
|
Value mutableFrom(from);
|
||||||
|
if (UNLIKELY(Value::isInt32ConvertibleDouble(mutableFrom.asNumber(), i32))) {
|
||||||
|
mutableFrom = Value(i32);
|
||||||
|
}
|
||||||
intptr_t payload = m_data.payload;
|
intptr_t payload = m_data.payload;
|
||||||
|
|
||||||
if (!HAS_SMI_TAG(payload) && ((size_t)payload > (size_t)ValueLast)) {
|
if (!HAS_SMI_TAG(payload) && ((size_t)payload > (size_t)ValueLast)) {
|
||||||
void* v = (void*)payload;
|
void* v = (void*)payload;
|
||||||
if (readPointerIsNumberEncodedValue(v)) {
|
if (readPointerIsNumberEncodedValue(v)) {
|
||||||
((NumberInEncodedValue*)m_data.payload)->setValue(from);
|
((NumberInEncodedValue*)m_data.payload)->setValue(mutableFrom);
|
||||||
return;
|
return *this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_data.payload = reinterpret_cast<intptr_t>(new NumberInEncodedValue(from));
|
m_data.payload = reinterpret_cast<intptr_t>(new NumberInEncodedValue(mutableFrom));
|
||||||
ASSERT(readPointerIsNumberEncodedValue((void*)m_data.payload));
|
ASSERT(readPointerIsNumberEncodedValue((void*)m_data.payload));
|
||||||
return;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ESCARGOT_32
|
#ifdef ESCARGOT_32
|
||||||
|
|
@ -373,6 +396,7 @@ public:
|
||||||
#else
|
#else
|
||||||
m_data.payload = from.payload();
|
m_data.payload = from.payload();
|
||||||
#endif
|
#endif
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
@ -394,7 +418,11 @@ protected:
|
||||||
if (from.isInt32() && EncodedValueImpl::PlatformSmiTagging::IsValidSmi(i32 = from.asInt32())) {
|
if (from.isInt32() && EncodedValueImpl::PlatformSmiTagging::IsValidSmi(i32 = from.asInt32())) {
|
||||||
m_data.payload = EncodedValueImpl::PlatformSmiTagging::IntToSmi(i32);
|
m_data.payload = EncodedValueImpl::PlatformSmiTagging::IntToSmi(i32);
|
||||||
} else if (from.isNumber()) {
|
} else if (from.isNumber()) {
|
||||||
m_data.payload = reinterpret_cast<intptr_t>(new NumberInEncodedValue(from));
|
if (UNLIKELY(Value::isInt32ConvertibleDouble(from.asNumber(), i32) && EncodedValueImpl::PlatformSmiTagging::IsValidSmi(i32))) {
|
||||||
|
m_data.payload = EncodedValueImpl::PlatformSmiTagging::IntToSmi(i32);
|
||||||
|
} else {
|
||||||
|
m_data.payload = reinterpret_cast<intptr_t>(new NumberInEncodedValue(from));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
#ifdef ESCARGOT_32
|
#ifdef ESCARGOT_32
|
||||||
m_data.payload = ~from.tag();
|
m_data.payload = ~from.tag();
|
||||||
|
|
@ -413,6 +441,7 @@ protected:
|
||||||
private:
|
private:
|
||||||
EncodedValueData m_data;
|
EncodedValueData m_data;
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
#if defined(ESCARGOT_64) && defined(ESCARGOT_USE_32BIT_IN_64BIT)
|
#if defined(ESCARGOT_64) && defined(ESCARGOT_USE_32BIT_IN_64BIT)
|
||||||
class EncodedSmallValue {
|
class EncodedSmallValue {
|
||||||
|
|
@ -439,7 +468,11 @@ public:
|
||||||
if (from.isInt32() && EncodedValueImpl::PlatformSmiTagging::IsValidSmi(i32 = from.asInt32())) {
|
if (from.isInt32() && EncodedValueImpl::PlatformSmiTagging::IsValidSmi(i32 = from.asInt32())) {
|
||||||
setPayload(EncodedValueImpl::PlatformSmiTagging::IntToSmi(i32));
|
setPayload(EncodedValueImpl::PlatformSmiTagging::IntToSmi(i32));
|
||||||
} else if (from.isNumber()) {
|
} else if (from.isNumber()) {
|
||||||
setPayload(reinterpret_cast<intptr_t>(new NumberInEncodedValue(from)));
|
if (UNLIKELY(Value::isInt32ConvertibleDouble(from.asNumber(), i32) && EncodedValueImpl::PlatformSmiTagging::IsValidSmi(i32))) {
|
||||||
|
setPayload(EncodedValueImpl::PlatformSmiTagging::IntToSmi(i32));
|
||||||
|
} else {
|
||||||
|
setPayload(reinterpret_cast<intptr_t>(new NumberInEncodedValue(from)));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
setPayload(from.payload());
|
setPayload(from.payload());
|
||||||
}
|
}
|
||||||
|
|
@ -518,38 +551,44 @@ public:
|
||||||
return payload() == other.payload();
|
return payload() == other.payload();
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE void operator=(const EncodedValue& from)
|
ALWAYS_INLINE const EncodedSmallValue& operator=(const EncodedValue& from)
|
||||||
{
|
{
|
||||||
setPayload(from.payload());
|
setPayload(from.payload());
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE void operator=(const Value& from)
|
ALWAYS_INLINE const EncodedSmallValue& operator=(const Value& from)
|
||||||
{
|
{
|
||||||
if (from.isPointerValue()) {
|
if (from.isPointerValue()) {
|
||||||
setPayload(reinterpret_cast<intptr_t>(from.asPointerValue()));
|
setPayload(reinterpret_cast<intptr_t>(from.asPointerValue()));
|
||||||
return;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t i32;
|
int32_t i32;
|
||||||
if (from.isInt32() && EncodedValueImpl::PlatformSmiTagging::IsValidSmi(i32 = from.asInt32())) {
|
if (from.isInt32() && EncodedValueImpl::PlatformSmiTagging::IsValidSmi(i32 = from.asInt32())) {
|
||||||
setPayload(EncodedValueImpl::PlatformSmiTagging::IntToSmi(i32));
|
setPayload(EncodedValueImpl::PlatformSmiTagging::IntToSmi(i32));
|
||||||
return;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (from.isNumber()) {
|
if (from.isNumber()) {
|
||||||
|
Value mutableFrom(from);
|
||||||
|
if (UNLIKELY(Value::isInt32ConvertibleDouble(mutableFrom.asNumber(), i32))) {
|
||||||
|
mutableFrom = Value(i32);
|
||||||
|
}
|
||||||
auto pl = payload();
|
auto pl = payload();
|
||||||
if (!isSMI() && ((size_t)pl > (size_t)ValueLast)) {
|
if (!isSMI() && ((size_t)pl > (size_t)ValueLast)) {
|
||||||
void* v = reinterpret_cast<void*>(pl);
|
void* v = reinterpret_cast<void*>(pl);
|
||||||
if (EncodedValue::readPointerIsNumberEncodedValue(v)) {
|
if (EncodedValue::readPointerIsNumberEncodedValue(v)) {
|
||||||
reinterpret_cast<NumberInEncodedValue*>(v)->setValue(from);
|
reinterpret_cast<NumberInEncodedValue*>(v)->setValue(mutableFrom);
|
||||||
return;
|
return *this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setPayload(reinterpret_cast<intptr_t>(new NumberInEncodedValue(from)));
|
setPayload(reinterpret_cast<intptr_t>(new NumberInEncodedValue(mutableFrom)));
|
||||||
ASSERT(EncodedValue::readPointerIsNumberEncodedValue((void*)payload()));
|
ASSERT(EncodedValue::readPointerIsNumberEncodedValue((void*)payload()));
|
||||||
return;
|
return *this;
|
||||||
}
|
}
|
||||||
setPayload(from.payload());
|
setPayload(from.payload());
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -38,14 +38,16 @@ public:
|
||||||
RELEASE_ASSERT_NOT_REACHED();
|
RELEASE_ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Object* m_object;
|
||||||
|
uint32_t m_arrayLength;
|
||||||
size_t m_index;
|
size_t m_index;
|
||||||
EncodedValueTightVector m_keys;
|
EncodedValueTightVector m_keys;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
EnumerateObject(Object* obj)
|
EnumerateObject(Object* obj)
|
||||||
: m_index(0)
|
: m_object(obj)
|
||||||
, m_object(obj)
|
|
||||||
, m_arrayLength(0)
|
, m_arrayLength(0)
|
||||||
|
, m_index(0)
|
||||||
{
|
{
|
||||||
ASSERT(!!m_object);
|
ASSERT(!!m_object);
|
||||||
}
|
}
|
||||||
|
|
@ -54,9 +56,6 @@ protected:
|
||||||
|
|
||||||
virtual void executeEnumeration(ExecutionState& state, EncodedValueTightVector& keys) = 0;
|
virtual void executeEnumeration(ExecutionState& state, EncodedValueTightVector& keys) = 0;
|
||||||
virtual bool checkIfModified(ExecutionState& state);
|
virtual bool checkIfModified(ExecutionState& state);
|
||||||
|
|
||||||
Object* m_object;
|
|
||||||
uint32_t m_arrayLength;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// enumerate object for destruction operation e.g. var obj = { a, ...b };
|
// 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()) {
|
if (existingKey.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (existingKey.equalsToByTheSameValueZeroAlgorithm(state, key)) {
|
if (existingKey.equalsToByTheSameValueZeroAlgorithm(key)) {
|
||||||
m_storage[i] = std::make_pair(Value(Value::EmptyValue), Value(Value::EmptyValue));
|
m_storage[i] = std::make_pair(Value(Value::EmptyValue), Value(Value::EmptyValue));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -90,7 +90,7 @@ Value MapObject::get(ExecutionState& state, const Value& key)
|
||||||
if (existingKey.isEmpty()) {
|
if (existingKey.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (existingKey.equalsToByTheSameValueZeroAlgorithm(state, key)) {
|
if (existingKey.equalsToByTheSameValueZeroAlgorithm(key)) {
|
||||||
return m_storage[i].second;
|
return m_storage[i].second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -104,7 +104,7 @@ bool MapObject::has(ExecutionState& state, const Value& key)
|
||||||
if (existingKey.isEmpty()) {
|
if (existingKey.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (existingKey.equalsToByTheSameValueZeroAlgorithm(state, key)) {
|
if (existingKey.equalsToByTheSameValueZeroAlgorithm(key)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -118,7 +118,7 @@ void MapObject::set(ExecutionState& state, const Value& key, const Value& value)
|
||||||
if (existingKey.isEmpty()) {
|
if (existingKey.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (existingKey.equalsToByTheSameValueZeroAlgorithm(state, key)) {
|
if (existingKey.equalsToByTheSameValueZeroAlgorithm(key)) {
|
||||||
m_storage[i].second = value;
|
m_storage[i].second = value;
|
||||||
return;
|
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.[[Value]] is present, return SameValue(Desc.[[Value]], current.[[Value]]).
|
||||||
if (desc.isValuePresent()) {
|
if (desc.isValuePresent()) {
|
||||||
return desc.value().equalsToByTheSameValueAlgorithm(state, current.value(state, this));
|
return desc.value().equalsToByTheSameValueAlgorithm(current.value(state, this));
|
||||||
}
|
}
|
||||||
// Return true.
|
// Return true.
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -809,7 +809,7 @@ bool Object::defineOwnPropertyMethod(ExecutionState& state, const ObjectProperty
|
||||||
}
|
}
|
||||||
// If the [[Writable]] field of current is false, then
|
// 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.
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1471,7 +1471,7 @@ bool Object::isCompatiblePropertyDescriptor(ExecutionState& state, bool extensib
|
||||||
// ii. If the [[Writable]] field of current is false, then
|
// ii. If the [[Writable]] field of current is false, then
|
||||||
if (!current.isWritable()) {
|
if (!current.isWritable()) {
|
||||||
// 1. Return false, if the [[Value]] field of Desc is present and SameValue(Desc.[[Value]], current.[[Value]]) is false.
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ bool SetObject::deleteOperation(ExecutionState& state, const Value& key)
|
||||||
if (existingKey.isEmpty()) {
|
if (existingKey.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (existingKey.equalsToByTheSameValueZeroAlgorithm(state, key)) {
|
if (existingKey.equalsToByTheSameValueZeroAlgorithm(key)) {
|
||||||
m_storage[i] = Value(Value::EmptyValue);
|
m_storage[i] = Value(Value::EmptyValue);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -77,7 +77,7 @@ void SetObject::add(ExecutionState& state, const Value& key)
|
||||||
if (existingKey.isEmpty()) {
|
if (existingKey.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (existingKey.equalsToByTheSameValueZeroAlgorithm(state, key)) {
|
if (existingKey.equalsToByTheSameValueZeroAlgorithm(key)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -97,7 +97,7 @@ bool SetObject::has(ExecutionState& state, const Value& key)
|
||||||
if (existingKey.isEmpty()) {
|
if (existingKey.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (existingKey.equalsToByTheSameValueZeroAlgorithm(state, key)) {
|
if (existingKey.equalsToByTheSameValueZeroAlgorithm(key)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -316,7 +316,7 @@ bool Value::abstractEqualsToSlowCase(ExecutionState& state, const Value& val) co
|
||||||
|
|
||||||
return a == b;
|
return a == b;
|
||||||
} else {
|
} else {
|
||||||
if (u.asInt64 == val.u.asInt64) {
|
if (m_data.payload == val.m_data.payload) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -443,9 +443,9 @@ bool Value::equalsToSlowCase(ExecutionState& state, const Value& val) const
|
||||||
return a == b;
|
return a == b;
|
||||||
}
|
}
|
||||||
|
|
||||||
return u.asInt64 == val.u.asInt64;
|
return m_data.payload == val.m_data.payload;
|
||||||
} else {
|
} else {
|
||||||
if (u.asInt64 == val.u.asInt64) {
|
if (m_data.payload == val.m_data.payload) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -470,7 +470,7 @@ bool Value::equalsToSlowCase(ExecutionState& state, const Value& val) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Value::equalsToByTheSameValueAlgorithm(ExecutionState& ec, const Value& val) const
|
bool Value::equalsToByTheSameValueAlgorithm(const Value& val) const
|
||||||
{
|
{
|
||||||
if (!val.isPointerValue()) {
|
if (!val.isPointerValue()) {
|
||||||
if (isNumber() && val.isNumber()) {
|
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 a == b && std::signbit(a) == std::signbit(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
return u.asInt64 == val.u.asInt64;
|
return m_data.payload == val.m_data.payload;
|
||||||
} else {
|
} else {
|
||||||
if (u.asInt64 == val.u.asInt64) {
|
if (m_data.payload == val.m_data.payload) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -518,7 +518,7 @@ bool Value::equalsToByTheSameValueAlgorithm(ExecutionState& ec, const Value& val
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Value::equalsToByTheSameValueZeroAlgorithm(ExecutionState& ec, const Value& val) const
|
bool Value::equalsToByTheSameValueZeroAlgorithm(const Value& val) const
|
||||||
{
|
{
|
||||||
if (LIKELY(!val.isPointerValue())) {
|
if (LIKELY(!val.isPointerValue())) {
|
||||||
if (isNumber() && val.isNumber()) {
|
if (isNumber() && val.isNumber()) {
|
||||||
|
|
@ -532,9 +532,9 @@ bool Value::equalsToByTheSameValueZeroAlgorithm(ExecutionState& ec, const Value&
|
||||||
return a == b;
|
return a == b;
|
||||||
}
|
}
|
||||||
|
|
||||||
return u.asInt64 == val.u.asInt64;
|
return m_data.payload == val.m_data.payload;
|
||||||
} else {
|
} else {
|
||||||
if (u.asInt64 == val.u.asInt64) {
|
if (m_data.payload == val.m_data.payload) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,96 @@
|
||||||
|
|
||||||
namespace Escargot {
|
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 PointerValue;
|
||||||
class ExecutionState;
|
class ExecutionState;
|
||||||
class Object;
|
class Object;
|
||||||
|
|
@ -89,6 +179,10 @@ inline ToType bitwise_cast(FromType from)
|
||||||
#define CellPayloadOffset PayloadOffset
|
#define CellPayloadOffset PayloadOffset
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// basic class for representing ECMAScript Value
|
||||||
|
// Int32 convertible double value can exist rarely(for interpreter performance)
|
||||||
|
// but Int32 convertible double case is not exist with EncodedValue
|
||||||
|
// so, public API users should not care the case
|
||||||
class Value {
|
class Value {
|
||||||
public:
|
public:
|
||||||
static constexpr const double MinusZeroIndex = std::numeric_limits<double>::min();
|
static constexpr const double MinusZeroIndex = std::numeric_limits<double>::min();
|
||||||
|
|
@ -127,6 +221,10 @@ public:
|
||||||
explicit Value(TrueInitTag);
|
explicit Value(TrueInitTag);
|
||||||
explicit Value(FalseInitTag);
|
explicit Value(FalseInitTag);
|
||||||
explicit Value(FromPayloadTag, intptr_t ptr);
|
explicit Value(FromPayloadTag, intptr_t ptr);
|
||||||
|
|
||||||
|
explicit Value(PointerValue* ptr);
|
||||||
|
Value(const PointerValue* ptr);
|
||||||
|
/*
|
||||||
#ifdef ESCARGOT_64
|
#ifdef ESCARGOT_64
|
||||||
explicit Value(PointerValue* ptr);
|
explicit Value(PointerValue* ptr);
|
||||||
Value(const PointerValue* ptr);
|
Value(const PointerValue* ptr);
|
||||||
|
|
@ -141,10 +239,10 @@ public:
|
||||||
Value(const String* ptr);
|
Value(const String* ptr);
|
||||||
explicit Value(FromTagTag, uint32_t tag);
|
explicit Value(FromTagTag, uint32_t tag);
|
||||||
#endif
|
#endif
|
||||||
|
*/
|
||||||
// Numbers
|
// Numbers
|
||||||
Value(EncodeAsDoubleTag, double);
|
Value(EncodeAsDoubleTag, const double&);
|
||||||
explicit Value(double);
|
explicit Value(const double&);
|
||||||
explicit Value(bool);
|
explicit Value(bool);
|
||||||
explicit Value(char);
|
explicit Value(char);
|
||||||
explicit Value(unsigned char);
|
explicit Value(unsigned char);
|
||||||
|
|
@ -171,7 +269,7 @@ public:
|
||||||
double asDouble() const;
|
double asDouble() const;
|
||||||
bool asBoolean() const;
|
bool asBoolean() const;
|
||||||
double asNumber() const;
|
double asNumber() const;
|
||||||
uint64_t asRawData() const;
|
intptr_t asRawData() const;
|
||||||
inline PointerValue* asPointerValue() const;
|
inline PointerValue* asPointerValue() const;
|
||||||
inline Object* asObject() const;
|
inline Object* asObject() const;
|
||||||
inline FunctionObject* asFunction() const;
|
inline FunctionObject* asFunction() const;
|
||||||
|
|
@ -198,6 +296,7 @@ public:
|
||||||
inline bool isPrimitive() const;
|
inline bool isPrimitive() const;
|
||||||
bool isGetterSetter() const;
|
bool isGetterSetter() const;
|
||||||
bool isCustomGetterSetter() const;
|
bool isCustomGetterSetter() const;
|
||||||
|
inline bool isHeapValue() const;
|
||||||
inline bool isPointerValue() const;
|
inline bool isPointerValue() const;
|
||||||
bool isObject() const;
|
bool isObject() const;
|
||||||
bool isCallable() const;
|
bool isCallable() const;
|
||||||
|
|
@ -246,36 +345,20 @@ public:
|
||||||
bool abstractEqualsToSlowCase(ExecutionState& ec, const Value& val) const;
|
bool abstractEqualsToSlowCase(ExecutionState& ec, const Value& val) const;
|
||||||
inline bool equalsTo(ExecutionState& ec, const Value& val) const;
|
inline bool equalsTo(ExecutionState& ec, const Value& val) const;
|
||||||
bool equalsToSlowCase(ExecutionState& ec, const Value& val) const;
|
bool equalsToSlowCase(ExecutionState& ec, const Value& val) const;
|
||||||
bool equalsToByTheSameValueAlgorithm(ExecutionState& ec, const Value& val) const;
|
bool equalsToByTheSameValueAlgorithm(const Value& val) const;
|
||||||
bool equalsToByTheSameValueZeroAlgorithm(ExecutionState& ec, const Value& val) const;
|
bool equalsToByTheSameValueZeroAlgorithm(const Value& val) const;
|
||||||
bool instanceOf(ExecutionState& ec, const Value& other) 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 constexpr double maximumLength();
|
||||||
|
|
||||||
|
static bool isInt32ConvertibleDouble(const double& d);
|
||||||
|
static bool isInt32ConvertibleDouble(const double& d, int32_t& asInt32);
|
||||||
private:
|
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
|
double toNumberSlowCase(ExecutionState& ec) const; // $7.1.3 ToNumber
|
||||||
std::pair<Value, bool> toNumericSlowCase(ExecutionState& ec) const;
|
std::pair<Value, bool> toNumericSlowCase(ExecutionState& ec) const;
|
||||||
String* toStringSlowCase(ExecutionState& ec) const; // $7.1.12 ToString
|
String* toStringSlowCase(ExecutionState& ec) const; // $7.1.12 ToString
|
||||||
|
|
|
||||||
|
|
@ -50,436 +50,243 @@ constexpr double Value::maximumLength()
|
||||||
return 9007199254740991.0;
|
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========================================================
|
// ===32-bit architecture========================================================
|
||||||
// ==============================================================================
|
// ==============================================================================
|
||||||
|
|
||||||
#ifdef ESCARGOT_32
|
#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, 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
|
#else
|
||||||
|
|
||||||
// ==============================================================================
|
// ==============================================================================
|
||||||
// ===64-bit architecture========================================================
|
// ===64-bit architecture========================================================
|
||||||
// ==============================================================================
|
// ==============================================================================
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
inline Value::Value()
|
// ==============================================================================
|
||||||
{
|
// ===common architecture========================================================
|
||||||
u.asInt64 = ValueUndefined;
|
// ==============================================================================
|
||||||
}
|
|
||||||
|
|
||||||
inline Value::Value(ForceUninitializedTag)
|
inline Value::Value(ForceUninitializedTag)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Value::Value()
|
||||||
|
{
|
||||||
|
m_data.payload = ValueUndefined;
|
||||||
|
}
|
||||||
|
|
||||||
inline Value::Value(NullInitTag)
|
inline Value::Value(NullInitTag)
|
||||||
{
|
{
|
||||||
u.asInt64 = ValueNull;
|
m_data.payload = ValueNull;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Value::Value(UndefinedInitTag)
|
inline Value::Value(UndefinedInitTag)
|
||||||
{
|
{
|
||||||
u.asInt64 = ValueUndefined;
|
m_data.payload = ValueUndefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Value::Value(EmptyValueInitTag)
|
inline Value::Value(EmptyValueInitTag)
|
||||||
{
|
{
|
||||||
u.asInt64 = ValueEmpty;
|
m_data.payload = ValueEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Value::Value(TrueInitTag)
|
inline Value::Value(TrueInitTag)
|
||||||
{
|
{
|
||||||
u.asInt64 = ValueTrue;
|
m_data.payload = ValueTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Value::Value(FalseInitTag)
|
inline Value::Value(FalseInitTag)
|
||||||
{
|
{
|
||||||
u.asInt64 = ValueFalse;
|
m_data.payload = ValueFalse;
|
||||||
}
|
|
||||||
|
|
||||||
inline Value::Value(FromPayloadTag, intptr_t ptr)
|
|
||||||
{
|
|
||||||
u.ptr = (PointerValue*)ptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Value::Value(bool b)
|
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)
|
inline Value::Value(PointerValue* ptr)
|
||||||
{
|
{
|
||||||
u.ptr = ptr;
|
m_data.payload = reinterpret_cast<intptr_t>(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Value::Value(const PointerValue* ptr)
|
inline Value::Value(const PointerValue* ptr)
|
||||||
{
|
{
|
||||||
u.ptr = const_cast<PointerValue*>(ptr);
|
m_data.payload = reinterpret_cast<intptr_t>(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, double d)
|
|
||||||
{
|
|
||||||
u.asInt64 = reinterpretDoubleToInt64(d) + DoubleEncodeOffset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Value::Value(int i)
|
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
|
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
|
inline bool Value::operator!=(const Value& other) const
|
||||||
{
|
{
|
||||||
return u.asInt64 != other.u.asInt64;
|
return !equalsToByTheSameValueAlgorithm(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE bool Value::isInt32() const
|
ALWAYS_INLINE bool Value::isInt32() const
|
||||||
{
|
{
|
||||||
#ifdef ESCARGOT_LITTLE_ENDIAN
|
return HAS_SMI_TAG(m_data.payload);
|
||||||
ASSERT(sizeof(short) == 2);
|
|
||||||
unsigned short* firstByte = (unsigned short*)&u.asInt64;
|
|
||||||
return firstByte[3] == 0xffff;
|
|
||||||
#else
|
|
||||||
return (u.asInt64 & TagTypeNumber) == TagTypeNumber;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
inline int32_t Value::asInt32() const
|
||||||
{
|
{
|
||||||
ASSERT(isInt32());
|
ASSERT(isInt32());
|
||||||
return static_cast<int32_t>(u.asInt64);
|
return EncodedValueImpl::PlatformSmiTagging::SmiToInt(m_data.payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool Value::asBoolean() const
|
inline bool Value::asBoolean() const
|
||||||
{
|
{
|
||||||
ASSERT(isBoolean());
|
ASSERT(isBoolean());
|
||||||
return u.asInt64 == ValueTrue;
|
return m_data.payload == ValueTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline double Value::asDouble() const
|
inline double Value::asDouble() const
|
||||||
{
|
{
|
||||||
ASSERT(isDouble());
|
ASSERT(isDouble());
|
||||||
return reinterpretInt64ToDouble(u.asInt64 - DoubleEncodeOffset);
|
return reinterpret_cast<DoubleInValue*>(m_data.payload)->value();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool Value::isEmpty() const
|
inline bool Value::isEmpty() const
|
||||||
{
|
{
|
||||||
return u.asInt64 == ValueEmpty;
|
return m_data.payload == ValueEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE bool Value::isNumber() const
|
ALWAYS_INLINE bool Value::isNumber() const
|
||||||
{
|
{
|
||||||
#ifdef ESCARGOT_LITTLE_ENDIAN
|
return isInt32() || isDouble();
|
||||||
ASSERT(sizeof(short) == 2);
|
}
|
||||||
unsigned short* firstByte = (unsigned short*)&u.asInt64;
|
|
||||||
return firstByte[3];
|
inline bool Value::isHeapValue() const
|
||||||
#else
|
{
|
||||||
return u.asInt64 & TagTypeNumber;
|
return !(m_data.payload & (EncodedValueImpl::kSmiTagMask | TagBitTypeOther));
|
||||||
#endif
|
}
|
||||||
|
|
||||||
|
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
|
inline bool Value::isString() const
|
||||||
|
|
@ -515,47 +322,14 @@ inline BigInt* Value::asBigInt() const
|
||||||
return asPointerValue()->asBigInt();
|
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
|
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
|
inline Object* Value::asObject() const
|
||||||
|
|
@ -568,40 +342,42 @@ inline bool Value::isFunction() const
|
||||||
return isPointerValue() && asPointerValue()->isFunctionObject();
|
return isPointerValue() && asPointerValue()->isFunctionObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool Value::isExtendedNativeFunctionObject() const
|
||||||
|
{
|
||||||
|
return isPointerValue() && asPointerValue()->isExtendedNativeFunctionObject();
|
||||||
|
}
|
||||||
|
|
||||||
inline FunctionObject* Value::asFunction() const
|
inline FunctionObject* Value::asFunction() const
|
||||||
{
|
{
|
||||||
return asPointerValue()->asFunctionObject();
|
return asPointerValue()->asFunctionObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ExtendedNativeFunctionObject* Value::asExtendedNativeFunctionObject() const
|
ALWAYS_INLINE bool Value::isInt32ConvertibleDouble(const double& d)
|
||||||
{
|
{
|
||||||
return asPointerValue()->asExtendedNativeFunctionObject();
|
int32_t asInt32 = static_cast<int32_t>(d);
|
||||||
|
if (LIKELY(LIKELY(asInt32 != d) || UNLIKELY(!asInt32 && std::signbit(d)))) { // true for -0.0
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline intptr_t Value::payload() const
|
ALWAYS_INLINE bool Value::isInt32ConvertibleDouble(const double& d, int32_t& asInt32)
|
||||||
{
|
{
|
||||||
return u.asInt64;
|
asInt32 = static_cast<int32_t>(d);
|
||||||
|
if (LIKELY(LIKELY(asInt32 != d) || UNLIKELY(!asInt32 && std::signbit(d)))) { // true for -0.0
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
inline Value::Value(const double& d)
|
||||||
|
|
||||||
// ==============================================================================
|
|
||||||
// ===common architecture========================================================
|
|
||||||
// ==============================================================================
|
|
||||||
|
|
||||||
inline Value::Value(double d)
|
|
||||||
{
|
{
|
||||||
const int32_t asInt32 = static_cast<int32_t>(d);
|
int32_t asInt32;
|
||||||
if (asInt32 != d || (!asInt32 && std::signbit(d))) { // true for -0.0
|
if (UNLIKELY(isInt32ConvertibleDouble(d, asInt32))) {
|
||||||
#ifdef ESCARGOT_64
|
*this = Value(asInt32);
|
||||||
if (UNLIKELY((bitwise_cast<int64_t>(d) & DoubleInvalidBeginning) == DoubleInvalidBeginning)) {
|
|
||||||
d = std::numeric_limits<double>::quiet_NaN();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
*this = Value(EncodeAsDouble, d);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*this = Value(static_cast<int32_t>(d));
|
*this = Value(EncodeAsDouble, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Value::Value(char i)
|
inline Value::Value(char i)
|
||||||
|
|
@ -626,25 +402,28 @@ inline Value::Value(unsigned short i)
|
||||||
|
|
||||||
inline Value::Value(unsigned i)
|
inline Value::Value(unsigned i)
|
||||||
{
|
{
|
||||||
if (static_cast<int32_t>(i) < 0) {
|
const int32_t asInt32 = static_cast<int32_t>(i);
|
||||||
|
if (UNLIKELY(asInt32 < 0)) {
|
||||||
*this = Value(EncodeAsDouble, static_cast<double>(i));
|
*this = Value(EncodeAsDouble, static_cast<double>(i));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*this = Value(static_cast<int32_t>(i));
|
*this = Value(asInt32);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Value::Value(long i)
|
inline Value::Value(long i)
|
||||||
{
|
{
|
||||||
if (static_cast<int32_t>(i) != i) {
|
const int32_t asInt32 = static_cast<int32_t>(i);
|
||||||
|
if (UNLIKELY(asInt32 != i)) {
|
||||||
*this = Value(EncodeAsDouble, static_cast<double>(i));
|
*this = Value(EncodeAsDouble, static_cast<double>(i));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*this = Value(static_cast<int32_t>(i));
|
*this = Value(asInt32);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Value::Value(unsigned long i)
|
inline Value::Value(unsigned long i)
|
||||||
{
|
{
|
||||||
if (static_cast<uint32_t>(i) != i) {
|
const uint32_t asInt32 = static_cast<uint32_t>(i);
|
||||||
|
if (UNLIKELY(asInt32 != i)) {
|
||||||
*this = Value(EncodeAsDouble, static_cast<double>(i));
|
*this = Value(EncodeAsDouble, static_cast<double>(i));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -653,20 +432,22 @@ inline Value::Value(unsigned long i)
|
||||||
|
|
||||||
inline Value::Value(long long i)
|
inline Value::Value(long long i)
|
||||||
{
|
{
|
||||||
if (static_cast<int32_t>(i) != i) {
|
const int32_t asInt32 = static_cast<int32_t>(i);
|
||||||
|
if (UNLIKELY(asInt32 != i)) {
|
||||||
*this = Value(EncodeAsDouble, static_cast<double>(i));
|
*this = Value(EncodeAsDouble, static_cast<double>(i));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*this = Value(static_cast<int32_t>(i));
|
*this = Value(asInt32);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Value::Value(unsigned long long i)
|
inline Value::Value(unsigned long long i)
|
||||||
{
|
{
|
||||||
if (static_cast<uint32_t>(i) != i) {
|
const uint32_t asInt32 = static_cast<uint32_t>(i);
|
||||||
|
if (UNLIKELY(asInt32 != i)) {
|
||||||
*this = Value(EncodeAsDouble, static_cast<double>(i));
|
*this = Value(EncodeAsDouble, static_cast<double>(i));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*this = Value(static_cast<uint32_t>(i));
|
*this = Value(asInt32);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool Value::isUInt32() const
|
inline bool Value::isUInt32() const
|
||||||
|
|
@ -688,11 +469,7 @@ ALWAYS_INLINE double Value::asNumber() const
|
||||||
|
|
||||||
inline bool Value::isPrimitive() const
|
inline bool Value::isPrimitive() const
|
||||||
{
|
{
|
||||||
#ifdef ESCARGOT_32
|
|
||||||
return tag() != ObjectPointerTag;
|
|
||||||
#else
|
|
||||||
return isUndefined() || isNull() || isNumber() || isString() || isBoolean() || isSymbol() || isBigInt();
|
return isUndefined() || isNull() || isNumber() || isString() || isBoolean() || isSymbol() || isBigInt();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool Value::isCallable() const
|
inline bool Value::isCallable() const
|
||||||
|
|
@ -706,21 +483,10 @@ inline bool Value::isCallable() const
|
||||||
// https://www.ecma-international.org/ecma-262/6.0/#sec-tonumber
|
// https://www.ecma-international.org/ecma-262/6.0/#sec-tonumber
|
||||||
inline double Value::toNumber(ExecutionState& state) const
|
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()))
|
if (LIKELY(isInt32()))
|
||||||
return FastI2D(asInt32());
|
return FastI2D(asInt32());
|
||||||
else if (isDouble())
|
else if (isDouble())
|
||||||
return asDouble();
|
return asDouble();
|
||||||
#endif
|
|
||||||
else if (isUndefined())
|
else if (isUndefined())
|
||||||
return std::numeric_limits<double>::quiet_NaN();
|
return std::numeric_limits<double>::quiet_NaN();
|
||||||
else if (isNull())
|
else if (isNull())
|
||||||
|
|
@ -734,20 +500,11 @@ inline double Value::toNumber(ExecutionState& state) const
|
||||||
|
|
||||||
inline std::pair<Value, bool> Value::toNumeric(ExecutionState& state) const // <Value, isBigInt>
|
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())) {
|
if (LIKELY(isInt32())) {
|
||||||
return std::make_pair(*this, false);
|
return std::make_pair(*this, false);
|
||||||
} else if (isDouble()) {
|
} else if (isDouble()) {
|
||||||
return std::make_pair(*this, false);
|
return std::make_pair(*this, false);
|
||||||
}
|
} else if (isUndefined()) {
|
||||||
#endif
|
|
||||||
else if (isUndefined()) {
|
|
||||||
return std::make_pair(Value(std::numeric_limits<double>::quiet_NaN()), false);
|
return std::make_pair(Value(std::numeric_limits<double>::quiet_NaN()), false);
|
||||||
} else if (isNull()) {
|
} else if (isNull()) {
|
||||||
return std::make_pair(Value(0), false);
|
return std::make_pair(Value(0), false);
|
||||||
|
|
@ -779,11 +536,7 @@ inline Value Value::toPrimitive(ExecutionState& ec, PrimitiveTypeHint preferredT
|
||||||
inline bool Value::abstractEqualsTo(ExecutionState& state, const Value& val) const
|
inline bool Value::abstractEqualsTo(ExecutionState& state, const Value& val) const
|
||||||
{
|
{
|
||||||
if (isInt32() && val.isInt32()) {
|
if (isInt32() && val.isInt32()) {
|
||||||
#ifdef ESCARGOT_64
|
return m_data.payload == val.m_data.payload;
|
||||||
return u.asInt64 == val.u.asInt64;
|
|
||||||
#else
|
|
||||||
return u.asBits.payload == val.u.asBits.payload;
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
return abstractEqualsToSlowCase(state, val);
|
return abstractEqualsToSlowCase(state, val);
|
||||||
}
|
}
|
||||||
|
|
@ -792,11 +545,7 @@ inline bool Value::abstractEqualsTo(ExecutionState& state, const Value& val) con
|
||||||
inline bool Value::equalsTo(ExecutionState& state, const Value& val) const
|
inline bool Value::equalsTo(ExecutionState& state, const Value& val) const
|
||||||
{
|
{
|
||||||
if (isInt32() && val.isInt32()) {
|
if (isInt32() && val.isInt32()) {
|
||||||
#ifdef ESCARGOT_64
|
return m_data.payload == val.m_data.payload;
|
||||||
return u.asInt64 == val.u.asInt64;
|
|
||||||
#else
|
|
||||||
return u.asBits.payload == val.u.asBits.payload;
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
return equalsToSlowCase(state, val);
|
return equalsToSlowCase(state, val);
|
||||||
}
|
}
|
||||||
|
|
@ -887,7 +636,7 @@ uint32_t Value::tryToUseAsIndexProperty(ExecutionState& ec) const
|
||||||
|
|
||||||
inline double Value::toInteger(ExecutionState& state) const
|
inline double Value::toInteger(ExecutionState& state) const
|
||||||
{
|
{
|
||||||
if (isInt32()) {
|
if (LIKELY(isInt32())) {
|
||||||
return asInt32();
|
return asInt32();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -903,7 +652,7 @@ inline double Value::toInteger(ExecutionState& state) const
|
||||||
|
|
||||||
inline bool Value::isInteger(ExecutionState& state) const
|
inline bool Value::isInteger(ExecutionState& state) const
|
||||||
{
|
{
|
||||||
if (isInt32()) {
|
if (LIKELY(isInt32())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -917,7 +666,7 @@ inline bool Value::isInteger(ExecutionState& state) const
|
||||||
inline uint64_t Value::toLength(ExecutionState& state) const
|
inline uint64_t Value::toLength(ExecutionState& state) const
|
||||||
{
|
{
|
||||||
double len = toInteger(state);
|
double len = toInteger(state);
|
||||||
if (len <= 0.0) {
|
if (UNLIKELY(len <= 0.0)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return std::min(len, maximumLength());
|
return std::min(len, maximumLength());
|
||||||
|
|
|
||||||
|
|
@ -921,8 +921,16 @@ PersistentRefHolder<ContextRef> createEscargotContext(VMInstanceRef* instance, b
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(ESCARGOT_GPERF)
|
||||||
|
#include <gperftools/profiler.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
#if defined(ESCARGOT_GPERF)
|
||||||
|
ProfilerStart("profile.log");
|
||||||
|
#endif
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
setbuf(stdout, NULL);
|
setbuf(stdout, NULL);
|
||||||
setbuf(stderr, NULL);
|
setbuf(stderr, NULL);
|
||||||
|
|
@ -1090,5 +1098,9 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
Globals::finalize();
|
Globals::finalize();
|
||||||
|
|
||||||
|
#if defined(ESCARGOT_GPERF)
|
||||||
|
ProfilerStop();
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue