Преглед на файлове

Update test262 harness and fix issues (#2029)

Marko Lahma преди 6 месеца
родител
ревизия
dd779482e2

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

@@ -1,5 +1,5 @@
 {
-  "SuiteGitSha": "d62fa93c8f9ce5e687c0bbaa5d2b59670ab2ff60",
+  "SuiteGitSha": "b0f03cb22d8b9233347782d166e7793d4d4c757f",
   //"SuiteDirectory": "//mnt/c/work/test262",
   "TargetPath": "./Generated",
   "Namespace": "Jint.Tests.Test262",
@@ -9,8 +9,12 @@
     "async-iteration",
     "Atomics",
     "decorators",
+    "Error.isError",
     "explicit-resource-management",
+    "import-defer",
     "iterator-helpers",
+    "iterator-sequencing",
+    "json-parse-with-source",
     "regexp-lookbehind",
     "regexp-modifiers",
     "regexp-unicode-property-escapes",
@@ -29,6 +33,14 @@
   ],
   "ExcludedFiles": [
 
+    // requires rewrite of destructing towards spec
+    "language/destructuring/binding/keyed-destructuring-property-reference-target-evaluation-order-with-bindings.js",
+    "language/expressions/assignment/destructuring/keyed-destructuring-property-reference-target-evaluation-order-with-bindings.js",
+
+    // Acornima doesn't implement unicode 15/16 yet
+    "language/identifiers/*-unicode-15.*.js",
+    "language/identifiers/*-unicode-16.*.js",
+
     // Currently quite impossible to detect if assignment target is CoverParenthesizedExpression
     "language/expressions/assignment/fn-name-lhs-cover.js",
 
@@ -106,6 +118,7 @@
     "built-ins/GeneratorPrototype/return/try-finally-nested-try-catch-within-outer-try-after-nested.js",
     "built-ins/GeneratorPrototype/return/try-finally-nested-try-catch-within-outer-try-before-nested.js",
     "built-ins/GeneratorPrototype/return/try-finally-nested-try-catch-within-outer-try-before-nested.js",
+    "built-ins/GeneratorPrototype/return/try-finally-set-property-within-try.js",
     "built-ins/GeneratorPrototype/return/try-finally-within-finally.js",
     "built-ins/GeneratorPrototype/return/try-finally-within-finally.js",
     "built-ins/GeneratorPrototype/return/try-finally-within-try.js",

+ 1 - 1
Jint.Tests.Test262/Test262Test.cs

@@ -8,7 +8,7 @@ namespace Jint.Tests.Test262;
 
 public abstract partial class Test262Test
 {
-    private Engine BuildTestExecutor(Test262File file)
+    private static Engine BuildTestExecutor(Test262File file)
     {
         var engine = new Engine(cfg =>
         {

+ 13 - 10
Jint/Engine.cs

@@ -704,7 +704,7 @@ public sealed partial class Engine : IDisposable
             var succeeded = baseObject.Set(reference.ReferencedName, value, reference.ThisValue);
             if (!succeeded && reference.Strict)
             {
-                ExceptionHelper.ThrowTypeError(Realm, "Cannot assign to read only property '" + property + "' of " + baseObject);
+                ExceptionHelper.ThrowTypeError(Realm, $"Cannot assign to read only property '{property}' of {baseObject}");
             }
         }
         else
@@ -906,18 +906,21 @@ public sealed partial class Engine : IDisposable
 
     private static Reference GetIdentifierReference(Environment? env, string name, bool strict)
     {
-        if (env is null)
+        Key key = name;
+        while (true)
         {
-            return new Reference(JsValue.Undefined, name, strict);
-        }
+            if (env is null)
+            {
+                return new Reference(JsValue.Undefined, name, strict);
+            }
 
-        var envRec = env;
-        if (envRec.HasBinding(name))
-        {
-            return new Reference(envRec, name, strict);
-        }
+            if (env.HasBinding(key))
+            {
+                return new Reference(env, name, strict);
+            }
 
-        return GetIdentifierReference(env._outerEnv, name, strict);
+            env = env._outerEnv;
+        }
     }
 
     /// <summary>

+ 3 - 16
Jint/Native/FinalizationRegistry/FinalizationRegistryPrototype.cs

@@ -29,7 +29,9 @@ internal sealed class FinalizationRegistryPrototype : Prototype
         const PropertyFlag PropertyFlags = PropertyFlag.NonEnumerable;
         var properties = new PropertyDictionary(4, checkExistingKeys: false)
         {
-            [KnownKeys.Constructor] = new(_constructor, PropertyFlag.NonEnumerable), ["register"] = new(new ClrFunction(Engine, "register", Register, 2, PropertyFlag.Configurable), PropertyFlags), ["unregister"] = new(new ClrFunction(Engine, "unregister", Unregister, 1, PropertyFlag.Configurable), PropertyFlags), ["cleanupSome"] = new(new ClrFunction(Engine, "cleanupSome", CleanupSome, 0, PropertyFlag.Configurable), PropertyFlags),
+            [KnownKeys.Constructor] = new PropertyDescriptor(_constructor, PropertyFlag.NonEnumerable),
+            ["register"] = new PropertyDescriptor(new ClrFunction(Engine, "register", Register, 2, PropertyFlag.Configurable), PropertyFlags),
+            ["unregister"] = new PropertyDescriptor(new ClrFunction(Engine, "unregister", Unregister, 1, PropertyFlag.Configurable), PropertyFlags),
         };
         SetProperties(properties);
 
@@ -88,21 +90,6 @@ internal sealed class FinalizationRegistryPrototype : Prototype
         return finalizationRegistry.Remove(unregisterToken);
     }
 
-    private JsValue CleanupSome(JsValue thisObject, JsValue[] arguments)
-    {
-        var finalizationRegistry = AssertFinalizationRegistryInstance(thisObject);
-        var callback = arguments.At(0);
-
-        if (!callback.IsUndefined() && callback is not ICallable)
-        {
-            ExceptionHelper.ThrowTypeError(_realm, callback + " must be callable");
-        }
-
-        FinalizationRegistryInstance.CleanupFinalizationRegistry(callback as ICallable);
-
-        return Undefined;
-    }
-
     private FinalizationRegistryInstance AssertFinalizationRegistryInstance(JsValue thisObject)
     {
         if (thisObject is FinalizationRegistryInstance finalizationRegistryInstance)

+ 32 - 0
Jint/Native/JsTypedArray.cs

@@ -58,6 +58,38 @@ public sealed class JsTypedArray : ObjectInstance
         return record.IsTypedArrayOutOfBounds ? 0 : record.TypedArrayLength;
     }
 
+    public override bool PreventExtensions()
+    {
+        if (!IsTypedArrayFixedLength)
+        {
+            return false;
+        }
+
+        return base.PreventExtensions();
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-istypedarrayfixedlength
+    /// </summary>
+    private bool IsTypedArrayFixedLength
+    {
+        get
+        {
+            if (_arrayLength == LengthAuto)
+            {
+                return false;
+            }
+
+            var buffer = _viewedArrayBuffer;
+            if (!buffer.IsFixedLengthArrayBuffer && !buffer.IsSharedArrayBuffer)
+            {
+                return false;
+            }
+
+            return true;
+        }
+    }
+
     internal override bool IsArrayLike => true;
 
     internal override bool IsIntegerIndexedArray => true;

+ 3 - 3
Jint/Native/Object/ObjectConstructor.cs

@@ -109,7 +109,7 @@ public sealed class ObjectConstructor : Constructor
     private JsValue FromEntries(JsValue thisObject, JsValue[] arguments)
     {
         var iterable = arguments.At(0);
-        TypeConverter.CheckObjectCoercible(_engine, iterable);
+        TypeConverter.RequireObjectCoercible(_engine, iterable);
 
         var obj = _realm.Intrinsics.Object.Construct(0);
 
@@ -206,7 +206,7 @@ public sealed class ObjectConstructor : Constructor
     private JsValue SetPrototypeOf(JsValue thisObject, JsValue[] arguments)
     {
         var oArg = arguments.At(0);
-        TypeConverter.CheckObjectCoercible(_engine, oArg);
+        TypeConverter.RequireObjectCoercible(_engine, oArg);
 
         var prototype = arguments.At(1);
         if (!prototype.IsObject() && !prototype.IsNull())
@@ -214,7 +214,7 @@ public sealed class ObjectConstructor : Constructor
             ExceptionHelper.ThrowTypeError(_realm, $"Object prototype may only be an Object or null: {prototype}");
         }
 
-        if (!(oArg is ObjectInstance o))
+        if (oArg is not ObjectInstance o)
         {
             return oArg;
         }

+ 3 - 0
Jint/Native/Object/ObjectInstance.cs

@@ -1217,6 +1217,9 @@ public partial class ObjectInstance : JsValue, IEquatable<ObjectInstance>
 
     internal virtual uint GetLength() => (uint) TypeConverter.ToLength(Get(CommonProperties.Length));
 
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-ordinarypreventextensions
+    /// </summary>
     public virtual bool PreventExtensions()
     {
         Extensible = false;

+ 1 - 1
Jint/Native/Object/ObjectPrototype.cs

@@ -38,7 +38,7 @@ public sealed class ObjectPrototype : Prototype
                 new ClrFunction(Engine, "get __proto__", (thisObject, _) => TypeConverter.ToObject(_realm, thisObject).GetPrototypeOf() ?? Null, 0, LengthFlags),
                 new ClrFunction(Engine, "set __proto__", (thisObject, arguments) =>
                 {
-                    TypeConverter.CheckObjectCoercible(_engine, thisObject);
+                    TypeConverter.RequireObjectCoercible(_engine, thisObject);
 
                     var proto = arguments.At(0);
                     if (!proto.IsObject() && !proto.IsNull() || thisObject is not ObjectInstance objectInstance)

+ 34 - 34
Jint/Native/String/StringPrototype.cs

@@ -100,7 +100,7 @@ internal sealed class StringPrototype : StringInstance
 
     private ObjectInstance Iterator(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(_engine, thisObject);
+        TypeConverter.RequireObjectCoercible(_engine, thisObject);
         var str = TypeConverter.ToString(thisObject);
         return _realm.Intrinsics.StringIteratorPrototype.Construct(str);
     }
@@ -195,7 +195,7 @@ internal sealed class StringPrototype : StringInstance
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     private JsValue Trim(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(Engine, thisObject);
+        TypeConverter.RequireObjectCoercible(Engine, thisObject);
         var s = TypeConverter.ToJsString(thisObject);
         if (s.Length == 0 || (!IsWhiteSpaceEx(s[0]) && !IsWhiteSpaceEx(s[s.Length - 1])))
         {
@@ -209,7 +209,7 @@ internal sealed class StringPrototype : StringInstance
     /// </summary>
     private JsValue TrimStart(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(Engine, thisObject);
+        TypeConverter.RequireObjectCoercible(Engine, thisObject);
         var s = TypeConverter.ToJsString(thisObject);
         if (s.Length == 0 || !IsWhiteSpaceEx(s[0]))
         {
@@ -223,7 +223,7 @@ internal sealed class StringPrototype : StringInstance
     /// </summary>
     private JsValue TrimEnd(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(Engine, thisObject);
+        TypeConverter.RequireObjectCoercible(Engine, thisObject);
         var s = TypeConverter.ToJsString(thisObject);
         if (s.Length == 0 || !IsWhiteSpaceEx(s[s.Length - 1]))
         {
@@ -234,7 +234,7 @@ internal sealed class StringPrototype : StringInstance
 
     private JsValue ToLocaleUpperCase(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(_engine, thisObject);
+        TypeConverter.RequireObjectCoercible(_engine, thisObject);
         var s = TypeConverter.ToString(thisObject);
         var culture = CultureInfo.InvariantCulture;
         if (arguments.Length > 0 && arguments[0].IsString())
@@ -266,21 +266,21 @@ internal sealed class StringPrototype : StringInstance
 
     private JsValue ToUpperCase(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(_engine, thisObject);
+        TypeConverter.RequireObjectCoercible(_engine, thisObject);
         var s = TypeConverter.ToString(thisObject);
         return new JsString(s.ToUpperInvariant());
     }
 
     private JsValue ToLocaleLowerCase(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(_engine, thisObject);
+        TypeConverter.RequireObjectCoercible(_engine, thisObject);
         var s = TypeConverter.ToString(thisObject);
         return new JsString(s.ToLower(CultureInfo.InvariantCulture));
     }
 
     private JsValue ToLowerCase(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(_engine, thisObject);
+        TypeConverter.RequireObjectCoercible(_engine, thisObject);
         var s = TypeConverter.ToString(thisObject);
         return s.ToLowerInvariant();
     }
@@ -308,7 +308,7 @@ internal sealed class StringPrototype : StringInstance
 
     private JsValue Substring(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(Engine, thisObject);
+        TypeConverter.RequireObjectCoercible(Engine, thisObject);
 
         var s = TypeConverter.ToString(thisObject);
         var start = TypeConverter.ToNumber(arguments.At(0));
@@ -377,7 +377,7 @@ internal sealed class StringPrototype : StringInstance
     /// </summary>
     private JsValue Split(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(Engine, thisObject);
+        TypeConverter.RequireObjectCoercible(Engine, thisObject);
 
         var separator = arguments.At(0);
         var limit = arguments.At(1);
@@ -470,7 +470,7 @@ internal sealed class StringPrototype : StringInstance
     /// </summary>
     private JsValue At(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(_engine, thisObject);
+        TypeConverter.RequireObjectCoercible(_engine, thisObject);
         var start = arguments.At(0);
 
         var o = thisObject.ToString();
@@ -498,7 +498,7 @@ internal sealed class StringPrototype : StringInstance
 
     private JsValue Slice(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(Engine, thisObject);
+        TypeConverter.RequireObjectCoercible(Engine, thisObject);
 
         var start = TypeConverter.ToNumber(arguments.At(0));
         if (double.IsNegativeInfinity(start))
@@ -539,7 +539,7 @@ internal sealed class StringPrototype : StringInstance
 
     private JsValue Search(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(Engine, thisObject);
+        TypeConverter.RequireObjectCoercible(Engine, thisObject);
         var regex = arguments.At(0);
 
         if (regex is ObjectInstance oi)
@@ -561,7 +561,7 @@ internal sealed class StringPrototype : StringInstance
     /// </summary>
     private JsValue Replace(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(Engine, thisObject);
+        TypeConverter.RequireObjectCoercible(Engine, thisObject);
 
         var searchValue = arguments.At(0);
         var replaceValue = arguments.At(1);
@@ -613,7 +613,7 @@ internal sealed class StringPrototype : StringInstance
     /// </summary>
     private JsValue ReplaceAll(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(Engine, thisObject);
+        TypeConverter.RequireObjectCoercible(Engine, thisObject);
 
         var searchValue = arguments.At(0);
         var replaceValue = arguments.At(1);
@@ -623,7 +623,7 @@ internal sealed class StringPrototype : StringInstance
             if (searchValue.IsRegExp())
             {
                 var flags = searchValue.Get(RegExpPrototype.PropertyFlags);
-                TypeConverter.CheckObjectCoercible(_engine, flags);
+                TypeConverter.RequireObjectCoercible(_engine, flags);
                 if (!TypeConverter.ToString(flags).Contains('g'))
                 {
                     ExceptionHelper.ThrowTypeError(_realm, "String.prototype.replaceAll called with a non-global RegExp argument");
@@ -708,7 +708,7 @@ internal sealed class StringPrototype : StringInstance
 
     private JsValue Match(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(Engine, thisObject);
+        TypeConverter.RequireObjectCoercible(Engine, thisObject);
 
         var regex = arguments.At(0);
         if (regex is ObjectInstance oi)
@@ -728,7 +728,7 @@ internal sealed class StringPrototype : StringInstance
 
     private JsValue MatchAll(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(_engine, thisObject);
+        TypeConverter.RequireObjectCoercible(_engine, thisObject);
 
         var regex = arguments.At(0);
         if (!regex.IsNullOrUndefined())
@@ -736,7 +736,7 @@ internal sealed class StringPrototype : StringInstance
             if (regex.IsRegExp())
             {
                 var flags = regex.Get(RegExpPrototype.PropertyFlags);
-                TypeConverter.CheckObjectCoercible(_engine, flags);
+                TypeConverter.RequireObjectCoercible(_engine, flags);
                 if (!TypeConverter.ToString(flags).Contains('g'))
                 {
                     ExceptionHelper.ThrowTypeError(_realm);
@@ -757,7 +757,7 @@ internal sealed class StringPrototype : StringInstance
 
     private JsValue LocaleCompare(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(Engine, thisObject);
+        TypeConverter.RequireObjectCoercible(Engine, thisObject);
 
         var s = TypeConverter.ToString(thisObject);
         var that = TypeConverter.ToString(arguments.At(0));
@@ -777,7 +777,7 @@ internal sealed class StringPrototype : StringInstance
     /// </summary>
     private JsValue LastIndexOf(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(Engine, thisObject);
+        TypeConverter.RequireObjectCoercible(Engine, thisObject);
 
         var jsString = TypeConverter.ToJsString(thisObject);
         var searchStr = TypeConverter.ToString(arguments.At(0));
@@ -833,7 +833,7 @@ internal sealed class StringPrototype : StringInstance
     /// </summary>
     private JsValue IndexOf(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(Engine, thisObject);
+        TypeConverter.RequireObjectCoercible(Engine, thisObject);
 
         var s = TypeConverter.ToJsString(thisObject);
         var searchStr = TypeConverter.ToString(arguments.At(0));
@@ -858,7 +858,7 @@ internal sealed class StringPrototype : StringInstance
 
     private JsValue Concat(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(Engine, thisObject);
+        TypeConverter.RequireObjectCoercible(Engine, thisObject);
 
         if (thisObject is not JsString jsString)
         {
@@ -879,7 +879,7 @@ internal sealed class StringPrototype : StringInstance
 
     private JsValue CharCodeAt(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(Engine, thisObject);
+        TypeConverter.RequireObjectCoercible(Engine, thisObject);
 
         JsValue pos = arguments.Length > 0 ? arguments[0] : 0;
         var s = TypeConverter.ToJsString(thisObject);
@@ -896,7 +896,7 @@ internal sealed class StringPrototype : StringInstance
     /// </summary>
     private JsValue CodePointAt(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(Engine, thisObject);
+        TypeConverter.RequireObjectCoercible(Engine, thisObject);
 
         JsValue pos = arguments.Length > 0 ? arguments[0] : 0;
         var s = TypeConverter.ToString(thisObject);
@@ -941,7 +941,7 @@ internal sealed class StringPrototype : StringInstance
 
     private JsValue CharAt(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(Engine, thisObject);
+        TypeConverter.RequireObjectCoercible(Engine, thisObject);
         var s = TypeConverter.ToJsString(thisObject);
         var position = TypeConverter.ToInteger(arguments.At(0));
         var size = s.Length;
@@ -989,7 +989,7 @@ internal sealed class StringPrototype : StringInstance
     /// </summary>
     private JsValue StringPad(JsValue thisObject, JsValue[] arguments, bool padStart)
     {
-        TypeConverter.CheckObjectCoercible(Engine, thisObject);
+        TypeConverter.RequireObjectCoercible(Engine, thisObject);
         var s = TypeConverter.ToJsString(thisObject);
 
         var targetLength = TypeConverter.ToInt32(arguments.At(0));
@@ -1020,7 +1020,7 @@ internal sealed class StringPrototype : StringInstance
     /// </summary>
     private JsValue StartsWith(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(Engine, thisObject);
+        TypeConverter.RequireObjectCoercible(Engine, thisObject);
 
         var s = TypeConverter.ToJsString(thisObject);
 
@@ -1052,7 +1052,7 @@ internal sealed class StringPrototype : StringInstance
     /// </summary>
     private JsValue EndsWith(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(Engine, thisObject);
+        TypeConverter.RequireObjectCoercible(Engine, thisObject);
 
         var s = TypeConverter.ToJsString(thisObject);
 
@@ -1083,7 +1083,7 @@ internal sealed class StringPrototype : StringInstance
     /// </summary>
     private JsValue Includes(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(Engine, thisObject);
+        TypeConverter.RequireObjectCoercible(Engine, thisObject);
 
         var s = TypeConverter.ToJsString(thisObject);
         var searchString = arguments.At(0);
@@ -1115,7 +1115,7 @@ internal sealed class StringPrototype : StringInstance
 
     private JsValue Normalize(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(Engine, thisObject);
+        TypeConverter.RequireObjectCoercible(Engine, thisObject);
         var str = TypeConverter.ToString(thisObject);
 
         var param = arguments.At(0);
@@ -1156,7 +1156,7 @@ internal sealed class StringPrototype : StringInstance
     /// </summary>
     private JsValue Repeat(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(Engine, thisObject);
+        TypeConverter.RequireObjectCoercible(Engine, thisObject);
         var s = TypeConverter.ToString(thisObject);
         var count = arguments.At(0);
 
@@ -1188,7 +1188,7 @@ internal sealed class StringPrototype : StringInstance
 
     private JsValue IsWellFormed(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(_engine, thisObject);
+        TypeConverter.RequireObjectCoercible(_engine, thisObject);
         var s = TypeConverter.ToString(thisObject);
 
         return IsStringWellFormedUnicode(s);
@@ -1196,7 +1196,7 @@ internal sealed class StringPrototype : StringInstance
 
     private JsValue ToWellFormed(JsValue thisObject, JsValue[] arguments)
     {
-        TypeConverter.CheckObjectCoercible(_engine, thisObject);
+        TypeConverter.RequireObjectCoercible(_engine, thisObject);
         var s = TypeConverter.ToString(thisObject);
 
         var strLen = s.Length;

+ 31 - 33
Jint/Runtime/Environments/ObjectEnvironment.cs

@@ -27,27 +27,13 @@ internal sealed class ObjectEnvironment : Environment
         _withEnvironment = withEnvironment;
     }
 
-    internal override bool HasBinding(Key name)
-    {
-        var property = new JsString(name.Name);
-        var foundBinding = _bindingObject.HasProperty(property);
+    internal override bool HasBinding(Key name) => HasBinding(JsString.Create(name.Name));
 
-        if (!foundBinding)
-        {
-            return false;
-        }
+    internal override bool HasBinding(BindingName name) => HasBinding(name.Value);
 
-        if (!_withEnvironment)
-        {
-            return true;
-        }
-
-        return !IsBlocked(property);
-    }
-
-    internal override bool HasBinding(BindingName name)
+    private bool HasBinding(JsString nameValue)
     {
-        var foundBinding = _bindingObject.HasProperty(name.Value);
+        var foundBinding = _bindingObject.HasProperty(nameValue);
 
         if (!foundBinding)
         {
@@ -59,7 +45,7 @@ internal sealed class ObjectEnvironment : Environment
             return true;
         }
 
-        return !IsBlocked(name.Value);
+        return !IsBlocked(nameValue);
     }
 
     internal override bool TryGetBinding(BindingName name, bool strict, [NotNullWhen(true)] out JsValue? value)
@@ -77,14 +63,17 @@ internal sealed class ObjectEnvironment : Environment
             return false;
         }
 
-        value = _bindingObject.Get(name.Value);
-
-        if (strict && value.IsUndefined() && !_bindingObject.HasProperty(name.Value))
+        if (!_bindingObject.HasProperty(name.Value))
         {
-            // data was deleted during reading of unscopable information, of course...
-            ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name.Key);
+            if (strict)
+            {
+                // data was deleted during reading of unscopable information, of course...
+                ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name.Key);
+            }
         }
 
+        value = _bindingObject.Get(name.Value);
+
         return true;
     }
 
@@ -129,32 +118,41 @@ internal sealed class ObjectEnvironment : Environment
     internal override void SetMutableBinding(Key name, JsValue value, bool strict)
     {
         var jsString = new JsString(name);
-        if (strict && !_bindingObject.HasProperty(jsString))
+        if (!_bindingObject.HasProperty(jsString))
         {
-            ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name);
+            if (strict)
+            {
+                ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name);
+            }
         }
 
-        _bindingObject.Set(jsString, value);
+        _bindingObject.Set(jsString, value, strict);
     }
 
     internal override void SetMutableBinding(BindingName name, JsValue value, bool strict)
     {
-        if (strict && !_bindingObject.HasProperty(name.Value))
+        if (!_bindingObject.HasProperty(name.Value))
         {
-            ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name.Key);
+            if (strict)
+            {
+                ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name.Key);
+            }
         }
 
-        _bindingObject.Set(name.Value, value);
+        _bindingObject.Set(name.Value, value, strict);
     }
 
     internal override JsValue GetBindingValue(Key name, bool strict)
     {
-        if (!_bindingObject.TryGetValue(name.Name, out var value) && strict)
+        if (!_bindingObject.HasProperty(name.Name))
         {
-            ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name.Name);
+            if (strict)
+            {
+                ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name.Name);
+            }
         }
 
-        return value;
+        return _bindingObject.Get(name.Name);
     }
 
     internal override bool DeleteBinding(Key name) => _bindingObject.Delete(name.Name);

+ 2 - 2
Jint/Runtime/Interpreter/Expressions/JintUnaryExpression.cs

@@ -210,7 +210,7 @@ internal sealed class JintUnaryExpression : JintExpression
                 {
                     if (r.IsSuperReference)
                     {
-                        ExceptionHelper.ThrowReferenceError(engine.Realm, r);
+                        ExceptionHelper.ThrowReferenceError(engine.Realm, "Unsupported reference to 'super'");
                     }
 
                     var o = TypeConverter.ToObject(engine.Realm, r.Base);
@@ -315,4 +315,4 @@ internal sealed class JintUnaryExpression : JintExpression
         result = null;
         return false;
     }
-}
+}

+ 8 - 2
Jint/Runtime/TypeConverter.cs

@@ -1032,11 +1032,17 @@ public static class TypeConverter
             .SetJavaScriptCallstack(engine, sourceNode.Location, overwriteExisting: true);
     }
 
-    public static void CheckObjectCoercible(Engine engine, JsValue o)
+    [Obsolete("Use TypeConverter.RequireObjectCoercible")]
+    public static void CheckObjectCoercible(Engine engine, JsValue o) => RequireObjectCoercible(engine, o);
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-requireobjectcoercible
+    /// </summary>
+    public static void RequireObjectCoercible(Engine engine, JsValue o)
     {
         if (o._type < InternalTypes.Boolean)
         {
-            ExceptionHelper.ThrowTypeError(engine.Realm, "Cannot call method on " + o);
+            ExceptionHelper.ThrowTypeError(engine.Realm, $"Cannot call method on {o}");
         }
     }
 }