[JSC] Date functions should have intrinsic
authorysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 31 Oct 2019 00:37:03 +0000 (00:37 +0000)
committerysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 31 Oct 2019 00:37:03 +0000 (00:37 +0000)
https://bugs.webkit.org/show_bug.cgi?id=202187

Reviewed by Keith Miller.

JSTests:

* stress/date-cse.js: Added.
(shouldBe):
(test):
(test2):
(test3):
* stress/date-get-date-jit.js: Added.
(shouldBe):
(test):
* stress/date-get-day-jit.js: Added.
(shouldBe):
(test):
* stress/date-get-full-year-jit.js: Added.
(shouldBe):
(test):
* stress/date-get-hours-jit.js: Added.
(shouldBe):
(test):
* stress/date-get-milliseconds-jit.js: Added.
(shouldBe):
(test):
* stress/date-get-minutes-jit.js: Added.
(shouldBe):
(test):
* stress/date-get-month-jit.js: Added.
(shouldBe):
(test):
* stress/date-get-seconds-jit.js: Added.
(shouldBe):
(test):
* stress/date-get-time-jit.js: Added.
(shouldBe):
(test):
* stress/date-get-timezone-offset-jit.js: Added.
(shouldBe):
(test):
* stress/date-get-utc-date-jit.js: Added.
(shouldBe):
(test):
* stress/date-get-utc-day-jit.js: Added.
(shouldBe):
(test):
* stress/date-get-utc-full-year-jit.js: Added.
(shouldBe):
(test):
* stress/date-get-utc-hours-jit.js: Added.
(shouldBe):
(test):
* stress/date-get-utc-milliseconds-jit.js: Added.
(shouldBe):
(test):
* stress/date-get-utc-minutes-jit.js: Added.
(shouldBe):
(test):
* stress/date-get-utc-month-jit.js: Added.
(shouldBe):
(test):
* stress/date-get-utc-seconds-jit.js: Added.
(shouldBe):
(test):
* stress/date-get-year-jit.js: Added.
(shouldBe):
(test):
* stress/date-value-of-jit.js: Added.
(shouldBe):
(test):

Source/JavaScriptCore:

This patch adds intrinsic to Date object getter functions to make it inlined in DFG and FTL.
We add two DFG nodes, DateGetInt32OrNaN and DateGetTime. DateGetTime is used when we know
that the result is always machine double. On the other hand, DateGetInt32OrNaN is used when the result is Int32 or NaN.

Run SunSpider 100 times and get the solid improvement in Date related benchmarks.

                                  ToT                     Patched

    date-format-tofte        5.3511+-0.0260     ^      5.2747+-0.0273        ^ definitely 1.0145x faster
    date-format-xparb        4.9196+-0.0265     ^      4.7067+-0.0200        ^ definitely 1.0452x faster

* bytecode/SpeculatedType.cpp:
(JSC::dumpSpeculation):
(JSC::speculationFromClassInfo):
(JSC::speculationFromJSType):
(JSC::speculationFromString):
* bytecode/SpeculatedType.h:
* dfg/DFGAbstractHeap.h:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsicCall):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
* dfg/DFGHeapLocation.cpp:
(WTF::printInternal):
* dfg/DFGHeapLocation.h:
* dfg/DFGNode.h:
(JSC::DFG::Node::hasIntrinsic):
(JSC::DFG::Node::intrinsic):
(JSC::DFG::Node::hasHeapPrediction):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::SafeToExecuteEdge::operator()):
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::speculateDateObject):
(JSC::DFG::SpeculativeJIT::speculate):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
(JSC::DFG::SpeculativeJIT::compileDateGet):
* dfg/DFGUseKind.cpp:
(WTF::printInternal):
* dfg/DFGUseKind.h:
(JSC::DFG::typeFilterFor):
(JSC::DFG::isCell):
* ftl/FTLAbstractHeapRepository.cpp:
* ftl/FTLAbstractHeapRepository.h:
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileDateGet):
(JSC::FTL::DFG::LowerDFGToB3::lowDateObject):
(JSC::FTL::DFG::LowerDFGToB3::speculate):
(JSC::FTL::DFG::LowerDFGToB3::speculateDateObject):
* runtime/DateConversion.cpp:
(JSC::formatDateTime):
* runtime/DateInstance.cpp:
(JSC::DateInstance::calculateGregorianDateTime const):
(JSC::DateInstance::calculateGregorianDateTimeUTC const):
* runtime/DateInstance.h:
* runtime/DateInstanceCache.h:
(JSC::DateInstanceData::offsetOfGregorianDateTimeCachedForMS):
(JSC::DateInstanceData::offsetOfCachedGregorianDateTime):
(JSC::DateInstanceData::offsetOfGregorianDateTimeUTCCachedForMS):
(JSC::DateInstanceData::offsetOfCachedGregorianDateTimeUTC):
(JSC::DateInstanceData::DateInstanceData): Deleted.
* runtime/DatePrototype.cpp:
(JSC::formatLocaleDate):
(JSC::formateDateInstance):
(JSC::dateProtoFuncToISOString):
(JSC::dateProtoFuncGetFullYear):
(JSC::dateProtoFuncGetUTCFullYear):
(JSC::dateProtoFuncGetMonth):
(JSC::dateProtoFuncGetUTCMonth):
(JSC::dateProtoFuncGetDate):
(JSC::dateProtoFuncGetUTCDate):
(JSC::dateProtoFuncGetDay):
(JSC::dateProtoFuncGetUTCDay):
(JSC::dateProtoFuncGetHours):
(JSC::dateProtoFuncGetUTCHours):
(JSC::dateProtoFuncGetMinutes):
(JSC::dateProtoFuncGetUTCMinutes):
(JSC::dateProtoFuncGetSeconds):
(JSC::dateProtoFuncGetUTCSeconds):
(JSC::dateProtoFuncGetMilliSeconds):
(JSC::dateProtoFuncGetUTCMilliseconds):
(JSC::dateProtoFuncGetTimezoneOffset):
(JSC::setNewValueFromTimeArgs):
(JSC::setNewValueFromDateArgs):
(JSC::dateProtoFuncSetYear):
(JSC::dateProtoFuncGetYear):
* runtime/Intrinsic.cpp:
(JSC::intrinsicName):
* runtime/Intrinsic.h:
* runtime/JSDateMath.cpp:
(JSC::msToGregorianDateTime):
* runtime/JSType.cpp:
(WTF::printInternal):
* runtime/JSType.h:

Source/WebCore:

* loader/archive/mhtml/MHTMLArchive.cpp:
(WebCore::MHTMLArchive::generateMHTMLData):

Source/WTF:

* wtf/DateMath.h:
* wtf/GregorianDateTime.cpp:
(WTF::GregorianDateTime::setToCurrentLocalTime):
* wtf/GregorianDateTime.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@251826 268f45cc-cd09-0410-ab3c-d52691b4dbfc

66 files changed:
JSTests/ChangeLog
JSTests/stress/date-cse.js [new file with mode: 0644]
JSTests/stress/date-get-date-jit.js [new file with mode: 0644]
JSTests/stress/date-get-day-jit.js [new file with mode: 0644]
JSTests/stress/date-get-full-year-jit.js [new file with mode: 0644]
JSTests/stress/date-get-hours-jit.js [new file with mode: 0644]
JSTests/stress/date-get-milliseconds-jit.js [new file with mode: 0644]
JSTests/stress/date-get-minutes-jit.js [new file with mode: 0644]
JSTests/stress/date-get-month-jit.js [new file with mode: 0644]
JSTests/stress/date-get-seconds-jit.js [new file with mode: 0644]
JSTests/stress/date-get-time-jit.js [new file with mode: 0644]
JSTests/stress/date-get-timezone-offset-jit.js [new file with mode: 0644]
JSTests/stress/date-get-utc-date-jit.js [new file with mode: 0644]
JSTests/stress/date-get-utc-day-jit.js [new file with mode: 0644]
JSTests/stress/date-get-utc-full-year-jit.js [new file with mode: 0644]
JSTests/stress/date-get-utc-hours-jit.js [new file with mode: 0644]
JSTests/stress/date-get-utc-milliseconds-jit.js [new file with mode: 0644]
JSTests/stress/date-get-utc-minutes-jit.js [new file with mode: 0644]
JSTests/stress/date-get-utc-month-jit.js [new file with mode: 0644]
JSTests/stress/date-get-utc-seconds-jit.js [new file with mode: 0644]
JSTests/stress/date-get-year-jit.js [new file with mode: 0644]
JSTests/stress/date-value-of-jit.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/SpeculatedType.cpp
Source/JavaScriptCore/bytecode/SpeculatedType.h
Source/JavaScriptCore/dfg/DFGAbstractHeap.h
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGGraph.cpp
Source/JavaScriptCore/dfg/DFGHeapLocation.cpp
Source/JavaScriptCore/dfg/DFGHeapLocation.h
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGOperations.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGUseKind.cpp
Source/JavaScriptCore/dfg/DFGUseKind.h
Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.cpp
Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
Source/JavaScriptCore/runtime/DateConversion.cpp
Source/JavaScriptCore/runtime/DateInstance.cpp
Source/JavaScriptCore/runtime/DateInstance.h
Source/JavaScriptCore/runtime/DateInstanceCache.h
Source/JavaScriptCore/runtime/DatePrototype.cpp
Source/JavaScriptCore/runtime/Intrinsic.cpp
Source/JavaScriptCore/runtime/Intrinsic.h
Source/JavaScriptCore/runtime/JSDateMath.cpp
Source/JavaScriptCore/runtime/JSType.cpp
Source/JavaScriptCore/runtime/JSType.h
Source/WTF/ChangeLog
Source/WTF/wtf/DateMath.h
Source/WTF/wtf/GregorianDateTime.cpp
Source/WTF/wtf/GregorianDateTime.h
Source/WebCore/ChangeLog
Source/WebCore/loader/archive/mhtml/MHTMLArchive.cpp

index 3ff0d5e..ca41168 100644 (file)
@@ -1,3 +1,76 @@
+2019-10-30  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] Date functions should have intrinsic
+        https://bugs.webkit.org/show_bug.cgi?id=202187
+
+        Reviewed by Keith Miller.
+
+        * stress/date-cse.js: Added.
+        (shouldBe):
+        (test):
+        (test2):
+        (test3):
+        * stress/date-get-date-jit.js: Added.
+        (shouldBe):
+        (test):
+        * stress/date-get-day-jit.js: Added.
+        (shouldBe):
+        (test):
+        * stress/date-get-full-year-jit.js: Added.
+        (shouldBe):
+        (test):
+        * stress/date-get-hours-jit.js: Added.
+        (shouldBe):
+        (test):
+        * stress/date-get-milliseconds-jit.js: Added.
+        (shouldBe):
+        (test):
+        * stress/date-get-minutes-jit.js: Added.
+        (shouldBe):
+        (test):
+        * stress/date-get-month-jit.js: Added.
+        (shouldBe):
+        (test):
+        * stress/date-get-seconds-jit.js: Added.
+        (shouldBe):
+        (test):
+        * stress/date-get-time-jit.js: Added.
+        (shouldBe):
+        (test):
+        * stress/date-get-timezone-offset-jit.js: Added.
+        (shouldBe):
+        (test):
+        * stress/date-get-utc-date-jit.js: Added.
+        (shouldBe):
+        (test):
+        * stress/date-get-utc-day-jit.js: Added.
+        (shouldBe):
+        (test):
+        * stress/date-get-utc-full-year-jit.js: Added.
+        (shouldBe):
+        (test):
+        * stress/date-get-utc-hours-jit.js: Added.
+        (shouldBe):
+        (test):
+        * stress/date-get-utc-milliseconds-jit.js: Added.
+        (shouldBe):
+        (test):
+        * stress/date-get-utc-minutes-jit.js: Added.
+        (shouldBe):
+        (test):
+        * stress/date-get-utc-month-jit.js: Added.
+        (shouldBe):
+        (test):
+        * stress/date-get-utc-seconds-jit.js: Added.
+        (shouldBe):
+        (test):
+        * stress/date-get-year-jit.js: Added.
+        (shouldBe):
+        (test):
+        * stress/date-value-of-jit.js: Added.
+        (shouldBe):
+        (test):
+
 2019-10-30  Guillaume Emont  <guijemont@igalia.com>
 
         Temporarily skip ChakraCore/test/Math/max.js on arm and mips
