ソースを参照

`Date` ctr spec compliance (#6845)

According to the spec, the Date ctr should use the TimeClip function.
Since it did not, -0 was not converted to +0 in the ctr (See issue #5442).

The ctr now uses JavascriptDate::TimeClip (moved from IntlEngineInterfaceExtensionObject.cpp).
However, this does not fix the original issue, as the underlying JavascriptConversion::ToInteger function is also not spec compliant regarding the conversion from -0 to +0.

This non-compliance is also true for the other ToIntXX and ToUintXX functions (Not covered by this PR).

Fix #5442
Related to #6743
Lukas Kurz 3 年 前
コミット
0bd75fb330

+ 3 - 3
lib/Runtime/Language/JavascriptConversion.cpp

@@ -1,5 +1,6 @@
 //-------------------------------------------------------------------------------------------------------
 // Copyright (C) Microsoft. All rights reserved.
+// Copyright (c) 2022 ChakraCore Project Contributors. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 #include "RuntimeLanguagePch.h"
@@ -949,10 +950,9 @@ CommonNumber:
 
     double JavascriptConversion::ToInteger(double val)
     {
-        if(JavascriptNumber::IsNan(val))
+        if(JavascriptNumber::IsNan(val) || JavascriptNumber::IsZero(val))
             return 0;
-        if(JavascriptNumber::IsPosInf(val) || JavascriptNumber::IsNegInf(val) ||
-            JavascriptNumber::IsZero(val))
+        if(JavascriptNumber::IsPosInf(val) || JavascriptNumber::IsNegInf(val))
         {
             return val;
         }

+ 2 - 35
lib/Runtime/Library/IntlEngineInterfaceExtensionObject.cpp

@@ -1,6 +1,6 @@
 //-------------------------------------------------------------------------------------------------------
 // Copyright (C) Microsoft. All rights reserved.
-// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
+// Copyright (c) 2022 ChakraCore Project Contributors. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 #include "RuntimeLibraryPch.h"
@@ -2513,39 +2513,6 @@ DEFINE_ISXLOCALEAVAILABLE(PR, uloc)
     }
 
 #ifdef INTL_ICU
-    // Implementation of ECMA 262 #sec-timeclip
-    // REVIEW(jahorto): Where is a better place for this function? JavascriptDate? DateUtilities? JavascriptConversion?
-    static double TimeClip(Var x)
-    {
-        double time = 0.0;
-        if (TaggedInt::Is(x))
-        {
-            time = TaggedInt::ToDouble(x);
-        }
-        else
-        {
-            AssertOrFailFast(JavascriptNumber::Is(x));
-            time = JavascriptNumber::GetValue(x);
-
-            // Only perform steps 1, 3, and 4 if the input was not a TaggedInt, since TaggedInts cant be infinite or -0
-            if (!NumberUtilities::IsFinite(time))
-            {
-                return NumberConstants::NaN;
-            }
-
-            // This performs both steps 3 and 4
-            time = JavascriptConversion::ToInteger(time);
-        }
-
-        // Step 2: If abs(time) > 8.64e15, return NaN.
-        if (Math::Abs(time) > 8.64e15)
-        {
-            return NumberConstants::NaN;
-        }
-
-        return time;
-    }
-
     static void AddPartToPartsArray(ScriptContext *scriptContext, JavascriptArray *arr, int arrIndex, const char16 *src, int start, int end, JavascriptString *partType)
     {
         JavascriptString *partValue = JavascriptString::NewCopyBuffer(
@@ -2640,7 +2607,7 @@ DEFINE_ISXLOCALEAVAILABLE(PR, uloc)
 
         // 1. Let x be TimeClip(x)
         // 2. If x is NaN, throw a RangeError exception
-        double date = TimeClip(args[2]);
+        double date = JavascriptDate::TimeClip(args[2]);
         if (JavascriptNumber::IsNan(date))
         {
             JavascriptError::ThrowRangeError(scriptContext, JSERR_InvalidDate);

+ 35 - 0
lib/Runtime/Library/JavascriptDate.cpp

@@ -1,5 +1,6 @@
 //-------------------------------------------------------------------------------------------------------
 // Copyright (C) Microsoft. All rights reserved.
+// Copyright (c) 2022 ChakraCore Project Contributors. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 #include "RuntimeLibraryPch.h"
@@ -162,6 +163,8 @@ namespace Js
                     timeValue = JavascriptConversion::ToNumber(value, scriptContext);
                 }
             }
+            
+            timeValue = TimeClip(JavascriptNumber::New(timeValue, scriptContext));
 
             pDate->m_date.SetTvUtc(timeValue);
             return pDate;
@@ -215,6 +218,38 @@ namespace Js
         return pDate;
     }
 
+    // Implementation of ECMA 262 #sec-timeclip
+    double JavascriptDate::TimeClip(Var x)
+    {
+        double time = 0.0;
+        if (TaggedInt::Is(x))
+        {
+            time = TaggedInt::ToDouble(x);
+        }
+        else
+        {
+            AssertOrFailFast(JavascriptNumber::Is(x));
+            time = JavascriptNumber::GetValue(x);
+
+            // Only perform steps 1, 3, and 4 if the input was not a TaggedInt, since TaggedInts cant be infinite or -0
+            if (!NumberUtilities::IsFinite(time))
+            {
+                return NumberConstants::NaN;
+            }
+
+            // This performs both steps 3 and 4
+            time = JavascriptConversion::ToInteger(time);
+        }
+
+        // Step 2: If abs(time) > 8.64e15, return NaN.
+        if (Math::Abs(time) > 8.64e15)
+        {
+            return NumberConstants::NaN;
+        }
+
+        return time;
+    }
+
     // Date.prototype[@@toPrimitive] as described in ES6 spec (Draft May 22, 2014) 20.3.4.45
     Var JavascriptDate::EntrySymbolToPrimitive(RecyclableObject* function, CallInfo callInfo, ...)
     {

+ 2 - 0
lib/Runtime/Library/JavascriptDate.h

@@ -1,5 +1,6 @@
 //-------------------------------------------------------------------------------------------------------
 // Copyright (C) Microsoft. All rights reserved.
+// Copyright (c) 2022 ChakraCore Project Contributors. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 #pragma once
@@ -127,6 +128,7 @@ namespace Js
         static Var EntryUTC(RecyclableObject* function, CallInfo callInfo, ...);
         static Var EntryValueOf(RecyclableObject* function, CallInfo callInfo, ...);
         static Var EntrySymbolToPrimitive(RecyclableObject* function, CallInfo callInfo, ...);
+        static double JavascriptDate::TimeClip(Var x);
 
         static JavascriptString* ToLocaleString(JavascriptDate* date, ScriptContext* requestContext);
         static JavascriptString* ToString(JavascriptDate* date, ScriptContext* requestContext);

+ 6 - 0
test/Date/DateCtr.js

@@ -1,5 +1,6 @@
 //-------------------------------------------------------------------------------------------------------
 // Copyright (C) Microsoft. All rights reserved.
+// Copyright (c) 2022 ChakraCore Project Contributors. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 
@@ -59,6 +60,11 @@ function Test()
     d = new Date("", 1e81); if (!CHECK(d + "")) return; // WOOB 1139099
     d = new Date(); d.setSeconds(Number.MAX_VALUE); if (!CHECK(d + "")) return;  // WOOB 1142298
     d = new Date(); d.setSeconds(-Number.MAX_VALUE); if (!CHECK(d + "")) return; // WOOB 1142298
+
+    // Issue #5442
+    d = new Date(-0);
+    if (!Object.is(d.getTime(), 0)) throw new Error("Expected getTime() to return +0");
+
     console.log("PASS");
 }