mirror of
https://github.com/Samsung/escargot.git
synced 2026-06-22 10:01:50 +00:00
Implement Temporal.Instant.{add, subtract, compare}
Signed-off-by: Seonghyun Kim <sh8281.kim@samsung.com>
This commit is contained in:
parent
34c2f0a20e
commit
7135cbaefe
12 changed files with 214 additions and 139 deletions
|
|
@ -123,6 +123,21 @@ static Value builtinTemporalInstantFrom(ExecutionState& state, Value thisValue,
|
|||
return Temporal::toTemporalInstant(state, argv[0]);
|
||||
}
|
||||
|
||||
static Value builtinTemporalInstantCompare(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
// Set one to ? ToTemporalInstant(one).
|
||||
auto one = Temporal::toTemporalInstant(state, argv[0]);
|
||||
// Set two to ? ToTemporalInstant(two).
|
||||
auto two = Temporal::toTemporalInstant(state, argv[1]);
|
||||
// Return 𝔽(CompareEpochNanoseconds(one.[[EpochNanoseconds]], two.[[EpochNanoseconds]])).
|
||||
if (one->epochNanoseconds() > two->epochNanoseconds()) {
|
||||
return Value(1);
|
||||
} else if (one->epochNanoseconds() < two->epochNanoseconds()) {
|
||||
return Value(-1);
|
||||
}
|
||||
return Value(0);
|
||||
}
|
||||
|
||||
static Value builtinTemporalInstantFromEpochMilliseconds(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
// Set epochMilliseconds to ? ToNumber(epochMilliseconds).
|
||||
|
|
@ -231,6 +246,18 @@ static Value builtinTemporalInstantSince(ExecutionState& state, Value thisValue,
|
|||
return instant->differenceTemporalInstant(state, TemporalInstantObject::DifferenceTemporalInstantOperation::Since, argv[0], argc > 1 ? argv[1] : Value());
|
||||
}
|
||||
|
||||
static Value builtinTemporalInstantAdd(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
RESOLVE_THIS_BINDING_TO_INSTANT2(instant, add);
|
||||
return instant->addDurationToInstant(state, TemporalInstantObject::AddDurationOperation::Add, argv[0]);
|
||||
}
|
||||
|
||||
static Value builtinTemporalInstantSubtract(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
RESOLVE_THIS_BINDING_TO_INSTANT(instant, Subtract);
|
||||
return instant->addDurationToInstant(state, TemporalInstantObject::AddDurationOperation::Subtract, argv[0]);
|
||||
}
|
||||
|
||||
#define RESOLVE_THIS_BINDING_TO_PLAINDATE(NAME, BUILT_IN_METHOD) \
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isTemporalPlainDateObject()) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().lazyCapitalPlainDate().string(), true, state.context()->staticStrings().lazy##BUILT_IN_METHOD().string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
|
|
@ -469,6 +496,11 @@ void GlobalObject::installTemporal(ExecutionState& state)
|
|||
NativeFunctionInfo(strings->lazyFromEpochNanoseconds(), builtinTemporalInstantFromEpochNanoseconds, 1, NativeFunctionInfo::Strict)),
|
||||
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||||
|
||||
m_temporalInstant->directDefineOwnProperty(state, ObjectPropertyName(strings->lazyCompare()),
|
||||
ObjectPropertyDescriptor(new NativeFunctionObject(state,
|
||||
NativeFunctionInfo(strings->lazyCompare(), builtinTemporalInstantCompare, 2, NativeFunctionInfo::Strict)),
|
||||
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||||
|
||||
|
||||
m_temporalInstantPrototype = m_temporalInstant->getFunctionPrototype(state).asObject();
|
||||
m_temporalInstantPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().toStringTag),
|
||||
|
|
@ -482,6 +514,8 @@ void GlobalObject::installTemporal(ExecutionState& state)
|
|||
m_temporalInstantPrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->round), ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->round, builtinTemporalInstantRound, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||||
m_temporalInstantPrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->lazyUntil()), ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->lazyUntil(), builtinTemporalInstantUntil, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||||
m_temporalInstantPrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->lazySince()), ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->lazySince(), builtinTemporalInstantSince, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||||
m_temporalInstantPrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->add), ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->add, builtinTemporalInstantAdd, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||||
m_temporalInstantPrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->lazySubtract()), ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->lazySubtract(), builtinTemporalInstantSubtract, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||||
|
||||
{
|
||||
auto getter = new NativeFunctionObject(state, NativeFunctionInfo(strings->lazyGetEpochMilliseconds(), builtinTemporalInstantGetEpochMilliseconds, 0, NativeFunctionInfo::Strict));
|
||||
|
|
|
|||
|
|
@ -993,6 +993,7 @@ namespace Escargot {
|
|||
F(PlainTimeISO, "plainTimeISO") \
|
||||
F(Since, "since") \
|
||||
F(SmallestUnit, "smallestUnit") \
|
||||
F(Subtract, "subtract") \
|
||||
F(TemporalDotDuration, "Temporal.Duration") \
|
||||
F(TemporalDotInstant, "Temporal.Instant") \
|
||||
F(TemporalDotNow, "Temporal.Now") \
|
||||
|
|
|
|||
|
|
@ -344,6 +344,30 @@ ISO8601::InternalDuration TemporalDurationObject::toInternalDurationRecord(ISO86
|
|||
return ISO8601::InternalDuration(dateDuration, t);
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-temporal/#sec-temporal-add24hourdaystonormalizedtimeduration
|
||||
Int128 TemporalDurationObject::add24HourDaysToTimeDuration(ExecutionState& state, Int128 d, double days)
|
||||
{
|
||||
CheckedInt128 daysInNanoseconds = checkedCastDoubleToInt128(days) * ISO8601::ExactTime::nsPerDay;
|
||||
CheckedInt128 result = d + daysInNanoseconds;
|
||||
ASSERT(!result.hasOverflowed());
|
||||
if (std::abs(result) > ISO8601::InternalDuration::maxTimeDuration) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Total time in duration is out of range");
|
||||
return {};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ISO8601::InternalDuration TemporalDurationObject::toInternalDurationRecordWith24HourDays(ExecutionState& state, ISO8601::Duration duration)
|
||||
{
|
||||
// Let timeDuration be TimeDurationFromComponents(duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]], duration.[[Nanoseconds]]).
|
||||
auto timeDuration = timeDurationFromComponents(state, duration.hours(), duration.minutes(), duration.seconds(), duration.milliseconds(), duration.microseconds(), duration.nanoseconds());
|
||||
// Set timeDuration to ! Add24HourDaysToTimeDuration(timeDuration, duration.[[Days]]).
|
||||
timeDuration = add24HourDaysToTimeDuration(state, timeDuration, duration.days());
|
||||
// Let dateDuration be ! CreateDateDurationRecord(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], 0).
|
||||
ISO8601::Duration dateDuration = ISO8601::Duration{ duration.years(), duration.months(), duration.weeks(), 0, 0, 0, 0, 0, 0, 0 };
|
||||
return ISO8601::InternalDuration::combineDateAndTimeDuration(dateDuration, timeDuration);
|
||||
}
|
||||
|
||||
Int128 TemporalDurationObject::roundTimeDuration(ExecutionState& state, Int128 timeDuration, unsigned increment, ISO8601::DateTimeUnit unit, ISO8601::RoundingMode roundingMode)
|
||||
{
|
||||
// Let divisor be the value in the "Length in Nanoseconds" column of the row of Table 21 whose "Value" column contains unit.
|
||||
|
|
@ -364,6 +388,24 @@ Int128 TemporalDurationObject::roundTimeDurationToIncrement(ExecutionState& stat
|
|||
return rounded;
|
||||
}
|
||||
|
||||
Int128 TemporalDurationObject::timeDurationFromComponents(ExecutionState& state, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds)
|
||||
{
|
||||
CheckedInt128 min = checkedCastDoubleToInt128(minutes) + checkedCastDoubleToInt128(hours) * Int128{ 60 };
|
||||
CheckedInt128 sec = checkedCastDoubleToInt128(seconds) + min * Int128{ 60 };
|
||||
CheckedInt128 millis = checkedCastDoubleToInt128(milliseconds) + sec * Int128{ 1000 };
|
||||
CheckedInt128 micros = checkedCastDoubleToInt128(microseconds) + millis * Int128{ 1000 };
|
||||
CheckedInt128 nanos = checkedCastDoubleToInt128(nanoseconds) + micros * Int128{ 1000 };
|
||||
if (nanos.hasOverflowed() || std::abs(nanos) > ISO8601::InternalDuration::maxTimeDuration) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "time duration exceeds maximum");
|
||||
}
|
||||
// The components come from a TemporalDuration, so as per
|
||||
// TemporalDuration::tryCreateIfValid(), these components can at most add up
|
||||
// to ISO8601::InternalDuration::maxTimeDuration
|
||||
ASSERT(!nanos.hasOverflowed());
|
||||
ASSERT(std::abs(nanos) <= ISO8601::InternalDuration::maxTimeDuration);
|
||||
return nanos;
|
||||
}
|
||||
|
||||
} // namespace Escargot
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -79,15 +79,25 @@ public:
|
|||
|
||||
String* toString(ExecutionState& state, Value options);
|
||||
static String* temporalDurationToString(ISO8601::Duration duration, Value precision);
|
||||
|
||||
// https://tc39.es/proposal-temporal/#sec-temporal-tointernaldurationrecord
|
||||
static ISO8601::InternalDuration toInternalDurationRecord(ISO8601::Duration duration);
|
||||
|
||||
// https://tc39.es/proposal-temporal/#sec-temporal-tointernaldurationrecordwith24hourdays
|
||||
static ISO8601::InternalDuration toInternalDurationRecordWith24HourDays(ExecutionState& state, ISO8601::Duration duration);
|
||||
|
||||
// https://tc39.es/proposal-temporal/#sec-temporal-roundtimeduration
|
||||
static Int128 roundTimeDuration(ExecutionState& state, Int128 timeDuration, unsigned increment, ISO8601::DateTimeUnit unit, ISO8601::RoundingMode roundingMode);
|
||||
|
||||
// https://tc39.es/proposal-temporal/#sec-temporal-roundtimedurationtoincrement
|
||||
static Int128 roundTimeDurationToIncrement(ExecutionState& state, Int128 d, Int128 increment, ISO8601::RoundingMode roundingMode);
|
||||
|
||||
// https://tc39.es/proposal-temporal/#sec-temporal-timedurationfromcomponents
|
||||
static Int128 timeDurationFromComponents(ExecutionState& state, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds);
|
||||
|
||||
// https://tc39.es/proposal-temporal/#sec-temporal-add24hourdaystonormalizedtimeduration
|
||||
static Int128 add24HourDaysToTimeDuration(ExecutionState& state, Int128 d, double days);
|
||||
|
||||
private:
|
||||
ISO8601::Duration m_duration;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -34,9 +34,7 @@ TemporalInstantObject::TemporalInstantObject(ExecutionState& state, Object* prot
|
|||
|
||||
Value TemporalInstantObject::epochMilliseconds() const
|
||||
{
|
||||
Int128 s = *m_nanoseconds;
|
||||
s /= 1000000;
|
||||
return Value(static_cast<int64_t>(s));
|
||||
return Value(static_cast<int64_t>(ISO8601::ExactTime(*m_nanoseconds).floorEpochMilliseconds()));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -277,11 +275,41 @@ TemporalDurationObject* TemporalInstantObject::differenceTemporalInstant(Executi
|
|||
return new TemporalDurationObject(state, result);
|
||||
}
|
||||
|
||||
TemporalInstantObject* TemporalInstantObject::addDurationToInstant(AddDurationOperation operation, const Value& temporalDurationLike)
|
||||
TemporalInstantObject* TemporalInstantObject::addDurationToInstant(ExecutionState& state, AddDurationOperation operation, const Value& temporalDurationLike)
|
||||
{
|
||||
TemporalInstantObject* instant = this;
|
||||
// TODO
|
||||
return nullptr;
|
||||
// Let duration be ? ToTemporalDuration(temporalDurationLike).
|
||||
auto duration = Temporal::toTemporalDuration(state, temporalDurationLike)->duration();
|
||||
|
||||
bool hasPositive = false;
|
||||
bool hasNegative = false;
|
||||
for (auto n : duration) {
|
||||
if (n > 0) {
|
||||
hasPositive = true;
|
||||
} else if (n < 0) {
|
||||
hasNegative = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasPositive && hasNegative) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Invalid duration");
|
||||
}
|
||||
|
||||
// If operation is subtract, set duration to CreateNegatedTemporalDuration(duration).
|
||||
if (operation == AddDurationOperation::Subtract) {
|
||||
duration = TemporalDurationObject::createNegatedTemporalDuration(duration);
|
||||
}
|
||||
// Let largestUnit be DefaultTemporalLargestUnit(duration).
|
||||
auto largestUnit = duration.defaultTemporalLargestUnit();
|
||||
// If TemporalUnitCategory(largestUnit) is date, throw a RangeError exception.
|
||||
if (ISO8601::toDateTimeCategory(largestUnit) == ISO8601::DateTimeUnitCategory::Date) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Invalid duration");
|
||||
}
|
||||
// Let internalDuration be ToInternalDurationRecordWith24HourDays(duration).
|
||||
auto internalDuration = TemporalDurationObject::toInternalDurationRecordWith24HourDays(state, duration);
|
||||
// Let ns be ? AddInstant(instant.[[EpochNanoseconds]], internalDuration.[[Time]]).
|
||||
Int128 ns = addInstant(state, epochNanoseconds(), internalDuration.time());
|
||||
// Return ! CreateTemporalInstant(ns).
|
||||
return new TemporalInstantObject(state, state.context()->globalObject()->temporalInstantPrototype(), ns);
|
||||
}
|
||||
|
||||
ISO8601::InternalDuration TemporalInstantObject::differenceInstant(ExecutionState& state, Int128 ns1, Int128 ns2, unsigned roundingIncrement,
|
||||
|
|
@ -295,6 +323,18 @@ ISO8601::InternalDuration TemporalInstantObject::differenceInstant(ExecutionStat
|
|||
return ISO8601::InternalDuration(ISO8601::Duration(), timeDuration);
|
||||
}
|
||||
|
||||
Int128 TemporalInstantObject::addInstant(ExecutionState& state, Int128 epochNanoseconds, Int128 timeDuration)
|
||||
{
|
||||
// Let result be AddTimeDurationToEpochNanoseconds(timeDuration, epochNanoseconds).
|
||||
auto result = timeDuration + epochNanoseconds;
|
||||
// If IsValidEpochNanoseconds(result) is false, throw a RangeError exception.
|
||||
if (!ISO8601::ExactTime(result).isValid()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Invalid time or date");
|
||||
}
|
||||
// Return result.
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Escargot
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -53,18 +53,21 @@ public:
|
|||
};
|
||||
TemporalDurationObject* differenceTemporalInstant(ExecutionState& state, DifferenceTemporalInstantOperation operation, Value other, Value options);
|
||||
|
||||
private:
|
||||
// https://tc39.es/proposal-temporal/#sec-temporal-adddurationtoinstant
|
||||
enum class AddDurationOperation {
|
||||
Add,
|
||||
Subtract
|
||||
};
|
||||
TemporalInstantObject* addDurationToInstant(AddDurationOperation operation, const Value& temporalDurationLike);
|
||||
TemporalInstantObject* addDurationToInstant(ExecutionState& state, AddDurationOperation operation, const Value& temporalDurationLike);
|
||||
|
||||
// https://tc39.es/proposal-temporal/#sec-temporal-differenceinstant
|
||||
static ISO8601::InternalDuration differenceInstant(ExecutionState& state, Int128 ns1, Int128 ns2, unsigned roundingIncrement,
|
||||
ISO8601::DateTimeUnit smallestUnit, ISO8601::RoundingMode roundingMode);
|
||||
|
||||
// https://tc39.es/proposal-temporal/#sec-temporal-addinstant
|
||||
static Int128 addInstant(ExecutionState& state, Int128 epochNanoseconds, Int128 timeDuration);
|
||||
|
||||
private:
|
||||
Int128* m_nanoseconds; // [[EpochNanoseconds]]
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -452,7 +452,7 @@ TemporalDurationObject* Temporal::toTemporalDuration(ExecutionState& state, cons
|
|||
// Return ? ParseTemporalDurationString(item).
|
||||
auto duration = ISO8601::Duration::parseDurationString(item.asString());
|
||||
if (!duration) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, msg);
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, msg);
|
||||
}
|
||||
return new TemporalDurationObject(state, duration.value());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@
|
|||
#include "runtime/Context.h"
|
||||
#include "runtime/Object.h"
|
||||
#include "intl/Intl.h"
|
||||
#include "CheckedArithmetic.h"
|
||||
|
||||
namespace Escargot {
|
||||
namespace ISO8601 {
|
||||
|
|
@ -156,7 +155,7 @@ static void handleFraction(Duration& duration, int factor, std::string fractionS
|
|||
|
||||
static double parseInt(std::string src)
|
||||
{
|
||||
return std::stoi(src);
|
||||
return std::stod(src);
|
||||
}
|
||||
|
||||
DateTimeUnitCategory toDateTimeCategory(DateTimeUnit u)
|
||||
|
|
@ -1540,49 +1539,6 @@ InternalDuration InternalDuration::combineDateAndTimeDuration(Duration dateDurat
|
|||
return InternalDuration{ std::move(dateDuration), timeDuration };
|
||||
}
|
||||
|
||||
using CheckedInt128 = Checked<Int128, RecordOverflow>;
|
||||
|
||||
static CheckedInt128 checkedCastDoubleToInt128(double n)
|
||||
{
|
||||
// Based on __fixdfti() and __fixunsdfti() from compiler_rt:
|
||||
// https://github.com/llvm/llvm-project/blob/f3671de5500ff1f8210419226a9603a7d83b1a31/compiler-rt/lib/builtins/fp_fixint_impl.inc
|
||||
// https://github.com/llvm/llvm-project/blob/f3671de5500ff1f8210419226a9603a7d83b1a31/compiler-rt/lib/builtins/fp_fixuint_impl.inc
|
||||
|
||||
static constexpr int significandBits = std::numeric_limits<double>::digits - 1;
|
||||
static constexpr int exponentBits = std::numeric_limits<uint64_t>::digits - std::numeric_limits<double>::digits;
|
||||
static constexpr int exponentBias = std::numeric_limits<double>::max_exponent - 1;
|
||||
static constexpr uint64_t implicitBit = uint64_t{ 1 } << significandBits;
|
||||
static constexpr uint64_t significandMask = implicitBit - uint64_t{ 1 };
|
||||
static constexpr uint64_t signMask = uint64_t{ 1 } << (significandBits + exponentBits);
|
||||
static constexpr uint64_t absMask = signMask - uint64_t{ 1 };
|
||||
|
||||
// Break n into sign, exponent, significand parts.
|
||||
const uint64_t bits = *reinterpret_cast<uint64_t*>(&n);
|
||||
const uint64_t nAbs = bits & absMask;
|
||||
const int sign = bits & signMask ? -1 : 1;
|
||||
const int exponent = (nAbs >> significandBits) - exponentBias;
|
||||
const uint64_t significand = (nAbs & significandMask) | implicitBit;
|
||||
|
||||
// If exponent is negative, the result is zero.
|
||||
if (exponent < 0)
|
||||
return { 0 };
|
||||
|
||||
// If the value is too large for the integer type, overflow.
|
||||
if (exponent >= 128)
|
||||
return { ResultOverflowed };
|
||||
|
||||
// If 0 <= exponent < significandBits, right shift to get the result.
|
||||
// Otherwise, shift left.
|
||||
Int128 result{ significand };
|
||||
if (exponent < significandBits)
|
||||
result >>= significandBits - exponent;
|
||||
else
|
||||
result <<= exponent - significandBits;
|
||||
result *= sign;
|
||||
return { result };
|
||||
}
|
||||
|
||||
|
||||
Optional<ExactTime> parseISODateTimeWithInstantFormat(String* input)
|
||||
{
|
||||
// https://tc39.es/proposal-temporal/#prod-TemporalInstantString
|
||||
|
|
|
|||
66
src/util/Int128.cpp
Normal file
66
src/util/Int128.cpp
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Sony Interactive Entertainment Inc.
|
||||
* Copyright (C) 2021 Apple Inc. All rights reserved.
|
||||
* Copyright (c) 2025-present Samsung Electronics Co., Ltd
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
* USA
|
||||
*/
|
||||
#include "Escargot.h"
|
||||
#include "Int128.h"
|
||||
|
||||
namespace Escargot {
|
||||
|
||||
CheckedInt128 checkedCastDoubleToInt128(double n)
|
||||
{
|
||||
// Based on __fixdfti() and __fixunsdfti() from compiler_rt:
|
||||
// https://github.com/llvm/llvm-project/blob/f3671de5500ff1f8210419226a9603a7d83b1a31/compiler-rt/lib/builtins/fp_fixint_impl.inc
|
||||
// https://github.com/llvm/llvm-project/blob/f3671de5500ff1f8210419226a9603a7d83b1a31/compiler-rt/lib/builtins/fp_fixuint_impl.inc
|
||||
|
||||
static constexpr int significandBits = std::numeric_limits<double>::digits - 1;
|
||||
static constexpr int exponentBits = std::numeric_limits<uint64_t>::digits - std::numeric_limits<double>::digits;
|
||||
static constexpr int exponentBias = std::numeric_limits<double>::max_exponent - 1;
|
||||
static constexpr uint64_t implicitBit = uint64_t{ 1 } << significandBits;
|
||||
static constexpr uint64_t significandMask = implicitBit - uint64_t{ 1 };
|
||||
static constexpr uint64_t signMask = uint64_t{ 1 } << (significandBits + exponentBits);
|
||||
static constexpr uint64_t absMask = signMask - uint64_t{ 1 };
|
||||
|
||||
// Break n into sign, exponent, significand parts.
|
||||
const uint64_t bits = *reinterpret_cast<uint64_t*>(&n);
|
||||
const uint64_t nAbs = bits & absMask;
|
||||
const int sign = bits & signMask ? -1 : 1;
|
||||
const int exponent = (nAbs >> significandBits) - exponentBias;
|
||||
const uint64_t significand = (nAbs & significandMask) | implicitBit;
|
||||
|
||||
// If exponent is negative, the result is zero.
|
||||
if (exponent < 0)
|
||||
return { 0 };
|
||||
|
||||
// If the value is too large for the integer type, overflow.
|
||||
if (exponent >= 128)
|
||||
return { ResultOverflowed };
|
||||
|
||||
// If 0 <= exponent < significandBits, right shift to get the result.
|
||||
// Otherwise, shift left.
|
||||
Int128 result{ significand };
|
||||
if (exponent < significandBits)
|
||||
result >>= significandBits - exponent;
|
||||
else
|
||||
result <<= exponent - significandBits;
|
||||
result *= sign;
|
||||
return { result };
|
||||
}
|
||||
|
||||
} // namespace Escargot
|
||||
|
|
@ -81,9 +81,13 @@ static __forceinline int __builtin_clzl(unsigned long x)
|
|||
#undef INT128_SPECIALIZATION
|
||||
#define INT128_NO_EXPORT
|
||||
|
||||
#include "CheckedArithmetic.h"
|
||||
|
||||
namespace Escargot {
|
||||
|
||||
using Int128 = large_int::int128_t;
|
||||
using CheckedInt128 = Checked<Int128, RecordOverflow>;
|
||||
CheckedInt128 checkedCastDoubleToInt128(double n);
|
||||
|
||||
} // namespace Escargot
|
||||
|
||||
|
|
|
|||
|
|
@ -187,19 +187,19 @@ static inline bool isInBounds(Source value)
|
|||
template <typename T>
|
||||
struct RemoveChecked {
|
||||
typedef T CleanType;
|
||||
static const CleanType DefaultValue = 0;
|
||||
static constexpr CleanType DefaultValue = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct RemoveChecked<Checked<T, CrashOnOverflow> > {
|
||||
typedef typename RemoveChecked<T>::CleanType CleanType;
|
||||
static const CleanType DefaultValue = 0;
|
||||
static constexpr CleanType DefaultValue = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct RemoveChecked<Checked<T, RecordOverflow> > {
|
||||
typedef typename RemoveChecked<T>::CleanType CleanType;
|
||||
static const CleanType DefaultValue = 0;
|
||||
static constexpr CleanType DefaultValue = 0;
|
||||
};
|
||||
|
||||
// The ResultBase and SignednessSelector are used to workaround typeof not being
|
||||
|
|
|
|||
|
|
@ -183,8 +183,6 @@
|
|||
<test id="built-ins/Temporal/Duration/from/argument-duration-out-of-range"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Duration/from/argument-duration-precision-exact-numerical-values"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Duration/from/argument-object-invalid"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Duration/from/argument-string-fractional-with-zero-subparts"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Duration/from/argument-string-invalid"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Duration/from/argument-string-is-infinity"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Duration/from/infinity-throws-rangeerror"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Duration/from/negative-inifinity-throws-rangeerror"><reason>TODO</reason></test>
|
||||
|
|
@ -381,8 +379,6 @@
|
|||
<test id="built-ins/Temporal/Duration/prototype/toJSON/prop-desc"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Duration/prototype/toLocaleString/branding"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Duration/prototype/toLocaleString/prop-desc"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Duration/prototype/toString/balance-subseconds"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Duration/prototype/toString/negative-components"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Duration/prototype/toString/smallestunit-plurals-accepted"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Duration/prototype/toString/total-of-duration-time-units-out-of-range"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Duration/prototype/total/balance-negative-result"><reason>TODO</reason></test>
|
||||
|
|
@ -469,85 +465,10 @@
|
|||
<test id="built-ins/Temporal/Duration/prototype/with/sign-conflict-throws-rangeerror"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Duration/prototype/with/sign-replace"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Duration/prototype/with/subclassing-ignored"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/argument-object-tostring"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/argument-string-calendar-annotation"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/argument-string-calendar-annotation-invalid-key"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/argument-string-critical-unknown-annotation"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/argument-string-date-with-utc-offset"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/argument-string-invalid"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/argument-string-limits"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/argument-string-minus-sign"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/argument-string-multiple-calendar"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/argument-string-multiple-time-zone"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/argument-string-time-separators"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/argument-string-time-zone-annotation"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/argument-string-unknown-annotation"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/argument-string-with-offset-not-valid-epoch-nanoseconds"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/argument-wrong-type"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/argument-zoneddatetime"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/builtin"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/cross-epoch"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/exhaustive"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/instant-string"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/instant-string-multiple-offsets"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/instant-string-sub-minute-offset"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/leap-second"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/length"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/name"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/not-a-constructor"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/prop-desc"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/compare/year-zero"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/from/argument-zoneddatetime"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/add/argument-duration-max"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/add/argument-duration-out-of-range"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/add/argument-mixed-sign"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/add/argument-not-object"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/add/argument-string"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/add/argument-string-fractional-units-rounding-mode"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/add/argument-string-negative-fractional-units"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/add/basic"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/add/branding"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/add/builtin"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/add/cross-epoch"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/add/disallowed-duration-units"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/add/infinity-throws-rangeerror"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/add/length"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/add/minimum-maximum-instant"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/add/name"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/add/negative-infinity-throws-rangeerror"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/add/non-integer-throws-rangeerror"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/add/not-a-constructor"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/add/order-of-operations"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/add/prop-desc"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/add/result-out-of-range"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/add/subclassing-ignored"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/epochMilliseconds/basic"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/equals/argument-zoneddatetime"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/since/add-subtract"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/since/argument-zoneddatetime"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/since/subseconds"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/subtract/argument-duration-max"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/subtract/argument-duration-out-of-range"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/subtract/argument-mixed-sign"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/subtract/argument-not-object"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/subtract/argument-string"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/subtract/argument-string-fractional-units-rounding-mode"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/subtract/argument-string-negative-fractional-units"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/subtract/basic"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/subtract/branding"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/subtract/builtin"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/subtract/disallowed-duration-units"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/subtract/infinity-throws-rangeerror"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/subtract/length"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/subtract/minimum-maximum-instant"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/subtract/name"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/subtract/negative-infinity-throws-rangeerror"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/subtract/non-integer-throws-rangeerror"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/subtract/not-a-constructor"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/subtract/order-of-operations"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/subtract/prop-desc"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/subtract/result-out-of-range"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/subtract/subclassing-ignored"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/toString/smallestunit-plurals-accepted"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/toZonedDateTimeISO/branding"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/toZonedDateTimeISO/builtin"><reason>TODO</reason></test>
|
||||
|
|
@ -565,9 +486,7 @@
|
|||
<test id="built-ins/Temporal/Instant/prototype/toZonedDateTimeISO/timezone-string-year-zero"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/toZonedDateTimeISO/timezone-wrong-type"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/toZonedDateTimeISO/to-zoned-date-time-iso"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/until/add-subtract"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/until/argument-zoneddatetime"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Instant/prototype/until/subseconds"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Now/plainDateISO/length"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Now/plainDateISO/prop-desc"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Temporal/Now/plainDateISO/return-value"><reason>TODO</reason></test>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue