From 9c4652305ade4ec803a79a5e659464806873a061 Mon Sep 17 00:00:00 2001 From: Marko Lahma Date: Wed, 25 Sep 2024 21:57:28 +0300 Subject: [PATCH] Update test262 harness and fix issues --- .../Test262Harness.settings.json | 15 +++- Jint.Tests.Test262/Test262Test.cs | 2 +- Jint/Engine.cs | 23 ++++--- .../FinalizationRegistryPrototype.cs | 19 +----- Jint/Native/JsTypedArray.cs | 32 +++++++++ Jint/Native/Object/ObjectConstructor.cs | 6 +- Jint/Native/Object/ObjectInstance.cs | 3 + Jint/Native/Object/ObjectPrototype.cs | 2 +- Jint/Native/String/StringPrototype.cs | 68 +++++++++---------- .../Runtime/Environments/ObjectEnvironment.cs | 64 +++++++++-------- .../Expressions/JintUnaryExpression.cs | 4 +- Jint/Runtime/TypeConverter.cs | 10 ++- 12 files changed, 145 insertions(+), 103 deletions(-) diff --git a/Jint.Tests.Test262/Test262Harness.settings.json b/Jint.Tests.Test262/Test262Harness.settings.json index 91af0acb29..75eed76e51 100644 --- a/Jint.Tests.Test262/Test262Harness.settings.json +++ b/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", diff --git a/Jint.Tests.Test262/Test262Test.cs b/Jint.Tests.Test262/Test262Test.cs index e0ae188798..565027b956 100644 --- a/Jint.Tests.Test262/Test262Test.cs +++ b/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 => { diff --git a/Jint/Engine.cs b/Jint/Engine.cs index 40bf799dd6..932ed400ca 100644 --- a/Jint/Engine.cs +++ b/Jint/Engine.cs @@ -704,7 +704,7 @@ internal void PutValue(Reference reference, JsValue value) 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 @@ internal Reference ResolveBinding(string name, Environment? env = null) 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; + } } /// diff --git a/Jint/Native/FinalizationRegistry/FinalizationRegistryPrototype.cs b/Jint/Native/FinalizationRegistry/FinalizationRegistryPrototype.cs index 3ec8fb96e9..f032195d60 100644 --- a/Jint/Native/FinalizationRegistry/FinalizationRegistryPrototype.cs +++ b/Jint/Native/FinalizationRegistry/FinalizationRegistryPrototype.cs @@ -29,7 +29,9 @@ protected override void Initialize() 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 @@ private JsValue Unregister(JsValue thisObject, JsValue[] arguments) 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) diff --git a/Jint/Native/JsTypedArray.cs b/Jint/Native/JsTypedArray.cs index 2df1b56d60..c9b8f0baa4 100644 --- a/Jint/Native/JsTypedArray.cs +++ b/Jint/Native/JsTypedArray.cs @@ -58,6 +58,38 @@ internal override uint GetLength() return record.IsTypedArrayOutOfBounds ? 0 : record.TypedArrayLength; } + public override bool PreventExtensions() + { + if (!IsTypedArrayFixedLength) + { + return false; + } + + return base.PreventExtensions(); + } + + /// + /// https://tc39.es/ecma262/#sec-istypedarrayfixedlength + /// + 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; diff --git a/Jint/Native/Object/ObjectConstructor.cs b/Jint/Native/Object/ObjectConstructor.cs index e3724023e8..92e5a2c53b 100644 --- a/Jint/Native/Object/ObjectConstructor.cs +++ b/Jint/Native/Object/ObjectConstructor.cs @@ -109,7 +109,7 @@ private JsValue Entries(JsValue thisObject, JsValue[] arguments) 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 JsValue GetPrototypeOf(JsValue thisObject, JsValue[] arguments) 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 @@ private JsValue SetPrototypeOf(JsValue thisObject, JsValue[] arguments) 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; } diff --git a/Jint/Native/Object/ObjectInstance.cs b/Jint/Native/Object/ObjectInstance.cs index 2f6d6bf839..2afc454187 100644 --- a/Jint/Native/Object/ObjectInstance.cs +++ b/Jint/Native/Object/ObjectInstance.cs @@ -1217,6 +1217,9 @@ internal bool IsConcatSpreadable internal virtual uint GetLength() => (uint) TypeConverter.ToLength(Get(CommonProperties.Length)); + /// + /// https://tc39.es/ecma262/#sec-ordinarypreventextensions + /// public virtual bool PreventExtensions() { Extensible = false; diff --git a/Jint/Native/Object/ObjectPrototype.cs b/Jint/Native/Object/ObjectPrototype.cs index df841e1a70..623005aed8 100644 --- a/Jint/Native/Object/ObjectPrototype.cs +++ b/Jint/Native/Object/ObjectPrototype.cs @@ -38,7 +38,7 @@ protected override void Initialize() 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) diff --git a/Jint/Native/String/StringPrototype.cs b/Jint/Native/String/StringPrototype.cs index c1a13ec06c..91fb71574a 100644 --- a/Jint/Native/String/StringPrototype.cs +++ b/Jint/Native/String/StringPrototype.cs @@ -100,7 +100,7 @@ protected override void Initialize() 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 static string TrimEx(string s) [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 @@ private JsValue Trim(JsValue thisObject, JsValue[] arguments) /// 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 @@ private JsValue TrimStart(JsValue thisObject, JsValue[] arguments) /// 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 @@ private JsValue TrimEnd(JsValue thisObject, JsValue[] arguments) 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 @@ private JsValue ToLocaleUpperCase(JsValue thisObject, JsValue[] arguments) 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 @@ private static int ToIntegerSupportInfinityUnlikely(JsValue numberVal) 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 @@ private static JsValue Substr(JsValue thisObject, JsValue[] arguments) /// 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 static JsValue SplitWithStringSeparator(Realm realm, JsValue separator, /// 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 @@ private JsValue At(JsValue thisObject, JsValue[] arguments) 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 @@ private JsValue Slice(JsValue thisObject, JsValue[] arguments) 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 @@ private JsValue Search(JsValue thisObject, JsValue[] arguments) /// 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 @@ private JsValue Replace(JsValue thisObject, JsValue[] arguments) /// 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 @@ private JsValue ReplaceAll(JsValue thisObject, JsValue[] arguments) 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 @@ static int StringIndexOf(string s, string search, int fromIndex) 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 @@ private JsValue Match(JsValue thisObject, JsValue[] arguments) 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 @@ private JsValue MatchAll(JsValue thisObject, JsValue[] arguments) 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 @@ private JsValue MatchAll(JsValue thisObject, JsValue[] arguments) 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 @@ private JsValue LocaleCompare(JsValue thisObject, JsValue[] arguments) /// 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 @@ private JsValue LastIndexOf(JsValue thisObject, JsValue[] arguments) /// 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 @@ private JsValue IndexOf(JsValue thisObject, JsValue[] arguments) 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 @@ private JsValue Concat(JsValue thisObject, JsValue[] arguments) 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 @@ private JsValue CharCodeAt(JsValue thisObject, JsValue[] arguments) /// 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 @@ private static CodePointResult CodePointAt(string s, int position) 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 @@ private JsValue PadEnd(JsValue thisObject, JsValue[] arguments) /// 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 @@ private JsValue StringPad(JsValue thisObject, JsValue[] arguments, bool padStart /// private JsValue StartsWith(JsValue thisObject, JsValue[] arguments) { - TypeConverter.CheckObjectCoercible(Engine, thisObject); + TypeConverter.RequireObjectCoercible(Engine, thisObject); var s = TypeConverter.ToJsString(thisObject); @@ -1052,7 +1052,7 @@ private JsValue StartsWith(JsValue thisObject, JsValue[] arguments) /// private JsValue EndsWith(JsValue thisObject, JsValue[] arguments) { - TypeConverter.CheckObjectCoercible(Engine, thisObject); + TypeConverter.RequireObjectCoercible(Engine, thisObject); var s = TypeConverter.ToJsString(thisObject); @@ -1083,7 +1083,7 @@ private JsValue EndsWith(JsValue thisObject, JsValue[] arguments) /// 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 @@ private JsValue Includes(JsValue thisObject, JsValue[] arguments) 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 @@ private JsValue Normalize(JsValue thisObject, JsValue[] arguments) /// 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 @@ private JsValue Repeat(JsValue thisObject, JsValue[] arguments) 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 @@ private JsValue IsWellFormed(JsValue thisObject, JsValue[] arguments) private JsValue ToWellFormed(JsValue thisObject, JsValue[] arguments) { - TypeConverter.CheckObjectCoercible(_engine, thisObject); + TypeConverter.RequireObjectCoercible(_engine, thisObject); var s = TypeConverter.ToString(thisObject); var strLen = s.Length; diff --git a/Jint/Runtime/Environments/ObjectEnvironment.cs b/Jint/Runtime/Environments/ObjectEnvironment.cs index 731b20a848..695aadaa72 100644 --- a/Jint/Runtime/Environments/ObjectEnvironment.cs +++ b/Jint/Runtime/Environments/ObjectEnvironment.cs @@ -27,27 +27,13 @@ public ObjectEnvironment( _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 override bool HasBinding(BindingName name) 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 override bool TryGetBinding(BindingName name, bool strict, [NotNullWhen 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 override void CreateImmutableBinding(Key name, bool strict = true) 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); diff --git a/Jint/Runtime/Interpreter/Expressions/JintUnaryExpression.cs b/Jint/Runtime/Interpreter/Expressions/JintUnaryExpression.cs index cf71a3ca47..c3e04451f3 100644 --- a/Jint/Runtime/Interpreter/Expressions/JintUnaryExpression.cs +++ b/Jint/Runtime/Interpreter/Expressions/JintUnaryExpression.cs @@ -210,7 +210,7 @@ private JsValue EvaluateJsValue(EvaluationContext context) { 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 static bool TryOperatorOverloading(EvaluationContext context, JsValue v result = null; return false; } -} \ No newline at end of file +} diff --git a/Jint/Runtime/TypeConverter.cs b/Jint/Runtime/TypeConverter.cs index bbca3b175f..568457e2cc 100644 --- a/Jint/Runtime/TypeConverter.cs +++ b/Jint/Runtime/TypeConverter.cs @@ -1032,11 +1032,17 @@ private static void ThrowMemberNullOrUndefinedError( .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); + + /// + /// https://tc39.es/ecma262/#sec-requireobjectcoercible + /// + 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}"); } } }