Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[JSC] Make Date.UTC simpler
https://bugs.webkit.org/show_bug.cgi?id=243446

Reviewed by Ross Kirsling.

Avoid creating GregorianDateTime to generate ms from Date.UTC / Date constructor arguments
and making computation simpler and aligned to the spec.

* JSTests/test262/expectations.yaml:
* Source/JavaScriptCore/runtime/DateConstructor.cpp:
(JSC::millisecondsFromComponents):
(JSC::constructDate):
(JSC::JSC_DEFINE_HOST_FUNCTION):
* Source/JavaScriptCore/runtime/JSDateMath.cpp:
(JSC::DateCache::localTimeToMS):
* Source/JavaScriptCore/runtime/JSDateMath.h:

Canonical link: https://commits.webkit.org/253044@main
  • Loading branch information
Constellation committed Aug 2, 2022
1 parent 285b652 commit 445da21
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 18 deletions.
3 changes: 0 additions & 3 deletions JSTests/test262/expectations.yaml
Expand Up @@ -609,9 +609,6 @@ test/built-ins/AsyncGeneratorPrototype/return/return-suspendedStart-broken-promi
test/built-ins/AsyncGeneratorPrototype/return/return-suspendedYield-broken-promise-try-catch.js:
default: 'Test262:AsyncTestFailure:Error: broken promise'
strict mode: 'Test262:AsyncTestFailure:Error: broken promise'
test/built-ins/Date/UTC/fp-evaluation-order.js:
default: 'Test262Error: order of operations / precision in MakeTime Expected SameValue(«NaN», «29312») to be true'
strict mode: 'Test262Error: order of operations / precision in MakeTime Expected SameValue(«NaN», «29312») to be true'
test/built-ins/Function/internals/Construct/derived-return-val-realm.js:
default: 'Test262Error: Expected a TypeError but got a different error constructor with the same name'
strict mode: 'Test262Error: Expected a TypeError but got a different error constructor with the same name'
Expand Down
62 changes: 47 additions & 15 deletions Source/JavaScriptCore/runtime/DateConstructor.cpp
Expand Up @@ -71,6 +71,37 @@ static double millisecondsFromComponents(JSGlobalObject* globalObject, const Arg
VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);

auto toIntegerOrInfinity = [](double d) {
return trunc(std::isnan(d) ? 0.0 : d + 0.0);
};

// https://tc39.es/ecma262/#sec-maketime
auto makeTime = [](double hour, double min, double sec, double ms) {
return ((hour * msPerHour + min * msPerMinute) + sec * msPerSecond) + ms;
};

// https://tc39.es/ecma262/#sec-makeday
auto makeDay = [](double year, double month, double date) {
double additionalYears = std::floor(month / 12);
double ym = year + additionalYears;
if (!std::isfinite(ym))
return PNaN;
double mm = month - additionalYears * 12;
int32_t yearInt32 = toInt32(ym);
int32_t monthInt32 = toInt32(mm);
if (yearInt32 != ym || monthInt32 != mm)
return PNaN;
double days = dateToDaysFrom1970(yearInt32, monthInt32, 1);
return days + date - 1;
};

// https://tc39.es/ecma262/#sec-makedate
auto makeDate = [](double day, double time) {
if (!std::isfinite(day) || !std::isfinite(time))
return PNaN;
return day * msPerDay + time;
};

