ソースを参照

Fix issues related to JSON, Math, RegExp and Proxy (#1045)

Marko Lahma 3 年 前
コミット
8f0d433737

+ 1 - 1
Jint/Engine.cs

@@ -301,7 +301,7 @@ namespace Jint
                 return this;
             }
 
-            var strict = _isStrict | script.Strict;
+            var strict = _isStrict || script.Strict;
             ExecuteWithConstraints(strict, DoInvoke);
 
             return this;

+ 4 - 3
Jint/Native/Array/ArrayConstructor.cs

@@ -348,12 +348,13 @@ namespace Jint.Native.Array
         /// <summary>
         /// https://tc39.es/ecma262/#sec-arraycreate
         /// </summary>
-        private ArrayInstance ArrayCreate(uint capacity, ObjectInstance proto)
+        internal ArrayInstance ArrayCreate(uint length, ObjectInstance proto = null)
         {
             proto ??= PrototypeObject;
-            var instance = new ArrayInstance(Engine, capacity)
+            var instance = new ArrayInstance(Engine, length)
             {
-                _prototype = proto
+                _prototype = proto,
+                _length = new PropertyDescriptor(length, PropertyFlag.OnlyWritable)
             };
             return instance;
         }

+ 1 - 1
Jint/Native/BigInt/BigIntPrototype.cs

@@ -22,7 +22,7 @@ public sealed class BigIntPrototype : ObjectInstance
         Realm realm,
         BigIntConstructor constructor,
         ObjectPrototype objectPrototype)
-        : base(engine)
+        : base(engine, ObjectClass.Object, InternalTypes.BigInt)
     {
         _prototype = objectPrototype;
         _realm = realm;

+ 6 - 7
Jint/Native/JsValue.cs

@@ -288,6 +288,8 @@ namespace Jint.Native
                 return true;
             }
 
+            // TODO move to type specific IsLooselyEqual
+
             var x = this;
             var y = value;
 
@@ -311,14 +313,12 @@ namespace Jint.Native
                 return x.IsLooselyEqual(TypeConverter.ToNumber(y));
             }
 
-            const InternalTypes stringOrNumber = InternalTypes.String | InternalTypes.Integer | InternalTypes.Number | InternalTypes.BigInt;
-
-            if (y.IsObject() && (x._type & stringOrNumber) != 0)
+            if (y.IsObject() && (x._type & InternalTypes.Primitive) != 0)
             {
                 return x.IsLooselyEqual(TypeConverter.ToPrimitive(y));
             }
 
-            if (x.IsObject() && (y._type & stringOrNumber) != 0)
+            if (x.IsObject() && (y._type & InternalTypes.Primitive) != 0)
             {
                 return y.IsLooselyEqual(TypeConverter.ToPrimitive(x));
             }
@@ -500,13 +500,12 @@ namespace Jint.Native
 
         internal static IConstructor AssertConstructor(Engine engine, JsValue c)
         {
-            var constructor = c as IConstructor;
-            if (constructor is null)
+            if (!c.IsConstructor)
             {
                 ExceptionHelper.ThrowTypeError(engine.Realm, c + " is not a constructor");
             }
 
-            return constructor;
+            return (IConstructor) c;
         }
     }
 }

+ 36 - 36
Jint/Native/Json/JsonSerializer.cs

@@ -1,5 +1,4 @@
 using System.Collections.Generic;
-using System.Linq;
 using Jint.Collections;
 using Jint.Native.BigInt;
 using Jint.Native.Boolean;
@@ -40,43 +39,47 @@ namespace Jint.Native.Json
                 return Undefined.Instance;
             }
 
