diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 018cf19085..00dad9694f 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -3,7 +3,7 @@ name: Build
on:
push:
- branches: [ main ]
+ branches: [ main, 3.x ]
paths-ignore:
- 'doc/**'
- '**.md'
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index 1892f041ac..adb4a3387d 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -3,7 +3,7 @@ name: PR Check
on:
pull_request:
- branches: [ main, release/2.x ]
+ branches: [ main, release/2.x, 3.x ]
jobs:
diff --git a/Jint.Tests.Test262/Test262Harness.settings.json b/Jint.Tests.Test262/Test262Harness.settings.json
index 443d8f1e08..76a0084d2b 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",
@@ -8,10 +8,12 @@
"Array.fromAsync",
"async-iteration",
"Atomics",
+ "Float16Array",
"import-assertions",
"iterator-helpers",
"regexp-duplicate-named-groups",
"regexp-lookbehind",
+ "regexp-modifiers",
"regexp-unicode-property-escapes",
"regexp-v-flag",
"tail-call-optimization",
@@ -44,6 +46,9 @@
"built-ins/RegExp/lookahead-quantifier-match-groups.js",
"built-ins/RegExp/unicode_full_case_folding.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",
@@ -68,7 +73,7 @@
// C# can't distinguish 1.797693134862315808e+308 and 1.797693134862315708145274237317e+308
"language/types/number/8.5.1.js",
- // inner binding is immutable (from parameters) Expected SameValue(«null», «function() {{ ... }}») to be true
+ // inner binding is immutable (from parameters) Expected SameValue(«null», «function() {{ ... }}») to be true
"language/expressions/function/scope-name-var-open-non-strict.js",
"language/expressions/function/scope-name-var-open-strict.js",
diff --git a/Jint/Engine.cs b/Jint/Engine.cs
index 6a9fd505bf..5c94a6dafb 100644
--- a/Jint/Engine.cs
+++ b/Jint/Engine.cs
@@ -570,6 +570,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;
@@ -607,7 +610,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;
}
@@ -684,33 +688,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);
}
}
@@ -891,7 +897,7 @@ internal SyntaxElement 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;
}
@@ -1002,7 +1008,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");
}
@@ -1017,7 +1023,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];
@@ -1367,7 +1373,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 c0d4018199..3572c48141 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 614e091ebd..f48968e69b 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 28aed9df53..6dc361a645 100644
--- a/Jint/Runtime/Interpreter/Expressions/JintUnaryExpression.cs
+++ b/Jint/Runtime/Interpreter/Expressions/JintUnaryExpression.cs
@@ -207,7 +207,6 @@ private JsValue EvaluateJsValue(EvaluationContext context)
return JsBoolean.True;
}
- var referencedName = r.ReferencedName;
if (r.IsPropertyReference)
{
if (r.IsSuperReference)
@@ -216,17 +215,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}");
}
}
@@ -240,10 +242,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);
+ }
+ }
}