diff --git a/JSTests/stress/date-cse.js b/JSTests/stress/date-cse.js
new file mode 100644 (file)
index 0000000..1a12522
--- /dev/null
@@ -0,0 +1,37 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(date)
+{
+    return date.getTime() + date.getTime();
+}
+noInline(test);
+
+function test2()
+{
+    var date = new Date();
+    date.setTime(20);
+    var first = date.getTime();
+    date.setTime(0);
+    var second = date.getTime();
+    return first + second;
+}
+noInline(test2);
+
+function test3(date)
+{
+    return date.getTime() + date.getFullYear();
+}
+noInline(test3);
+
+var date = new Date();
+var result = date.getTime() + date.getTime();
+var result2 = (new Date(20)).getTime() + (new Date(0)).getTime();
+var result3 = date.getTime() + date.getFullYear();
+for (var i = 0; i < 1e6; ++i) {
+    shouldBe(test(date), result);
+    shouldBe(test2(date), result2);
+    shouldBe(test3(date), result3);
+}
diff --git a/JSTests/stress/date-get-date-jit.js b/JSTests/stress/date-get-date-jit.js
new file mode 100644 (file)
index 0000000..f43e7be
--- /dev/null
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(date) {
+    return date.getDate();
+}
+noInline(test);
+
+var date = new Date();
+var invalid = new Date(NaN);
+var expected = date.getDate();
+for (var i = 0; i < 1e6; ++i) {
+    shouldBe(test(date), expected);
+    var d = new Date();
+    shouldBe(test(d), d.getDate());
+    shouldBe(isNaN(test(invalid)), true);
+}
diff --git a/JSTests/stress/date-get-day-jit.js b/JSTests/stress/date-get-day-jit.js
new file mode 100644 (file)
index 0000000..db57731
--- /dev/null
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(date) {
+    return date.getDay();
+}
+noInline(test);
+
+var date = new Date();
+var invalid = new Date(NaN);
+var expected = date.getDay();
+for (var i = 0; i < 1e6; ++i) {
+    shouldBe(test(date), expected);
+    var d = new Date();
+    shouldBe(test(d), d.getDay());
+    shouldBe(isNaN(test(invalid)), true);
+}
diff --git a/JSTests/stress/date-get-full-year-jit.js b/JSTests/stress/date-get-full-year-jit.js
new file mode 100644 (file)
index 0000000..bc38bb1
--- /dev/null
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(date) {
+    return date.getFullYear();
+}
+noInline(test);
+
+var date = new Date();
+var invalid = new Date(NaN);
+var expected = date.getFullYear();
+for (var i = 0; i < 1e6; ++i) {
+    shouldBe(test(date), expected);
+    var d = new Date();
+    shouldBe(test(d), d.getFullYear());
+    shouldBe(isNaN(test(invalid)), true);
+}
diff --git a/JSTests/stress/date-get-hours-jit.js b/JSTests/stress/date-get-hours-jit.js
new file mode 100644 (file)
index 0000000..7f28704
--- /dev/null
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(date) {
+    return date.getHours();
+}
+noInline(test);
+
+var date = new Date();
+var invalid = new Date(NaN);
+var expected = date.getHours();
+for (var i = 0; i < 1e6; ++i) {
+    shouldBe(test(date), expected);
+    var d = new Date();
+    shouldBe(test(d), d.getHours());
+    shouldBe(isNaN(test(invalid)), true);
+}
diff --git a/JSTests/stress/date-get-milliseconds-jit.js b/JSTests/stress/date-get-milliseconds-jit.js
new file mode 100644 (file)
index 0000000..24909cf
--- /dev/null
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(date) {
+    return date.getMilliseconds();
+}
+noInline(test);
+
+var date = new Date();
+var invalid = new Date(NaN);
+var expected = date.getMilliseconds();
+for (var i = 0; i < 1e6; ++i) {
+    shouldBe(test(date), expected);
+    var d = new Date();
+    shouldBe(test(d), d.getMilliseconds());
+    shouldBe(isNaN(test(invalid)), true);
+}
diff --git a/JSTests/stress/date-get-minutes-jit.js b/JSTests/stress/date-get-minutes-jit.js
new file mode 100644 (file)
index 0000000..3f4774a
--- /dev/null
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(date) {
+    return date.getMinutes();
+}
+noInline(test);
+
+var date = new Date();
+var invalid = new Date(NaN);
+var expected = date.getMinutes();
+for (var i = 0; i < 1e6; ++i) {
+    shouldBe(test(date), expected);
+    var d = new Date();
+    shouldBe(test(d), d.getMinutes());
+    shouldBe(isNaN(test(invalid)), true);
+}
diff --git a/JSTests/stress/date-get-month-jit.js b/JSTests/stress/date-get-month-jit.js
new file mode 100644 (file)
index 0000000..945dc1a
--- /dev/null
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(date) {
+    return date.getMonth();
+}
+noInline(test);
+
+var date = new Date();
+var invalid = new Date(NaN);
+var expected = date.getMonth();
+for (var i = 0; i < 1e6; ++i) {
+    shouldBe(test(date), expected);
+    var d = new Date();
+    shouldBe(test(d), d.getMonth());
+    shouldBe(isNaN(test(invalid)), true);
+}
diff --git a/JSTests/stress/date-get-seconds-jit.js b/JSTests/stress/date-get-seconds-jit.js
new file mode 100644 (file)
index 0000000..ff476cb
--- /dev/null
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(date) {
+    return date.getSeconds();
+}
+noInline(test);
+
+var date = new Date();
+var invalid = new Date(NaN);
+var expected = date.getSeconds();
+for (var i = 0; i < 1e6; ++i) {
+    shouldBe(test(date), expected);
+    var d = new Date();
+    shouldBe(test(d), d.getSeconds());
+    shouldBe(isNaN(test(invalid)), true);
+}
diff --git a/JSTests/stress/date-get-time-jit.js b/JSTests/stress/date-get-time-jit.js
new file mode 100644 (file)
index 0000000..e8e1641
--- /dev/null
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(date) {
+    return date.getTime();
+}
+noInline(test);
+
+var date = new Date();
+var invalid = new Date(NaN);
+var expected = date.getTime();
+for (var i = 0; i < 1e6; ++i) {
+    shouldBe(test(date), expected);
+    var d = new Date();
+    shouldBe(test(d), d.getTime());
+    shouldBe(isNaN(test(invalid)), true);
+}
diff --git a/JSTests/stress/date-get-timezone-offset-jit.js b/JSTests/stress/date-get-timezone-offset-jit.js
new file mode 100644 (file)
index 0000000..34f7772
--- /dev/null
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(date) {
+    return date.getTimezoneOffset();
+}
+noInline(test);
+
+var date = new Date();
+var invalid = new Date(NaN);
+var expected = date.getTimezoneOffset();
+for (var i = 0; i < 1e6; ++i) {
+    shouldBe(test(date), expected);
+    var d = new Date();
+    shouldBe(test(d), d.getTimezoneOffset());
+    shouldBe(isNaN(test(invalid)), true);
+}
diff --git a/JSTests/stress/date-get-utc-date-jit.js b/JSTests/stress/date-get-utc-date-jit.js
new file mode 100644 (file)
index 0000000..20e152d
--- /dev/null
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(date) {
+    return date.getUTCDate();
+}
+noInline(test);
+
+var date = new Date();
+var invalid = new Date(NaN);
+var expected = date.getUTCDate();
+for (var i = 0; i < 1e6; ++i) {
+    shouldBe(test(date), expected);
+    var d = new Date();
+    shouldBe(test(d), d.getUTCDate());
+    shouldBe(isNaN(test(invalid)), true);
+}
diff --git a/JSTests/stress/date-get-utc-day-jit.js b/JSTests/stress/date-get-utc-day-jit.js
new file mode 100644 (file)
index 0000000..f63accc
--- /dev/null
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(date) {
+    return date.getUTCDay();
+}
+noInline(test);
+
+var date = new Date();
+var invalid = new Date(NaN);
+var expected = date.getUTCDay();
+for (var i = 0; i < 1e6; ++i) {
+    shouldBe(test(date), expected);
+    var d = new Date();
+    shouldBe(test(d), d.getUTCDay());
+    shouldBe(isNaN(test(invalid)), true);
+}
diff --git a/JSTests/stress/date-get-utc-full-year-jit.js b/JSTests/stress/date-get-utc-full-year-jit.js
new file mode 100644 (file)
index 0000000..b7ad63e
--- /dev/null
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(date) {
+    return date.getUTCFullYear();
+}
+noInline(test);
+
+var date = new Date();
+var invalid = new Date(NaN);
+var expected = date.getUTCFullYear();
+for (var i = 0; i < 1e6; ++i) {
+    shouldBe(test(date), expected);
+    var d = new Date();
+    shouldBe(test(d), d.getUTCFullYear());
+    shouldBe(isNaN(test(invalid)), true);
+}
diff --git a/JSTests/stress/date-get-utc-hours-jit.js b/JSTests/stress/date-get-utc-hours-jit.js
new file mode 100644 (file)
index 0000000..875dd74
--- /dev/null
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(date) {
+    return date.getUTCHours();
+}
+noInline(test);
+
+var date = new Date();
+var invalid = new Date(NaN);
+var expected = date.getUTCHours();
+for (var i = 0; i < 1e6; ++i) {
+    shouldBe(test(date), expected);
+    var d = new Date();
+    shouldBe(test(d), d.getUTCHours());
+    shouldBe(isNaN(test(invalid)), true);
+}
diff --git a/JSTests/stress/date-get-utc-milliseconds-jit.js b/JSTests/stress/date-get-utc-milliseconds-jit.js
new file mode 100644 (file)
index 0000000..bc7421e
--- /dev/null
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(date) {
+    return date.getUTCMilliseconds();
+}
+noInline(test);
+
+var date = new Date();
+var invalid = new Date(NaN);
+var expected = date.getUTCMilliseconds();
+for (var i = 0; i < 1e6; ++i) {
+    shouldBe(test(date), expected);
+    var d = new Date();
+    shouldBe(test(d), d.getUTCMilliseconds());
+    shouldBe(isNaN(test(invalid)), true);
+}
diff --git a/JSTests/stress/date-get-utc-minutes-jit.js b/JSTests/stress/date-get-utc-minutes-jit.js
new file mode 100644 (file)
index 0000000..59263c5
--- /dev/null
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(date) {
+    return date.getUTCMinutes();
+}
+noInline(test);
+
+var date = new Date();
+var invalid = new Date(NaN);
+var expected = date.getUTCMinutes();
+for (var i = 0; i < 1e6; ++i) {
+    shouldBe(test(date), expected);
+    var d = new Date();
+    shouldBe(test(d), d.getUTCMinutes());
+    shouldBe(isNaN(test(invalid)), true);
+}
diff --git a/JSTests/stress/date-get-utc-month-jit.js b/JSTests/stress/date-get-utc-month-jit.js
new file mode 100644 (file)
index 0000000..86bc524
--- /dev/null
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(date) {
+    return date.getUTCMonth();
+}
+noInline(test);
+
+var date = new Date();
+var invalid = new Date(NaN);
+var expected = date.getUTCMonth();
+for (var i = 0; i < 1e6; ++i) {
+    shouldBe(test(date), expected);
+    var d = new Date();
+    shouldBe(test(d), d.getUTCMonth());
+    shouldBe(isNaN(test(invalid)), true);
+}
diff --git a/JSTests/stress/date-get-utc-seconds-jit.js b/JSTests/stress/date-get-utc-seconds-jit.js
new file mode 100644 (file)
index 0000000..b787c30
--- /dev/null
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(date) {
+    return date.getUTCSeconds();
+}
+noInline(test);
+
+var date = new Date();
+var invalid = new Date(NaN);
+var expected = date.getUTCSeconds();
+for (var i = 0; i < 1e6; ++i) {
+    shouldBe(test(date), expected);
+    var d = new Date();
+    shouldBe(test(d), d.getUTCSeconds());
+    shouldBe(isNaN(test(invalid)), true);
+}
diff --git a/JSTests/stress/date-get-year-jit.js b/JSTests/stress/date-get-year-jit.js
new file mode 100644 (file)
index 0000000..7e16b83
--- /dev/null
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(date) {
+    return date.getYear();
+}
+noInline(test);
+
+var date = new Date();
+var invalid = new Date(NaN);
+var expected = date.getYear();
+for (var i = 0; i < 1e6; ++i) {
+    shouldBe(test(date), expected);
+    var d = new Date();
+    shouldBe(test(d), d.getYear());
+    shouldBe(isNaN(test(invalid)), true);
+}
diff --git a/JSTests/stress/date-value-of-jit.js b/JSTests/stress/date-value-of-jit.js
new file mode 100644 (file)
index 0000000..3c3938b
--- /dev/null
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(date) {
+    return date.valueOf();
+}
+noInline(test);
+
+var date = new Date();
+var invalid = new Date(NaN);
+var expected = date.valueOf();
+for (var i = 0; i < 1e6; ++i) {
+    shouldBe(test(date), expected);
+    var d = new Date();
+    shouldBe(test(d), d.valueOf());
+    shouldBe(isNaN(test(invalid)), true);
+}
index 8c1a775..0b64503 100644 (file)
@@ -1,3 +1,124 @@
+2019-10-30  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] Date functions should have intrinsic
+        https://bugs.webkit.org/show_bug.cgi?id=202187
+
+        Reviewed by Keith Miller.
+
+        This patch adds intrinsic to Date object getter functions to make it inlined in DFG and FTL.
+        We add two DFG nodes, DateGetInt32OrNaN and DateGetTime. DateGetTime is used when we know
+        that the result is always machine double. On the other hand, DateGetInt32OrNaN is used when the result is Int32 or NaN.
+
+        Run SunSpider 100 times and get the solid improvement in Date related benchmarks.
+
+                                          ToT                     Patched
+
+            date-format-tofte        5.3511+-0.0260     ^      5.2747+-0.0273        ^ definitely 1.0145x faster
+            date-format-xparb        4.9196+-0.0265     ^      4.7067+-0.0200        ^ definitely 1.0452x faster
+
+        * bytecode/SpeculatedType.cpp:
+        (JSC::dumpSpeculation):
+        (JSC::speculationFromClassInfo):
+        (JSC::speculationFromJSType):
+        (JSC::speculationFromString):
+        * bytecode/SpeculatedType.h:
+        * dfg/DFGAbstractHeap.h:
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::dump):
+        * dfg/DFGHeapLocation.cpp:
+        (WTF::printInternal):
+        * dfg/DFGHeapLocation.h:
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::hasIntrinsic):
+        (JSC::DFG::Node::intrinsic):
+        (JSC::DFG::Node::hasHeapPrediction):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::SafeToExecuteEdge::operator()):
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::speculateDateObject):
+        (JSC::DFG::SpeculativeJIT::speculate):
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        (JSC::DFG::SpeculativeJIT::compileDateGet):
+        * dfg/DFGUseKind.cpp:
+        (WTF::printInternal):
+        * dfg/DFGUseKind.h:
+        (JSC::DFG::typeFilterFor):
+        (JSC::DFG::isCell):
+        * ftl/FTLAbstractHeapRepository.cpp:
+        * ftl/FTLAbstractHeapRepository.h:
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileDateGet):
+        (JSC::FTL::DFG::LowerDFGToB3::lowDateObject):
+        (JSC::FTL::DFG::LowerDFGToB3::speculate):
+        (JSC::FTL::DFG::LowerDFGToB3::speculateDateObject):
+        * runtime/DateConversion.cpp:
+        (JSC::formatDateTime):
+        * runtime/DateInstance.cpp:
+        (JSC::DateInstance::calculateGregorianDateTime const):
+        (JSC::DateInstance::calculateGregorianDateTimeUTC const):
+        * runtime/DateInstance.h:
+        * runtime/DateInstanceCache.h:
+        (JSC::DateInstanceData::offsetOfGregorianDateTimeCachedForMS):
+        (JSC::DateInstanceData::offsetOfCachedGregorianDateTime):
+        (JSC::DateInstanceData::offsetOfGregorianDateTimeUTCCachedForMS):
+        (JSC::DateInstanceData::offsetOfCachedGregorianDateTimeUTC):
+        (JSC::DateInstanceData::DateInstanceData): Deleted.
+        * runtime/DatePrototype.cpp:
+        (JSC::formatLocaleDate):
+        (JSC::formateDateInstance):
+        (JSC::dateProtoFuncToISOString):
+        (JSC::dateProtoFuncGetFullYear):
+        (JSC::dateProtoFuncGetUTCFullYear):
+        (JSC::dateProtoFuncGetMonth):
+        (JSC::dateProtoFuncGetUTCMonth):
+        (JSC::dateProtoFuncGetDate):
+        (JSC::dateProtoFuncGetUTCDate):
+        (JSC::dateProtoFuncGetDay):
+        (JSC::dateProtoFuncGetUTCDay):
+        (JSC::dateProtoFuncGetHours):
+        (JSC::dateProtoFuncGetUTCHours):
+        (JSC::dateProtoFuncGetMinutes):
+        (JSC::dateProtoFuncGetUTCMinutes):
+        (JSC::dateProtoFuncGetSeconds):
+        (JSC::dateProtoFuncGetUTCSeconds):
+        (JSC::dateProtoFuncGetMilliSeconds):
+        (JSC::dateProtoFuncGetUTCMilliseconds):
+        (JSC::dateProtoFuncGetTimezoneOffset):
+        (JSC::setNewValueFromTimeArgs):
+        (JSC::setNewValueFromDateArgs):
+        (JSC::dateProtoFuncSetYear):
+        (JSC::dateProtoFuncGetYear):
+        * runtime/Intrinsic.cpp:
+        (JSC::intrinsicName):
+        * runtime/Intrinsic.h:
+        * runtime/JSDateMath.cpp:
+        (JSC::msToGregorianDateTime):
+        * runtime/JSType.cpp:
+        (WTF::printInternal):
+        * runtime/JSType.h:
+
 2019-10-30  Ross Kirsling  <ross.kirsling@sony.com>
 
         Intl.DateTimeFormat returns resolvedOptions in the wrong order
index 84438e3..419eebd 100644 (file)
@@ -29,6 +29,7 @@
 #include "config.h"
 #include "SpeculatedType.h"
 
+#include "DateInstance.h"
 #include "DirectArguments.h"
 #include "JSArray.h"
 #include "JSBigInt.h"
@@ -174,6 +175,11 @@ void dumpSpeculation(PrintStream& outStream, SpeculatedType value)
             else
                 isTop = false;
 
+            if (value & SpecDateObject)
+                strOut.print("DateObject");
+            else
+                isTop = false;
+
             if (value & SpecPromiseObject)
                 strOut.print("PromiseObject");
             else
@@ -445,6 +451,9 @@ SpeculatedType speculationFromClassInfo(const ClassInfo* classInfo)
     if (classInfo == RegExpObject::info())
         return SpecRegExpObject;
 
+    if (classInfo == DateInstance::info())
+        return SpecDateObject;
+
     if (classInfo == JSMap::info())
         return SpecMapObject;
 
@@ -594,6 +603,8 @@ Optional<SpeculatedType> speculationFromJSType(JSType type)
         return SpecDerivedArray;
     case RegExpObjectType:
         return SpecRegExpObject;
