فهرست منبع

Fix issues when running on ARM architecture (#1061)

Marko Lahma 3 سال پیش
والد
کامیت
903588b596

+ 87 - 59
Jint/Native/Array/ArrayPrototype.cs

@@ -139,39 +139,47 @@ namespace Jint.Native.Array
         /// </summary>
         private JsValue Fill(JsValue thisObj, JsValue[] arguments)
         {
+            var value = arguments.At(0);
+            var start = arguments.At(1);
+            var end = arguments.At(2);
+
             var o = TypeConverter.ToObject(_realm, thisObj);
 
             var operations = ArrayOperations.For(o);
             var length = operations.GetLongLength();
 
-            var value = arguments.At(0);
-
-            var start = ConvertAndCheckForInfinity(arguments.At(1), 0);
+            var relativeStart = TypeConverter.ToIntegerOrInfinity(start);
 
-            var relativeStart = TypeConverter.ToInteger(start);
-            ulong actualStart;
-            if (relativeStart < 0)
+            ulong k;
+            if (double.IsNegativeInfinity(relativeStart))
+            {
+                k = 0;
+            }
+            else if (relativeStart < 0)
             {
-                actualStart = (ulong) System.Math.Max(length + relativeStart, 0);
+                k = (ulong) System.Math.Max(length + relativeStart, 0);
             }
             else
             {
-                actualStart = (ulong) System.Math.Min(relativeStart, length);
+                k = (ulong) System.Math.Min(relativeStart, length);
             }
 
-            var end = ConvertAndCheckForInfinity(arguments.At(2), (long) length);
-            var relativeEnd = TypeConverter.ToInteger(end);
-            ulong actualEnd;
-            if (relativeEnd < 0)
+            var relativeEnd = end.IsUndefined() ? length : TypeConverter.ToIntegerOrInfinity(end);
+            ulong final;
+            if (double.IsNegativeInfinity(relativeEnd))
             {
-                actualEnd = (ulong) System.Math.Max(length + relativeEnd, 0);
+                final = 0;
+            }
+            else if (relativeEnd < 0)
+            {
+                final = (ulong) System.Math.Max(length + relativeEnd, 0);
             }
             else
             {
-                actualEnd = (ulong) System.Math.Min(relativeEnd, length);
+                final = (ulong) System.Math.Min(relativeEnd, length);
             }
 
-            for (var i = actualStart; i < actualEnd; ++i)
+            for (var i = k; i < final; ++i)
             {
                 operations.Set(i, value, throwOnError: false);
             }
@@ -191,28 +199,47 @@ namespace Jint.Native.Array
             JsValue end = arguments.At(2);
 
             var operations = ArrayOperations.For(o);
-            var initialLength = operations.GetLongLength();
-            var len = ConvertAndCheckForInfinity(initialLength, 0);
+            var len = operations.GetLongLength();
 
-            var relativeTarget = ConvertAndCheckForInfinity(target, 0);
+            var relativeTarget = TypeConverter.ToIntegerOrInfinity(target);
 
             var to = relativeTarget < 0 ?
                 System.Math.Max(len + relativeTarget, 0) :
                 System.Math.Min(relativeTarget, len);
 
-            var relativeStart = ConvertAndCheckForInfinity(start, 0);
+            var relativeStart = TypeConverter.ToIntegerOrInfinity(start);
 
-            var from = relativeStart < 0 ?
-                System.Math.Max(len + relativeStart, 0) :
-                System.Math.Min(relativeStart, len);
+            long from;
+            if (double.IsNegativeInfinity(relativeStart))
+            {
+                from = 0;
+            }
+            else if (relativeStart < 0)
+            {
+                from = (long) System.Math.Max(len + relativeStart, 0);
+            }
+            else
+            {
+                from = (long) System.Math.Min(relativeStart, len);
+            }
 
-            var relativeEnd = ConvertAndCheckForInfinity(end, len);
+            var relativeEnd = end.IsUndefined() ? len : TypeConverter.ToIntegerOrInfinity(end);
 
-            var final = relativeEnd < 0 ?
-                System.Math.Max(len + relativeEnd, 0) :
-                System.Math.Min(relativeEnd, len);
+            long final;
+            if (double.IsNegativeInfinity(relativeEnd))
+            {
+                final = 0;
+            }
+            else if (relativeEnd < 0)
+            {
+                final = (long) System.Math.Max(len + relativeEnd, 0);
+            }
+            else
+            {
+                final = (long) System.Math.Min(relativeEnd, len);
+            }
 
-            var count = System.Math.Min(final - from, len - to);
+            var count = (long) System.Math.Min(final - from, len - to);
 
             long direction = 1;
 
@@ -243,23 +270,6 @@ namespace Jint.Native.Array
             return o;
         }
 
-        static long ConvertAndCheckForInfinity(JsValue jsValue, long defaultValue)
-        {
-            if (jsValue.IsUndefined())
-            {
-                return defaultValue;
-            }
-
-            var num = TypeConverter.ToNumber(jsValue);
-
-            if (double.IsPositiveInfinity(num))
-            {
-                return long.MaxValue;
-            }
-
-            return (long) num;
-        }
-
         /// <summary>
         /// https://tc39.es/ecma262/#sec-array.prototype.lastindexof
         /// </summary>
@@ -601,32 +611,48 @@ namespace Jint.Native.Array
             return Undefined;
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-array.prototype.includes
+        /// </summary>
         private JsValue Includes(JsValue thisObj, JsValue[] arguments)
         {
             var o = ArrayOperations.For(_realm, thisObj);
-            var len = o.GetLongLength();
+            var len = (long) o.GetLongLength();
 
             if (len == 0)
             {
-                return false;
+                return JsBoolean.False;
             }
 
             var searchElement = arguments.At(0);
-            var fromIndex = arguments.At(1, 0);
-
-            var n = TypeConverter.ToNumber(fromIndex);
-            n = n > ArrayOperations.MaxArrayLikeLength
-                ? ArrayOperations.MaxArrayLikeLength
-                : n;
+            var fromIndex = arguments.At(1);
 
-            var k = (ulong) System.Math.Max(
-                n >= 0
-                    ? n
-                    : len - System.Math.Abs(n), 0);
+            long k = 0;
+            var n = TypeConverter.ToIntegerOrInfinity(fromIndex);
+            if (double.IsPositiveInfinity(n))
+            {
+                return JsBoolean.False;
+            }
+            else if (double.IsNegativeInfinity(n))
+            {
+                n = 0;
+            }
+            else if (n >= 0)
+            {
+                k = (long) n;
+            }
+            else
+            {
+                k = len + (long) n;
+                if (k < 0)
+                {
+                    k = 0;
+                }
+            }
 
             while (k < len)
             {
-                var value = o.Get(k);
+                var value = o.Get((ulong) k);
                 if (SameValueZeroComparer.Equals(value, searchElement))
                 {
                     return true;
@@ -676,6 +702,9 @@ namespace Jint.Native.Array
             return JsBoolean.True;
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-array.prototype.indexof
+        /// </summary>
         private JsValue IndexOf(JsValue thisObj, JsValue[] arguments)
         {
             var o = ArrayOperations.For(_realm, thisObj);
@@ -686,7 +715,7 @@ namespace Jint.Native.Array
             }
 
             var startIndex = arguments.Length > 1
-                ? TypeConverter.ToNumber(arguments[1])
+                ? TypeConverter.ToIntegerOrInfinity(arguments.At(1))
                 : 0;
 
             if (startIndex > ArrayOperations.MaxArrayLikeLength)
@@ -1502,5 +1531,4 @@ namespace Jint.Native.Array
             }
         }
     }
-
 }