-            if (replacer.IsObject())
+            if (replacer is ObjectInstance oi)
             {
-                if (replacer is ICallable)
+                if (oi.IsCallable)
                 {
                     _replacerFunction = replacer;
                 }
                 else
                 {
-                    var replacerObj = replacer.AsObject();
-                    _propertyList = new List<JsValue>();
-
-                    foreach (var pair in replacerObj.GetOwnProperties())
+                    if (oi.IsArray())
                     {
-                        var v = replacerObj.UnwrapJsValue(pair.Value);
-                        string item = null;
-                        if (v.IsString())
-                        {
-                            item = v.ToString();
-                        }
-                        else if (v.IsNumber())
-                        {
-                            item = TypeConverter.ToString(v);
-                        }
-                        else if (v.IsObject())
+                        _propertyList = new List<JsValue>();
+                        var len = oi.Length;
+                        var k = 0;
+                        while (k < len)
                         {
-                            var propertyObj = v.AsObject();
-                            if (propertyObj.Class == ObjectClass.String || propertyObj.Class == ObjectClass.Number)
+                            var prop = JsString.Create(k);
+                            var v = replacer.Get(prop);
+                            var item = JsValue.Undefined;
+                            if (v.IsString())
+                            {
+                                item = v;
+                            }
+                            else if (v.IsNumber())
                             {
                                 item = TypeConverter.ToString(v);
                             }
-                        }
+                            else if (v.IsObject())
+                            {
+                                if (v is StringInstance or NumberInstance)
+                                {
+                                    item = TypeConverter.ToString(v);
+                                }
+                            }
 
-                        if (item != null && !_propertyList.Contains(item))
-                        {
-                            _propertyList.Add(item);
-                        }
+                            if (!item.IsUndefined() && !_propertyList.Contains(item))
+                            {
+                                _propertyList.Add(item);
+                            }
 
+                            k++;
+                        }
                     }
                 }
             }
@@ -141,7 +144,7 @@ namespace Jint.Native.Json
                 {
                     if (toJson.AsObject() is ICallable callableToJson)
                     {
-                        value = callableToJson.Call(value, Arguments.From(key));
+                        value = callableToJson.Call(value, Arguments.From(TypeConverter.ToPropertyKey(key)));
                     }
                 }
             }
@@ -149,19 +152,18 @@ namespace Jint.Native.Json
             if (!_replacerFunction.IsUndefined())
             {
                 var replacerFunctionCallable = (ICallable) _replacerFunction.AsObject();
-                value = replacerFunctionCallable.Call(holder, Arguments.From(key, value));
+                value = replacerFunctionCallable.Call(holder, Arguments.From(TypeConverter.ToPropertyKey(key), value));
             }
 
             if (value.IsObject())
             {
-                var valueObj = value.AsObject();
-                switch (valueObj)
+                switch (value)
                 {
-                    case NumberInstance numberInstance:
-                        value = numberInstance.NumberData;
+                    case NumberInstance:
+                        value = TypeConverter.ToNumber(value);
                         break;
-                    case StringInstance stringInstance:
-                        value = stringInstance.StringData;
+                    case StringInstance:
+                        value = TypeConverter.ToString(value);
                         break;
                     case BooleanInstance booleanInstance:
                         value = booleanInstance.BooleanData;
@@ -326,9 +328,7 @@ namespace Jint.Native.Json
             var stepback = _indent;
             _indent += _gap;
 
-            var k = _propertyList ?? value.GetOwnProperties()
-                .Where(x => !x.Key.IsSymbol() && x.Value.Enumerable)
-                .Select(x => x.Key);
+            var k = (IEnumerable<JsValue>) _propertyList ?? value.EnumerableOwnPropertyNames(ObjectInstance.EnumerableOwnPropertyNamesKind.Key);
 
             var partial = new List<string>();
             foreach (var p in k)

+ 74 - 34
Jint/Native/Math/MathInstance.cs

@@ -369,7 +369,7 @@ namespace Jint.Native.Math
                 return JsNumber.NegativeZero;
             }
 #endif
-            
+
             return System.Math.Ceiling(x);
         }
 
@@ -600,6 +600,9 @@ namespace Jint.Native.Math
             return System.Math.Log10(x);
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-math.max
+        /// </summary>
         private static JsValue Max(JsValue thisObject, JsValue[] arguments)
         {
             if (arguments.Length == 0)
@@ -607,36 +610,31 @@ namespace Jint.Native.Math
                 return JsNumber.DoubleNegativeInfinity;
             }
 
