Forráskód Böngészése

Upgrade test262 suite and fix issues (#1910)

* create shims for async generators
* add initial version of Math.sumPrecise which won't pass all the tests (insane as usual)
* harmonize function expression building
Marko Lahma 1 éve
szülő
commit
e3a3d5599f

+ 4 - 1
Jint.Tests.Test262/Test262Harness.settings.json

@@ -1,5 +1,5 @@
 {
-  "SuiteGitSha": "c3a326ace810e7c80a4e1b8df8c8b704ed223c28",
+  "SuiteGitSha": "b8cb40b66a61afd57550a84f4170e16ebfbd1e46",
   //"SuiteDirectory": "//mnt/c/work/test262",
   "TargetPath": "./Generated",
   "Namespace": "Jint.Tests.Test262",
@@ -11,11 +11,14 @@
     "decorators",
     "import-assertions",
     "iterator-helpers",
+    "Math.sumPrecise",
     "regexp-lookbehind",
     "regexp-modifiers",
     "regexp-unicode-property-escapes",
     "regexp-v-flag",
+    "source-phase-imports",
     "tail-call-optimization",
+    "uint8array-base64",
     "Temporal",
     "u180e"
   ],

+ 0 - 21
Jint/IsExternalInit.cs

@@ -1,21 +0,0 @@
-#if !NET5_0_OR_GREATER
-
-// Source: https://github.com/dotnet/runtime/blob/v6.0.5/src/libraries/Common/src/System/Runtime/CompilerServices/IsExternalInit.cs
-
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.ComponentModel;
-
-namespace System.Runtime.CompilerServices;
-
-/// <summary>
-/// Reserved to be used by the compiler for tracking metadata.
-/// This class should not be used by developers in source code.
-/// </summary>
-[EditorBrowsable(EditorBrowsableState.Never)]
-internal static class IsExternalInit
-{
-}
-
-#endif

+ 1 - 1
Jint/Jint.csproj

@@ -19,7 +19,7 @@
 
     <IsAotCompatible Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net7.0'))">true</IsAotCompatible>
 
-    <PolySharpExcludeGeneratedTypes>System.Runtime.CompilerServices.IsExternalInit;System.Runtime.CompilerServices.RequiresLocationAttribute</PolySharpExcludeGeneratedTypes>
+    <PolySharpExcludeGeneratedTypes>System.Runtime.CompilerServices.RequiresLocationAttribute</PolySharpExcludeGeneratedTypes>
     <PolySharpIncludeRuntimeSupportedAttributes>true</PolySharpIncludeRuntimeSupportedAttributes>
 
   </PropertyGroup>

+ 1 - 1
Jint/Native/Array/ArrayOperations.cs

@@ -351,7 +351,7 @@ namespace Jint.Native.Array
 
             public override bool TryGetValue(ulong index, out JsValue value)
             {
-                if (index < _target.GetLength())
+                if (_target.IsValidIntegerIndex(index))
                 {
                     value = _target[(int) index];
                     return true;

+ 47 - 0
Jint/Native/AsyncGenerator/AsyncGeneratorFunctionConstructor.cs

@@ -0,0 +1,47 @@
+using Jint.Native.AsyncFunction;
+using Jint.Native.Function;
+using Jint.Native.Iterator;
+using Jint.Native.Object;
+using Jint.Runtime;
+using Jint.Runtime.Descriptors;
+
+namespace Jint.Native.Generator;
+
+/// <summary>
+/// https://tc39.es/ecma262/#sec-asyncgeneratorfunction-constructor
+/// </summary>
+internal sealed class AsyncGeneratorFunctionConstructor : Constructor
+{
+    private static readonly JsString _functionName = new("AsyncGeneratorFunction");
+
+    internal AsyncGeneratorFunctionConstructor(
+        Engine engine,
+        Realm realm,
+        AsyncFunctionPrototype prototype,
+        IteratorPrototype iteratorPrototype)
+        : base(engine, realm, _functionName)
+    {
+        PrototypeObject = new AsyncGeneratorFunctionPrototype(engine, this, prototype, iteratorPrototype);
+        _prototype = PrototypeObject;
+        _prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
+        _length = new PropertyDescriptor(JsNumber.PositiveOne, PropertyFlag.Configurable);
+    }
+
+    public AsyncGeneratorFunctionPrototype PrototypeObject { get; }
+
+    protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
+    {
+        return Construct(arguments, thisObject);
+    }
+
+    public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
+    {
+        var function = _realm.Intrinsics.Function.CreateDynamicFunction(
+            this,
+            newTarget,
+            FunctionKind.AsyncGenerator,
+            arguments);
+
+        return function;
+    }
+}

+ 44 - 0
Jint/Native/AsyncGenerator/AsyncGeneratorFunctionPrototype.cs

@@ -0,0 +1,44 @@
+using Jint.Collections;
+using Jint.Native.AsyncFunction;
+using Jint.Native.Iterator;
+using Jint.Native.Symbol;
+using Jint.Runtime;
+using Jint.Runtime.Descriptors;
+
+namespace Jint.Native.Generator;
+
+/// <summary>
+/// https://tc39.es/ecma262/#sec-properties-of-asyncgeneratorfunction-prototype
+/// </summary>
+internal sealed class AsyncGeneratorFunctionPrototype : Prototype
+{
+    private readonly AsyncGeneratorFunctionConstructor? _constructor;
+
+    internal AsyncGeneratorFunctionPrototype(
+        Engine engine,
+        AsyncGeneratorFunctionConstructor constructor,
+        AsyncFunctionPrototype prototype,
+        IteratorPrototype iteratorPrototype) : base(engine, engine.Realm)
+    {
+        _constructor = constructor;
+        _prototype = prototype;
+        PrototypeObject = new AsyncGeneratorPrototype(engine, this, iteratorPrototype);
+    }
+
+    public AsyncGeneratorPrototype PrototypeObject { get; }
+
+    protected override void Initialize()
+    {
+        var properties = new PropertyDictionary(2, checkExistingKeys: false)
+        {
+            [KnownKeys.Constructor] = new PropertyDescriptor(_constructor, PropertyFlag.Configurable),
+            [KnownKeys.Prototype] = new PropertyDescriptor(PrototypeObject, PropertyFlag.Configurable)
+        };
+        SetProperties(properties);
+        var symbols = new SymbolDictionary(1)
+        {
+            [GlobalSymbolRegistry.ToStringTag] = new PropertyDescriptor("AsyncGeneratorFunction", PropertyFlag.Configurable)
+        };
+        SetSymbols(symbols);
+    }
+}

+ 89 - 0
Jint/Native/AsyncGenerator/AsyncGeneratorPrototype.cs

@@ -0,0 +1,89 @@
+using Jint.Collections;
+using Jint.Native.Iterator;
+using Jint.Native.Object;
+using Jint.Native.Symbol;
+using Jint.Runtime;
+using Jint.Runtime.Descriptors;
+using Jint.Runtime.Interop;
+
+namespace Jint.Native.Generator;
+
+/// <summary>
+/// https://tc39.es/ecma262/#sec-asyncgenerator-objects
+/// </summary>
+internal sealed class AsyncGeneratorPrototype : ObjectInstance
+{
+    private readonly AsyncGeneratorFunctionPrototype _constructor;
+
+    internal AsyncGeneratorPrototype(
+        Engine engine,
+        AsyncGeneratorFunctionPrototype constructor,
+        IteratorPrototype iteratorPrototype) : base(engine)
+    {
+        _constructor = constructor;
+        _prototype = iteratorPrototype;
+    }
+
+    protected override void Initialize()
+    {
+        const PropertyFlag PropertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
+        const PropertyFlag LengthFlags = PropertyFlag.Configurable;
+        var properties = new PropertyDictionary(4, false)
+        {
+            ["constructor"] = new(_constructor, PropertyFlag.Configurable),
+            ["next"] = new(new ClrFunction(Engine, "next", Next, 1, LengthFlags), PropertyFlags),
+            ["return"] = new(new ClrFunction(Engine, "return", Return, 1, LengthFlags), PropertyFlags),
+            ["throw"] = new(new ClrFunction(Engine, "throw", Throw, 1, LengthFlags), PropertyFlags)
+        };
+        SetProperties(properties);
+
+        var symbols = new SymbolDictionary(1)
+        {
+            [GlobalSymbolRegistry.ToStringTag] = new("Generator", PropertyFlag.Configurable)
+        };
+        SetSymbols(symbols);
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-generator.prototype.next
+    /// </summary>
+    private ObjectInstance Next(JsValue thisObject, JsValue[] arguments)
+    {
+        var g = AssertGeneratorInstance(thisObject);
+        var value = arguments.At(0, null!);
+        return g.GeneratorResume(value, null);
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-generator.prototype.return
+    /// </summary>
+    private JsValue Return(JsValue thisObject, JsValue[] arguments)
+    {
+        var g = AssertGeneratorInstance(thisObject);
+        var value = arguments.At(0);
+        var C = new Completion(CompletionType.Return, value, null!);
+        return g.GeneratorResumeAbrupt(C, null);
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-generator.prototype.throw
+    /// </summary>
+    private JsValue Throw(JsValue thisObject, JsValue[] arguments)
+    {
+        var g = AssertGeneratorInstance(thisObject);
+        var exception = arguments.At(0);
+        var C = new Completion(CompletionType.Throw, exception, null!);
+        return g.GeneratorResumeAbrupt(C, null);
+    }
+
+    private GeneratorInstance AssertGeneratorInstance(JsValue thisObj)
+    {
+        var generatorInstance = thisObj as GeneratorInstance;
+        if (generatorInstance is null)
+        {
+            ExceptionHelper.ThrowTypeError(_engine.Realm, "object must be a Generator instance");
+        }
+
+        return generatorInstance;
+    }
+}

+ 6 - 6
Jint/Native/Function/FunctionInstance.Dynamic.cs

@@ -47,6 +47,8 @@ public partial class Function
                 fallbackProto = static intrinsics => intrinsics.GeneratorFunction.PrototypeObject;
                 break;
             case FunctionKind.AsyncGenerator:
+                fallbackProto = static intrinsics => intrinsics.AsyncGeneratorFunction.PrototypeObject;
+                break;
             default:
                 ExceptionHelper.ThrowArgumentOutOfRangeException(nameof(kind), kind.ToString());
                 break;
@@ -91,7 +93,7 @@ public partial class Function
                         functionExpression = "async function f(){}";
                         break;
                     case FunctionKind.AsyncGenerator:
-                        ExceptionHelper.ThrowNotImplementedException("Async generators not implemented");
+                        functionExpression = "async function* f(){}";
                         break;
                     default:
                         ExceptionHelper.ThrowArgumentOutOfRangeException(nameof(kind), kind.ToString());
@@ -112,7 +114,7 @@ public partial class Function
                         functionExpression = "function* f(";
                         break;
                     case FunctionKind.AsyncGenerator:
-                        ExceptionHelper.ThrowNotImplementedException("Async generators not implemented");
+                        functionExpression = "async function* f(";
                         break;
                     default:
                         ExceptionHelper.ThrowArgumentOutOfRangeException(nameof(kind), kind.ToString());
@@ -171,10 +173,8 @@ public partial class Function
         }
         else if (kind == FunctionKind.AsyncGenerator)
         {
-            // TODO
-            // Let prototype be ! OrdinaryObjectCreate(%AsyncGeneratorFunction.prototype.prototype%).
-            // Perform DefinePropertyOrThrow(F, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
-            ExceptionHelper.ThrowNotImplementedException("async generators not implemented");
+            var prototype = OrdinaryObjectCreate(_engine, _realm.Intrinsics.AsyncGeneratorFunction.PrototypeObject.PrototypeObject);
+            F.DefinePropertyOrThrow(CommonProperties.Prototype, new PropertyDescriptor(prototype, PropertyFlag.Writable));
         }
         else if (kind == FunctionKind.Normal)
         {

+ 108 - 17
Jint/Native/Math/MathInstance.cs

@@ -21,50 +21,51 @@ namespace Jint.Native.Math
         {
             var properties = new PropertyDictionary(45, checkExistingKeys: false)
             {
+                ["E"] = new PropertyDescriptor(System.Math.E, PropertyFlag.AllForbidden),
+                ["LN10"] = new PropertyDescriptor(System.Math.Log(10), PropertyFlag.AllForbidden),
+                ["LN2"] = new PropertyDescriptor(System.Math.Log(2), PropertyFlag.AllForbidden),
+                ["LOG10E"] = new PropertyDescriptor(System.Math.Log(System.Math.E, 10), PropertyFlag.AllForbidden),
+                ["LOG2E"] = new PropertyDescriptor(System.Math.Log(System.Math.E, 2), PropertyFlag.AllForbidden),
+                ["PI"] = new PropertyDescriptor(System.Math.PI, PropertyFlag.AllForbidden),
+                ["SQRT1_2"] = new PropertyDescriptor(System.Math.Sqrt(0.5), PropertyFlag.AllForbidden),
+                ["SQRT2"] = new PropertyDescriptor(System.Math.Sqrt(2), PropertyFlag.AllForbidden),
                 ["abs"] = new PropertyDescriptor(new ClrFunction(Engine, "abs", Abs, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["acos"] = new PropertyDescriptor(new ClrFunction(Engine, "acos", Acos, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["acosh"] = new PropertyDescriptor(new ClrFunction(Engine, "acosh", Acosh, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["asin"] = new PropertyDescriptor(new ClrFunction(Engine, "asin", Asin, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["asinh"] = new PropertyDescriptor(new ClrFunction(Engine, "asinh", Asinh, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["atan"] = new PropertyDescriptor(new ClrFunction(Engine, "atan", Atan, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
-                ["atanh"] = new PropertyDescriptor(new ClrFunction(Engine, "atanh", Atanh, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["atan2"] = new PropertyDescriptor(new ClrFunction(Engine, "atan2", Atan2, 2, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
+                ["atanh"] = new PropertyDescriptor(new ClrFunction(Engine, "atanh", Atanh, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
+                ["cbrt"] = new PropertyDescriptor(new ClrFunction(Engine, "cbrt", Cbrt, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["ceil"] = new PropertyDescriptor(new ClrFunction(Engine, "ceil", Ceil, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
+                ["clz32"] = new PropertyDescriptor(new ClrFunction(Engine, "clz32", Clz32, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["cos"] = new PropertyDescriptor(new ClrFunction(Engine, "cos", Cos, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["cosh"] = new PropertyDescriptor(new ClrFunction(Engine, "cosh", Cosh, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["exp"] = new PropertyDescriptor(new ClrFunction(Engine, "exp", Exp, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["expm1"] = new PropertyDescriptor(new ClrFunction(Engine, "expm1", Expm1, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
-                ["floor"] = new PropertyDescriptor(new ClrFunction(Engine, "floor", Floor, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["f16round"] = new PropertyDescriptor(new ClrFunction(Engine, "f16round", F16Round, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
+                ["floor"] = new PropertyDescriptor(new ClrFunction(Engine, "floor", Floor, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
+                ["fround"] = new PropertyDescriptor(new ClrFunction(Engine, "fround", Fround, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
+                ["hypot"] = new PropertyDescriptor(new ClrFunction(Engine, "hypot", Hypot, 2, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
+                ["imul"] = new PropertyDescriptor(new ClrFunction(Engine, "imul", Imul, 2, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["log"] = new PropertyDescriptor(new ClrFunction(Engine, "log", Log, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
+                ["log10"] = new PropertyDescriptor(new ClrFunction(Engine, "log10", Log10, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["log1p"] = new PropertyDescriptor(new ClrFunction(Engine, "log1p", Log1p, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["log2"] = new PropertyDescriptor(new ClrFunction(Engine, "log2", Log2, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
-                ["log10"] = new PropertyDescriptor(new ClrFunction(Engine, "log10", Log10, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["max"] = new PropertyDescriptor(new ClrFunction(Engine, "max", Max, 2, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["min"] = new PropertyDescriptor(new ClrFunction(Engine, "min", Min, 2, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["pow"] = new PropertyDescriptor(new ClrFunction(Engine, "pow", Pow, 2, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["random"] = new PropertyDescriptor(new ClrFunction(Engine, "random", Random, 0, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["round"] = new PropertyDescriptor(new ClrFunction(Engine, "round", Round, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
-                ["fround"] = new PropertyDescriptor(new ClrFunction(Engine, "fround", Fround, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
+                ["sign"] = new PropertyDescriptor(new ClrFunction(Engine, "sign", Sign, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["sin"] = new PropertyDescriptor(new ClrFunction(Engine, "sin", Sin, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["sinh"] = new PropertyDescriptor(new ClrFunction(Engine, "sinh", Sinh, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
+                ["sumPrecise"] = new PropertyDescriptor(new ClrFunction(Engine, "sumPrecise", SumPrecise, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["sqrt"] = new PropertyDescriptor(new ClrFunction(Engine, "sqrt", Sqrt, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["tan"] = new PropertyDescriptor(new ClrFunction(Engine, "tan", Tan, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["tanh"] = new PropertyDescriptor(new ClrFunction(Engine, "tanh", Tanh, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
                 ["trunc"] = new PropertyDescriptor(new ClrFunction(Engine, "trunc", Truncate, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
-                ["sign"] = new PropertyDescriptor(new ClrFunction(Engine, "sign", Sign, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
-                ["cbrt"] = new PropertyDescriptor(new ClrFunction(Engine, "cbrt", Cbrt, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
-                ["hypot"] = new PropertyDescriptor(new ClrFunction(Engine, "hypot", Hypot, 2, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
-                ["imul"] = new PropertyDescriptor(new ClrFunction(Engine, "imul", Imul, 2, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
-                ["clz32"] = new PropertyDescriptor(new ClrFunction(Engine, "clz32", Clz32, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
-                ["E"] = new PropertyDescriptor(System.Math.E, PropertyFlag.AllForbidden),
-                ["LN10"] = new PropertyDescriptor(System.Math.Log(10), PropertyFlag.AllForbidden),
-                ["LN2"] = new PropertyDescriptor(System.Math.Log(2), PropertyFlag.AllForbidden),
-                ["LOG2E"] = new PropertyDescriptor(System.Math.Log(System.Math.E, 2), PropertyFlag.AllForbidden),
-                ["LOG10E"] = new PropertyDescriptor(System.Math.Log(System.Math.E, 10), PropertyFlag.AllForbidden),
-                ["PI"] = new PropertyDescriptor(System.Math.PI, PropertyFlag.AllForbidden),
-                ["SQRT1_2"] = new PropertyDescriptor(System.Math.Sqrt(0.5), PropertyFlag.AllForbidden),
-                ["SQRT2"] = new PropertyDescriptor(System.Math.Sqrt(2), PropertyFlag.AllForbidden),
             };
             SetProperties(properties);
 
@@ -1066,6 +1067,96 @@ namespace Jint.Native.Math
             return System.Math.Sqrt(y);
         }
 
+        /// <summary>
+        /// https://github.com/tc39/proposal-math-sum
+        /// </summary>
+        private JsValue SumPrecise(JsValue thisObject, JsValue[] arguments)
+        {
+            var items = arguments.At(0);
+            if (items.IsNullOrUndefined())
+            {
+                ExceptionHelper.ThrowTypeError(_engine.Realm);
+            }
+
+            var iteratorRecord = items.GetIterator(_engine.Realm);
+            var state = JsNumber.NegativeZero._value;
+            List<double> sum = [];
+            long count = 0;
+            const double Finite = 1;
+            try
+            {
+                while (iteratorRecord.TryIteratorStep(out var next))
+                {
+                    next.TryGetValue(CommonProperties.Value, out var value);
+                    count++;
+                    if (count > 9007199254740992)
+                    {
+                        ExceptionHelper.ThrowRangeError(_engine.Realm);
+                    }
+
+                    if (value is not JsNumber jsNumber)
+                    {
+                        ExceptionHelper.ThrowTypeError(_engine.Realm, "Input is not a number: " + next);
+                        return default;
+                    }
+
+                    if (!double.IsNaN(state))
+                    {
+                        var n = jsNumber._value;
+                        if (double.IsNaN(n))
+                        {
+                            state = double.NaN;
+                        }
+                        else if (double.IsPositiveInfinity(n))
+                        {
+                            if (double.IsNegativeInfinity(state))
+                            {
+                                state = double.NaN;
+                            }
+                            else
+                            {
+                                state = double.PositiveInfinity;
+                            }
+                        }
+                        else if (double.IsNegativeInfinity(n))
+                        {
+                            if (double.IsPositiveInfinity(state))
+                            {
+                                state = double.NaN;
+                            }
+                            else
+                            {
+                                state = double.NegativeInfinity;
+                            }
+                        }
+                        else if (!NumberInstance.IsNegativeZero(n) && (NumberInstance.IsNegativeZero(state)  || state == Finite))
+                        {
+                            state = Finite;
+                            sum.Add(n);
+                        }
+                    }
+                }
+
+            }
+            catch
+            {
+                iteratorRecord.Close(CompletionType.Throw);
+                iteratorRecord = null;
+                throw;
+            }
+            finally
+            {
+                iteratorRecord?.Close(CompletionType.Normal);
+            }
+
+            if (state != Finite)
+            {
+                return state;
+            }
+
+            return sum.FSum();
+        }
+
         private static double[] Coerced(JsValue[] arguments)
         {
             // TODO stackalloc

+ 66 - 0
Jint/Native/Math/MathX.cs

@@ -0,0 +1,66 @@
+// based on https://raw.githubusercontent.com/AnthonyLloyd/CsCheck/master/Tests/MathX.cs
+
+namespace Jint.Native.Math;
+
+internal static class MathX
+{
+    private static double TwoSum(double a, double b, out double lo)
+    {
+        var hi = a + b;
+        lo = hi - b;
+        lo = lo - hi + b + (a - lo);
+        return hi;
+    }
+
+    /// <summary>Shewchuk summation</summary>
+    internal static double FSum(this List<double> values)
+    {
+        if (values.Count < 3) return values.Count == 2 ? values[0] + values[1] : values.Count == 1 ? values[0] : 0.0;
+        Span<double> partials = stackalloc double[16];
+        var hi = TwoSum(values[0], values[1], out var lo);
+        int count = 0;
+        for (int i = 2; i < values.Count; i++)
+        {
+            var v = TwoSum(values[i], lo, out lo);
+            int c = 0;
+            for (int j = 0; j < count; j++)
+            {
+                v = TwoSum(v, partials[j], out var p);
+                if (p != 0.0)
+                    partials[c++] = p;
+            }
+
+            hi = TwoSum(hi, v, out v);
+            if (v != 0.0)
+            {
+                if (c == partials.Length)
+                {
+                    var newPartials = new double[partials.Length * 2];
+                    partials.CopyTo(newPartials);
+                    partials = newPartials;
+                }
+
+                partials[c++] = v;
+            }
+
+            count = c;
+        }
+
+        if (count != 0)
+        {
+            if (lo == 0) // lo has a good chance of being zero
+            {
+                lo = partials[0];
+                if (count == 1) return lo + hi;
+                partials = partials.Slice(1, count - 1);
+            }
+            else
+                partials = partials.Slice(0, count);
+
+            foreach (var p in partials)
+                lo += p;
+        }
+
+        return lo + hi;
+    }
+}

+ 51 - 12
Jint/Runtime/Interpreter/Expressions/JintArrowFunctionExpression.cs

@@ -1,4 +1,3 @@
-using Jint.Native;
 using Jint.Native.Function;
 
 namespace Jint.Runtime.Interpreter.Expressions;
@@ -14,21 +13,61 @@ internal sealed class JintArrowFunctionExpression : JintExpression
 
     protected override object EvaluateInternal(EvaluationContext context)
     {
-        var engine = context.Engine;
-        var env = engine.ExecutionContext.LexicalEnvironment;
-        var privateEnv = engine.ExecutionContext.PrivateEnvironment;
+        return Build(context.Engine, _function);
+    }
+
+    private static ScriptFunction Build(Engine engine, JintFunctionDefinition function)
+    {
+        var functionName = function.Name ?? "";
+        var closure = function.Function.Async
+            ? InstantiateAsyncArrowFunctionExpression(engine, function, functionName)
+            : InstantiateArrowFunctionExpression(engine, function, functionName);
+
+        return closure;
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiatearrowfunctionexpression
+    /// </summary>
+    private static ScriptFunction InstantiateArrowFunctionExpression(Engine engine, JintFunctionDefinition function, string name)
+    {
+        var runningExecutionContext = engine.ExecutionContext;
+        var env = runningExecutionContext.LexicalEnvironment;
+        var privateEnv = runningExecutionContext.PrivateEnvironment;
+
+        var intrinsics = engine.Realm.Intrinsics;
+        var closure = intrinsics.Function.OrdinaryFunctionCreate(
+            intrinsics.Function.PrototypeObject,
+            function,
+            FunctionThisMode.Lexical,
+            env,
+            privateEnv
+        );
+
+        closure.SetFunctionName(name);
+
+        return closure;
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiateasyncarrowfunctionexpression
+    /// </summary>
+    private static ScriptFunction InstantiateAsyncArrowFunctionExpression(Engine engine, JintFunctionDefinition function, string name)
+    {
+        var executionContext = engine.ExecutionContext;
+        var env = executionContext.LexicalEnvironment;
+        var privateEnv = executionContext.PrivateEnvironment;
 
-        var closure = engine.Realm.Intrinsics.Function.OrdinaryFunctionCreate(
-            engine.Realm.Intrinsics.Function.PrototypeObject,
-            _function,
+        var intrinsics = engine.Realm.Intrinsics;
+        var closure = intrinsics.Function.OrdinaryFunctionCreate(
+            intrinsics.AsyncFunction.PrototypeObject,
+            function,
             FunctionThisMode.Lexical,
             env,
-            privateEnv);
+            privateEnv
+        );
 
-        if (_function.Name is null)
-        {
-            closure.SetFunctionName(JsString.Empty);
-        }
+        closure.SetFunctionName(name);
 
         return closure;
     }

+ 171 - 130
Jint/Runtime/Interpreter/Expressions/JintFunctionExpression.cs

@@ -4,163 +4,204 @@ using Jint.Native.Object;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Environments;
 
-namespace Jint.Runtime.Interpreter.Expressions
+namespace Jint.Runtime.Interpreter.Expressions;
+
+internal sealed class JintFunctionExpression : JintExpression
 {
-    internal sealed class JintFunctionExpression : JintExpression
+    private readonly JintFunctionDefinition _function;
+
+    public JintFunctionExpression(FunctionExpression function) : base(function)
+    {
+        _function = new JintFunctionDefinition(function);
+    }
+
+    protected override object EvaluateInternal(EvaluationContext context)
     {
-        private readonly JintFunctionDefinition _function;
+        return Build(context.Engine, _function);
+    }
 
-        public JintFunctionExpression(FunctionExpression function) : base(function)
+    public override JsValue GetValue(EvaluationContext context)
+    {
+        return Build(context.Engine, _function);
+    }
+
+    private static ScriptFunction Build(Engine engine, JintFunctionDefinition function)
+    {
+        ScriptFunction closure;
+        var functionName = function.Name ?? "";
+        if (!function.Function.Generator)
         {
-            _function = new JintFunctionDefinition(function);
+            closure = function.Function.Async
+                ? InstantiateAsyncFunctionExpression(engine, function, functionName)
+                : InstantiateOrdinaryFunctionExpression(engine, function, functionName);
         }
+        else
+        {
+            closure = function.Function.Async
+                ? InstantiateAsyncGeneratorFunctionExpression(engine, function, functionName)
+                : InstantiateGeneratorFunctionExpression(engine, function, functionName);
+        }
+
+        return closure;
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiateordinaryfunctionexpression
+    /// </summary>
+    private static ScriptFunction InstantiateOrdinaryFunctionExpression(Engine engine, JintFunctionDefinition function, string? name = "")
+    {
+        var runningExecutionContext = engine.ExecutionContext;
+        var env = runningExecutionContext.LexicalEnvironment;
+        var privateEnv = runningExecutionContext.PrivateEnvironment;
 
-        protected override object EvaluateInternal(EvaluationContext context)
+        DeclarativeEnvironment? funcEnv = null;
+        if (!string.IsNullOrWhiteSpace(name))
         {
-            return GetValue(context);
+            funcEnv = JintEnvironment.NewDeclarativeEnvironment(engine, engine.ExecutionContext.LexicalEnvironment);
+            funcEnv.CreateImmutableBinding(name!, strict: false);
         }
 
-        public override JsValue GetValue(EvaluationContext context)
+        var thisMode = function.Strict
+            ? FunctionThisMode.Strict
+            : FunctionThisMode.Global;
+
+        var intrinsics = engine.Realm.Intrinsics;
+        var closure = intrinsics.Function.OrdinaryFunctionCreate(
+            intrinsics.Function.PrototypeObject,
+            function,
+            thisMode,
+            funcEnv ?? env,
+            privateEnv
+        );
+
+        if (name is not null)
         {
-            ScriptFunction closure;
-            var functionName = _function.Name ?? "";
-            if (!_function.Function.Generator)
-            {
-                closure = _function.Function.Async
-                    ? InstantiateAsyncFunctionExpression(context, functionName)
-                    : InstantiateOrdinaryFunctionExpression(context, functionName);
-            }
-            else
-            {
-                closure = InstantiateGeneratorFunctionExpression(context, functionName);
-            }
-
-            return closure;
+            closure.SetFunctionName(name);
         }
+        closure.MakeConstructor();
+
+        funcEnv?.InitializeBinding(name!, closure);
+
+        return closure;
+    }
 
-        /// <summary>
-        /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiateordinaryfunctionexpression
-        /// </summary>
-        private ScriptFunction InstantiateOrdinaryFunctionExpression(EvaluationContext context, string? name = "")
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiateasyncfunctionexpression
+    /// </summary>
+    private static ScriptFunction InstantiateAsyncFunctionExpression(Engine engine, JintFunctionDefinition function, string? name = "")
+    {
+        var runningExecutionContext = engine.ExecutionContext;
+        var env = runningExecutionContext.LexicalEnvironment;
+        var privateEnv = runningExecutionContext.PrivateEnvironment;
+
+        DeclarativeEnvironment? funcEnv = null;
+        if (!string.IsNullOrWhiteSpace(name))
         {
-            var engine = context.Engine;
-            var runningExecutionContext = engine.ExecutionContext;
-            var scope = runningExecutionContext.LexicalEnvironment;
-
-            DeclarativeEnvironment? funcEnv = null;
-            if (!string.IsNullOrWhiteSpace(name))
-            {
-                funcEnv = JintEnvironment.NewDeclarativeEnvironment(engine, engine.ExecutionContext.LexicalEnvironment);
-                funcEnv.CreateImmutableBinding(name!, strict: false);
-            }
-
-            var privateEnv = runningExecutionContext.PrivateEnvironment;
-
-            var thisMode = _function.Strict
-                ? FunctionThisMode.Strict
-                : FunctionThisMode.Global;
-
-            var intrinsics = engine.Realm.Intrinsics;
-            var closure = intrinsics.Function.OrdinaryFunctionCreate(
-                intrinsics.Function.PrototypeObject,
-                _function,
-                thisMode,
-                funcEnv ?? scope,
-                privateEnv
-            );
-
-            if (name is not null)
-            {
-                closure.SetFunctionName(name);
-            }
-            closure.MakeConstructor();
-
-            funcEnv?.InitializeBinding(name!, closure);
-
-            return closure;
+            funcEnv = JintEnvironment.NewDeclarativeEnvironment(engine, engine.ExecutionContext.LexicalEnvironment);
+            funcEnv.CreateImmutableBinding(name!, strict: false);
         }
 
-        /// <summary>
-        /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiateasyncfunctionexpression
-        /// </summary>
-        private ScriptFunction InstantiateAsyncFunctionExpression(EvaluationContext context, string? name = "")
+        var thisMode = function.Strict
+            ? FunctionThisMode.Strict
+            : FunctionThisMode.Global;
+
+        var intrinsics = engine.Realm.Intrinsics;
+        var closure = intrinsics.Function.OrdinaryFunctionCreate(
+            intrinsics.AsyncFunction.PrototypeObject,
+            function,
+            thisMode,
+            funcEnv ?? env,
+            privateEnv
+        );
+
+        closure.SetFunctionName(name ?? "");
+
+        funcEnv?.InitializeBinding(name!, closure);
+
+        return closure;
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiategeneratorfunctionexpression
+    /// </summary>
+    private static ScriptFunction InstantiateGeneratorFunctionExpression(Engine engine, JintFunctionDefinition function, string? name)
+    {
+        var runningExecutionContext = engine.ExecutionContext;
+        var env = runningExecutionContext.LexicalEnvironment;
+        var privateEnv = runningExecutionContext.PrivateEnvironment;
+
+        DeclarativeEnvironment? funcEnv = null;
+        if (!string.IsNullOrWhiteSpace(name))
         {
-            var engine = context.Engine;
-            var runningExecutionContext = engine.ExecutionContext;
-            var scope = runningExecutionContext.LexicalEnvironment;
+            funcEnv = JintEnvironment.NewDeclarativeEnvironment(engine, engine.ExecutionContext.LexicalEnvironment);
+            funcEnv.CreateImmutableBinding(name!, strict: false);
+        }
 
-            DeclarativeEnvironment? funcEnv = null;
-            if (!string.IsNullOrWhiteSpace(name))
-            {
-                funcEnv = JintEnvironment.NewDeclarativeEnvironment(engine, engine.ExecutionContext.LexicalEnvironment);
-                funcEnv.CreateImmutableBinding(name!, strict: false);
-            }
+        var thisMode = function.Strict || engine._isStrict
+            ? FunctionThisMode.Strict
+            : FunctionThisMode.Global;
 
-            var privateScope = runningExecutionContext.PrivateEnvironment;
+        var intrinsics = engine.Realm.Intrinsics;
+        var closure = intrinsics.Function.OrdinaryFunctionCreate(
+            intrinsics.GeneratorFunction.PrototypeObject,
+            function,
+            thisMode,
+            funcEnv ?? env,
+            privateEnv
+        );
 
-            var thisMode = _function.Strict
-                ? FunctionThisMode.Strict
-                : FunctionThisMode.Global;
+        if (name is not null)
+        {
+            closure.SetFunctionName(name);
+        }
 
-            var intrinsics = engine.Realm.Intrinsics;
-            var closure = intrinsics.Function.OrdinaryFunctionCreate(
-                intrinsics.AsyncFunction.PrototypeObject,
-                _function,
-                thisMode,
-                funcEnv ?? scope,
-                privateScope
-            );
+        var prototype = ObjectInstance.OrdinaryObjectCreate(engine, intrinsics.GeneratorFunction.PrototypeObject.PrototypeObject);
+        closure.DefinePropertyOrThrow(CommonProperties.Prototype, new PropertyDescriptor(prototype, PropertyFlag.Writable));
 
-            closure.SetFunctionName(name ?? "");
+        funcEnv?.InitializeBinding(name!, closure);
 
-            funcEnv?.InitializeBinding(name!, closure);
+        return closure;
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiateasyncgeneratorfunctionexpression
+    /// </summary>
+    private static ScriptFunction InstantiateAsyncGeneratorFunctionExpression(Engine engine, JintFunctionDefinition function, string? name)
+    {
+        var runningExecutionContext = engine.ExecutionContext;
+        var env = runningExecutionContext.LexicalEnvironment;
+        var privateEnv = runningExecutionContext.PrivateEnvironment;
 
-            return closure;
+        DeclarativeEnvironment? funcEnv = null;
+        if (!string.IsNullOrWhiteSpace(name))
+        {
+            funcEnv = JintEnvironment.NewDeclarativeEnvironment(engine, engine.ExecutionContext.LexicalEnvironment);
+            funcEnv.CreateImmutableBinding(name!, strict: false);
         }
 
+        var thisMode = function.Strict || engine._isStrict
+            ? FunctionThisMode.Strict
+            : FunctionThisMode.Global;
+
+        var intrinsics = engine.Realm.Intrinsics;
+        var closure = intrinsics.Function.OrdinaryFunctionCreate(
+            intrinsics.AsyncGeneratorFunction.PrototypeObject,
+            function,
+            thisMode,
+            funcEnv ?? env,
+            privateEnv
+        );
 
-        /// <summary>
-        /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiategeneratorfunctionexpression
-        /// </summary>
-        private ScriptFunction InstantiateGeneratorFunctionExpression(EvaluationContext context, string? name)
+        if (name is not null)
         {
-            var engine = context.Engine;
-            var runningExecutionContext = engine.ExecutionContext;
-            var scope = runningExecutionContext.LexicalEnvironment;
-
-            DeclarativeEnvironment? funcEnv = null;
-            if (!string.IsNullOrWhiteSpace(name))
-            {
-                funcEnv = JintEnvironment.NewDeclarativeEnvironment(engine, engine.ExecutionContext.LexicalEnvironment);
-                funcEnv.CreateImmutableBinding(name!, strict: false);
-            }
-
-            var privateScope = runningExecutionContext.PrivateEnvironment;
-
-            var thisMode = _function.Strict || engine._isStrict
-                ? FunctionThisMode.Strict
-                : FunctionThisMode.Global;
-
-            var intrinsics = engine.Realm.Intrinsics;
-            var closure = intrinsics.Function.OrdinaryFunctionCreate(
-                intrinsics.GeneratorFunction.PrototypeObject,
-                _function,
-                thisMode,
-                funcEnv ?? scope,
-                privateScope
-            );
-
-            if (name is not null)
-            {
-                closure.SetFunctionName(name);
-            }
-
-            var prototype = ObjectInstance.OrdinaryObjectCreate(engine, intrinsics.GeneratorFunction.PrototypeObject.PrototypeObject);
-            closure.DefinePropertyOrThrow(CommonProperties.Prototype, new PropertyDescriptor(prototype, PropertyFlag.Writable));
-
-            funcEnv?.InitializeBinding(name!, closure);
-
-            return closure;
+            closure.SetFunctionName(name);
         }
+
+        var prototype = ObjectInstance.OrdinaryObjectCreate(engine, intrinsics.AsyncGeneratorFunction.PrototypeObject.PrototypeObject);
+        closure.DefinePropertyOrThrow(CommonProperties.Prototype, new PropertyDescriptor(prototype, PropertyFlag.Writable));
+
+        funcEnv?.InitializeBinding(name!, closure);
+
+        return closure;
     }
 }

+ 4 - 0
Jint/Runtime/Intrinsics.cs

@@ -68,6 +68,7 @@ namespace Jint.Runtime
         private MathInstance? _math;
         private JsonInstance? _json;
         private SymbolConstructor? _symbol;
+        private AsyncGeneratorFunctionConstructor? _asyncGeneratorFunction;
         private GeneratorFunctionConstructor? _generatorFunction;
         private RegExpConstructor? _regExp;
         private RegExpStringIteratorPrototype? _regExpStringIteratorPrototype;
@@ -258,6 +259,9 @@ namespace Jint.Runtime
         internal GeneratorFunctionConstructor GeneratorFunction =>
             _generatorFunction ??= new GeneratorFunctionConstructor(_engine, _realm, Function.PrototypeObject, IteratorPrototype);
 
+        internal AsyncGeneratorFunctionConstructor AsyncGeneratorFunction =>
+            _asyncGeneratorFunction ??= new AsyncGeneratorFunctionConstructor(_engine, _realm, AsyncFunction.PrototypeObject, IteratorPrototype);
+
         public EvalFunction Eval =>
             _eval ??= new EvalFunction(_engine, _realm, Function.PrototypeObject);