// Initialize doubleArguments with default values.
double doubleArguments[7] {
0, 0, 1, 0, 0, 0, 0
Expand All @@ -81,20 +112,18 @@ static double millisecondsFromComponents(JSGlobalObject* globalObject, const Arg
RETURN_IF_EXCEPTION(scope, 0);
}
for (unsigned i = 0; i < numberOfUsedArguments; ++i) {
if (!std::isfinite(doubleArguments[i]) || (doubleArguments[i] > INT_MAX) || (doubleArguments[i] < INT_MIN))
if (!std::isfinite(doubleArguments[i]))
return PNaN;
doubleArguments[i] = toIntegerOrInfinity(doubleArguments[i]);
}

GregorianDateTime t;
int year = JSC::toInt32(doubleArguments[0]);
t.setYear((year >= 0 && year <= 99) ? (year + 1900) : year);
t.setMonth(JSC::toInt32(doubleArguments[1]));
t.setMonthDay(JSC::toInt32(doubleArguments[2]));
t.setHour(JSC::toInt32(doubleArguments[3]));
t.setMinute(JSC::toInt32(doubleArguments[4]));
t.setSecond(JSC::toInt32(doubleArguments[5]));
t.setIsDST(-1);
return vm.dateCache.gregorianDateTimeToMS(t, doubleArguments[6], timeType);
if (0 <= doubleArguments[0] && doubleArguments[0] <= 99)
doubleArguments[0] += 1900;

double time = makeDate(makeDay(doubleArguments[0], doubleArguments[1], doubleArguments[2]), makeTime(doubleArguments[3], doubleArguments[4], doubleArguments[5], doubleArguments[6]));
if (!std::isfinite(time))
return PNaN;
return timeClip(vm.dateCache.localTimeToMS(time, timeType));
}

// ECMA 15.9.3
Expand All @@ -120,12 +149,15 @@ JSObject* constructDate(JSGlobalObject* globalObject, JSValue newTarget, const A
RETURN_IF_EXCEPTION(scope, nullptr);
value = vm.dateCache.parseDate(globalObject, vm, primitiveString);
RETURN_IF_EXCEPTION(scope, nullptr);
} else
} else {
value = primitive.toNumber(globalObject);
RETURN_IF_EXCEPTION(scope, nullptr);
}
}
} else
} else {
value = millisecondsFromComponents(globalObject, args, WTF::LocalTime);
RETURN_IF_EXCEPTION(scope, nullptr);
RETURN_IF_EXCEPTION(scope, nullptr);
}

Structure* dateStructure = nullptr;
if (!newTarget)
Expand Down Expand Up @@ -175,7 +207,7 @@ JSC_DEFINE_HOST_FUNCTION(dateNow, (JSGlobalObject*, CallFrame*))
JSC_DEFINE_HOST_FUNCTION(dateUTC, (JSGlobalObject* globalObject, CallFrame* callFrame))
{
double ms = millisecondsFromComponents(globalObject, ArgList(callFrame), WTF::UTCTime);
return JSValue::encode(jsNumber(timeClip(ms)));
return JSValue::encode(jsNumber(ms));
}

} // namespace JSC
6 changes: 6 additions & 0 deletions Source/JavaScriptCore/runtime/JSDateMath.cpp
Expand Up @@ -294,6 +294,12 @@ double DateCache::gregorianDateTimeToMS(const GregorianDateTime& t, double milli
return localTimeResult - localToUTCTimeOffset;
}

double DateCache::localTimeToMS(double milliseconds, WTF::TimeType inputTimeType)
{
double localToUTCTimeOffset = inputTimeType == WTF::LocalTime ? localTimeOffset(milliseconds, inputTimeType).offset : 0;
return milliseconds - localToUTCTimeOffset;
}

// input is UTC
void DateCache::msToGregorianDateTime(double millisecondsFromEpoch, WTF::TimeType outputTimeType, GregorianDateTime& tm)
{
Expand Down
1 change: 1 addition & 0 deletions Source/JavaScriptCore/runtime/JSDateMath.h
Expand Up @@ -99,6 +99,7 @@ class DateCache {

void msToGregorianDateTime(double millisecondsFromEpoch, WTF::TimeType outputTimeType, GregorianDateTime&);
double gregorianDateTimeToMS(const GregorianDateTime&, double milliseconds, WTF::TimeType inputTimeType);
double localTimeToMS(double milliseconds, WTF::TimeType inputTimeType);
JS_EXPORT_PRIVATE double parseDate(JSGlobalObject*, VM&, const WTF::String&);

static void timeZoneChanged();
Expand Down

0 comments on commit 445da21

Please sign in to comment.