-            double max = TypeConverter.ToNumber(arguments.At(0));
-
-            if (double.IsNaN(max))
-            {
-                return JsNumber.DoubleNaN;
-            }
-
-            for (int i = 0; i < arguments.Length; i++)
+            var highest = double.NegativeInfinity;
+            foreach (var number in Coerced(arguments))
             {
-                var value = TypeConverter.ToNumber(arguments[i]);
-
-                if (double.IsNaN(value))
+                if (double.IsNaN(number))
                 {
                     return JsNumber.DoubleNaN;
                 }
 
-                if (max == 0 && value == 0)
+                if (NumberInstance.IsPositiveZero(number) && NumberInstance.IsNegativeZero(highest))
                 {
-                    max = NumberInstance.IsNegativeZero(value)
-                        ? max
-                        : value;
+                    highest = 0;
                 }
-                else
+
+                if (number > highest)
                 {
-                    max = System.Math.Max(max, value);
+                    highest = number;
                 }
             }
-            return max;
+
+            return highest;
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-math.min
+        /// </summary>
         private static JsValue Min(JsValue thisObject, JsValue[] arguments)
         {
             if (arguments.Length == 0)
@@ -644,22 +642,26 @@ namespace Jint.Native.Math
                 return JsNumber.DoublePositiveInfinity;
             }
 
-            double min = TypeConverter.ToNumber(arguments.At(0));
-            for (int i = 0; i < arguments.Length; i++)
+            var lowest = double.PositiveInfinity;
+            foreach (var number in Coerced(arguments))
             {
-                var value = TypeConverter.ToNumber(arguments[i]);
-                if (min == 0 && value == 0)
+                if (double.IsNaN(number))
                 {
-                    min = NumberInstance.IsNegativeZero(min)
-                        ? min
-                        : value;
+                    return JsNumber.DoubleNaN;
                 }
-                else
+
+                if (NumberInstance.IsNegativeZero(number) && NumberInstance.IsPositiveZero(lowest))
                 {
-                    min = System.Math.Min(min, value);
+                    lowest = JsNumber.NegativeZero._value;
+                }
+
+                if (number < lowest)
+                {
+                    lowest = number;
                 }
             }
-            return min;
+
+            return lowest;
         }
 
         private static JsValue Pow(JsValue thisObject, JsValue[] arguments)
@@ -677,7 +679,7 @@ namespace Jint.Native.Math
             {
                 return 1;
             }
-            
+
             return HandlePowUnlikely(y, x);
         }
 
@@ -822,7 +824,7 @@ namespace Jint.Native.Math
             {
                 _random = new Random();
             }
-            
+
             return _random.NextDouble();
         }
 
@@ -997,21 +999,59 @@ namespace Jint.Native.Math
             return -1 * System.Math.Pow(System.Math.Abs(x), 1.0 / 3.0);
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-math.hypot
+        /// </summary>
         private static JsValue Hypot(JsValue thisObject, JsValue[] arguments)
         {
-            double y = 0;
-            for (int i = 0; i < arguments.Length; ++i)
+            var coerced = Coerced(arguments);
+
+            foreach (var number in coerced)
             {
-                var number = TypeConverter.ToNumber(arguments[i]);
                 if (double.IsInfinity(number))
                 {
                     return JsNumber.DoublePositiveInfinity;
                 }
+            }
+
+            var onlyZero = true;
+            double y = 0;
+            foreach (var number in coerced)
+            {
+                if (double.IsNaN(number))
+                {
+                    return JsNumber.DoubleNaN;
+                }
+
+                if (onlyZero && number != 0)
+                {
+                    onlyZero = false;
+                }
+
                 y += number * number;
             }
+
+            if (onlyZero)
+            {
+                return JsNumber.PositiveZero;
+            }
+
             return System.Math.Sqrt(y);
         }
 