+    case JSDateType:
+        return SpecDateObject;
     case ProxyObjectType:
         return SpecProxyObject;
     case JSPromiseType:
@@ -814,6 +825,8 @@ SpeculatedType speculationFromString(const char* speculation)
         return SpecStringObject;
     if (!strncmp(speculation, "SpecRegExpObject", strlen("SpecRegExpObject")))
         return SpecRegExpObject;
+    if (!strncmp(speculation, "SpecDateObject", strlen("SpecDateObject")))
+        return SpecDateObject;
     if (!strncmp(speculation, "SpecPromiseObject", strlen("SpecPromiseObject")))
         return SpecPromiseObject;
     if (!strncmp(speculation, "SpecMapObject", strlen("SpecMapObject")))
index b1153b4..a11238c 100644 (file)
@@ -58,32 +58,33 @@ static constexpr SpeculatedType SpecDirectArguments                   = 1ull <<
 static constexpr SpeculatedType SpecScopedArguments                   = 1ull << 14; // It's definitely a ScopedArguments object.
 static constexpr SpeculatedType SpecStringObject                      = 1ull << 15; // It's definitely a StringObject.
 static constexpr SpeculatedType SpecRegExpObject                      = 1ull << 16; // It's definitely a RegExpObject (and not any subclass of RegExpObject).
-static constexpr SpeculatedType SpecPromiseObject                     = 1ull << 17; // It's definitely a Promise object or one of its subclasses.
-static constexpr SpeculatedType SpecMapObject                         = 1ull << 18; // It's definitely a Map object or one of its subclasses.
-static constexpr SpeculatedType SpecSetObject                         = 1ull << 19; // It's definitely a Set object or one of its subclasses.
-static constexpr SpeculatedType SpecWeakMapObject                     = 1ull << 20; // It's definitely a WeakMap object or one of its subclasses.
-static constexpr SpeculatedType SpecWeakSetObject                     = 1ull << 21; // It's definitely a WeakSet object or one of its subclasses.
-static constexpr SpeculatedType SpecProxyObject                       = 1ull << 22; // It's definitely a Proxy object or one of its subclasses.
-static constexpr SpeculatedType SpecDerivedArray                      = 1ull << 23; // It's definitely a DerivedArray object.
-static constexpr SpeculatedType SpecObjectOther                       = 1ull << 24; // It's definitely an object but not JSFinalObject, JSArray, or JSFunction.
-static constexpr SpeculatedType SpecStringIdent                       = 1ull << 25; // It's definitely a JSString, and it's an identifier.
-static constexpr SpeculatedType SpecStringVar                         = 1ull << 26; // It's definitely a JSString, and it's not an identifier.
+static constexpr SpeculatedType SpecDateObject                        = 1ull << 17; // It's definitely a Date object or one of its subclasses.
+static constexpr SpeculatedType SpecPromiseObject                     = 1ull << 18; // It's definitely a Promise object or one of its subclasses.
+static constexpr SpeculatedType SpecMapObject                         = 1ull << 19; // It's definitely a Map object or one of its subclasses.
+static constexpr SpeculatedType SpecSetObject                         = 1ull << 20; // It's definitely a Set object or one of its subclasses.
+static constexpr SpeculatedType SpecWeakMapObject                     = 1ull << 21; // It's definitely a WeakMap object or one of its subclasses.
+static constexpr SpeculatedType SpecWeakSetObject                     = 1ull << 22; // It's definitely a WeakSet object or one of its subclasses.
+static constexpr SpeculatedType SpecProxyObject                       = 1ull << 23; // It's definitely a Proxy object or one of its subclasses.
+static constexpr SpeculatedType SpecDerivedArray                      = 1ull << 24; // It's definitely a DerivedArray object.
+static constexpr SpeculatedType SpecObjectOther                       = 1ull << 25; // It's definitely an object but not JSFinalObject, JSArray, or JSFunction.
+static constexpr SpeculatedType SpecStringIdent                       = 1ull << 26; // It's definitely a JSString, and it's an identifier.
+static constexpr SpeculatedType SpecStringVar                         = 1ull << 27; // It's definitely a JSString, and it's not an identifier.
 static constexpr SpeculatedType SpecString                            = SpecStringIdent | SpecStringVar; // It's definitely a JSString.
-static constexpr SpeculatedType SpecSymbol                            = 1ull << 27; // It's definitely a Symbol.
-static constexpr SpeculatedType SpecCellOther                         = 1ull << 28; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString, BigInt, or Symbol.
-static constexpr SpeculatedType SpecBoolInt32                         = 1ull << 29; // It's definitely an Int32 with value 0 or 1.
-static constexpr SpeculatedType SpecNonBoolInt32                      = 1ull << 30; // It's definitely an Int32 with value other than 0 or 1.
+static constexpr SpeculatedType SpecSymbol                            = 1ull << 28; // It's definitely a Symbol.
+static constexpr SpeculatedType SpecCellOther                         = 1ull << 29; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString, BigInt, or Symbol.
+static constexpr SpeculatedType SpecBoolInt32                         = 1ull << 30; // It's definitely an Int32 with value 0 or 1.
+static constexpr SpeculatedType SpecNonBoolInt32                      = 1ull << 31; // It's definitely an Int32 with value other than 0 or 1.
 static constexpr SpeculatedType SpecInt32Only                         = SpecBoolInt32 | SpecNonBoolInt32; // It's definitely an Int32.
 
-static constexpr SpeculatedType SpecInt32AsInt52                      = 1ull << 31; // It's an Int52 and it can fit in an int32.
-static constexpr SpeculatedType SpecNonInt32AsInt52                   = 1ull << 32; // It's an Int52 and it can't fit in an int32.
+static constexpr SpeculatedType SpecInt32AsInt52                      = 1ull << 32; // It's an Int52 and it can fit in an int32.
+static constexpr SpeculatedType SpecNonInt32AsInt52                   = 1ull << 33; // It's an Int52 and it can't fit in an int32.
 static constexpr SpeculatedType SpecInt52Any                          = SpecInt32AsInt52 | SpecNonInt32AsInt52; // It's any kind of Int52.
 
-static constexpr SpeculatedType SpecAnyIntAsDouble                    = 1ull << 33; // It's definitely an Int52 and it's inside a double.
-static constexpr SpeculatedType SpecNonIntAsDouble                    = 1ull << 34; // It's definitely not an Int52 but it's a real number and it's a double.
+static constexpr SpeculatedType SpecAnyIntAsDouble                    = 1ull << 34; // It's definitely an Int52 and it's inside a double.
+static constexpr SpeculatedType SpecNonIntAsDouble                    = 1ull << 35; // It's definitely not an Int52 but it's a real number and it's a double.
 static constexpr SpeculatedType SpecDoubleReal                        = SpecNonIntAsDouble | SpecAnyIntAsDouble; // It's definitely a non-NaN double.
-static constexpr SpeculatedType SpecDoublePureNaN                     = 1ull << 35; // It's definitely a NaN that is safe to tag (i.e. pure).
-static constexpr SpeculatedType SpecDoubleImpureNaN                   = 1ull << 36; // It's definitely a NaN that is unsafe to tag (i.e. impure).
+static constexpr SpeculatedType SpecDoublePureNaN                     = 1ull << 36; // It's definitely a NaN that is safe to tag (i.e. pure).
+static constexpr SpeculatedType SpecDoubleImpureNaN                   = 1ull << 37; // It's definitely a NaN that is unsafe to tag (i.e. impure).
 static constexpr SpeculatedType SpecDoubleNaN                         = SpecDoublePureNaN | SpecDoubleImpureNaN; // It's definitely some kind of NaN.
 static constexpr SpeculatedType SpecBytecodeDouble                    = SpecDoubleReal | SpecDoublePureNaN; // It's either a non-NaN or a NaN double, but it's definitely not impure NaN.
 static constexpr SpeculatedType SpecFullDouble                        = SpecDoubleReal | SpecDoubleNaN; // It's either a non-NaN or a NaN double.
@@ -93,14 +94,14 @@ static constexpr SpeculatedType SpecBytecodeNumber                    = SpecInt3
 static constexpr SpeculatedType SpecIntAnyFormat                      = SpecInt52Any | SpecInt32Only | SpecAnyIntAsDouble;
 
 static constexpr SpeculatedType SpecFullNumber                        = SpecIntAnyFormat | SpecFullDouble; // It's either an Int32, Int52, or a Double, and the Double can be impure NaN.
-static constexpr SpeculatedType SpecBoolean                           = 1ull << 37; // It's definitely a Boolean.
-static constexpr SpeculatedType SpecOther                             = 1ull << 38; // It's definitely either Null or Undefined.
+static constexpr SpeculatedType SpecBoolean                           = 1ull << 38; // It's definitely a Boolean.
+static constexpr SpeculatedType SpecOther                             = 1ull << 39; // It's definitely either Null or Undefined.
 static constexpr SpeculatedType SpecMisc                              = SpecBoolean | SpecOther; // It's definitely either a boolean, Null, or Undefined.
-static constexpr SpeculatedType SpecEmpty                             = 1ull << 39; // It's definitely an empty value marker.
-static constexpr SpeculatedType SpecBigInt                            = 1ull << 40; // It's definitely a BigInt.
-static constexpr SpeculatedType SpecDataViewObject                    = 1ull << 41; // It's definitely a JSDataView.
+static constexpr SpeculatedType SpecEmpty                             = 1ull << 40; // It's definitely an empty value marker.
+static constexpr SpeculatedType SpecBigInt                            = 1ull << 41; // It's definitely a BigInt.
+static constexpr SpeculatedType SpecDataViewObject                    = 1ull << 42; // It's definitely a JSDataView.
 static constexpr SpeculatedType SpecPrimitive                         = SpecString | SpecSymbol | SpecBytecodeNumber | SpecMisc | SpecBigInt; // It's any non-Object JSValue.
-static constexpr SpeculatedType SpecObject                            = SpecFinalObject | SpecArray | SpecFunction | SpecTypedArrayView | SpecDirectArguments | SpecScopedArguments | SpecStringObject | SpecRegExpObject | SpecPromiseObject | SpecMapObject | SpecSetObject | SpecWeakMapObject | SpecWeakSetObject | SpecProxyObject | SpecDerivedArray | SpecObjectOther | SpecDataViewObject; // Bitmask used for testing for any kind of object prediction.
+static constexpr SpeculatedType SpecObject                            = SpecFinalObject | SpecArray | SpecFunction | SpecTypedArrayView | SpecDirectArguments | SpecScopedArguments | SpecStringObject | SpecRegExpObject | SpecDateObject | SpecPromiseObject | SpecMapObject | SpecSetObject | SpecWeakMapObject | SpecWeakSetObject | SpecProxyObject | SpecDerivedArray | SpecObjectOther | SpecDataViewObject; // Bitmask used for testing for any kind of object prediction.
 static constexpr SpeculatedType SpecCell                              = SpecObject | SpecString | SpecSymbol | SpecCellOther | SpecBigInt; // It's definitely a JSCell.
 static constexpr SpeculatedType SpecHeapTop                           = SpecCell | SpecBytecodeNumber | SpecMisc; // It can be any of the above, except for SpecInt52Only and SpecDoubleImpureNaN.
 static constexpr SpeculatedType SpecBytecodeTop                       = SpecHeapTop | SpecEmpty; // It can be any of the above, except for SpecInt52Only and SpecDoubleImpureNaN. Corresponds to what could be found in a bytecode local.
