Allow to save Int32 convertible double value as double in Value for performance

Signed-off-by: Seonghyun Kim <sh8281.kim@samsung.com>
This commit is contained in:
Seonghyun Kim 2022-05-11 18:35:50 +09:00
commit 9e667ccdd2
6 changed files with 73 additions and 25 deletions

View file

@ -64,13 +64,13 @@ Value builtinArrayConstructor(ExecutionState& state, Value thisValue, size_t arg
ArrayObject* array = new ArrayObject(state, proto, size);
if (interpretArgumentsAsElements) {
Value val = argv[0];
if (argc > 1 || !val.isNumber()) {
if (argc > 1 || !argv[0].isNumber()) {
if (array->isFastModeArray()) {
for (size_t idx = 0; idx < argc; idx++) {
array->m_fastModeData[idx] = argv[idx];
}
} else {
Value val = argv[0];
for (size_t idx = 0; idx < argc; idx++) {
array->defineOwnProperty(state, ObjectPropertyName(state, idx), ObjectPropertyDescriptor(val, ObjectPropertyDescriptor::AllPresent));
val = argv[idx + 1];

View file

@ -258,7 +258,8 @@ Value ByteCodeInterpreter::interpret(ExecutionState* state, ByteCodeBlock* byteC
ret = Value(Value::EncodeAsDouble, (double)a + (double)b);
}
} 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 {
ret = plusSlowCase(*state, v0, v1);
}
@ -284,7 +285,8 @@ Value ByteCodeInterpreter::interpret(ExecutionState* state, ByteCodeBlock* byteC
ret = Value(Value::EncodeAsDouble, (double)a - (double)b);
}
} 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 {
ret = minusSlowCase(*state, left, right);
}
@ -314,7 +316,8 @@ Value ByteCodeInterpreter::interpret(ExecutionState* state, ByteCodeBlock* byteC
}
}
} 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 {
ret = multiplySlowCase(*state, left, right);
}
@ -330,7 +333,8 @@ Value ByteCodeInterpreter::interpret(ExecutionState* state, ByteCodeBlock* byteC
const Value& right = registerFile[code->m_srcIndex1];
Value& ret = registerFile[code->m_dstIndex];
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 {
ret = divisionSlowCase(*state, left, right);
}

View file

@ -335,7 +335,7 @@ void ArgumentsObject::setIndexedPropertyValueQuickly(ExecutionState& state, size
ASSERT(m_targetRecord != nullptr);
ArgumentsObjectNativeSetter(state, this, value, m_targetRecord, m_sourceFunctionObject->interpretedCodeBlock(), m_parameterMap[index].second);
} else {
return m_parameterMap[index].first = value;
m_parameterMap[index].first = value;
}
}

View file

@ -91,6 +91,26 @@ Context::Context(VMInstance* instance)
ExecutionState stateForInit(this);
m_globalObjectProxy = m_globalObject = new GlobalObject(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)

View file

@ -326,10 +326,11 @@ public:
return operator Escargot::Value().toUint32(state);
}
void operator=(PointerValue* from)
const EncodedValue& operator=(PointerValue* from)
{
ASSERT(from);
m_data.payload = (intptr_t)from;
return *this;
}
bool operator==(const EncodedValue& other) const
@ -337,35 +338,39 @@ public:
return m_data.payload == other.payload();
}
ALWAYS_INLINE void operator=(const Value& from)
ALWAYS_INLINE const EncodedValue& operator=(const Value& from)
{
if (from.isPointerValue()) {
#ifdef ESCARGOT_32
ASSERT(!from.isEmpty());
#endif
m_data.payload = (intptr_t)from.asPointerValue();
return;
return *this;
}
int32_t i32;
if (from.isInt32() && EncodedValueImpl::PlatformSmiTagging::IsValidSmi(i32 = from.asInt32())) {
m_data.payload = EncodedValueImpl::PlatformSmiTagging::IntToSmi(i32);
return;
return *this;
}
if (from.isNumber()) {
Value mutableFrom(from);
if (UNLIKELY(Value::isInt32ConvertibleDouble(mutableFrom.asNumber(), i32))) {
mutableFrom = Value(i32);
}
intptr_t payload = m_data.payload;
if (!HAS_SMI_TAG(payload) && ((size_t)payload > (size_t)ValueLast)) {
void* v = (void*)payload;
if (readPointerIsNumberEncodedValue(v)) {
((NumberInEncodedValue*)m_data.payload)->setValue(from);
return;
((NumberInEncodedValue*)m_data.payload)->setValue(mutableFrom);
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));
return;
return *this;
}
#ifdef ESCARGOT_32
@ -373,6 +378,7 @@ public:
#else
m_data.payload = from.payload();
#endif
return *this;
}
protected:
@ -394,7 +400,11 @@ protected:
if (from.isInt32() && EncodedValueImpl::PlatformSmiTagging::IsValidSmi(i32 = from.asInt32())) {
m_data.payload = EncodedValueImpl::PlatformSmiTagging::IntToSmi(i32);
} 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 {
#ifdef ESCARGOT_32
m_data.payload = ~from.tag();
@ -439,7 +449,11 @@ public:
if (from.isInt32() && EncodedValueImpl::PlatformSmiTagging::IsValidSmi(i32 = from.asInt32())) {
setPayload(EncodedValueImpl::PlatformSmiTagging::IntToSmi(i32));
} 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 {
setPayload(from.payload());
}
@ -518,38 +532,44 @@ public:
return payload() == other.payload();
}
ALWAYS_INLINE void operator=(const EncodedValue& from)
ALWAYS_INLINE const EncodedSmallValue& operator=(const EncodedValue& from)
{
setPayload(from.payload());
return *this;
}
ALWAYS_INLINE void operator=(const Value& from)
ALWAYS_INLINE const EncodedSmallValue& operator=(const Value& from)
{
if (from.isPointerValue()) {
setPayload(reinterpret_cast<intptr_t>(from.asPointerValue()));
return;
return *this;
}
int32_t i32;
if (from.isInt32() && EncodedValueImpl::PlatformSmiTagging::IsValidSmi(i32 = from.asInt32())) {
setPayload(EncodedValueImpl::PlatformSmiTagging::IntToSmi(i32));
return;
return *this;
}
if (from.isNumber()) {
Value mutableFrom(from);
if (UNLIKELY(Value::isInt32ConvertibleDouble(mutableFrom.asNumber(), i32))) {
mutableFrom = Value(i32);
}
auto pl = payload();
if (!isSMI() && ((size_t)pl > (size_t)ValueLast)) {
void* v = reinterpret_cast<void*>(pl);
if (EncodedValue::readPointerIsNumberEncodedValue(v)) {
reinterpret_cast<NumberInEncodedValue*>(v)->setValue(from);
return;
reinterpret_cast<NumberInEncodedValue*>(v)->setValue(mutableFrom);
return *this;
}
}
setPayload(reinterpret_cast<intptr_t>(new NumberInEncodedValue(from)));
setPayload(reinterpret_cast<intptr_t>(new NumberInEncodedValue(mutableFrom)));
ASSERT(EncodedValue::readPointerIsNumberEncodedValue((void*)payload()));
return;
return *this;
}
setPayload(from.payload());
return *this;
}
private:

View file

@ -89,6 +89,10 @@ inline ToType bitwise_cast(FromType from)
#define CellPayloadOffset PayloadOffset
#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 {
public:
static constexpr const double MinusZeroIndex = std::numeric_limits<double>::min();