Skip to content

Commit

Permalink
Introduce new Value ctor for NaN, Infinity regard to fix arm clang issue
Browse files Browse the repository at this point in the history
arm clang optimizer cannot generate correct code
with Value(std::numeric_limits<double>::quiet_NaN())
or Value(std::numeric_limits<double>::infinity())

Signed-off-by: Seonghyun Kim <[email protected]>
  • Loading branch information
ksh8281 authored and clover2123 committed Apr 4, 2023
1 parent 8b7456d commit 7414ebd
Show file tree
Hide file tree
Showing 11 changed files with 66 additions and 54 deletions.
4 changes: 0 additions & 4 deletions build/target.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@ ELSEIF (${ESCARGOT_HOST} STREQUAL "android")
SET (ESCARGOT_DEFINITIONS -DANDROID=1 -DESCARGOT_ANDROID=1)
SET (ESCARGOT_THIRDPARTY_CFLAGS ${ESCARGOT_THIRDPARTY_CFLAGS} -mstackrealign)
SET (ESCARGOT_CXXFLAGS -mstackrealign)
# android clang + -O2 option causes crash (gc cannot scan stack correctly I guess)
SET (ESCARGOT_CXXFLAGS_RELEASE -O1)
IF (${ESCARGOT_ARCH} STREQUAL "arm")
SET (ESCARGOT_BUILD_32BIT ON)
SET (ESCARGOT_LDFLAGS -fPIE -pie -march=armv7-a -Wl,--fix-cortex-a8 -llog -Wl,--gc-sections)
Expand Down Expand Up @@ -94,8 +92,6 @@ ELSEIF (ESCARGOT_BUILD_64BIT)
# 64bit build
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DESCARGOT_64=1 -DESCARGOT_USE_32BIT_IN_64BIT)
SET (ESCARGOT_THIRDPARTY_CFLAGS ${ESCARGOT_THIRDPARTY_CFLAGS} -DESCARGOT_USE_32BIT_IN_64BIT)
# -O2,Oz option causes crash (gc cannot scan stack correctly I guess)
SET (ESCARGOT_CXXFLAGS_RELEASE -O1)
ELSEIF (ESCARGOT_BUILD_64BIT_LARGE)
# 64bit build(large)
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DESCARGOT_64=1)
Expand Down
9 changes: 4 additions & 5 deletions src/builtins/BuiltinDate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ static Value builtinDateParse(ExecutionState& state, Value thisValue, size_t arg
d.setTimeValue(state, str);
return Value(d.primitiveValue());
}
return Value(std::numeric_limits<double>::quiet_NaN());
return Value(Value::NanInit);
}

static Value builtinDateUTC(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
Expand Down Expand Up @@ -399,17 +399,16 @@ static Value builtinDateSetTime(ExecutionState& state, Value thisValue, size_t a
thisObject->setTimeValue(DateObject::timeClip(state, argv[0].toNumber(state)));
return Value(thisObject->primitiveValue());
} else {
double value = std::numeric_limits<double>::quiet_NaN();
thisObject->setTimeValueAsNaN();
return Value(value);
return Value(Value::NanInit);
}
}