+        private static double[] Coerced(JsValue[] arguments)
+        {
+            // TODO stackalloc
+            var coerced = new double[arguments.Length];
+            for (var i = 0; i < arguments.Length; i++)
+            {
+                var argument = arguments[i];
+                coerced[i] = TypeConverter.ToNumber(argument);
+            }
+
+            return coerced;
+        }
+
         private static JsValue Imul(JsValue thisObject, JsValue[] arguments)
         {
             var x = TypeConverter.ToInt32(arguments.At(0));

+ 67 - 16
Jint/Native/Proxy/ProxyInstance.cs

@@ -38,6 +38,9 @@ namespace Jint.Native.Proxy
             _handler = handler;
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-call-thisargument-argumentslist
+        /// </summary>
         public JsValue Call(JsValue thisObject, JsValue[] arguments)
         {
             var jsValues = new[] { _target, thisObject, _engine.Realm.Intrinsics.Array.ConstructFast(arguments) };
@@ -55,6 +58,9 @@ namespace Jint.Native.Proxy
             return callable.Call(thisObject, arguments);
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-construct-argumentslist-newtarget
+        /// </summary>
         public ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
         {
             var argArray = _engine.Realm.Intrinsics.Array.Construct(arguments, _engine.Realm.Intrinsics.Array);
@@ -84,15 +90,30 @@ namespace Jint.Native.Proxy
             return _target.IsArray();
         }
 
-        internal override bool IsConstructor =>
-            _target is not null && _target.IsConstructor
-            || _handler is not null
-                && _handler.TryGetValue(TrapConstruct, out var handlerFunction)
-                && handlerFunction is IConstructor;
+        internal override bool IsConstructor
+        {
+            get
+            {
+                if (_target is not null && _target.IsConstructor)
+                {
+                    return true;
+                }
 
+                if (_handler is not null && _handler.TryGetValue(TrapConstruct, out var handlerFunction) && handlerFunction is IConstructor)
+                {
+                    return true;
+                }
+
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-get-p-receiver
+        /// </summary>
         public override JsValue Get(JsValue property, JsValue receiver)
         {
-            if (property == KeyFunctionRevoke || !TryCallHandler(TrapGet, new JsValue[] {_target, property, this}, out var result))
+            if (property == KeyFunctionRevoke || !TryCallHandler(TrapGet, new[] {_target, TypeConverter.ToPropertyKey(property), this }, out var result))
             {
                 AssertTargetNotRevoked(property);
                 return _target.Get(property, receiver);
@@ -115,9 +136,12 @@ namespace Jint.Native.Proxy
             return result;
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys
+        /// </summary>
         public override List<JsValue> GetOwnPropertyKeys(Types types = Types.None | Types.String | Types.Symbol)
         {
-            if (!TryCallHandler(TrapOwnKeys, new JsValue[] {_target }, out var result))
+            if (!TryCallHandler(TrapOwnKeys, new JsValue[] { _target }, out var result))
             {
                 return _target.GetOwnPropertyKeys(types);
             }
@@ -180,9 +204,12 @@ namespace Jint.Native.Proxy
             return trapResult;
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-getownproperty-p
+        /// </summary>
         public override PropertyDescriptor GetOwnProperty(JsValue property)
         {
-            if (!TryCallHandler(TrapGetOwnPropertyDescriptor, new[] { _target, property }, out var result))
+            if (!TryCallHandler(TrapGetOwnPropertyDescriptor, new[] { _target, TypeConverter.ToPropertyKey(property) }, out var result))
             {
                 return _target.GetOwnProperty(property);
             }
@@ -226,9 +253,12 @@ namespace Jint.Native.Proxy
             return resultDesc;
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-set-p-v-receiver
+        /// </summary>
         public override bool Set(JsValue property, JsValue value, JsValue receiver)
         {
-            if (!TryCallHandler(TrapSet, new[] { _target, property, value, this }, out var trapResult))
+            if (!TryCallHandler(TrapSet, new[] { _target, TypeConverter.ToPropertyKey(property), value, receiver }, out var trapResult))
             {
                 return _target.Set(property, value, receiver);
             }
@@ -262,9 +292,12 @@ namespace Jint.Native.Proxy
             return true;
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-getownproperty-p
+        /// </summary>
         public override bool DefineOwnProperty(JsValue property, PropertyDescriptor desc)
         {
-            var arguments = new[] { _target, property, PropertyDescriptor.FromPropertyDescriptor(_engine, desc) };
+            var arguments = new[] { _target, TypeConverter.ToPropertyKey(property), PropertyDescriptor.FromPropertyDescriptor(_engine, desc) };
             if (!TryCallHandler(TrapDefineProperty, arguments, out var result))
             {
                 return _target.DefineOwnProperty(property, desc);
@@ -307,9 +340,12 @@ namespace Jint.Native.Proxy
             return ValidateAndApplyPropertyDescriptor(null, JsString.Empty, extensible, desc, current);
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-hasproperty-p
+        /// </summary>
         public override bool HasProperty(JsValue property)
         {
-            if (!TryCallHandler(TrapHas, new [] { _target, property }, out var jsValue))
+            if (!TryCallHandler(TrapHas, new [] { _target, TypeConverter.ToPropertyKey(property) }, out var jsValue))
             {
                 return _target.HasProperty(property);
             }
@@ -336,9 +372,12 @@ namespace Jint.Native.Proxy
             return trapResult;
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-delete-p
+        /// </summary>
         public override bool Delete(JsValue property)
         {
-            if (!TryCallHandler(TrapDeleteProperty, new JsValue[] { _target, property }, out var result))
+            if (!TryCallHandler(TrapDeleteProperty, new[] { _target, TypeConverter.ToPropertyKey(property) }, out var result))
             {
                 return _target.Delete(property);
             }
@@ -357,9 +396,12 @@ namespace Jint.Native.Proxy
             return success;
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-preventextensions
+        /// </summary>
         public override JsValue PreventExtensions()
         {
-            if (!TryCallHandler(TrapPreventExtensions, new[] { _target }, out var result))
+            if (!TryCallHandler(TrapPreventExtensions, new JsValue[] { _target }, out var result))
             {
                 return _target.PreventExtensions();
             }
@@ -371,14 +413,17 @@ namespace Jint.Native.Proxy
                 ExceptionHelper.ThrowTypeError(_engine.Realm);
             }
 
-            return success ? JsBoolean.True : JsBoolean.False;
+            return success;
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-isextensible
+        /// </summary>
         public override bool Extensible
         {
             get
             {
-                if (!TryCallHandler(TrapIsExtensible, new[] { _target }, out var result))
+                if (!TryCallHandler(TrapIsExtensible, new JsValue[] { _target }, out var result))
                 {
                     return _target.Extensible;
                 }
@@ -393,9 +438,12 @@ namespace Jint.Native.Proxy
             }
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-getprototypeof
+        /// </summary>
         protected internal override ObjectInstance GetPrototypeOf()
         {
-            if (!TryCallHandler(TrapGetProtoTypeOf, new [] { _target }, out var handlerProto ))
+            if (!TryCallHandler(TrapGetProtoTypeOf, new JsValue[] { _target }, out var handlerProto ))
             {
                 return _target.Prototype;
             }
@@ -418,6 +466,9 @@ namespace Jint.Native.Proxy
             return (ObjectInstance) handlerProto;
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-setprototypeof-v
+        /// </summary>
         public override bool SetPrototypeOf(JsValue value)
         {
             if (!TryCallHandler(TrapSetProtoTypeOf, new[] { _target, value }, out var result))

+ 26 - 26
Jint/Native/RegExp/RegExpPrototype.cs

@@ -207,7 +207,7 @@ namespace Jint.Native.RegExp
                 var matchStr = TypeConverter.ToString(result.Get(0));
                 if (matchStr == "")
                 {
-                    var thisIndex = (int) TypeConverter.ToLength(rx.Get(RegExpInstance.PropertyLastIndex));
+                    var thisIndex = TypeConverter.ToLength(rx.Get(RegExpInstance.PropertyLastIndex));
                     var nextIndex = AdvanceStringIndex(s, thisIndex, fullUnicode);
                     rx.Set(RegExpInstance.PropertyLastIndex, nextIndex);
                 }
@@ -406,12 +406,12 @@ namespace Jint.Native.RegExp
 
             if (lim == 0)
             {
-                return _realm.Intrinsics.Array.ConstructFast(0);
+                return _realm.Intrinsics.Array.ArrayCreate(0);
             }
 
             if (s.Length == 0)
             {
-                var a = _realm.Intrinsics.Array.ConstructFast(0);
+                var a = _realm.Intrinsics.Array.ArrayCreate(0);
                 var z = RegExpExec(splitter, s);
                 if (!z.IsNull())
                 {
@@ -492,10 +492,10 @@ namespace Jint.Native.RegExp
 
         private JsValue SplitSlow(string s, ObjectInstance splitter, bool unicodeMatching, uint lengthA, long lim)
         {
-            var a = _realm.Intrinsics.Array.ConstructFast(0);
-            var previousStringIndex = 0;
-            var currentIndex = 0;
-            while (currentIndex < s.Length)
+            var a = _realm.Intrinsics.Array.ArrayCreate(0);
+            ulong previousStringIndex = 0;
+            ulong currentIndex = 0;
+            while (currentIndex < (ulong) s.Length)
             {
                 splitter.Set(RegExpInstance.PropertyLastIndex, currentIndex, true);
                 var z = RegExpExec(splitter, s);
@@ -505,15 +505,15 @@ namespace Jint.Native.RegExp
                     continue;
                 }
 
-                var endIndex = (int) TypeConverter.ToLength(splitter.Get(RegExpInstance.PropertyLastIndex));
-                endIndex = System.Math.Min(endIndex, s.Length);
+                var endIndex = TypeConverter.ToLength(splitter.Get(RegExpInstance.PropertyLastIndex));
+                endIndex = System.Math.Min(endIndex, (ulong) s.Length);
                 if (endIndex == previousStringIndex)
                 {
                     currentIndex = AdvanceStringIndex(s, currentIndex, unicodeMatching);
                     continue;
                 }
 
-                var t = s.Substring(previousStringIndex, currentIndex - previousStringIndex);
+                var t = s.Substring((int) previousStringIndex, (int) (currentIndex - previousStringIndex));
                 a.SetIndexValue(lengthA, t, updateLength: true);
                 lengthA++;
                 if (lengthA == lim)
@@ -540,7 +540,7 @@ namespace Jint.Native.RegExp
                 currentIndex = previousStringIndex;
             }
 
-            a.SetIndexValue(lengthA, s.Substring(previousStringIndex, s.Length - previousStringIndex), updateLength: true);
+            a.SetIndexValue(lengthA, s.Substring((int) previousStringIndex, s.Length - (int) previousStringIndex), updateLength: true);
             return a;
         }
 
@@ -652,7 +652,7 @@ namespace Jint.Native.RegExp
                 && rei.TryGetDefaultRegExpExec(out _))
             {
                 // fast path
-                var a = _realm.Intrinsics.Array.ConstructFast(0);
+                var a = _realm.Intrinsics.Array.ArrayCreate(0);
 
                 if (rei.Sticky)
                 {
@@ -697,7 +697,7 @@ namespace Jint.Native.RegExp
 
         private JsValue MatchSlow(ObjectInstance rx, string s, bool fullUnicode)
         {
-            var a = _realm.Intrinsics.Array.ConstructFast(0);
+            var a = _realm.Intrinsics.Array.ArrayCreate(0);
             uint n = 0;
             while (true)
             {
@@ -712,7 +712,7 @@ namespace Jint.Native.RegExp
                 a.SetIndexValue(n, matchStr, updateLength: false);
                 if (matchStr == "")
                 {
-                    var thisIndex = (int) TypeConverter.ToLength(rx.Get(RegExpInstance.PropertyLastIndex));
+                    var thisIndex = TypeConverter.ToLength(rx.Get(RegExpInstance.PropertyLastIndex));
                     var nextIndex = AdvanceStringIndex(s, thisIndex, fullUnicode);
                     rx.Set(RegExpInstance.PropertyLastIndex, nextIndex, true);
                 }
@@ -747,20 +747,20 @@ namespace Jint.Native.RegExp
             return _realm.Intrinsics.RegExpStringIteratorPrototype.Construct(matcher, s, global, fullUnicode);
         }
 
-        private static int AdvanceStringIndex(string s, int index, bool unicode)
+        private static ulong AdvanceStringIndex(string s, ulong index, bool unicode)
         {
-            if (!unicode || index + 1 >= s.Length)
+            if (!unicode || index + 1 >= (ulong) s.Length)
             {
                 return index + 1;
             }
 
-            var first = s[index];
+            var first = s[(int) index];
             if (first < 0xD800 || first > 0xDBFF)
             {
                 return index + 1;
             }
 
-            var second = s[index + 1];
+            var second = s[(int) (index + 1)];
             if (second < 0xDC00 || second > 0xDFFF)
             {
                 return index + 1;
@@ -806,8 +806,8 @@ namespace Jint.Native.RegExp
 
         private static JsValue RegExpBuiltinExec(RegExpInstance R, string s)
         {
-            var length = s.Length;
-            var lastIndex = (int) TypeConverter.ToLength(R.Get(RegExpInstance.PropertyLastIndex));
+            var length = (ulong) s.Length;
+            var lastIndex = TypeConverter.ToLength(R.Get(RegExpInstance.PropertyLastIndex));
 
             var global = R.Global;
             var sticky = R.Sticky;
@@ -818,13 +818,13 @@ namespace Jint.Native.RegExp
 
             if (R.Source == RegExpInstance.regExpForMatchingAllCharacters)  // Reg Exp is really ""
             {
-                if (lastIndex > s.Length)
+                if (lastIndex > (ulong) s.Length)
                 {
                     return Null;
                 }
 
                 // "aaa".match() => [ '', index: 0, input: 'aaa' ]
-                var array = R.Engine.Realm.Intrinsics.Array.ConstructFast(1);
+                var array = R.Engine.Realm.Intrinsics.Array.ArrayCreate(1);
                 array.FastAddProperty(PropertyIndex, lastIndex, true, true, true);
                 array.FastAddProperty(PropertyInput, s, true, true, true);
                 array.SetIndexValue(0, JsString.Empty, updateLength: false);
@@ -837,7 +837,7 @@ namespace Jint.Native.RegExp
             if (!global & !sticky && !fullUnicode)
             {
                 // we can the non-stateful fast path which is the common case
-                var m = matcher.Match(s, lastIndex);
+                var m = matcher.Match(s, (int) lastIndex);
                 if (!m.Success)
                 {
                     return Null;
@@ -856,8 +856,8 @@ namespace Jint.Native.RegExp
                     return Null;
                 }
 
-                match = R.Value.Match(s, lastIndex);
-                var success = match.Success && (!sticky || match.Index == lastIndex);
+                match = R.Value.Match(s, (int) lastIndex);
+                var success = match.Success && (!sticky || match.Index == (int) lastIndex);
                 if (!success)
                 {
                     if (sticky)
@@ -896,7 +896,7 @@ namespace Jint.Native.RegExp
 
         private static ArrayInstance CreateReturnValueArray(Engine engine, Match match, string inputValue, bool fullUnicode)
         {
-            var array = engine.Realm.Intrinsics.Array.ConstructFast((ulong) match.Groups.Count);
+            var array = engine.Realm.Intrinsics.Array.ArrayCreate((uint) match.Groups.Count);
             array.CreateDataProperty(PropertyIndex, match.Index);
             array.CreateDataProperty(PropertyInput, inputValue);
 

+ 12 - 1
Jint/Runtime/TypeConverter.cs

@@ -392,7 +392,18 @@ namespace Jint.Runtime
                 return number;
             }
 
-            return (long) number;
+            if (number is >= long.MinValue and <= long.MaxValue)
+            {
+                return (long) number;
+            }
+
+            var integer = Math.Floor(Math.Abs(number));
+            if (number < 0)
+            {
+                integer *= -1;
+            }
+
+            return integer;
         }
 
         internal static double ToInteger(string o)