From e3a3d5599fd59519257c715cf972742566f12d2e Mon Sep 17 00:00:00 2001 From: Marko Lahma Date: Tue, 9 Jul 2024 10:41:29 +0300 Subject: [PATCH] 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 --- .../Test262Harness.settings.json | 5 +- Jint/IsExternalInit.cs | 21 -- Jint/Jint.csproj | 2 +- Jint/Native/Array/ArrayOperations.cs | 2 +- .../AsyncGeneratorFunctionConstructor.cs | 47 +++ .../AsyncGeneratorFunctionPrototype.cs | 44 +++ .../AsyncGenerator/AsyncGeneratorPrototype.cs | 89 ++++++ .../Function/FunctionInstance.Dynamic.cs | 12 +- Jint/Native/Math/MathInstance.cs | 125 +++++++- Jint/Native/Math/MathX.cs | 66 ++++ .../JintArrowFunctionExpression.cs | 63 +++- .../Expressions/JintFunctionExpression.cs | 301 ++++++++++-------- Jint/Runtime/Intrinsics.cs | 4 + 13 files changed, 592 insertions(+), 189 deletions(-) delete mode 100644 Jint/IsExternalInit.cs create mode 100644 Jint/Native/AsyncGenerator/AsyncGeneratorFunctionConstructor.cs create mode 100644 Jint/Native/AsyncGenerator/AsyncGeneratorFunctionPrototype.cs create mode 100644 Jint/Native/AsyncGenerator/AsyncGeneratorPrototype.cs create mode 100644 Jint/Native/Math/MathX.cs diff --git a/Jint.Tests.Test262/Test262Harness.settings.json b/Jint.Tests.Test262/Test262Harness.settings.json index 2d2031e4b1..9bcf95bcb5 100644 --- a/Jint.Tests.Test262/Test262Harness.settings.json +++ b/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" ], diff --git a/Jint/IsExternalInit.cs b/Jint/IsExternalInit.cs deleted file mode 100644 index 6b9e1a7f42..0000000000 --- a/Jint/IsExternalInit.cs +++ /dev/null @@ -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; - -/// -/// Reserved to be used by the compiler for tracking metadata. -/// This class should not be used by developers in source code. -/// -[EditorBrowsable(EditorBrowsableState.Never)] -internal static class IsExternalInit -{ -} - -#endif diff --git a/Jint/Jint.csproj b/Jint/Jint.csproj index 460620fc9d..1730ed547d 100644 --- a/Jint/Jint.csproj +++ b/Jint/Jint.csproj @@ -19,7 +19,7 @@ true - System.Runtime.CompilerServices.IsExternalInit;System.Runtime.CompilerServices.RequiresLocationAttribute + System.Runtime.CompilerServices.RequiresLocationAttribute true diff --git a/Jint/Native/Array/ArrayOperations.cs b/Jint/Native/Array/ArrayOperations.cs index 3ba1b68091..9865558963 100644 --- a/Jint/Native/Array/ArrayOperations.cs +++ b/Jint/Native/Array/ArrayOperations.cs @@ -351,7 +351,7 @@ public override void EnsureCapacity(ulong capacity) public override bool TryGetValue(ulong index, out JsValue value) { - if (index < _target.GetLength()) + if (_target.IsValidIntegerIndex(index)) { value = _target[(int) index]; return true; diff --git a/Jint/Native/AsyncGenerator/AsyncGeneratorFunctionConstructor.cs b/Jint/Native/AsyncGenerator/AsyncGeneratorFunctionConstructor.cs new file mode 100644 index 0000000000..f3a5139518 --- /dev/null +++ b/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; + +/// +/// https://tc39.es/ecma262/#sec-asyncgeneratorfunction-constructor +/// +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; + } +} diff --git a/Jint/Native/AsyncGenerator/AsyncGeneratorFunctionPrototype.cs b/Jint/Native/AsyncGenerator/AsyncGeneratorFunctionPrototype.cs new file mode 100644 index 0000000000..0c65fceec6 --- /dev/null +++ b/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; + +/// +/// https://tc39.es/ecma262/#sec-properties-of-asyncgeneratorfunction-prototype +/// +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); + } +} diff --git a/Jint/Native/AsyncGenerator/AsyncGeneratorPrototype.cs b/Jint/Native/AsyncGenerator/AsyncGeneratorPrototype.cs new file mode 100644 index 0000000000..183136a0bf --- /dev/null +++ b/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; + +/// +/// https://tc39.es/ecma262/#sec-asyncgenerator-objects +/// +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); + } + + /// + /// https://tc39.es/ecma262/#sec-generator.prototype.next + /// + private ObjectInstance Next(JsValue thisObject, JsValue[] arguments) + { + var g = AssertGeneratorInstance(thisObject); + var value = arguments.At(0, null!); + return g.GeneratorResume(value, null); + } + + /// + /// https://tc39.es/ecma262/#sec-generator.prototype.return + /// + 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); + } + + /// + /// https://tc39.es/ecma262/#sec-generator.prototype.throw + /// + 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; + } +} diff --git a/Jint/Native/Function/FunctionInstance.Dynamic.cs b/Jint/Native/Function/FunctionInstance.Dynamic.cs index d0071529df..5576bdd76f 100644 --- a/Jint/Native/Function/FunctionInstance.Dynamic.cs +++ b/Jint/Native/Function/FunctionInstance.Dynamic.cs @@ -47,6 +47,8 @@ internal Function CreateDynamicFunction( 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 @@ internal Function CreateDynamicFunction( 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 @@ internal Function CreateDynamicFunction( 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 @@ internal Function CreateDynamicFunction( } 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) { diff --git a/Jint/Native/Math/MathInstance.cs b/Jint/Native/Math/MathInstance.cs index 27fb3a73b3..94fd1f4ac2 100644 --- a/Jint/Native/Math/MathInstance.cs +++ b/Jint/Native/Math/MathInstance.cs @@ -21,50 +21,51 @@ protected override void Initialize() { 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 @@ private static JsValue Hypot(JsValue thisObject, JsValue[] arguments) return System.Math.Sqrt(y); } + /// + /// https://github.com/tc39/proposal-math-sum + /// + 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 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 diff --git a/Jint/Native/Math/MathX.cs b/Jint/Native/Math/MathX.cs new file mode 100644 index 0000000000..87ac96bb50 --- /dev/null +++ b/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; + } + + /// Shewchuk summation + internal static double FSum(this List values) + { + if (values.Count < 3) return values.Count == 2 ? values[0] + values[1] : values.Count == 1 ? values[0] : 0.0; + Span 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; + } +} diff --git a/Jint/Runtime/Interpreter/Expressions/JintArrowFunctionExpression.cs b/Jint/Runtime/Interpreter/Expressions/JintArrowFunctionExpression.cs index cf165b2867..039c4fabfa 100644 --- a/Jint/Runtime/Interpreter/Expressions/JintArrowFunctionExpression.cs +++ b/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 @@ public JintArrowFunctionExpression(ArrowFunctionExpression function) : base(func 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; + } + + /// + /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiatearrowfunctionexpression + /// + 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; + } + + /// + /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiateasyncarrowfunctionexpression + /// + 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; } diff --git a/Jint/Runtime/Interpreter/Expressions/JintFunctionExpression.cs b/Jint/Runtime/Interpreter/Expressions/JintFunctionExpression.cs index d9a4e73c70..1c1708a9e1 100644 --- a/Jint/Runtime/Interpreter/Expressions/JintFunctionExpression.cs +++ b/Jint/Runtime/Interpreter/Expressions/JintFunctionExpression.cs @@ -4,163 +4,204 @@ 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; + } + + /// + /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiateordinaryfunctionexpression + /// + 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; + } - /// - /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiateordinaryfunctionexpression - /// - private ScriptFunction InstantiateOrdinaryFunctionExpression(EvaluationContext context, string? name = "") + /// + /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiateasyncfunctionexpression + /// + 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); } - /// - /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiateasyncfunctionexpression - /// - 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; + } + + /// + /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiategeneratorfunctionexpression + /// + 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; + } + + /// + /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiateasyncgeneratorfunctionexpression + /// + 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 + ); - /// - /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiategeneratorfunctionexpression - /// - 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; } } diff --git a/Jint/Runtime/Intrinsics.cs b/Jint/Runtime/Intrinsics.cs index 84e8d36d54..26b603a758 100644 --- a/Jint/Runtime/Intrinsics.cs +++ b/Jint/Runtime/Intrinsics.cs @@ -68,6 +68,7 @@ public sealed partial class Intrinsics 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 @@ internal Intrinsics(Engine engine, Realm realm) 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);