static Value builtinDateGetYear(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
RESOLVE_THIS_BINDING_TO_DATE(thisObject, Date, getYear);
if (!(thisObject->isValid())) {
return Value(std::numeric_limits<double>::quiet_NaN());
return Value(Value::NanInit);
}
int ret = thisObject->getFullYear(state) - 1900;
return Value(ret);
Expand Down Expand Up @@ -470,7 +469,7 @@ static Value builtinDateGetTimezoneOffset(ExecutionState& state, Value thisValue
{
RESOLVE_THIS_BINDING_TO_DATE(thisObject, Date, getTimezoneOffset);
if (!(thisObject->isValid()))
return Value(std::numeric_limits<double>::quiet_NaN());
return Value(Value::NanInit);
return Value(thisObject->getTimezoneOffset(state));
}

Expand Down
27 changes: 12 additions & 15 deletions src/builtins/BuiltinMath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,15 @@ static Value builtinMathMax(ExecutionState& state, Value thisValue, size_t argc,
maxValue = value;
}
if (is_NaN) {
double qnan = std::numeric_limits<double>::quiet_NaN();
return Value(qnan);
return Value(Value::NanInit);
}
return Value(maxValue);
}

static Value builtinMathMin(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
if (argc == 0) {
return Value(std::numeric_limits<double>::infinity());
return Value(Value::PostiveInfinityInit);
}

bool hasNaN = false;
Expand All @@ -76,8 +75,7 @@ static Value builtinMathMin(ExecutionState& state, Value thisValue, size_t argc,
}
}
if (hasNaN) {
double qnan = std::numeric_limits<double>::quiet_NaN();
return Value(qnan);
return Value(Value::NanInit);
}
return Value(minValue);
}
Expand Down Expand Up @@ -185,7 +183,7 @@ static Value builtinMathSign(ExecutionState& state, Value thisValue, size_t argc
{
double x = argv[0].toNumber(state);
if (std::isnan(x))
return Value(std::numeric_limits<double>::quiet_NaN());
return Value(Value::NanInit);
else if (x == 0.0) {
if (std::signbit(x)) {
return Value(Value::EncodeAsDouble, -0.0);
Expand All @@ -209,9 +207,9 @@ static Value builtinMathPow(ExecutionState& state, Value thisValue, size_t argc,
double x = argv[0].toNumber(state);
double y = argv[1].toNumber(state);
if (UNLIKELY(std::isnan(y)))
return Value(std::numeric_limits<double>::quiet_NaN());
return Value(Value::NanInit);
if (UNLIKELY(std::abs(x) == 1 && std::isinf(y)))
return Value(std::numeric_limits<double>::quiet_NaN());
return Value(Value::NanInit);

int y_int = static_cast<int>(y);

Expand Down Expand Up @@ -244,16 +242,16 @@ static Value builtinMathPow(ExecutionState& state, Value thisValue, size_t argc,
if (std::isinf(x)) {
if (x > 0) {
if (y > 0) {
return Value(std::numeric_limits<double>::infinity());
return Value(Value::PostiveInfinityInit);
} else {
return Value(0.0);
}
} else {
if (y > 0) {
if (y == y_int && y_int % 2) { // odd
return Value(-std::numeric_limits<double>::infinity());
return Value(Value::NegativeInfinityInit);
} else {
return Value(std::numeric_limits<double>::infinity());
return Value(Value::PostiveInfinityInit);
}
} else {
if (y == y_int && y_int % 2) {
Expand All @@ -270,7 +268,7 @@ static Value builtinMathPow(ExecutionState& state, Value thisValue, size_t argc,
if (y > 0) {
return Value(0);
} else if (y < 0) {
return Value(std::numeric_limits<double>::infinity());
return Value(Value::PostiveInfinityInit);
}
}

Expand Down Expand Up @@ -339,12 +337,11 @@ static Value builtinMathHypot(ExecutionState& state, Value thisValue, size_t arg
maxValue = std::max(maxValue, absValue);
}
if (has_inf) {
return Value(std::numeric_limits<double>::infinity());
return Value(Value::PostiveInfinityInit);
}

if (has_nan) {
double qnan = std::numeric_limits<double>::quiet_NaN();
return Value(qnan);
return Value(Value::NanInit);
}

if (maxValue == 0) {
Expand Down
6 changes: 3 additions & 3 deletions src/builtins/BuiltinNumber.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -467,11 +467,11 @@ void GlobalObject::installNumber(ExecutionState& state)
// $20.1.2.9 Number.MIN_VALUE
m_number->directDefineOwnProperty(state, strings->MIN_VALUE, ObjectPropertyDescriptor(Value(5E-324), allFalsePresent));
// $20.1.2.10 Number.NaN
m_number->directDefineOwnProperty(state, strings->NaN, ObjectPropertyDescriptor(Value(std::numeric_limits<double>::quiet_NaN()), allFalsePresent));
m_number->directDefineOwnProperty(state, strings->NaN, ObjectPropertyDescriptor(Value(Value::NanInit), allFalsePresent));
// $20.1.2.11 Number.NEGATIVE_INFINITY
m_number->directDefineOwnProperty(state, strings->NEGATIVE_INFINITY, ObjectPropertyDescriptor(Value(-std::numeric_limits<double>::infinity()), allFalsePresent));
m_number->directDefineOwnProperty(state, strings->NEGATIVE_INFINITY, ObjectPropertyDescriptor(Value(Value::NegativeInfinityInit), allFalsePresent));
// $20.1.2.14 Number.POSITIVE_INFINITY
m_number->directDefineOwnProperty(state, strings->POSITIVE_INFINITY, ObjectPropertyDescriptor(Value(std::numeric_limits<double>::infinity()), allFalsePresent));
m_number->directDefineOwnProperty(state, strings->POSITIVE_INFINITY, ObjectPropertyDescriptor(Value(Value::PostiveInfinityInit), allFalsePresent));

m_numberProxyObject = new NumberObject(state);

Expand Down
2 changes: 1 addition & 1 deletion src/builtins/BuiltinString.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -800,7 +800,7 @@ static Value builtinStringCharCodeAt(ExecutionState& state, Value thisValue, siz
Value ret;
size_t length = str->length();
if (position < 0 || position >= (int)length)
ret = Value(std::numeric_limits<double>::quiet_NaN());
ret = Value(Value::NanInit);
else {
ret = Value(str->charAt(position));
}
Expand Down
6 changes: 3 additions & 3 deletions src/interpreter/ByteCodeInterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1790,9 +1790,9 @@ NEVER_INLINE Value InterpreterSlowPath::modOperation(ExecutionState& state, cons
double rvalue = rnum.first.asNumber();
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.5.3
if (std::isnan(lvalue) || std::isnan(rvalue)) {
ret = Value(std::numeric_limits<double>::quiet_NaN());
ret = Value(Value::NanInit);
} else if (std::isinf(lvalue) || rvalue == 0 || rvalue == -0.0) {
ret = Value(std::numeric_limits<double>::quiet_NaN());
ret = Value(Value::NanInit);
} else if (std::isinf(rvalue)) {
ret = Value(lvalue);
} else if (lvalue == 0.0) {
Expand Down Expand Up @@ -1835,7 +1835,7 @@ NEVER_INLINE Value InterpreterSlowPath::exponentialOperation(ExecutionState& sta

// The result of base ** exponent when base is 1 or -1 and exponent is +Infinity or -Infinity differs from IEEE 754-2008. The first edition of ECMAScript specified a result of NaN for this operation, whereas later versions of IEEE 754-2008 specified 1. The historical ECMAScript behaviour is preserved for compatibility reasons.
if ((base == -1 || base == 1) && (exp == std::numeric_limits<double>::infinity() || exp == -std::numeric_limits<double>::infinity())) {
return Value(std::numeric_limits<double>::quiet_NaN());
return Value(Value::NanInit);
}

return Value(pow(base, exp));
Expand Down
1 change: 0 additions & 1 deletion src/interpreter/ByteCodeInterpreter.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/*
static void setObjectPreComputedCaseOperationCacheMiss(ExecutionState& state, Object* obj, const Value& willBeObject, const Value& value, SetObjectPreComputedCase* code, ByteCodeBlock* block);
* Copyright (c) 2016-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
Expand Down
8 changes: 4 additions & 4 deletions src/runtime/DateObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1547,7 +1547,7 @@ void* DateObject::operator new(size_t size)
Value DateObject::makeDay(ExecutionState& state, const Value& year, const Value& month, const Value& day)
{
if (!std::isfinite(year.asNumber()) && !std::isfinite(month.asNumber()) && !std::isfinite(day.asNumber())) {
return Value(std::numeric_limits<double>::quiet_NaN());
return Value(Value::NanInit);
}

double y = year.asNumber();
Expand All @@ -1559,7 +1559,7 @@ Value DateObject::makeDay(ExecutionState& state, const Value& year, const Value&
double ym = y + std::floor(m / const_Date_monthsPerYear);

if (!std::isfinite(ym)) {
return Value(std::numeric_limits<double>::quiet_NaN());
return Value(Value::NanInit);
}

result += const_Date_msPerDay * DAYS_IN_YEAR * (ym - 1970) + const_Date_msPerMonth * ((int)m % const_Date_monthsPerYear);
Expand All @@ -1569,7 +1569,7 @@ Value DateObject::makeDay(ExecutionState& state, const Value& year, const Value&
Value DateObject::makeTime(ExecutionState& state, const Value& hour, const Value& minute, const Value& sec, const Value& ms)
{
if (!std::isfinite(hour.asNumber()) && !std::isfinite(minute.asNumber()) && !std::isfinite(sec.asNumber()) && !std::isfinite(ms.asNumber())) {
return Value(std::numeric_limits<double>::quiet_NaN());
return Value(Value::NanInit);
}

double h = hour.asNumber();
Expand All @@ -1583,7 +1583,7 @@ Value DateObject::makeTime(ExecutionState& state, const Value& hour, const Value
Value DateObject::makeDate(ExecutionState& state, const Value& day, const Value& time)
{
if (!std::isfinite(day.asNumber()) && !std::isfinite(time.asNumber())) {
return Value(std::numeric_limits<double>::quiet_NaN());
return Value(Value::NanInit);
}

return Value(day.toLength(state) * const_Date_msPerDay + time.toLength(state));
Expand Down
22 changes: 11 additions & 11 deletions src/runtime/GlobalObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ static Value builtinParseInt(ExecutionState& state, Value thisValue, size_t argc

// 8.a If R < 2 or R > 36, then return NaN.
if (radix < 2 || radix > 36)
return Value(std::numeric_limits<double>::quiet_NaN());
return Value(Value::NanInit);

// 13. Let mathInt be the mathematical integer value that is represented by Z in radix-R notation,
// using the letters AZ and az for digits with values 10 through 35. (However, if R is 10 and Z contains more than 20 significant digits,
Expand All @@ -346,7 +346,7 @@ static Value builtinParseInt(ExecutionState& state, Value thisValue, size_t argc

// 12. If Z is empty, return NaN.
if (!sawDigit)
return Value(std::numeric_limits<double>::quiet_NaN());
return Value(Value::NanInit);

// 15. Return sign × number.
return Value(sign * number);
Expand All @@ -362,7 +362,7 @@ static Value builtinParseFloat(ExecutionState& state, Value thisValue, size_t ar
if (strLen == 1) {
if (isdigit(s->charAt(0)))
return Value(s->charAt(0) - '0');
return Value(std::numeric_limits<double>::quiet_NaN());
return Value(Value::NanInit);
}

// 2, Let trimmedString be a substring of inputString consisting of the leftmost character
Expand All @@ -378,7 +378,7 @@ static Value builtinParseFloat(ExecutionState& state, Value thisValue, size_t ar

// empty string
if (p == len)
return Value(std::numeric_limits<double>::quiet_NaN());
return Value(Value::NanInit);

char16_t ch = s->charAt(p);
// HexIntegerLiteral
Expand All @@ -393,23 +393,23 @@ static Value builtinParseFloat(ExecutionState& state, Value thisValue, size_t ar
switch (ch) {
case 'I':
if (isInfinity(s, p, len))
return Value(std::numeric_limits<double>::infinity());
return Value(Value::PostiveInfinityInit);
break;
case '+':
if (isInfinity(s, p + 1, len))
return Value(std::numeric_limits<double>::infinity());
return Value(Value::PostiveInfinityInit);
break;
case '-':
if (isInfinity(s, p + 1, len))
return Value(-std::numeric_limits<double>::infinity());
return Value(Value::NegativeInfinityInit);
break;
}
auto u8Str = s->substring(p, len)->toUTF8StringData();
double number = atof(u8Str.data());
if (number == 0.0 && !std::signbit(number) && !isdigit(ch) && !(len - p >= 1 && (ch == '.' || ch == '+') && isdigit(s->charAt(p + 1))))
return Value(std::numeric_limits<double>::quiet_NaN());
return Value(Value::NanInit);
if (number == std::numeric_limits<double>::infinity())
return Value(std::numeric_limits<double>::quiet_NaN());
return Value(Value::NanInit);

// 5. Return the Number value for the MV of numberString.
return Value(number);
Expand Down Expand Up @@ -860,8 +860,8 @@ void GlobalObject::initializeOthers(ExecutionState& state)
void GlobalObject::installOthers(ExecutionState& state)
{
const StaticStrings* strings = &state.context()->staticStrings();
defineOwnProperty(state, strings->Infinity, ObjectPropertyDescriptor(Value(std::numeric_limits<double>::infinity()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ValuePresent)));
defineOwnProperty(state, strings->NaN, ObjectPropertyDescriptor(Value(std::numeric_limits<double>::quiet_NaN()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ValuePresent)));
defineOwnProperty(state, strings->Infinity, ObjectPropertyDescriptor(Value(Value::PostiveInfinityInit), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ValuePresent)));
defineOwnProperty(state, strings->NaN, ObjectPropertyDescriptor(Value(Value::NanInit), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ValuePresent)));
defineOwnProperty(state, strings->undefined, ObjectPropertyDescriptor(Value(), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ValuePresent)));

// $18.2.1 eval (x)
Expand Down
18 changes: 12 additions & 6 deletions src/runtime/Value.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,12 @@ class Value {
static constexpr const double MinusZeroIndex = std::numeric_limits<double>::min();
static constexpr const double UndefinedIndex = std::numeric_limits<double>::max();
#ifdef ESCARGOT_32
enum { EmptyValueTag = ~ValueEmpty };
enum { BooleanFalseTag = ~ValueFalse };
enum { BooleanTrueTag = ~ValueTrue };
enum { NullTag = ~ValueNull };
enum { UndefinedTag = ~ValueUndefined };
enum { LowestTag = UndefinedTag };
enum : uint32_t { EmptyValueTag = ~ValueEmpty };
enum : uint32_t { BooleanFalseTag = ~ValueFalse };
enum : uint32_t { BooleanTrueTag = ~ValueTrue };
enum : uint32_t { NullTag = ~ValueNull };
enum : uint32_t { UndefinedTag = ~ValueUndefined };
enum : uint32_t { LowestTag = UndefinedTag };

// Any value which last bit is not set
enum { Int32Tag = 0xfffffffe - 0 };
Expand Down Expand Up @@ -148,6 +148,12 @@ class Value {

// Numbers
Value(EncodeAsDoubleTag, const double&);
enum NaNInitTag { NanInit };
explicit Value(NaNInitTag);
enum PostiveInfinityInitTag { PostiveInfinityInit };
enum NegativeInfinityInitTag { NegativeInfinityInit };
explicit Value(PostiveInfinityInitTag);
explicit Value(NegativeInfinityInitTag);
explicit Value(const double&);
explicit Value(bool);
explicit Value(char);
Expand Down
17 changes: 16 additions & 1 deletion src/runtime/ValueInlines.h
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,21 @@ ALWAYS_INLINE bool Value::isInt32ConvertibleDouble(const double& d, int32_t& asI
return true;
}

inline Value::Value(NaNInitTag)
{
*this = Value(EncodeAsDouble, std::numeric_limits<double>::quiet_NaN());
}

inline Value::Value(PostiveInfinityInitTag)
{
*this = Value(EncodeAsDouble, std::numeric_limits<double>::infinity());
}

inline Value::Value(NegativeInfinityInitTag)
{
*this = Value(EncodeAsDouble, -std::numeric_limits<double>::infinity());
}

inline Value::Value(const double& d)
{
int32_t asInt32;
Expand Down Expand Up @@ -772,7 +787,7 @@ inline std::pair<Value, bool> Value::toNumeric(ExecutionState& state) const // <
}
#endif
else if (isUndefined()) {
return std::make_pair(Value(std::numeric_limits<double>::quiet_NaN()), false);
return std::make_pair(Value(Value::NanInit), false);
} else if (isNull()) {
return std::make_pair(Value(0), false);
} else if (isBoolean()) {
Expand Down

0 comments on commit 7414ebd

Please sign in to comment.