+ 5 - 1
Jint/Native/ArrayBuffer/ArrayBufferInstance.cs

@@ -247,7 +247,11 @@ namespace Jint.Native.ArrayBuffer
             else
             {
                 // inlined conversion for faster speed instead of getting the method in spec
-                var intValue = (long) value.DoubleValue;
+                var doubleValue  = value.DoubleValue;
+                var intValue = double.IsNaN(doubleValue) || doubleValue == 0 || double.IsInfinity(doubleValue)
+                    ? 0
+                    : (long) doubleValue;
+
                 rawBytes = _workBuffer;
                 switch (type)
                 {

+ 15 - 4
Jint/Native/String/StringConstructor.cs

@@ -44,15 +44,26 @@ namespace Jint.Native.String
             SetProperties(properties);
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-string.fromcharcode
+        /// </summary>
         private static JsValue FromCharCode(JsValue thisObj, JsValue[] arguments)
         {
-            var chars = new char[arguments.Length];
-            for (var i = 0; i < chars.Length; i++ )
+            var length = arguments.Length;
+
+            if (length == 0)
+            {
+                return JsString.Empty;
+            }
+
+            var elements = new char[length];
+            for (var i = 0; i < elements.Length; i++ )
             {
-                chars[i] = (char)TypeConverter.ToUint16(arguments[i]);
+                var nextCu = TypeConverter.ToUint16(arguments[i]);
+                elements[i] = (char) nextCu;
             }
 
-            return JsString.Create(new string(chars));
+            return JsString.Create(new string(elements));
         }
 
         private JsValue FromCodePoint(JsValue thisObj, JsValue[] arguments)

+ 13 - 8
Jint/Native/String/StringPrototype.cs

@@ -1003,32 +1003,37 @@ namespace Jint.Native.String
             return str.Normalize(nf);
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-string.prototype.repeat
+        /// </summary>
         private JsValue Repeat(JsValue thisObj, JsValue[] arguments)
         {
             TypeConverter.CheckObjectCoercible(Engine, thisObj);
-            var str = TypeConverter.ToString(thisObj);
-            var n = (int) TypeConverter.ToInteger(arguments.At(0));
+            var s = TypeConverter.ToString(thisObj);
+            var count = arguments.At(0);
+
+            var n = TypeConverter.ToIntegerOrInfinity(count);
 
-            if (n < 0)
+            if (n < 0 || double.IsPositiveInfinity(n))
             {
                 ExceptionHelper.ThrowRangeError(_realm, "Invalid count value");
             }
 
-            if (n == 0 || str.Length == 0)
+            if (n == 0 || s.Length == 0)
             {
                 return JsString.Empty;
             }
 
-            if (str.Length == 1)
+            if (s.Length == 1)
             {
-                return new string(str[0], n);
+                return new string(s[0], (int) n);
             }
 
             using var sb = StringBuilderPool.Rent();
-            sb.Builder.EnsureCapacity(n * str.Length);
+            sb.Builder.EnsureCapacity((int) (n * s.Length));
             for (var i = 0; i < n; ++i)
             {
-                sb.Builder.Append(str);
+                sb.Builder.Append(s);
             }
 
             return sb.ToString();

+ 22 - 5
Jint/Native/TypedArray/TypedArrayInstance.cs

@@ -144,7 +144,7 @@ namespace Jint.Native.TypedArray
         /// </summary>
         public override bool DefineOwnProperty(JsValue property, PropertyDescriptor desc)
         {
-            if (property.IsNumber() || property.IsString())
+            if (property.IsString())
             {
                 var numericIndex = TypeConverter.CanonicalNumericIndexString(property);
                 if (numericIndex is not null)
@@ -341,10 +341,27 @@ namespace Jint.Native.TypedArray
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private bool IsValidIntegerIndex(double index)
         {
-            return !_viewedArrayBuffer.IsDetachedBuffer
-                   && TypeConverter.IsIntegralNumber(index)
-                   && !NumberInstance.IsNegativeZero(index)
-                   && (uint) index < _arrayLength;
+            if (_viewedArrayBuffer.IsDetachedBuffer)
+            {
+                return false;
+            }
+
+            if (!TypeConverter.IsIntegralNumber(index))
+            {
+                return false;
+            }
+
+            if (NumberInstance.IsNegativeZero(index))
+            {
+                return false;
+            }
+
+            if (index < 0 || index >= _arrayLength)
+            {
+                return false;
+            }
+
+            return true;
         }
 
         /// <summary>

+ 26 - 7
Jint/Runtime/TypeConverter.cs

@@ -466,7 +466,7 @@ namespace Jint.Runtime
         }
 
         /// <summary>
-        /// http://www.ecma-international.org/ecma-262/5.1/#sec-9.6
+        /// https://tc39.es/ecma262/#sec-touint32
         /// </summary>
         public static uint ToUint32(JsValue o)
         {
@@ -476,7 +476,7 @@ namespace Jint.Runtime
             }
 
             var doubleVal = ToNumber(o);
-            if (doubleVal >= 0.0 && doubleVal <= uint.MaxValue)
+            if (doubleVal is >= 0.0 and <= uint.MaxValue)
             {
                 // Double-to-uint cast is correct in this range
                 return (uint) doubleVal;
@@ -486,13 +486,32 @@ namespace Jint.Runtime
         }
 
         /// <summary>
-        /// http://www.ecma-international.org/ecma-262/5.1/#sec-9.7
+        /// https://tc39.es/ecma262/#sec-touint16
         /// </summary>
         public static ushort ToUint16(JsValue o)
         {
-            return o._type == InternalTypes.Integer
-                ? (ushort) (uint) o.AsInteger()
-                : (ushort) (uint) ToNumber(o);
+            if (o._type == InternalTypes.Integer)
+            {
+                var integer = o.AsInteger();
+                if (integer is >= 0 and <= ushort.MaxValue)
+                {
+                    return (ushort) integer;
+                }
+            }
+
+            var number = ToNumber(o);
+            if (double.IsNaN(number) || number == 0 || double.IsInfinity(number))
+            {
+                return 0;
+            }
+
+            var intValue = Math.Floor(Math.Abs(number));
+            if (number < 0)
+            {
+                intValue *= -1;
+            }
+            var int16Bit = intValue % 65_536; // 2^16
+            return (ushort) int16Bit;
         }
 
         /// <summary>
@@ -769,7 +788,7 @@ namespace Jint.Runtime
             {
                 if (jsString.ToString() == "-0")
                 {
-                    return -0d;
+                    return JsNumber.NegativeZero._value;
                 }
 
                 var n = ToNumber(value);