diff --git a/Jint.Tests.Test262/Test262Harness.settings.json b/Jint.Tests.Test262/Test262Harness.settings.json index 5f432ab3f5..a558e91faa 100644 --- a/Jint.Tests.Test262/Test262Harness.settings.json +++ b/Jint.Tests.Test262/Test262Harness.settings.json @@ -1,5 +1,5 @@ { - "SuiteGitSha": "45e740928f9ac3c2144307fee20bb58570fb9588", + "SuiteGitSha": "c2ae5ed5e90d86e17730730b003e9b6fb050693e", //"SuiteDirectory": "//mnt/c/work/test262", "TargetPath": "./Generated", "Namespace": "Jint.Tests.Test262", @@ -9,9 +9,11 @@ "async-iteration", "Atomics", "decorators", + "Float16Array", "import-assertions", "iterator-helpers", "regexp-lookbehind", + "regexp-modifiers", "regexp-unicode-property-escapes", "regexp-v-flag", "tail-call-optimization", @@ -62,6 +64,9 @@ "built-ins/String/prototype/match/duplicate-named-indices-groups-properties.js", "built-ins/String/prototype/match/duplicate-named-indices-groups-properties.js", + // needs "small" async rewrite + "language/module-code/top-level-await/async-module-does-not-block-sibling-modules.js", + // requires investigation how to process complex function name evaluation for property "built-ins/Function/prototype/toString/method-computed-property-name.js", "language/expressions/class/elements/class-name-static-initializer-anonymous.js", diff --git a/Jint/Engine.cs b/Jint/Engine.cs index 13fe7cb549..2d9a8fa554 100644 --- a/Jint/Engine.cs +++ b/Jint/Engine.cs @@ -566,6 +566,9 @@ internal JsValue GetValue(object value, bool returnReferenceToPool) return GetValue(reference, returnReferenceToPool); } + /// + /// https://tc39.es/ecma262/#sec-getvalue + /// internal JsValue GetValue(Reference reference, bool returnReferenceToPool) { var baseValue = reference.Base; @@ -603,7 +606,8 @@ internal JsValue GetValue(Reference reference, bool returnReferenceToPool) return baseObj.PrivateGet((PrivateName) reference.ReferencedName); } - var v = baseObj.Get(property, reference.ThisValue); + reference.EvaluateAndCachePropertyKey(); + var v = baseObj.Get(reference.ReferencedName, reference.ThisValue); return v; } @@ -680,33 +684,35 @@ private bool TryHandleStringValue(JsValue property, JsString s, ref ObjectInstan /// internal void PutValue(Reference reference, JsValue value) { + var property = reference.ReferencedName; if (reference.IsUnresolvableReference) { - if (reference.Strict && reference.ReferencedName != CommonProperties.Arguments) + if (reference.Strict && property != CommonProperties.Arguments) { ExceptionHelper.ThrowReferenceError(Realm, reference); } - Realm.GlobalObject.Set(reference.ReferencedName, value, throwOnError: false); + Realm.GlobalObject.Set(property, value, throwOnError: false); } else if (reference.IsPropertyReference) { var baseObject = Runtime.TypeConverter.ToObject(Realm, reference.Base); if (reference.IsPrivateReference) { - baseObject.PrivateSet((PrivateName) reference.ReferencedName, value); + baseObject.PrivateSet((PrivateName) property, value); return; } + reference.EvaluateAndCachePropertyKey(); var succeeded = baseObject.Set(reference.ReferencedName, value, reference.ThisValue); if (!succeeded && reference.Strict) { - ExceptionHelper.ThrowTypeError(Realm, "Cannot assign to read only property '" + reference.ReferencedName + "' of " + baseObject); + ExceptionHelper.ThrowTypeError(Realm, "Cannot assign to read only property '" + property + "' of " + baseObject); } } else { - ((Environment) reference.Base).SetMutableBinding(Runtime.TypeConverter.ToString(reference.ReferencedName), value, reference.Strict); + ((Environment) reference.Base).SetMutableBinding(Runtime.TypeConverter.ToString(property), value, reference.Strict); } } @@ -887,7 +893,7 @@ internal Node GetLastSyntaxElement() public JsValue GetValue(JsValue scope, JsValue property) { var reference = _referencePool.Rent(scope, property, _isStrict, thisValue: null); - var jsValue = GetValue(reference, false); + var jsValue = GetValue(reference, returnReferenceToPool: false); _referencePool.Return(reference); return jsValue; } @@ -998,7 +1004,7 @@ private void GlobalDeclarationInstantiation( for (var i = 0; i < lexNames.Count; i++) { var (dn, constant) = lexNames[i]; - if (env.HasVarDeclaration(dn) || env.HasLexicalDeclaration(dn) || env.HasRestrictedGlobalProperty(dn)) + if (env.HasLexicalDeclaration(dn) || env.HasRestrictedGlobalProperty(dn)) { ExceptionHelper.ThrowSyntaxError(realm, $"Identifier '{dn}' has already been declared"); } @@ -1013,7 +1019,7 @@ private void GlobalDeclarationInstantiation( } } - // we need to go trough in reverse order to handle the hoisting correctly + // we need to go through in reverse order to handle the hoisting correctly for (var i = functionToInitialize.Count - 1; i > -1; i--) { var f = functionToInitialize[i]; @@ -1363,7 +1369,7 @@ internal void EvalDeclarationInstantiation( { if (varEnvRec is GlobalEnvironment ger) { - ger.CreateGlobalVarBinding(vn, true); + ger.CreateGlobalVarBinding(vn, canBeDeleted: true); } else { diff --git a/Jint/Native/Array/ArrayIteratorPrototype.cs b/Jint/Native/Array/ArrayIteratorPrototype.cs index 3472caf36b..21060e9432 100644 --- a/Jint/Native/Array/ArrayIteratorPrototype.cs +++ b/Jint/Native/Array/ArrayIteratorPrototype.cs @@ -13,6 +13,8 @@ namespace Jint.Native.Array; /// internal sealed class ArrayIteratorPrototype : IteratorPrototype { + private ClrFunction? _originalNextFunction; + internal ArrayIteratorPrototype( Engine engine, Realm realm, @@ -22,9 +24,10 @@ internal ArrayIteratorPrototype( protected override void Initialize() { + _originalNextFunction = new ClrFunction(Engine, "next", Next, 0, PropertyFlag.Configurable); var properties = new PropertyDictionary(1, checkExistingKeys: false) { - [KnownKeys.Next] = new(new ClrFunction(Engine, "next", Next, 0, PropertyFlag.Configurable), true, false, true) + [KnownKeys.Next] = new(_originalNextFunction, PropertyFlag.NonEnumerable) }; SetProperties(properties); @@ -37,6 +40,11 @@ protected override void Initialize() internal IteratorInstance Construct(ObjectInstance array, ArrayIteratorType kind) { + if (!HasOriginalNext) + { + return new IteratorInstance.ObjectIterator(this); + } + IteratorInstance instance = array is JsArray jsArray ? new ArrayIterator(Engine, jsArray, kind) { _prototype = this } : new ArrayLikeIterator(Engine, array, kind) { _prototype = this }; @@ -44,6 +52,9 @@ internal IteratorInstance Construct(ObjectInstance array, ArrayIteratorType kind return instance; } + internal bool HasOriginalNext + => ReferenceEquals(Get(CommonProperties.Next), _originalNextFunction); + private sealed class ArrayIterator : IteratorInstance { private readonly ArrayIteratorType _kind; diff --git a/Jint/Native/TypedArray/IntrinsicTypedArrayPrototype.cs b/Jint/Native/TypedArray/IntrinsicTypedArrayPrototype.cs index f24d48b1a4..051e32450d 100644 --- a/Jint/Native/TypedArray/IntrinsicTypedArrayPrototype.cs +++ b/Jint/Native/TypedArray/IntrinsicTypedArrayPrototype.cs @@ -1313,56 +1313,73 @@ private JsValue Subarray(JsValue thisObject, JsValue[] arguments) ExceptionHelper.ThrowTypeError(_realm); } - var begin = arguments.At(0); + var start = arguments.At(0); var end = arguments.At(1); var buffer = o._viewedArrayBuffer; - var srcLength = o.GetLength(); - var relativeBegin = TypeConverter.ToIntegerOrInfinity(begin); + var srcRecord = MakeTypedArrayWithBufferWitnessRecord(o, ArrayBufferOrder.SeqCst); - double beginIndex; - if (double.IsNegativeInfinity(relativeBegin)) - { - beginIndex = 0; - } - else if (relativeBegin < 0) + uint srcLength = 0; + if (!srcRecord.IsTypedArrayOutOfBounds) { - beginIndex = System.Math.Max(srcLength + relativeBegin, 0); + srcLength = srcRecord.TypedArrayLength; } - else + + var relativeStart = TypeConverter.ToIntegerOrInfinity(start); + + double startIndex; + if (double.IsNegativeInfinity(relativeStart)) { - beginIndex = System.Math.Min(relativeBegin, srcLength); + startIndex = 0; } - - double relativeEnd; - if (end.IsUndefined()) + else if (relativeStart < 0) { - relativeEnd = srcLength; + startIndex = System.Math.Max(srcLength + relativeStart, 0); } else { - relativeEnd = TypeConverter.ToIntegerOrInfinity(end); + startIndex = System.Math.Min(relativeStart, srcLength); } - double endIndex; - if (double.IsNegativeInfinity(relativeEnd)) - { - endIndex = 0; - } - else if (relativeEnd < 0) + var elementSize = o._arrayElementType.GetElementSize(); + var srcByteOffset = o._byteOffset; + var beginByteOffset = srcByteOffset + startIndex * elementSize; + + JsValue[] argumentsList; + if (o._arrayLength == JsTypedArray.LengthAuto && end.IsUndefined()) { - endIndex = System.Math.Max(srcLength + relativeEnd, 0); + argumentsList = [buffer, beginByteOffset]; } else { - endIndex = System.Math.Min(relativeEnd, srcLength); + double relativeEnd; + if (end.IsUndefined()) + { + relativeEnd = srcLength; + } + else + { + relativeEnd = TypeConverter.ToIntegerOrInfinity(end); + } + + double endIndex; + if (double.IsNegativeInfinity(relativeEnd)) + { + endIndex = 0; + } + else if (relativeEnd < 0) + { + endIndex = System.Math.Max(srcLength + relativeEnd, 0); + } + else + { + endIndex = System.Math.Min(relativeEnd, srcLength); + } + + var newLength = System.Math.Max(endIndex - startIndex, 0); + argumentsList = [buffer, beginByteOffset, newLength]; } - var newLength = System.Math.Max(endIndex - beginIndex, 0); - var elementSize = o._arrayElementType.GetElementSize(); - var srcByteOffset = o._byteOffset; - var beginByteOffset = srcByteOffset + beginIndex * elementSize; - var argumentsList = new JsValue[] { buffer, beginByteOffset, newLength }; return _realm.Intrinsics.TypedArray.TypedArraySpeciesCreate(o, argumentsList); } diff --git a/Jint/Runtime/Environments/GlobalEnvironment.cs b/Jint/Runtime/Environments/GlobalEnvironment.cs index 00da01fb71..d957518c90 100644 --- a/Jint/Runtime/Environments/GlobalEnvironment.cs +++ b/Jint/Runtime/Environments/GlobalEnvironment.cs @@ -29,7 +29,6 @@ public GlobalDeclarativeEnvironment(Engine engine) : base(engine) // Environment records are needed by debugger internal readonly GlobalDeclarativeEnvironment _declarativeRecord; - private readonly HashSet _varNames = []; public GlobalEnvironment(Engine engine, ObjectInstance global) : base(engine) { @@ -258,15 +257,10 @@ internal override bool DeleteBinding(Key name) return _declarativeRecord.DeleteBinding(name); } - if (_global.HasOwnProperty(name.Name)) + var n = JsString.Create(name.Name); + if (_global.HasOwnProperty(n)) { - var status = _global.Delete(name.Name); - if (status) - { - _varNames.Remove(name); - } - - return status; + return _global.Delete(n); } return true; @@ -280,8 +274,6 @@ internal override bool DeleteBinding(Key name) internal override JsValue GetThisBinding() => _global; - internal bool HasVarDeclaration(Key name) => _varNames.Contains(name); - internal bool HasLexicalDeclaration(Key name) => _declarativeRecord.HasBinding(name); internal bool HasRestrictedGlobalProperty(Key name) @@ -334,12 +326,14 @@ public bool CanDeclareGlobalFunction(Key name) public void CreateGlobalVarBinding(Key name, bool canBeDeleted) { - if (_global.Extensible && _global._properties!.TryAdd(name, new PropertyDescriptor(Undefined, canBeDeleted - ? PropertyFlag.ConfigurableEnumerableWritable | PropertyFlag.MutableBinding - : PropertyFlag.NonConfigurable | PropertyFlag.MutableBinding))) + if (!_global.Extensible) { - _varNames.Add(name); + return; } + + _global._properties!.TryAdd(name, new PropertyDescriptor(Undefined, canBeDeleted + ? PropertyFlag.ConfigurableEnumerableWritable | PropertyFlag.MutableBinding + : PropertyFlag.NonConfigurable | PropertyFlag.MutableBinding)); } internal void CreateGlobalVarBindings(List names, bool canBeDeleted) @@ -356,8 +350,6 @@ internal void CreateGlobalVarBindings(List names, bool canBeDeleted) _global._properties!.TryAdd(name, new PropertyDescriptor(Undefined, canBeDeleted ? PropertyFlag.ConfigurableEnumerableWritable | PropertyFlag.MutableBinding : PropertyFlag.NonConfigurable | PropertyFlag.MutableBinding)); - - _varNames.Add(name); } } @@ -381,7 +373,6 @@ public void CreateGlobalFunctionBinding(Key name, JsValue value, bool canBeDelet _global.DefinePropertyOrThrow(jsString, desc); _global.Set(jsString, value, false); - _varNames.Add(name); } internal override bool HasBindings() diff --git a/Jint/Runtime/Interpreter/Expressions/DestructuringPatternAssignmentExpression.cs b/Jint/Runtime/Interpreter/Expressions/DestructuringPatternAssignmentExpression.cs index 39e57d268b..727fa94ec4 100644 --- a/Jint/Runtime/Interpreter/Expressions/DestructuringPatternAssignmentExpression.cs +++ b/Jint/Runtime/Interpreter/Expressions/DestructuringPatternAssignmentExpression.cs @@ -145,6 +145,7 @@ private static JsValue HandleArrayPattern( { close = true; var reference = GetReferenceFromMember(context, me); + JsValue value; if (arrayOperations != null) { diff --git a/Jint/Runtime/Interpreter/Expressions/JintMemberExpression.cs b/Jint/Runtime/Interpreter/Expressions/JintMemberExpression.cs index 96797480bf..eecb0e07fe 100644 --- a/Jint/Runtime/Interpreter/Expressions/JintMemberExpression.cs +++ b/Jint/Runtime/Interpreter/Expressions/JintMemberExpression.cs @@ -127,12 +127,7 @@ protected override object EvaluateInternal(EvaluationContext context) return MakePrivateReference(engine, baseValue, property); } - // only convert if necessary - var propertyKey = property.IsInteger() && baseValue.IsIntegerIndexedArray - ? property - : TypeConverter.ToPropertyKey(property); - - return context.Engine._referencePool.Rent(baseValue, propertyKey, isStrictModeCode, thisValue: actualThis); + return context.Engine._referencePool.Rent(baseValue, property, isStrictModeCode, thisValue: actualThis); } /// diff --git a/Jint/Runtime/Interpreter/Expressions/JintUnaryExpression.cs b/Jint/Runtime/Interpreter/Expressions/JintUnaryExpression.cs index 07f19fd5a6..ef5173d235 100644 --- a/Jint/Runtime/Interpreter/Expressions/JintUnaryExpression.cs +++ b/Jint/Runtime/Interpreter/Expressions/JintUnaryExpression.cs @@ -206,7 +206,6 @@ private JsValue EvaluateJsValue(EvaluationContext context) return JsBoolean.True; } - var referencedName = r.ReferencedName; if (r.IsPropertyReference) { if (r.IsSuperReference) @@ -215,17 +214,20 @@ private JsValue EvaluateJsValue(EvaluationContext context) } var o = TypeConverter.ToObject(engine.Realm, r.Base); - var deleteStatus = o.Delete(referencedName); + + r.EvaluateAndCachePropertyKey(); + var deleteStatus = o.Delete(r.ReferencedName); + if (!deleteStatus) { if (r.Strict) { - ExceptionHelper.ThrowTypeError(engine.Realm, $"Cannot delete property '{referencedName}' of {o}"); + ExceptionHelper.ThrowTypeError(engine.Realm, $"Cannot delete property '{r.ReferencedName}' of {o}"); } - if (StrictModeScope.IsStrictModeCode && !r.Base.AsObject().GetOwnProperty(referencedName).Configurable) + if (StrictModeScope.IsStrictModeCode && !r.Base.AsObject().GetOwnProperty(r.ReferencedName).Configurable) { - ExceptionHelper.ThrowTypeError(engine.Realm, $"Cannot delete property '{referencedName}' of {o}"); + ExceptionHelper.ThrowTypeError(engine.Realm, $"Cannot delete property '{r.ReferencedName}' of {o}"); } } @@ -239,10 +241,9 @@ private JsValue EvaluateJsValue(EvaluationContext context) } var bindings = (Environment) r.Base; - var property = referencedName; engine._referencePool.Return(r); - return bindings.DeleteBinding(property.ToString()) ? JsBoolean.True : JsBoolean.False; + return bindings.DeleteBinding(r.ReferencedName.ToString()) ? JsBoolean.True : JsBoolean.False; case Operator.Void: _argument.GetValue(context); diff --git a/Jint/Runtime/Reference.cs b/Jint/Runtime/Reference.cs index ac8226f1a3..eb1365f7a2 100644 --- a/Jint/Runtime/Reference.cs +++ b/Jint/Runtime/Reference.cs @@ -108,4 +108,12 @@ internal void InitializeReferencedBinding(JsValue value) { ((Environment) _base).InitializeBinding(TypeConverter.ToString(_referencedName), value); } + + internal void EvaluateAndCachePropertyKey() + { + if (!(_referencedName.IsInteger() && _base.IsIntegerIndexedArray)) + { + _referencedName = Runtime.TypeConverter.ToPropertyKey(_referencedName); + } + } }