index a30929d..bf99377 100644 (file)
@@ -71,6 +71,7 @@ namespace JSC { namespace DFG {
     macro(HeapObjectCount) /* Used to reflect the fact that some allocations reveal object identity */\
     macro(RegExpState) \
     macro(MathDotRandomState) \
+    macro(JSDateFields) \
     macro(JSMapFields) \
     macro(JSSetFields) \
     macro(JSWeakMapFields) \
index 5370337..41ca366 100644 (file)
@@ -4068,6 +4068,16 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         break;
     }
 
+    case DateGetInt32OrNaN: {
+        setNonCellTypeForNode(node, SpecInt32Only | SpecDoublePureNaN);
+        break;
+    }
+
+    case DateGetTime: {
+        setNonCellTypeForNode(node, SpecFullDouble);
+        break;
+    }
+
     case DataViewSet: {
         break;
     }
index 223445c..6d68f0f 100644 (file)
@@ -3195,6 +3195,41 @@ bool ByteCodeParser::handleIntrinsicCall(Node* callee, VirtualRegister result, I
             return true;
         }
 
+        case DatePrototypeGetTimeIntrinsic: {
+            if (!is64Bit())
+                return false;
+            insertChecks();
+            Node* base = get(virtualRegisterForArgument(0, registerOffset));
+            setResult(addToGraph(DateGetTime, OpInfo(intrinsic), OpInfo(), base));
+            return true;
+        }
+
+        case DatePrototypeGetFullYearIntrinsic:
+        case DatePrototypeGetUTCFullYearIntrinsic:
+        case DatePrototypeGetMonthIntrinsic:
+        case DatePrototypeGetUTCMonthIntrinsic:
+        case DatePrototypeGetDateIntrinsic:
+        case DatePrototypeGetUTCDateIntrinsic:
+        case DatePrototypeGetDayIntrinsic:
+        case DatePrototypeGetUTCDayIntrinsic:
+        case DatePrototypeGetHoursIntrinsic:
+        case DatePrototypeGetUTCHoursIntrinsic:
+        case DatePrototypeGetMinutesIntrinsic:
+        case DatePrototypeGetUTCMinutesIntrinsic:
+        case DatePrototypeGetSecondsIntrinsic:
+        case DatePrototypeGetUTCSecondsIntrinsic:
+        case DatePrototypeGetMillisecondsIntrinsic:
+        case DatePrototypeGetUTCMillisecondsIntrinsic:
+        case DatePrototypeGetTimezoneOffsetIntrinsic:
+        case DatePrototypeGetYearIntrinsic: {
+            if (!is64Bit())
+                return false;
+            insertChecks();
+            Node* base = get(virtualRegisterForArgument(0, registerOffset));
+            setResult(addToGraph(DateGetInt32OrNaN, OpInfo(intrinsic), OpInfo(prediction), base));
+            return true;
+        }
+
         case DataViewGetInt8:
         case DataViewGetUint8:
         case DataViewGetInt16:
index b89c03c..b747915 100644 (file)
@@ -1814,6 +1814,13 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
         def(PureValue(node, node->validRadixConstant()));
         return;
 
+    case DateGetTime:
+    case DateGetInt32OrNaN: {
+        read(JSDateFields);
+        def(HeapLocation(DateFieldLoc, AbstractHeap(JSDateFields, static_cast<uint64_t>(node->intrinsic())), node->child1()), LazyNode(node));
+        return;
+    }
+
     case DataViewGetFloat:
     case DataViewGetInt: {
         read(MiscFields);
index 5d2b05d..1d2be0b 100644 (file)
@@ -242,6 +242,8 @@ bool doesGC(Graph& graph, Node* node)
     case FilterGetByIdStatus:
     case FilterPutByIdStatus:
     case FilterInByIdStatus:
+    case DateGetInt32OrNaN:
+    case DateGetTime:
     case DataViewGetInt:
     case DataViewGetFloat:
     case DataViewSet:
index e1e1678..6bcb515 100644 (file)
@@ -2320,6 +2320,11 @@ private:
             fixEdge<CellUse>(node->child1());
             break;
 
+        case DateGetInt32OrNaN:
+        case DateGetTime:
+            fixEdge<DateObjectUse>(node->child1());
+            break;
+
         case DataViewGetInt:
         case DataViewGetFloat: {
             fixEdge<DataViewObjectUse>(node->child1());
index adbf502..ca9fc34 100644 (file)
@@ -365,6 +365,8 @@ void Graph::dump(PrintStream& out, const char* prefixStr, Node* node, DumpContex
     }
     if (node->hasIgnoreLastIndexIsWritable())
         out.print(comma, "ignoreLastIndexIsWritable = ", node->ignoreLastIndexIsWritable());
+    if (node->hasIntrinsic())
+        out.print(comma, "intrinsic = ", node->intrinsic());
     if (node->isConstant())
         out.print(comma, pointerDumpInContext(node->constant(), context));
     if (node->hasCallLinkStatus())
index e4b97b3..c2b96b5 100644 (file)
@@ -168,6 +168,10 @@ void printInternal(PrintStream& out, LocationKind kind)
         out.print("RegExpObjectLastIndexLoc");
         return;
 
+    case DateFieldLoc:
+        out.print("DateFieldLoc");
+        return;
+
     case MapBucketLoc:
         out.print("MapBucketLoc");
         return;
index 0910064..a8e7381 100644 (file)
@@ -64,6 +64,7 @@ enum LocationKind {
     PrototypeLoc,
     StackLoc,
     StackPayloadLoc,
+    DateFieldLoc,
     MapBucketLoc,
     MapBucketHeadLoc,
     MapBucketValueLoc,
index 11d8b40..c1053c7 100644 (file)
@@ -1554,9 +1554,21 @@ public:
         return m_opInfo.as<EntrySwitchData*>();
     }
 
+    bool hasIntrinsic()
+    {
+        switch (op()) {
+        case CPUIntrinsic:
+        case DateGetTime:
+        case DateGetInt32OrNaN:
+            return true;
+        default:
+            return false;
+        }
+    }
+
     Intrinsic intrinsic()
     {
-        RELEASE_ASSERT(op() == CPUIntrinsic);
+        ASSERT(hasIntrinsic());
         return m_opInfo.as<Intrinsic>();
     }
     
@@ -1753,6 +1765,7 @@ public:
         case ToThis:
         case DataViewGetInt:
         case DataViewGetFloat:
+        case DateGetInt32OrNaN:
             return true;
         default:
             return false;
index 8ca3b79..2881f4c 100644 (file)
@@ -516,6 +516,9 @@ namespace JSC { namespace DFG {
     macro(DataViewGetInt, NodeMustGenerate | NodeResultJS) /* The gets are must generate for now because they do bounds checks */ \
     macro(DataViewGetFloat, NodeMustGenerate | NodeResultDouble) \
     macro(DataViewSet, NodeMustGenerate | NodeMustGenerate | NodeHasVarArgs) \
+    /* Date access */ \
+    macro(DateGetInt32OrNaN, NodeResultJS) \
+    macro(DateGetTime, NodeResultDouble) \
 
 
 // This enum generates a monotonically increasing id for all Node types,
index 70efd6b..4db4627 100644 (file)
@@ -38,6 +38,7 @@
 #include "DFGToFTLDeferredCompilationCallback.h"
 #include "DFGToFTLForOSREntryDeferredCompilationCallback.h"
 #include "DFGWorklist.h"
+#include "DateInstance.h"
 #include "DefinePropertyAttributes.h"
 #include "DirectArguments.h"
 #include "EvalCodeBlock.h"
@@ -3391,6 +3392,198 @@ EncodedJSValue JIT_OPERATION operationGetPrototypeOf(JSGlobalObject* globalObjec
     RELEASE_AND_RETURN(scope, JSValue::encode(thisObject->getPrototype(vm, globalObject)));
 }
 
+EncodedJSValue JIT_OPERATION operationDateGetFullYear(VM* vmPointer, DateInstance* date)
+{
+    VM& vm = *vmPointer;
+    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+
+    const GregorianDateTime* gregorianDateTime = date->gregorianDateTime(vm);
+    if (!gregorianDateTime)
+        return JSValue::encode(jsNaN());
+    return JSValue::encode(jsNumber(gregorianDateTime->year()));
+}
+
+EncodedJSValue JIT_OPERATION operationDateGetUTCFullYear(VM* vmPointer, DateInstance* date)
+{
+    VM& vm = *vmPointer;
+    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+
+    const GregorianDateTime* gregorianDateTime = date->gregorianDateTimeUTC(vm);
+    if (!gregorianDateTime)
+        return JSValue::encode(jsNaN());
+    return JSValue::encode(jsNumber(gregorianDateTime->year()));
+}
+
+EncodedJSValue JIT_OPERATION operationDateGetMonth(VM* vmPointer, DateInstance* date)
+{
+    VM& vm = *vmPointer;
+    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+
+    const GregorianDateTime* gregorianDateTime = date->gregorianDateTime(vm);
+    if (!gregorianDateTime)
+        return JSValue::encode(jsNaN());
+    return JSValue::encode(jsNumber(gregorianDateTime->month()));
+}
+
+EncodedJSValue JIT_OPERATION operationDateGetUTCMonth(VM* vmPointer, DateInstance* date)
+{
+    VM& vm = *vmPointer;
+    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+
+    const GregorianDateTime* gregorianDateTime = date->gregorianDateTimeUTC(vm);
+    if (!gregorianDateTime)
+        return JSValue::encode(jsNaN());
+    return JSValue::encode(jsNumber(gregorianDateTime->month()));
+}
+
+EncodedJSValue JIT_OPERATION operationDateGetDate(VM* vmPointer, DateInstance* date)
+{
+    VM& vm = *vmPointer;
+    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+
+    const GregorianDateTime* gregorianDateTime = date->gregorianDateTime(vm);
+    if (!gregorianDateTime)
+        return JSValue::encode(jsNaN());
+    return JSValue::encode(jsNumber(gregorianDateTime->monthDay()));
+}
+
+EncodedJSValue JIT_OPERATION operationDateGetUTCDate(VM* vmPointer, DateInstance* date)
+{
+    VM& vm = *vmPointer;
+    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+
+    const GregorianDateTime* gregorianDateTime = date->gregorianDateTimeUTC(vm);
+    if (!gregorianDateTime)
+        return JSValue::encode(jsNaN());
+    return JSValue::encode(jsNumber(gregorianDateTime->monthDay()));
+}
+
+EncodedJSValue JIT_OPERATION operationDateGetDay(VM* vmPointer, DateInstance* date)
+{
+    VM& vm = *vmPointer;
+    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+
+    const GregorianDateTime* gregorianDateTime = date->gregorianDateTime(vm);
+    if (!gregorianDateTime)
+        return JSValue::encode(jsNaN());
+    return JSValue::encode(jsNumber(gregorianDateTime->weekDay()));
+}
+
+EncodedJSValue JIT_OPERATION operationDateGetUTCDay(VM* vmPointer, DateInstance* date)
+{
+    VM& vm = *vmPointer;
+    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+
+    const GregorianDateTime* gregorianDateTime = date->gregorianDateTimeUTC(vm);
+    if (!gregorianDateTime)
+        return JSValue::encode(jsNaN());
+    return JSValue::encode(jsNumber(gregorianDateTime->weekDay()));
+}
+
+EncodedJSValue JIT_OPERATION operationDateGetHours(VM* vmPointer, DateInstance* date)
+{
+    VM& vm = *vmPointer;
+    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+
+    const GregorianDateTime* gregorianDateTime = date->gregorianDateTime(vm);
+    if (!gregorianDateTime)
+        return JSValue::encode(jsNaN());
+    return JSValue::encode(jsNumber(gregorianDateTime->hour()));
+}
+
+EncodedJSValue JIT_OPERATION operationDateGetUTCHours(VM* vmPointer, DateInstance* date)
+{
+    VM& vm = *vmPointer;
+    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+
+    const GregorianDateTime* gregorianDateTime = date->gregorianDateTimeUTC(vm);
+    if (!gregorianDateTime)
+        return JSValue::encode(jsNaN());
+    return JSValue::encode(jsNumber(gregorianDateTime->hour()));
+}
+
+EncodedJSValue JIT_OPERATION operationDateGetMinutes(VM* vmPointer, DateInstance* date)
+{
+    VM& vm = *vmPointer;
+    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+
+    const GregorianDateTime* gregorianDateTime = date->gregorianDateTime(vm);
+    if (!gregorianDateTime)
+        return JSValue::encode(jsNaN());
+    return JSValue::encode(jsNumber(gregorianDateTime->minute()));
+}
+
+EncodedJSValue JIT_OPERATION operationDateGetUTCMinutes(VM* vmPointer, DateInstance* date)
+{
+    VM& vm = *vmPointer;
+    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+
+    const GregorianDateTime* gregorianDateTime = date->gregorianDateTimeUTC(vm);
+    if (!gregorianDateTime)
+        return JSValue::encode(jsNaN());
+    return JSValue::encode(jsNumber(gregorianDateTime->minute()));
+}
+
+EncodedJSValue JIT_OPERATION operationDateGetSeconds(VM* vmPointer, DateInstance* date)
+{
+    VM& vm = *vmPointer;
+    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+
+    const GregorianDateTime* gregorianDateTime = date->gregorianDateTime(vm);
+    if (!gregorianDateTime)
+        return JSValue::encode(jsNaN());
+    return JSValue::encode(jsNumber(gregorianDateTime->second()));
+}
+
+EncodedJSValue JIT_OPERATION operationDateGetUTCSeconds(VM* vmPointer, DateInstance* date)
+{
+    VM& vm = *vmPointer;
+    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+
+    const GregorianDateTime* gregorianDateTime = date->gregorianDateTimeUTC(vm);
+    if (!gregorianDateTime)
+        return JSValue::encode(jsNaN());
+    return JSValue::encode(jsNumber(gregorianDateTime->second()));
+}
+
+EncodedJSValue JIT_OPERATION operationDateGetTimezoneOffset(VM* vmPointer, DateInstance* date)
+{
+    VM& vm = *vmPointer;
+    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+
+    const GregorianDateTime* gregorianDateTime = date->gregorianDateTime(vm);
+    if (!gregorianDateTime)
+        return JSValue::encode(jsNaN());
+    return JSValue::encode(jsNumber(-gregorianDateTime->utcOffsetInMinute()));
+}
+
+EncodedJSValue JIT_OPERATION operationDateGetYear(VM* vmPointer, DateInstance* date)
+{
+    VM& vm = *vmPointer;
+    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+
+    const GregorianDateTime* gregorianDateTime = date->gregorianDateTime(vm);
+    if (!gregorianDateTime)
+        return JSValue::encode(jsNaN());
+    return JSValue::encode(jsNumber(gregorianDateTime->year() - 1900));
+}
+
 void JIT_OPERATION operationThrowDFG(JSGlobalObject* globalObject, EncodedJSValue valueToThrow)
 {
     VM& vm = globalObject->vm();
index 2564d9f..274f8a5 100644 (file)
 #include "JITOperations.h"
 #include "TypedArrayType.h"
 
-namespace JSC { namespace DFG {
+namespace JSC {
+
+class DateInstance;
+
+namespace DFG {
 
 struct OSRExitBase;
 
@@ -294,6 +298,23 @@ JSCell* JIT_OPERATION operationNewObjectWithButterflyWithIndexingHeaderAndVector
 
 void JIT_OPERATION operationLinkDirectCall(CallLinkInfo*, JSFunction*) WTF_INTERNAL;
 
+EncodedJSValue JIT_OPERATION operationDateGetFullYear(VM*, DateInstance*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationDateGetUTCFullYear(VM*, DateInstance*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationDateGetMonth(VM*, DateInstance*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationDateGetUTCMonth(VM*, DateInstance*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationDateGetDate(VM*, DateInstance*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationDateGetUTCDate(VM*, DateInstance*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationDateGetDay(VM*, DateInstance*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationDateGetUTCDay(VM*, DateInstance*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationDateGetHours(VM*, DateInstance*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationDateGetUTCHours(VM*, DateInstance*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationDateGetMinutes(VM*, DateInstance*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationDateGetUTCMinutes(VM*, DateInstance*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationDateGetSeconds(VM*, DateInstance*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationDateGetUTCSeconds(VM*, DateInstance*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationDateGetTimezoneOffset(VM*, DateInstance*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationDateGetYear(VM*, DateInstance*) WTF_INTERNAL;
+
 void JIT_OPERATION operationProcessTypeProfilerLogDFG(VM*) WTF_INTERNAL;
 
 void JIT_OPERATION operationTriggerReoptimizationNow(CodeBlock* baselineCodeBlock, CodeBlock* optiimzedCodeBlock, OSRExitBase*) WTF_INTERNAL;
index e72aa5d..4a5cd95 100644 (file)
@@ -845,11 +845,17 @@ private:
         case GetPrototypeOf:
         case ExtractValueFromWeakMapGet: 
         case DataViewGetInt:
-        case DataViewGetFloat: {
+        case DataViewGetFloat:
+        case DateGetInt32OrNaN: {
             setPrediction(m_currentNode->getHeapPrediction());
             break;
         }
 
+        case DateGetTime: {
+            setPrediction(SpecFullNumber);
+            break;
+        }
+
         case WeakMapGet:
         case ResolveScopeForHoistingFuncDeclInEval: {
             setPrediction(SpecBytecodeTop);
index 46061c8..69c4173 100644 (file)
@@ -62,6 +62,7 @@ public:
         case PromiseObjectUse:
         case ProxyObjectUse:
         case DerivedArrayUse:
+        case DateObjectUse:
         case MapObjectUse:
         case SetObjectUse:
         case WeakMapObjectUse:
@@ -489,6 +490,8 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node, bool igno
     case AtomicsIsLockFree:
     case InitializeEntrypointArguments:
     case MatchStructure:
+    case DateGetInt32OrNaN:
+    case DateGetTime:
     case DataViewGetInt:
     case DataViewGetFloat:
         return true;
index 4741614..843c491 100644 (file)
@@ -39,6 +39,7 @@
 #include "DFGSaneStringGetByValSlowPathGenerator.h"
 #include "DFGSlowPathGenerator.h"
 #include "DFGSnippetParams.h"
+#include "DateInstance.h"
 #include "DirectArguments.h"
 #include "DisallowMacroScratchRegisterUsage.h"
 #include "JITAddGenerator.h"
@@ -10195,6 +10196,20 @@ void SpeculativeJIT::speculatePromiseObject(Edge edge)
     speculatePromiseObject(edge, operand.gpr());
 }
 
+void SpeculativeJIT::speculateDateObject(Edge edge, GPRReg cell)
+{
+    speculateCellType(edge, cell, SpecDateObject, JSDateType);
+}
+
+void SpeculativeJIT::speculateDateObject(Edge edge)
+{
+    if (!needsTypeCheck(edge, SpecDateObject))
+        return;
+
+    SpeculateCellOperand operand(this, edge);
+    speculateDateObject(edge, operand.gpr());
+}
+
 void SpeculativeJIT::speculateMapObject(Edge edge, GPRReg cell)
 {
     speculateCellType(edge, cell, SpecMapObject, JSMapType);
@@ -10600,6 +10615,9 @@ void SpeculativeJIT::speculate(Node*, Edge edge)
     case DerivedArrayUse:
         speculateDerivedArray(edge);
         break;
+    case DateObjectUse:
+        speculateDateObject(edge);
+        break;
     case MapObjectUse:
         speculateMapObject(edge);
         break;
index 1ba5211..1b20d94 100644 (file)
@@ -1489,6 +1489,7 @@ public:
     void compileClearCatchLocals(Node*);
     void compileProfileType(Node*);
     void compileStringCodePointAt(Node*);
+    void compileDateGet(Node*);
 
     template<typename JSClass, typename Operation>
     void compileCreateInternalFieldObject(Node*, Operation);
@@ -1616,6 +1617,8 @@ public:
     void speculateProxyObject(Edge);
     void speculateDerivedArray(Edge, GPRReg cell);
     void speculateDerivedArray(Edge);
+    void speculateDateObject(Edge);
+    void speculateDateObject(Edge, GPRReg cell);
     void speculateMapObject(Edge);
     void speculateMapObject(Edge, GPRReg cell);
     void speculateSetObject(Edge);
index 14f21c7..f6c6e2d 100644 (file)
@@ -4162,6 +4162,8 @@ void SpeculativeJIT::compile(Node* node)
     case DataViewGetInt:
     case DataViewGetFloat:
     case DataViewSet:
+    case DateGetInt32OrNaN:
+    case DateGetTime:
     case StringCodePointAt:
         DFG_CRASH(m_jit.graph(), node, "unexpected node in DFG backend");
         break;
index 142c7e0..2aa9356 100644 (file)
@@ -36,6 +36,7 @@
 #include "DFGDoesGC.h"
 #include "DFGOperations.h"
 #include "DFGSlowPathGenerator.h"
+#include "DateInstance.h"
 #include "DirectArguments.h"
 #include "GetterSetter.h"
 #include "HasOwnPropertyCache.h"
@@ -4874,6 +4875,11 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
 
+    case DateGetInt32OrNaN:
+    case DateGetTime:
+        compileDateGet(node);
+        break;
+
     case DataViewSet: {
         SpeculateCellOperand dataView(this, m_graph.varArgChild(node, 0));
         GPRReg dataViewGPR = dataView.gpr();
@@ -5348,6 +5354,143 @@ void SpeculativeJIT::compileStringCodePointAt(Node* node)
     int32Result(scratch1GPR, m_currentNode);
 }
 
+void SpeculativeJIT::compileDateGet(Node* node)
+{
+    SpeculateCellOperand base(this, node->child1());
+    GPRReg baseGPR = base.gpr();
+    speculateDateObject(node->child1(), baseGPR);
+
+    auto emitGetCodeWithCallback = [&] (ptrdiff_t cachedDoubleOffset, ptrdiff_t cachedDataOffset, auto* operation, auto callback) {
+        JSValueRegsTemporary result(this);
+        FPRTemporary temp1(this);
+        FPRTemporary temp2(this);
+
+        JSValueRegs resultRegs = result.regs();
+        FPRReg temp1FPR = temp1.fpr();
+        FPRReg temp2FPR = temp2.fpr();
+
+        CCallHelpers::JumpList slowCases;
+
+        m_jit.loadPtr(CCallHelpers::Address(baseGPR, DateInstance::offsetOfData()), resultRegs.payloadGPR());
+        slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, resultRegs.payloadGPR()));
+        m_jit.loadDouble(CCallHelpers::Address(baseGPR, DateInstance::offsetOfInternalNumber()), temp1FPR);
+        m_jit.loadDouble(CCallHelpers::Address(resultRegs.payloadGPR(), cachedDoubleOffset), temp2FPR);
+        slowCases.append(m_jit.branchDouble(CCallHelpers::DoubleNotEqualOrUnordered, temp1FPR, temp2FPR));
+        m_jit.load32(CCallHelpers::Address(resultRegs.payloadGPR(), cachedDataOffset), resultRegs.payloadGPR());
+        callback(resultRegs.payloadGPR());
+        m_jit.boxInt32(resultRegs.payloadGPR(), resultRegs);
+
+        addSlowPathGenerator(slowPathCall(slowCases, this, operation, resultRegs, &vm(), baseGPR));
+
+        jsValueResult(resultRegs, node);
+    };
+
+    auto emitGetCode = [&] (ptrdiff_t cachedDoubleOffset, ptrdiff_t cachedDataOffset, auto* operation) {
+        emitGetCodeWithCallback(cachedDoubleOffset, cachedDataOffset, operation, [] (GPRReg) { });
+    };
+
+    switch (node->intrinsic()) {
+    case DatePrototypeGetTimeIntrinsic: {
+        FPRTemporary result(this);
+        FPRReg resultFPR = result.fpr();
+        m_jit.loadDouble(CCallHelpers::Address(baseGPR, DateInstance::offsetOfInternalNumber()), resultFPR);
+        doubleResult(resultFPR, node);
+        break;
+    }
+
+    // We do not have any timezone offset which affects on milliseconds.
+    // So Date#getMilliseconds and Date#getUTCMilliseconds have the same implementation.
+    case DatePrototypeGetMillisecondsIntrinsic:
+    case DatePrototypeGetUTCMillisecondsIntrinsic: {
+        JSValueRegsTemporary result(this);
+        FPRTemporary temp1(this);
+        FPRTemporary temp2(this);
+        FPRTemporary temp3(this);
+        JSValueRegs resultRegs = result.regs();
+        FPRReg temp1FPR = temp1.fpr();
+        FPRReg temp2FPR = temp2.fpr();
+        FPRReg temp3FPR = temp3.fpr();
+
+        m_jit.moveTrustedValue(jsNaN(), resultRegs);
+        m_jit.loadDouble(CCallHelpers::Address(baseGPR, DateInstance::offsetOfInternalNumber()), temp1FPR);
+        auto isNaN = m_jit.branchIfNaN(temp1FPR);
+
+        static const double msPerSecondConstant = msPerSecond;
+        m_jit.loadDouble(TrustedImmPtr(&msPerSecondConstant), temp2FPR);
+        m_jit.divDouble(temp1FPR, temp2FPR, temp3FPR);
+        m_jit.floorDouble(temp3FPR, temp3FPR);
+        m_jit.mulDouble(temp3FPR, temp2FPR, temp3FPR);
+        m_jit.subDouble(temp1FPR, temp3FPR, temp1FPR);
+        m_jit.truncateDoubleToInt32(temp1FPR, resultRegs.payloadGPR());
+        m_jit.boxInt32(resultRegs.payloadGPR(), resultRegs);
+
+        isNaN.link(&m_jit);
+        jsValueResult(resultRegs, node);
+        break;
+    }
+
+    case DatePrototypeGetFullYearIntrinsic:
+        emitGetCode(DateInstanceData::offsetOfGregorianDateTimeCachedForMS(), DateInstanceData::offsetOfCachedGregorianDateTime() + GregorianDateTime::offsetOfYear(), operationDateGetFullYear);
+        break;
+    case DatePrototypeGetUTCFullYearIntrinsic:
+        emitGetCode(DateInstanceData::offsetOfGregorianDateTimeUTCCachedForMS(), DateInstanceData::offsetOfCachedGregorianDateTimeUTC() + GregorianDateTime::offsetOfYear(), operationDateGetUTCFullYear);
+        break;
+    case DatePrototypeGetMonthIntrinsic:
+        emitGetCode(DateInstanceData::offsetOfGregorianDateTimeCachedForMS(), DateInstanceData::offsetOfCachedGregorianDateTime() + GregorianDateTime::offsetOfMonth(), operationDateGetMonth);
+        break;
+    case DatePrototypeGetUTCMonthIntrinsic:
+        emitGetCode(DateInstanceData::offsetOfGregorianDateTimeUTCCachedForMS(), DateInstanceData::offsetOfCachedGregorianDateTimeUTC() + GregorianDateTime::offsetOfMonth(), operationDateGetUTCMonth);
+        break;
+    case DatePrototypeGetDateIntrinsic:
+        emitGetCode(DateInstanceData::offsetOfGregorianDateTimeCachedForMS(), DateInstanceData::offsetOfCachedGregorianDateTime() + GregorianDateTime::offsetOfMonthDay(), operationDateGetDate);
+        break;
+    case DatePrototypeGetUTCDateIntrinsic:
+        emitGetCode(DateInstanceData::offsetOfGregorianDateTimeUTCCachedForMS(), DateInstanceData::offsetOfCachedGregorianDateTimeUTC() + GregorianDateTime::offsetOfMonthDay(), operationDateGetUTCDate);
+        break;
+    case DatePrototypeGetDayIntrinsic:
+        emitGetCode(DateInstanceData::offsetOfGregorianDateTimeCachedForMS(), DateInstanceData::offsetOfCachedGregorianDateTime() + GregorianDateTime::offsetOfWeekDay(), operationDateGetDay);
+        break;
+    case DatePrototypeGetUTCDayIntrinsic:
+        emitGetCode(DateInstanceData::offsetOfGregorianDateTimeUTCCachedForMS(), DateInstanceData::offsetOfCachedGregorianDateTimeUTC() + GregorianDateTime::offsetOfWeekDay(), operationDateGetUTCDay);
+        break;
+    case DatePrototypeGetHoursIntrinsic:
+        emitGetCode(DateInstanceData::offsetOfGregorianDateTimeCachedForMS(), DateInstanceData::offsetOfCachedGregorianDateTime() + GregorianDateTime::offsetOfHour(), operationDateGetHours);
+        break;
+    case DatePrototypeGetUTCHoursIntrinsic:
+        emitGetCode(DateInstanceData::offsetOfGregorianDateTimeUTCCachedForMS(), DateInstanceData::offsetOfCachedGregorianDateTimeUTC() + GregorianDateTime::offsetOfHour(), operationDateGetUTCHours);
+        break;
+    case DatePrototypeGetMinutesIntrinsic:
+        emitGetCode(DateInstanceData::offsetOfGregorianDateTimeCachedForMS(), DateInstanceData::offsetOfCachedGregorianDateTime() + GregorianDateTime::offsetOfMinute(), operationDateGetMinutes);
+        break;
+    case DatePrototypeGetUTCMinutesIntrinsic:
+        emitGetCode(DateInstanceData::offsetOfGregorianDateTimeUTCCachedForMS(), DateInstanceData::offsetOfCachedGregorianDateTimeUTC() + GregorianDateTime::offsetOfMinute(), operationDateGetUTCMinutes);
+        break;
+    case DatePrototypeGetSecondsIntrinsic:
+        emitGetCode(DateInstanceData::offsetOfGregorianDateTimeCachedForMS(), DateInstanceData::offsetOfCachedGregorianDateTime() + GregorianDateTime::offsetOfSecond(), operationDateGetSeconds);
+        break;
+    case DatePrototypeGetUTCSecondsIntrinsic:
+        emitGetCode(DateInstanceData::offsetOfGregorianDateTimeUTCCachedForMS(), DateInstanceData::offsetOfCachedGregorianDateTimeUTC() + GregorianDateTime::offsetOfSecond(), operationDateGetUTCSeconds);
+        break;
+
+    case DatePrototypeGetTimezoneOffsetIntrinsic: {
+        emitGetCodeWithCallback(DateInstanceData::offsetOfGregorianDateTimeCachedForMS(), DateInstanceData::offsetOfCachedGregorianDateTime() + GregorianDateTime::offsetOfUTCOffsetInMinute(), operationDateGetTimezoneOffset, [&] (GPRReg offsetGPR) {
+            m_jit.neg32(offsetGPR);
+        });
+        break;
+    }
+
+    case DatePrototypeGetYearIntrinsic: {
+        emitGetCodeWithCallback(DateInstanceData::offsetOfGregorianDateTimeCachedForMS(), DateInstanceData::offsetOfCachedGregorianDateTime() + GregorianDateTime::offsetOfYear(), operationDateGetYear, [&] (GPRReg yearGPR) {
+            m_jit.sub32(TrustedImm32(1900), yearGPR);
+        });
+        break;
+    }
+
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+}
+
 #endif
 
 } } // namespace JSC::DFG
index 084b595..8ef73b6 100644 (file)
@@ -106,6 +106,9 @@ void printInternal(PrintStream& out, UseKind useKind)
     case DerivedArrayUse:
         out.print("DerivedArray");
         return;
+    case DateObjectUse:
+        out.print("DateObject");
+        return;
     case MapObjectUse:
         out.print("MapObject");
         return;
index 2ec4ea1..9c13c5b 100644 (file)
@@ -67,6 +67,7 @@ enum UseKind {
     KnownPrimitiveUse, // This bizarre type arises for op_strcat, which has a bytecode guarantee that it will only see primitives (i.e. not objects).
     SymbolUse,
     BigIntUse,
+    DateObjectUse,
     MapObjectUse,
     SetObjectUse,
     WeakMapObjectUse,
@@ -155,6 +156,8 @@ inline SpeculatedType typeFilterFor(UseKind useKind)
         return SpecBigInt;
     case PromiseObjectUse:
         return SpecPromiseObject;
+    case DateObjectUse:
+        return SpecDateObject;
     case MapObjectUse:
         return SpecMapObject;
     case SetObjectUse:
@@ -261,6 +264,7 @@ inline bool isCell(UseKind kind)
     case BigIntUse:
     case StringObjectUse:
     case StringOrStringObjectUse:
+    case DateObjectUse:
     case MapObjectUse:
     case SetObjectUse:
     case WeakMapObjectUse:
index 9c3c1c7..c45c9d1 100644 (file)
@@ -33,6 +33,7 @@
 #include "B3MemoryValue.h"
 #include "B3PatchpointValue.h"
 #include "B3ValueInlines.h"
+#include "DateInstance.h"
 #include "DirectArguments.h"
 #include "FTLState.h"
 #include "GetterSetter.h"
index 10369e4..5df43f7 100644 (file)
@@ -52,6 +52,26 @@ namespace JSC { namespace FTL {
     macro(Butterfly_vectorLength, Butterfly::offsetOfVectorLength()) \
     macro(CallFrame_callerFrame, CallFrame::callerFrameOffset()) \
     macro(ClassInfo_parentClass, ClassInfo::offsetOfParentClass()) \
+    macro(DateInstance_internalNumber, DateInstance::offsetOfInternalNumber()) \
+    macro(DateInstance_data, DateInstance::offsetOfData()) \
+    macro(DateInstanceData_gregorianDateTimeCachedForMS, DateInstanceData::offsetOfGregorianDateTimeCachedForMS()) \
+    macro(DateInstanceData_gregorianDateTimeUTCCachedForMS, DateInstanceData::offsetOfGregorianDateTimeUTCCachedForMS()) \
+    macro(DateInstanceData_cachedGregorianDateTime_year, DateInstanceData::offsetOfCachedGregorianDateTime() + GregorianDateTime::offsetOfYear()) \
+    macro(DateInstanceData_cachedGregorianDateTimeUTC_year, DateInstanceData::offsetOfCachedGregorianDateTimeUTC() + GregorianDateTime::offsetOfYear()) \
+    macro(DateInstanceData_cachedGregorianDateTime_month, DateInstanceData::offsetOfCachedGregorianDateTime() + GregorianDateTime::offsetOfMonth()) \
+    macro(DateInstanceData_cachedGregorianDateTimeUTC_month, DateInstanceData::offsetOfCachedGregorianDateTimeUTC() + GregorianDateTime::offsetOfMonth()) \
+    macro(DateInstanceData_cachedGregorianDateTime_monthDay, DateInstanceData::offsetOfCachedGregorianDateTime() + GregorianDateTime::offsetOfMonthDay()) \
+    macro(DateInstanceData_cachedGregorianDateTimeUTC_monthDay, DateInstanceData::offsetOfCachedGregorianDateTimeUTC() + GregorianDateTime::offsetOfMonthDay()) \
+    macro(DateInstanceData_cachedGregorianDateTime_weekDay, DateInstanceData::offsetOfCachedGregorianDateTime() + GregorianDateTime::offsetOfWeekDay()) \
+    macro(DateInstanceData_cachedGregorianDateTimeUTC_weekDay, DateInstanceData::offsetOfCachedGregorianDateTimeUTC() + GregorianDateTime::offsetOfWeekDay()) \
+    macro(DateInstanceData_cachedGregorianDateTime_hour, DateInstanceData::offsetOfCachedGregorianDateTime() + GregorianDateTime::offsetOfHour()) \
+    macro(DateInstanceData_cachedGregorianDateTimeUTC_hour, DateInstanceData::offsetOfCachedGregorianDateTimeUTC() + GregorianDateTime::offsetOfHour()) \
+    macro(DateInstanceData_cachedGregorianDateTime_minute, DateInstanceData::offsetOfCachedGregorianDateTime() + GregorianDateTime::offsetOfMinute()) \
+    macro(DateInstanceData_cachedGregorianDateTimeUTC_minute, DateInstanceData::offsetOfCachedGregorianDateTimeUTC() + GregorianDateTime::offsetOfMinute()) \
+    macro(DateInstanceData_cachedGregorianDateTime_second, DateInstanceData::offsetOfCachedGregorianDateTime() + GregorianDateTime::offsetOfSecond()) \
+    macro(DateInstanceData_cachedGregorianDateTimeUTC_second, DateInstanceData::offsetOfCachedGregorianDateTimeUTC() + GregorianDateTime::offsetOfSecond()) \
+    macro(DateInstanceData_cachedGregorianDateTime_utcOffsetInMinute, DateInstanceData::offsetOfCachedGregorianDateTime() + GregorianDateTime::offsetOfUTCOffsetInMinute()) \
+    macro(DateInstanceData_cachedGregorianDateTimeUTC_utcOffsetInMinute, DateInstanceData::offsetOfCachedGregorianDateTimeUTC() + GregorianDateTime::offsetOfUTCOffsetInMinute()) \
     macro(DirectArguments_callee, DirectArguments::offsetOfCallee()) \
     macro(DirectArguments_length, DirectArguments::offsetOfLength()) \
     macro(DirectArguments_minCapacity, DirectArguments::offsetOfMinCapacity()) \
index c61f9e6..30fc4d4 100644 (file)
@@ -388,6 +388,8 @@ inline CapabilityLevel canCompile(Node* node)
     case DataViewGetInt:
     case DataViewGetFloat:
     case DataViewSet:
+    case DateGetInt32OrNaN:
+    case DateGetTime:
         // These are OK.
         break;
 
@@ -470,6 +472,7 @@ CapabilityLevel canCompile(Graph& graph)
                 case StringOrStringObjectUse:
                 case SymbolUse:
                 case BigIntUse:
+                case DateObjectUse:
                 case MapObjectUse:
                 case SetObjectUse:
                 case WeakMapObjectUse:
index af0a8eb..5d48c0b 100644 (file)
@@ -1545,6 +1545,10 @@ private:
         case FilterInByIdStatus:
             compileFilterICStatus();
             break;
+        case DateGetInt32OrNaN:
+        case DateGetTime:
+            compileDateGet();
+            break;
         case DataViewGetInt:
         case DataViewGetFloat:
             compileDataViewGet();
@@ -13407,6 +13411,115 @@ private:
             }
         }
     }
+
+    void compileDateGet()
+    {
+        LValue base = lowDateObject(m_node->child1());
+
+        auto emitGetCodeWithCallback = [&] (const AbstractHeap& cachedDoubleOffset, const AbstractHeap& cachedDataOffset, auto* operation, auto callback) {
+            LBasicBlock dataExistsCase = m_out.newBlock();
+            LBasicBlock fastCase = m_out.newBlock();
+            LBasicBlock slowCase = m_out.newBlock();
+            LBasicBlock continuation = m_out.newBlock();
+
+            LValue data = m_out.loadPtr(base, m_heaps.DateInstance_data);
+            m_out.branch(m_out.notZero64(data), unsure(dataExistsCase), unsure(slowCase));
+
+            LBasicBlock lastNext = m_out.appendTo(dataExistsCase, fastCase);
+            LValue milliseconds = m_out.loadDouble(base, m_heaps.DateInstance_internalNumber);
+            LValue cachedMilliseconds = m_out.loadDouble(data, cachedDoubleOffset);
+            m_out.branch(m_out.doubleNotEqualOrUnordered(milliseconds, cachedMilliseconds), unsure(slowCase), unsure(fastCase));
+
+            m_out.appendTo(fastCase, slowCase);
+            ValueFromBlock fastResult = m_out.anchor(boxInt32(callback(m_out.load32(data, cachedDataOffset))));
+            m_out.jump(continuation);
+
+            m_out.appendTo(slowCase, continuation);
+            ValueFromBlock slowResult = m_out.anchor(vmCall(Int64, operation, m_vmValue, base));
+            m_out.jump(continuation);
+
+            m_out.appendTo(continuation, lastNext);
+            setJSValue(m_out.phi(Int64, fastResult, slowResult));
+        };
+
+        auto emitGetCode = [&] (const AbstractHeap& cachedDoubleOffset, const AbstractHeap& cachedDataOffset, auto* operation) {
+            emitGetCodeWithCallback(cachedDoubleOffset, cachedDataOffset, operation, [] (LValue value) { return value; });
+        };
+
+        switch (m_node->intrinsic()) {
+        case DatePrototypeGetTimeIntrinsic:
+            setDouble(m_out.loadDouble(base, m_heaps.DateInstance_internalNumber));
+            break;
+
+        case DatePrototypeGetMillisecondsIntrinsic:
+        case DatePrototypeGetUTCMillisecondsIntrinsic: {
+            LValue milliseconds = m_out.loadDouble(base, m_heaps.DateInstance_internalNumber);
+            LValue msPerSecondConstant = m_out.constDouble(msPerSecond);
+            LValue seconds = m_out.doubleFloor(m_out.doubleDiv(milliseconds, msPerSecondConstant));
+            LValue result = m_out.doubleToInt(m_out.doubleSub(milliseconds, m_out.doubleMul(seconds, msPerSecondConstant)));
+            setJSValue(m_out.select(m_out.doubleNotEqualOrUnordered(milliseconds, milliseconds), m_out.constInt64(JSValue::encode(jsNaN())), boxInt32(result)));
+            break;
+        }
+
+        case DatePrototypeGetFullYearIntrinsic:
+            emitGetCode(m_heaps.DateInstanceData_gregorianDateTimeCachedForMS, m_heaps.DateInstanceData_cachedGregorianDateTime_year, operationDateGetFullYear);
+            break;
+        case DatePrototypeGetUTCFullYearIntrinsic:
+            emitGetCode(m_heaps.DateInstanceData_gregorianDateTimeUTCCachedForMS, m_heaps.DateInstanceData_cachedGregorianDateTimeUTC_year, operationDateGetUTCFullYear);
+            break;
+        case DatePrototypeGetMonthIntrinsic:
+            emitGetCode(m_heaps.DateInstanceData_gregorianDateTimeCachedForMS, m_heaps.DateInstanceData_cachedGregorianDateTime_month, operationDateGetMonth);
+            break;
+        case DatePrototypeGetUTCMonthIntrinsic:
+            emitGetCode(m_heaps.DateInstanceData_gregorianDateTimeUTCCachedForMS, m_heaps.DateInstanceData_cachedGregorianDateTimeUTC_month, operationDateGetUTCMonth);
+            break;
+        case DatePrototypeGetDateIntrinsic:
+            emitGetCode(m_heaps.DateInstanceData_gregorianDateTimeCachedForMS, m_heaps.DateInstanceData_cachedGregorianDateTime_monthDay, operationDateGetDate);
+            break;
+        case DatePrototypeGetUTCDateIntrinsic:
+            emitGetCode(m_heaps.DateInstanceData_gregorianDateTimeUTCCachedForMS, m_heaps.DateInstanceData_cachedGregorianDateTimeUTC_monthDay, operationDateGetUTCDate);
+            break;
+        case DatePrototypeGetDayIntrinsic:
+            emitGetCode(m_heaps.DateInstanceData_gregorianDateTimeCachedForMS, m_heaps.DateInstanceData_cachedGregorianDateTime_weekDay, operationDateGetDay);
+            break;
+        case DatePrototypeGetUTCDayIntrinsic:
+            emitGetCode(m_heaps.DateInstanceData_gregorianDateTimeUTCCachedForMS, m_heaps.DateInstanceData_cachedGregorianDateTimeUTC_weekDay, operationDateGetUTCDay);
+            break;
+        case DatePrototypeGetHoursIntrinsic:
+            emitGetCode(m_heaps.DateInstanceData_gregorianDateTimeCachedForMS, m_heaps.DateInstanceData_cachedGregorianDateTime_hour, operationDateGetHours);
+            break;
+        case DatePrototypeGetUTCHoursIntrinsic:
+            emitGetCode(m_heaps.DateInstanceData_gregorianDateTimeUTCCachedForMS, m_heaps.DateInstanceData_cachedGregorianDateTimeUTC_hour, operationDateGetUTCHours);
+            break;
+        case DatePrototypeGetMinutesIntrinsic:
+            emitGetCode(m_heaps.DateInstanceData_gregorianDateTimeCachedForMS, m_heaps.DateInstanceData_cachedGregorianDateTime_minute, operationDateGetMinutes);
+            break;
+        case DatePrototypeGetUTCMinutesIntrinsic:
+            emitGetCode(m_heaps.DateInstanceData_gregorianDateTimeUTCCachedForMS, m_heaps.DateInstanceData_cachedGregorianDateTimeUTC_minute, operationDateGetUTCMinutes);
+            break;
+        case DatePrototypeGetSecondsIntrinsic:
+            emitGetCode(m_heaps.DateInstanceData_gregorianDateTimeCachedForMS, m_heaps.DateInstanceData_cachedGregorianDateTime_second, operationDateGetSeconds);
+            break;
+        case DatePrototypeGetUTCSecondsIntrinsic:
+            emitGetCode(m_heaps.DateInstanceData_gregorianDateTimeUTCCachedForMS, m_heaps.DateInstanceData_cachedGregorianDateTimeUTC_second, operationDateGetUTCSeconds);
+            break;
+
+        case DatePrototypeGetTimezoneOffsetIntrinsic:
+            emitGetCodeWithCallback(m_heaps.DateInstanceData_gregorianDateTimeCachedForMS, m_heaps.DateInstanceData_cachedGregorianDateTime_utcOffsetInMinute, operationDateGetTimezoneOffset, [&] (LValue offset) {
+                return m_out.neg(offset);
+            });
+            break;
+
+        case DatePrototypeGetYearIntrinsic:
+            emitGetCodeWithCallback(m_heaps.DateInstanceData_gregorianDateTimeCachedForMS, m_heaps.DateInstanceData_cachedGregorianDateTime_year, operationDateGetYear, [&] (LValue year) {
+                return m_out.sub(year, m_out.constInt32(1900));
+            });
+            break;
+
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+    }
     
     void emitSwitchForMultiByOffset(LValue base, bool structuresChecked, Vector<SwitchCase, 2>& cases, LBasicBlock exit)
     {
@@ -15756,6 +15869,13 @@ private:
         speculateDataViewObject(edge, result);
         return result;
     }
+
+    LValue lowDateObject(Edge edge)
+    {
+        LValue result = lowCell(edge);
+        speculateDateObject(edge, result);
+        return result;
+    }
     
     LValue lowString(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
     {
@@ -16240,6 +16360,9 @@ private:
         case DerivedArrayUse:
             speculateDerivedArray(edge);
             break;
+        case DateObjectUse:
+            speculateDateObject(edge);
+            break;
         case MapObjectUse:
             speculateMapObject(edge);
             break;
@@ -16766,6 +16889,17 @@ private:
         speculatePromiseObject(edge, lowCell(edge));
     }
 
+    void speculateDateObject(Edge edge, LValue cell)
+    {
+        FTL_TYPE_CHECK(
+            jsValueValue(cell), edge, SpecDateObject, isNotType(cell, JSDateType));
+    }
+
+    void speculateDateObject(Edge edge)
+    {
+        speculateDateObject(edge, lowCell(edge));
+    }
+
     void speculateMapObject(Edge edge, LValue cell)
     {
         FTL_TYPE_CHECK(
index ae9f4e0..5b2aa1a 100644 (file)
@@ -97,8 +97,8 @@ String formatDateTime(const GregorianDateTime& t, DateTimeFormat format, bool as
         builder.appendLiteral(" GMT");
 
         if (!asUTCVariant) {
-            int offset = abs(t.utcOffset()) / 60;
-            builder.append(t.utcOffset() < 0 ? '-' : '+');
+            int offset = abs(t.utcOffsetInMinute());
+            builder.append(t.utcOffsetInMinute() < 0 ? '-' : '+');
             appendNumber<2>(builder, offset / 60);
             appendNumber<2>(builder, offset % 60);
 
index 7b4e45c..8f5c2ed 100644 (file)
@@ -57,13 +57,12 @@ void DateInstance::destroy(JSCell* cell)
     static_cast<DateInstance*>(cell)->DateInstance::~DateInstance();
 }
 
-const GregorianDateTime* DateInstance::calculateGregorianDateTime(JSGlobalObject* globalObject) const
+const GregorianDateTime* DateInstance::calculateGregorianDateTime(VM& vm) const
 {
     double milli = internalNumber();
     if (std::isnan(milli))
-        return 0;
+        return nullptr;
 
-    VM& vm = globalObject->vm();
     if (!m_data)
         m_data = vm.dateInstanceCache.add(milli);
 
@@ -74,13 +73,12 @@ const GregorianDateTime* DateInstance::calculateGregorianDateTime(JSGlobalObject
     return &m_data->m_cachedGregorianDateTime;
 }
 
-const GregorianDateTime* DateInstance::calculateGregorianDateTimeUTC(JSGlobalObject* globalObject) const
+const GregorianDateTime* DateInstance::calculateGregorianDateTimeUTC(VM& vm) const
 {
     double milli = internalNumber();
     if (std::isnan(milli))
-        return 0;
+        return nullptr;
 
-    VM& vm = globalObject->vm();
     if (!m_data)
         m_data = vm.dateInstanceCache.add(milli);
 
index 3578ab8..9e77839 100644 (file)
@@ -54,28 +54,31 @@ public:
 
     DECLARE_EXPORT_INFO;
 
-    const GregorianDateTime* gregorianDateTime(JSGlobalObject* globalObject) const
+    const GregorianDateTime* gregorianDateTime(VM& vm) const
     {
         if (m_data && m_data->m_gregorianDateTimeCachedForMS == internalNumber())
             return &m_data->m_cachedGregorianDateTime;
-        return calculateGregorianDateTime(globalObject);
+        return calculateGregorianDateTime(vm);
     }
 
-    const GregorianDateTime* gregorianDateTimeUTC(JSGlobalObject* globalObject) const
+    const GregorianDateTime* gregorianDateTimeUTC(VM& vm) const
     {
         if (m_data && m_data->m_gregorianDateTimeUTCCachedForMS == internalNumber())
             return &m_data->m_cachedGregorianDateTimeUTC;
-        return calculateGregorianDateTimeUTC(globalObject);
+        return calculateGregorianDateTimeUTC(vm);
     }
 
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     {
-        return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+        return Structure::create(vm, globalObject, prototype, TypeInfo(JSDateType, StructureFlags), info());
     }
 
+    static ptrdiff_t offsetOfInternalNumber() { return OBJECT_OFFSETOF(DateInstance, m_internalNumber); }
+    static ptrdiff_t offsetOfData() { return OBJECT_OFFSETOF(DateInstance, m_data); }
+
 private:
-    JS_EXPORT_PRIVATE const GregorianDateTime* calculateGregorianDateTime(JSGlobalObject*) const;
-    JS_EXPORT_PRIVATE const GregorianDateTime* calculateGregorianDateTimeUTC(JSGlobalObject*) const;
+    JS_EXPORT_PRIVATE const GregorianDateTime* calculateGregorianDateTime(VM&) const;
+    JS_EXPORT_PRIVATE const GregorianDateTime* calculateGregorianDateTimeUTC(VM&) const;
 
     double m_internalNumber { PNaN };
     mutable RefPtr<DateInstanceData> m_data;
index 75640eb..2c4fb52 100644 (file)
@@ -37,17 +37,18 @@ class DateInstanceData : public RefCounted<DateInstanceData> {
 public:
     static Ref<DateInstanceData> create() { return adoptRef(*new DateInstanceData); }
 
-    double m_gregorianDateTimeCachedForMS;
+    static ptrdiff_t offsetOfGregorianDateTimeCachedForMS() { return OBJECT_OFFSETOF(DateInstanceData, m_gregorianDateTimeCachedForMS); }
+    static ptrdiff_t offsetOfCachedGregorianDateTime() { return OBJECT_OFFSETOF(DateInstanceData, m_cachedGregorianDateTime); }
+    static ptrdiff_t offsetOfGregorianDateTimeUTCCachedForMS() { return OBJECT_OFFSETOF(DateInstanceData, m_gregorianDateTimeUTCCachedForMS); }
+    static ptrdiff_t offsetOfCachedGregorianDateTimeUTC() { return OBJECT_OFFSETOF(DateInstanceData, m_cachedGregorianDateTimeUTC); }
+
+    double m_gregorianDateTimeCachedForMS { PNaN };
     GregorianDateTime m_cachedGregorianDateTime;
-    double m_gregorianDateTimeUTCCachedForMS;
+    double m_gregorianDateTimeUTCCachedForMS { PNaN };
     GregorianDateTime m_cachedGregorianDateTimeUTC;
 
 private:
-    DateInstanceData()
-        : m_gregorianDateTimeCachedForMS(PNaN)
-        , m_gregorianDateTimeUTCCachedForMS(PNaN)
-    {
-    }
+    DateInstanceData() = default;
 };
 
 class DateInstanceCache {
index 239e932..2aff0f7 100644 (file)
@@ -313,7 +313,7 @@ static JSCell* formatLocaleDate(JSGlobalObject* globalObject, CallFrame* callFra
 static JSCell* formatLocaleDate(JSGlobalObject* globalObject, CallFrame* callFrame, DateInstance* dateObject, double, LocaleDateTimeFormat format)
 {
     VM& vm = globalObject->vm();
-    const GregorianDateTime* gregorianDateTime = dateObject->gregorianDateTime(globalObject);
+    const GregorianDateTime* gregorianDateTime = dateObject->gregorianDateTime(vm);
     if (!gregorianDateTime)
         return jsNontrivialString(vm, "Invalid Date"_s);
     return formatLocaleDate(globalObject, callFrame, *gregorianDateTime, format);
@@ -331,8 +331,8 @@ static EncodedJSValue formateDateInstance(JSGlobalObject* globalObject, CallFram
         return throwVMTypeError(globalObject, scope);
 
     const GregorianDateTime* gregorianDateTime = asUTCVariant
-        ? thisDateObj->gregorianDateTimeUTC(globalObject)
-        : thisDateObj->gregorianDateTime(globalObject);
+        ? thisDateObj->gregorianDateTimeUTC(vm)
+        : thisDateObj->gregorianDateTime(vm);
     if (!gregorianDateTime)
         return JSValue::encode(jsNontrivialString(vm, String("Invalid Date"_s)));
 
@@ -454,25 +454,26 @@ const ClassInfo DatePrototype::s_info = {"Object", &JSNonFinalObject::s_info, &d
   toLocaleString        dateProtoFuncToLocaleString          DontEnum|Function       0
   toLocaleDateString    dateProtoFuncToLocaleDateString      DontEnum|Function       0
   toLocaleTimeString    dateProtoFuncToLocaleTimeString      DontEnum|Function       0
-  valueOf               dateProtoFuncGetTime                 DontEnum|Function       0
-  getTime               dateProtoFuncGetTime                 DontEnum|Function       0
-  getFullYear           dateProtoFuncGetFullYear             DontEnum|Function       0
-  getUTCFullYear        dateProtoFuncGetUTCFullYear          DontEnum|Function       0
-  getMonth              dateProtoFuncGetMonth                DontEnum|Function       0
-  getUTCMonth           dateProtoFuncGetUTCMonth             DontEnum|Function       0
-  getDate               dateProtoFuncGetDate                 DontEnum|Function       0
-  getUTCDate            dateProtoFuncGetUTCDate              DontEnum|Function       0
-  getDay                dateProtoFuncGetDay                  DontEnum|Function       0
-  getUTCDay             dateProtoFuncGetUTCDay               DontEnum|Function       0
-  getHours              dateProtoFuncGetHours                DontEnum|Function       0
-  getUTCHours           dateProtoFuncGetUTCHours             DontEnum|Function       0
-  getMinutes            dateProtoFuncGetMinutes              DontEnum|Function       0
-  getUTCMinutes         dateProtoFuncGetUTCMinutes           DontEnum|Function       0
-  getSeconds            dateProtoFuncGetSeconds              DontEnum|Function       0
-  getUTCSeconds         dateProtoFuncGetUTCSeconds           DontEnum|Function       0
-  getMilliseconds       dateProtoFuncGetMilliSeconds         DontEnum|Function       0
-  getUTCMilliseconds    dateProtoFuncGetUTCMilliseconds      DontEnum|Function       0
-  getTimezoneOffset     dateProtoFuncGetTimezoneOffset       DontEnum|Function       0
+  valueOf               dateProtoFuncGetTime                 DontEnum|Function       0  DatePrototypeGetTimeIntrinsic
+  getTime               dateProtoFuncGetTime                 DontEnum|Function       0  DatePrototypeGetTimeIntrinsic
+  getFullYear           dateProtoFuncGetFullYear             DontEnum|Function       0  DatePrototypeGetFullYearIntrinsic
+  getUTCFullYear        dateProtoFuncGetUTCFullYear          DontEnum|Function       0  DatePrototypeGetUTCFullYearIntrinsic
+  getMonth              dateProtoFuncGetMonth                DontEnum|Function       0  DatePrototypeGetMonthIntrinsic
+  getUTCMonth           dateProtoFuncGetUTCMonth             DontEnum|Function       0  DatePrototypeGetUTCMonthIntrinsic
+  getDate               dateProtoFuncGetDate                 DontEnum|Function       0  DatePrototypeGetDateIntrinsic
+  getUTCDate            dateProtoFuncGetUTCDate              DontEnum|Function       0  DatePrototypeGetUTCDateIntrinsic
+  getDay                dateProtoFuncGetDay                  DontEnum|Function       0  DatePrototypeGetDayIntrinsic
+  getUTCDay             dateProtoFuncGetUTCDay               DontEnum|Function       0  DatePrototypeGetUTCDayIntrinsic
+  getHours              dateProtoFuncGetHours                DontEnum|Function       0  DatePrototypeGetHoursIntrinsic
+  getUTCHours           dateProtoFuncGetUTCHours             DontEnum|Function       0  DatePrototypeGetUTCHoursIntrinsic
+  getMinutes            dateProtoFuncGetMinutes              DontEnum|Function       0  DatePrototypeGetMinutesIntrinsic
+  getUTCMinutes         dateProtoFuncGetUTCMinutes           DontEnum|Function       0  DatePrototypeGetUTCMinutesIntrinsic
+  getSeconds            dateProtoFuncGetSeconds              DontEnum|Function       0  DatePrototypeGetSecondsIntrinsic
+  getUTCSeconds         dateProtoFuncGetUTCSeconds           DontEnum|Function       0  DatePrototypeGetUTCSecondsIntrinsic
+  getMilliseconds       dateProtoFuncGetMilliSeconds         DontEnum|Function       0  DatePrototypeGetMillisecondsIntrinsic
+  getUTCMilliseconds    dateProtoFuncGetUTCMilliseconds      DontEnum|Function       0  DatePrototypeGetUTCMillisecondsIntrinsic
+  getTimezoneOffset     dateProtoFuncGetTimezoneOffset       DontEnum|Function       0  DatePrototypeGetTimezoneOffsetIntrinsic
+  getYear               dateProtoFuncGetYear                 DontEnum|Function       0  DatePrototypeGetYearIntrinsic
   setTime               dateProtoFuncSetTime                 DontEnum|Function       1
   setMilliseconds       dateProtoFuncSetMilliSeconds         DontEnum|Function       1
   setUTCMilliseconds    dateProtoFuncSetUTCMilliseconds      DontEnum|Function       1
@@ -489,7 +490,6 @@ const ClassInfo DatePrototype::s_info = {"Object", &JSNonFinalObject::s_info, &d
   setFullYear           dateProtoFuncSetFullYear             DontEnum|Function       3
   setUTCFullYear        dateProtoFuncSetUTCFullYear          DontEnum|Function       3
   setYear               dateProtoFuncSetYear                 DontEnum|Function       1
-  getYear               dateProtoFuncGetYear                 DontEnum|Function       0
   toJSON                dateProtoFuncToJSON                  DontEnum|Function       1
 @end
 */
@@ -549,7 +549,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(JSGlobalObject* globalObje
     if (!std::isfinite(thisDateObj->internalNumber()))
         return throwVMError(globalObject, scope, createRangeError(globalObject, "Invalid Date"_s));
 
-    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(globalObject);
+    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(vm);
     if (!gregorianDateTime)
         return JSValue::encode(jsNontrivialString(vm, String("Invalid Date"_s)));
     // Maximum amount of space we need in buffer: 7 (max. digits in year) + 2 * 5 (2 characters each for month, day, hour, minute, second) + 4 (. + 3 digits for milliseconds)
@@ -664,7 +664,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(JSGlobalObject* globalObje
     if (UNLIKELY(!thisDateObj))
         return throwVMTypeError(globalObject, scope);
 
-    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(globalObject);
+    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(vm);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
     return JSValue::encode(jsNumber(gregorianDateTime->year()));
@@ -679,7 +679,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(JSGlobalObject* globalO
     if (UNLIKELY(!thisDateObj))
         return throwVMTypeError(globalObject, scope);
 
-    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(globalObject);
+    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(vm);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
     return JSValue::encode(jsNumber(gregorianDateTime->year()));
@@ -694,7 +694,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(JSGlobalObject* globalObject,
     if (UNLIKELY(!thisDateObj))
         return throwVMTypeError(globalObject, scope);
 
-    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(globalObject);
+    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(vm);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
     return JSValue::encode(jsNumber(gregorianDateTime->month()));
@@ -709,7 +709,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(JSGlobalObject* globalObje
     if (UNLIKELY(!thisDateObj))
         return throwVMTypeError(globalObject, scope);
 
-    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(globalObject);
+    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(vm);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
     return JSValue::encode(jsNumber(gregorianDateTime->month()));
@@ -724,7 +724,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(JSGlobalObject* globalObject,
     if (UNLIKELY(!thisDateObj))
         return throwVMTypeError(globalObject, scope);
 
-    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(globalObject);
+    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(vm);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
     return JSValue::encode(jsNumber(gregorianDateTime->monthDay()));
@@ -739,7 +739,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(JSGlobalObject* globalObjec
     if (UNLIKELY(!thisDateObj))
         return throwVMTypeError(globalObject, scope);
 
-    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(globalObject);
+    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(vm);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
     return JSValue::encode(jsNumber(gregorianDateTime->monthDay()));
@@ -754,7 +754,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(JSGlobalObject* globalObject, C
     if (UNLIKELY(!thisDateObj))
         return throwVMTypeError(globalObject, scope);
 
-    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(globalObject);
+    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(vm);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
     return JSValue::encode(jsNumber(gregorianDateTime->weekDay()));
@@ -769,7 +769,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(JSGlobalObject* globalObject
     if (UNLIKELY(!thisDateObj))
         return throwVMTypeError(globalObject, scope);
 
-    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(globalObject);
+    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(vm);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
     return JSValue::encode(jsNumber(gregorianDateTime->weekDay()));
@@ -784,7 +784,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(JSGlobalObject* globalObject,
     if (UNLIKELY(!thisDateObj))
         return throwVMTypeError(globalObject, scope);
 
-    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(globalObject);
+    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(vm);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
     return JSValue::encode(jsNumber(gregorianDateTime->hour()));
@@ -799,7 +799,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(JSGlobalObject* globalObje
     if (UNLIKELY(!thisDateObj))
         return throwVMTypeError(globalObject, scope);
 
-    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(globalObject);
+    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(vm);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
     return JSValue::encode(jsNumber(gregorianDateTime->hour()));
@@ -814,7 +814,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(JSGlobalObject* globalObjec
     if (UNLIKELY(!thisDateObj))
         return throwVMTypeError(globalObject, scope);
 
-    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(globalObject);
+    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(vm);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
     return JSValue::encode(jsNumber(gregorianDateTime->minute()));
@@ -829,7 +829,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(JSGlobalObject* globalOb
     if (UNLIKELY(!thisDateObj))
         return throwVMTypeError(globalObject, scope);
 
-    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(globalObject);
+    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(vm);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
     return JSValue::encode(jsNumber(gregorianDateTime->minute()));
@@ -844,7 +844,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(JSGlobalObject* globalObjec
     if (UNLIKELY(!thisDateObj))
         return throwVMTypeError(globalObject, scope);
 
-    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(globalObject);
+    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(vm);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
     return JSValue::encode(jsNumber(gregorianDateTime->second()));
@@ -859,7 +859,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(JSGlobalObject* globalOb
     if (UNLIKELY(!thisDateObj))
         return throwVMTypeError(globalObject, scope);
 
-    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(globalObject);
+    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(vm);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
     return JSValue::encode(jsNumber(gregorianDateTime->second()));
@@ -880,7 +880,8 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(JSGlobalObject* global
 
     double secs = floor(milli / msPerSecond);
     double ms = milli - secs * msPerSecond;
-    return JSValue::encode(jsNumber(ms));
+    // Since timeClip makes internalNumber integer milliseconds, this result is always int32_t.
+    return JSValue::encode(jsNumber(static_cast<int32_t>(ms)));
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(JSGlobalObject* globalObject, CallFrame* callFrame)
@@ -898,7 +899,8 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(JSGlobalObject* glo
 
     double secs = floor(milli / msPerSecond);
     double ms = milli - secs * msPerSecond;
-    return JSValue::encode(jsNumber(ms));
+    // Since timeClip makes internalNumber integer milliseconds, this result is always int32_t.
+    return JSValue::encode(jsNumber(static_cast<int32_t>(ms)));
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(JSGlobalObject* globalObject, CallFrame* callFrame)
@@ -910,10 +912,10 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(JSGlobalObject* glob
     if (UNLIKELY(!thisDateObj))
         return throwVMTypeError(globalObject, scope);
 
-    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(globalObject);
+    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(vm);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
-    return JSValue::encode(jsNumber(-gregorianDateTime->utcOffset() / minutesPerHour));
+    return JSValue::encode(jsNumber(-gregorianDateTime->utcOffsetInMinute()));
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(JSGlobalObject* globalObject, CallFrame* callFrame)
@@ -951,13 +953,12 @@ static EncodedJSValue setNewValueFromTimeArgs(JSGlobalObject* globalObject, Call
     double ms = milli - secs * msPerSecond;
 
     const GregorianDateTime* other = inputTimeType == WTF::UTCTime
-        ? thisDateObj->gregorianDateTimeUTC(globalObject)
-        : thisDateObj->gregorianDateTime(globalObject);
+        ? thisDateObj->gregorianDateTimeUTC(vm)
+        : thisDateObj->gregorianDateTime(vm);
     if (!other)
         return JSValue::encode(jsNaN());
 
-    GregorianDateTime gregorianDateTime;
-    gregorianDateTime.copyFrom(*other);
+    GregorianDateTime gregorianDateTime(*other);
     bool success = fillStructuresUsingTimeArgs(globalObject, callFrame, numArgsToUse, &ms, &gregorianDateTime);
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
     if (!success) {
@@ -994,11 +995,11 @@ static EncodedJSValue setNewValueFromDateArgs(JSGlobalObject* globalObject, Call
     else { 
         ms = milli - floor(milli / msPerSecond) * msPerSecond; 
         const GregorianDateTime* other = inputTimeType == WTF::UTCTime
-            ? thisDateObj->gregorianDateTimeUTC(globalObject)
-            : thisDateObj->gregorianDateTime(globalObject);
+            ? thisDateObj->gregorianDateTimeUTC(vm)
+            : thisDateObj->gregorianDateTime(vm);
         if (!other)
             return JSValue::encode(jsNaN());
-        gregorianDateTime.copyFrom(*other);
+        gregorianDateTime = *other;
     }
     
     bool success = fillStructuresUsingDateArgs(globalObject, callFrame, numArgsToUse, &ms, &gregorianDateTime);
@@ -1109,8 +1110,8 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(JSGlobalObject* globalObject,
     else {
         double secs = floor(milli / msPerSecond);
         ms = milli - secs * msPerSecond;
-        if (const GregorianDateTime* other = thisDateObj->gregorianDateTime(globalObject))
-            gregorianDateTime.copyFrom(*other);
+        if (const GregorianDateTime* other = thisDateObj->gregorianDateTime(vm))
+            gregorianDateTime = *other;
     }
 
     double year = callFrame->argument(0).toIntegerPreserveNaN(globalObject);
@@ -1136,7 +1137,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(JSGlobalObject* globalObject,
     if (UNLIKELY(!thisDateObj))
         return throwVMTypeError(globalObject, scope);
 
-    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(globalObject);
+    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(vm);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
 
index a12a240..a41b57b 100644 (file)
@@ -83,6 +83,44 @@ const char* intrinsicName(Intrinsic intrinsic)
         return "CharCodeAtIntrinsic";
     case CharAtIntrinsic:
         return "CharAtIntrinsic";
+    case DatePrototypeGetTimeIntrinsic:
+        return "DatePrototypeGetTimeIntrinsic";
+    case DatePrototypeGetFullYearIntrinsic:
+        return "DatePrototypeGetFullYearIntrinsic";
+    case DatePrototypeGetUTCFullYearIntrinsic:
+        return "DatePrototypeGetUTCFullYearIntrinsic";
+    case DatePrototypeGetMonthIntrinsic:
+        return "DatePrototypeGetMonthIntrinsic";
+    case DatePrototypeGetUTCMonthIntrinsic:
+        return "DatePrototypeGetUTCMonthIntrinsic";
+    case DatePrototypeGetDateIntrinsic:
+        return "DatePrototypeGetDateIntrinsic";
+    case DatePrototypeGetUTCDateIntrinsic:
+        return "DatePrototypeGetUTCDateIntrinsic";
+    case DatePrototypeGetDayIntrinsic:
+        return "DatePrototypeGetDayIntrinsic";
+    case DatePrototypeGetUTCDayIntrinsic:
+        return "DatePrototypeGetUTCDayIntrinsic";
+    case DatePrototypeGetHoursIntrinsic:
+        return "DatePrototypeGetHoursIntrinsic";
+    case DatePrototypeGetUTCHoursIntrinsic:
+        return "DatePrototypeGetUTCHoursIntrinsic";
+    case DatePrototypeGetMinutesIntrinsic:
+        return "DatePrototypeGetMinutesIntrinsic";
+    case DatePrototypeGetUTCMinutesIntrinsic:
+        return "DatePrototypeGetUTCMinutesIntrinsic";
+    case DatePrototypeGetSecondsIntrinsic:
+        return "DatePrototypeGetSecondsIntrinsic";
+    case DatePrototypeGetUTCSecondsIntrinsic:
+        return "DatePrototypeGetUTCSecondsIntrinsic";
+    case DatePrototypeGetMillisecondsIntrinsic:
+        return "DatePrototypeGetMillisecondsIntrinsic";
+    case DatePrototypeGetUTCMillisecondsIntrinsic:
+        return "DatePrototypeGetUTCMillisecondsIntrinsic";
+    case DatePrototypeGetTimezoneOffsetIntrinsic:
+        return "DatePrototypeGetTimezoneOffsetIntrinsic";
+    case DatePrototypeGetYearIntrinsic:
+        return "DatePrototypeGetYearIntrinsic";
     case FromCharCodeIntrinsic:
         return "FromCharCodeIntrinsic";
     case PowIntrinsic:
index e51b839..fe2e910 100644 (file)
@@ -54,6 +54,25 @@ enum Intrinsic : uint8_t {
     ArrayIndexOfIntrinsic,
     CharCodeAtIntrinsic,
     CharAtIntrinsic,
+    DatePrototypeGetTimeIntrinsic,
+    DatePrototypeGetFullYearIntrinsic,
+    DatePrototypeGetUTCFullYearIntrinsic,
+    DatePrototypeGetMonthIntrinsic,
+    DatePrototypeGetUTCMonthIntrinsic,
+    DatePrototypeGetDateIntrinsic,
+    DatePrototypeGetUTCDateIntrinsic,
+    DatePrototypeGetDayIntrinsic,
+    DatePrototypeGetUTCDayIntrinsic,
+    DatePrototypeGetHoursIntrinsic,
+    DatePrototypeGetUTCHoursIntrinsic,
+    DatePrototypeGetMinutesIntrinsic,
+    DatePrototypeGetUTCMinutesIntrinsic,
+    DatePrototypeGetSecondsIntrinsic,
+    DatePrototypeGetUTCSecondsIntrinsic,
+    DatePrototypeGetMillisecondsIntrinsic,
+    DatePrototypeGetUTCMillisecondsIntrinsic,
+    DatePrototypeGetTimezoneOffsetIntrinsic,
+    DatePrototypeGetYearIntrinsic,
     FromCharCodeIntrinsic,
     PowIntrinsic,
     FloorIntrinsic,
index 7996a8f..6c8b379 100644 (file)
@@ -219,7 +219,7 @@ void msToGregorianDateTime(VM& vm, double ms, WTF::TimeType outputTimeType, Greg
     tm.setMonth(monthFromDayInYear(tm.yearDay(), isLeapYear(year)));
     tm.setYear(year);
     tm.setIsDST(localTime.isDST);
-    tm.setUtcOffset(localTime.offset / WTF::msPerSecond);
+    tm.setUTCOffsetInMinute(localTime.offset / WTF::msPerMinute);
 }
 
 double parseDateFromNullTerminatedCharacters(VM& vm, const char* dateString)
index d1c673e..16dc9b9 100644 (file)
@@ -96,6 +96,7 @@ void printInternal(PrintStream& out, JSC::JSType type)
     CASE(WithScopeType)
     CASE(ModuleNamespaceObjectType)
     CASE(RegExpObjectType)
+    CASE(JSDateType)
     CASE(ProxyObjectType)
     CASE(JSGeneratorType)
     CASE(JSAsyncGeneratorType)
index 6e99687..80bd34c 100644 (file)
@@ -107,6 +107,7 @@ enum JSType : uint8_t {
 
     ModuleNamespaceObjectType,
     RegExpObjectType,
+    JSDateType,
     ProxyObjectType,
     JSGeneratorType,
     JSAsyncGeneratorType,
index 0c95598..8321dbd 100644 (file)
@@ -1,3 +1,15 @@
+2019-10-30  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] Date functions should have intrinsic
+        https://bugs.webkit.org/show_bug.cgi?id=202187
+
+        Reviewed by Keith Miller.
+
+        * wtf/DateMath.h:
+        * wtf/GregorianDateTime.cpp:
+        (WTF::GregorianDateTime::setToCurrentLocalTime):
+        * wtf/GregorianDateTime.h:
+
 2019-10-30  Per Arne Vollan  <pvollan@apple.com>
 
         It should be possible to create a mach sandbox extension for the WebContent process before the audit token is known
index f9e2811..7e2d1de 100644 (file)
@@ -106,16 +106,16 @@ const char* const weekdayName[7] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "
 const char* const monthName[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
 const char* const monthFullName[12] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
 
-const double hoursPerDay = 24.0;
-const double minutesPerHour = 60.0;
-const double secondsPerMinute = 60.0;
-const double msPerSecond = 1000.0;
-const double msPerMonth = 2592000000.0;
-const double secondsPerHour = secondsPerMinute * minutesPerHour;
-const double secondsPerDay = secondsPerHour * hoursPerDay;
-const double msPerMinute = msPerSecond * secondsPerMinute;
-const double msPerHour = msPerSecond * secondsPerHour;
-const double msPerDay = msPerSecond * secondsPerDay;
+static constexpr double hoursPerDay = 24.0;
+static constexpr double minutesPerHour = 60.0;
+static constexpr double secondsPerMinute = 60.0;
+static constexpr double msPerSecond = 1000.0;
+static constexpr double msPerMonth = 2592000000.0;
+static constexpr double secondsPerHour = secondsPerMinute * minutesPerHour;
+static constexpr double secondsPerDay = secondsPerHour * hoursPerDay;
+static constexpr double msPerMinute = msPerSecond * secondsPerMinute;
+static constexpr double msPerHour = msPerSecond * secondsPerHour;
+static constexpr double msPerDay = msPerSecond * secondsPerDay;
 
 WTF_EXPORT_PRIVATE bool isLeapYear(int year);
 
index a3c44b9..3214887 100644 (file)
@@ -62,7 +62,7 @@ void GregorianDateTime::setToCurrentLocalTime()
     m_hour = systemTime.wHour;
     m_minute = systemTime.wMinute;
     m_second = systemTime.wSecond;
-    m_utcOffset = -bias * secondsPerMinute;
+    m_utcOffsetInMinute = -bias;
     m_isDST = timeZoneId == TIME_ZONE_ID_DAYLIGHT ? 1 : 0;
 #else
     tm localTM;
@@ -83,9 +83,9 @@ void GregorianDateTime::setToCurrentLocalTime()
     m_second = localTM.tm_sec;
     m_isDST = localTM.tm_isdst;
 #if HAVE(TM_GMTOFF)
-    m_utcOffset = localTM.tm_gmtoff;
+    m_utcOffsetInMinute = localTM.tm_gmtoff / secondsPerMinute;
 #else
-    m_utcOffset = calculateLocalTimeOffset(localTime * msPerSecond).offset / msPerSecond;
+    m_utcOffsetInMinute = calculateLocalTimeOffset(localTime * msPerSecond).offset / msPerMinute;
 #endif
 #endif
 }
index 25dd15c..02c2ec7 100644 (file)
 
 #include <string.h>
 #include <time.h>
+#include <wtf/DateMath.h>
 #include <wtf/Noncopyable.h>
+#include <wtf/StdLibExtras.h>
 
 namespace WTF {
 
 class GregorianDateTime final {
     WTF_MAKE_FAST_ALLOCATED;
-    WTF_MAKE_NONCOPYABLE(GregorianDateTime);
 public:
-    GregorianDateTime()
-        : m_year(0)
-        , m_month(0)
-        , m_yearDay(0)
-        , m_monthDay(0)
-        , m_weekDay(0)
-        , m_hour(0)
-        , m_minute(0)
-        , m_second(0)
-        , m_utcOffset(0)
-        , m_isDST(0)
-    {
-    }
+    GregorianDateTime() = default;
 
     inline int year() const { return m_year; }
     inline int month() const { return m_month; }
@@ -56,7 +45,7 @@ public:
     inline int hour() const { return m_hour; }
     inline int minute() const { return m_minute; }
     inline int second() const { return m_second; }
-    inline int utcOffset() const { return m_utcOffset; }
+    inline int utcOffsetInMinute() const { return m_utcOffsetInMinute; }
     inline int isDST() const { return m_isDST; }
 
     inline void setYear(int year) { m_year = year; }
@@ -67,9 +56,20 @@ public:
     inline void setHour(int hour) { m_hour = hour; }
     inline void setMinute(int minute) { m_minute = minute; }
     inline void setSecond(int second) { m_second = second; }
-    inline void setUtcOffset(int utcOffset) { m_utcOffset = utcOffset; }
+    inline void setUTCOffsetInMinute(int utcOffsetInMinute) { m_utcOffsetInMinute = utcOffsetInMinute; }
     inline void setIsDST(int isDST) { m_isDST = isDST; }
 
+    static ptrdiff_t offsetOfYear() { return OBJECT_OFFSETOF(GregorianDateTime, m_year); }
+    static ptrdiff_t offsetOfMonth() { return OBJECT_OFFSETOF(GregorianDateTime, m_month); }
+    static ptrdiff_t offsetOfYearDay() { return OBJECT_OFFSETOF(GregorianDateTime, m_yearDay); }
+    static ptrdiff_t offsetOfMonthDay() { return OBJECT_OFFSETOF(GregorianDateTime, m_monthDay); }
+    static ptrdiff_t offsetOfWeekDay() { return OBJECT_OFFSETOF(GregorianDateTime, m_weekDay); }
+    static ptrdiff_t offsetOfHour() { return OBJECT_OFFSETOF(GregorianDateTime, m_hour); }
+    static ptrdiff_t offsetOfMinute() { return OBJECT_OFFSETOF(GregorianDateTime, m_minute); }
+    static ptrdiff_t offsetOfSecond() { return OBJECT_OFFSETOF(GregorianDateTime, m_second); }
+    static ptrdiff_t offsetOfUTCOffsetInMinute() { return OBJECT_OFFSETOF(GregorianDateTime, m_utcOffsetInMinute); }
+    static ptrdiff_t offsetOfIsDST() { return OBJECT_OFFSETOF(GregorianDateTime, m_isDST); }
+
     WTF_EXPORT_PRIVATE void setToCurrentLocalTime();
 
     operator tm() const
@@ -88,37 +88,23 @@ public:
         ret.tm_isdst = m_isDST;
 
 #if HAVE(TM_GMTOFF)
-        ret.tm_gmtoff = static_cast<long>(m_utcOffset);
+        ret.tm_gmtoff = static_cast<long>(m_utcOffsetInMinute) * static_cast<long>(secondsPerMinute);
 #endif
 
         return ret;
     }
 
-    void copyFrom(const GregorianDateTime& other)
-    {
-        m_year = other.m_year;
-        m_month = other.m_month;
-        m_yearDay = other.m_yearDay;
-        m_monthDay = other.m_monthDay;
-        m_weekDay = other.m_weekDay;
-        m_hour = other.m_hour;
-        m_minute = other.m_minute;
-        m_second = other.m_second;
-        m_utcOffset = other.m_utcOffset;
-        m_isDST = other.m_isDST;
-    }
-
 private:
-    int m_year;
-    int m_month;
-    int m_yearDay;
-    int m_monthDay;
-    int m_weekDay;
-    int m_hour;
-    int m_minute;
-    int m_second;
-    int m_utcOffset;
-    int m_isDST;
+    int m_year { 0 };
+    int m_month { 0 };
+    int m_yearDay { 0 };
+    int m_monthDay { 0 };
+    int m_weekDay { 0 };
+    int m_hour { 0 };
+    int m_minute { 0 };
+    int m_second { 0 };
+    int m_utcOffsetInMinute { 0 };
+    int m_isDST { 0 };
 };
 
 } // namespace WTF
index be1aac8..9767506 100644 (file)
@@ -1,3 +1,13 @@
+2019-10-30  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] Date functions should have intrinsic
+        https://bugs.webkit.org/show_bug.cgi?id=202187
+
+        Reviewed by Keith Miller.
+
+        * loader/archive/mhtml/MHTMLArchive.cpp:
+        (WebCore::MHTMLArchive::generateMHTMLData):
+
 2019-10-30  Chris Dumez  <cdumez@apple.com>
 
         GPUCanvasContext should not prevent entering the back/forward cache
index c997b31..106a7f8 100644 (file)
@@ -141,7 +141,7 @@ Ref<SharedBuffer> MHTMLArchive::generateMHTMLData(Page* page)
 
     GregorianDateTime now;
     now.setToCurrentLocalTime();
-    String dateString = makeRFC2822DateString(now.weekDay(), now.monthDay(), now.month(), now.year(), now.hour(), now.minute(), now.second(), now.utcOffset() / 60);
+    String dateString = makeRFC2822DateString(now.weekDay(), now.monthDay(), now.month(), now.year(), now.hour(), now.minute(), now.second(), now.utcOffsetInMinute());
 
     StringBuilder stringBuilder;
     stringBuilder.append("From: <Saved by WebKit>\r\n");