浏览代码

Update to latest test262 suite and implement Symbols as WeakMap keys (#1365)

Marko Lahma 2 年之前
父节点
当前提交
7fab0dbf19

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

@@ -1,5 +1,5 @@
 {
 {
-  "SuiteGitSha": "8565eea8be06eee720b9af42235d1ecf5df0dc5f",
+  "SuiteGitSha": "83a46bfe0e79aed8274a1b9f4beb0a2efa0b3533",
   //"SuiteDirectory": "//mnt/c/work/test262",
   //"SuiteDirectory": "//mnt/c/work/test262",
   "TargetPath": "./Generated",
   "TargetPath": "./Generated",
   "Namespace": "Jint.Tests.Test262",
   "Namespace": "Jint.Tests.Test262",
@@ -7,6 +7,7 @@
   "ExcludedFeatures": [
   "ExcludedFeatures": [
     "async-iteration",
     "async-iteration",
     "Atomics",
     "Atomics",
+    "change-array-by-copy",
     "class-fields-private",
     "class-fields-private",
     "class-fields-public",
     "class-fields-public",
     "class-methods-private",
     "class-methods-private",

+ 2 - 3
Jint.Tests/Runtime/WeakSetMapTests.cs

@@ -31,8 +31,7 @@ public class WeakSetMapTests
         100.04,
         100.04,
         double.NaN,
         double.NaN,
         "hello",
         "hello",
-        true,
-        new JsSymbol("hello")
+        true
     };
     };
 
 
     [Theory]
     [Theory]
@@ -43,7 +42,7 @@ public class WeakSetMapTests
         var weakSet = new WeakSetInstance(engine);
         var weakSet = new WeakSetInstance(engine);
 
 
         var e = Assert.Throws<JavaScriptException>(() => weakSet.WeakSetAdd(key));
         var e = Assert.Throws<JavaScriptException>(() => weakSet.WeakSetAdd(key));
-        Assert.StartsWith("WeakSet value must be an object, got ", e.Message);
+        Assert.StartsWith("WeakSet value must be an object or symbol, got ", e.Message);
 
 
         Assert.False(weakSet.WeakSetHas(key));
         Assert.False(weakSet.WeakSetHas(key));
     }
     }

+ 7 - 0
Jint/JsValueExtensions.cs

@@ -124,6 +124,13 @@ namespace Jint
             return value._type == InternalTypes.Symbol;
             return value._type == InternalTypes.Symbol;
         }
         }
 
 
+        [Pure]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        internal static bool CanBeHeldWeakly(this JsValue value, GlobalSymbolRegistry symbolRegistry)
+        {
+            return value.IsObject() || (value.IsSymbol() && !symbolRegistry.ContainsCustom(value));
+        }
+
         [Pure]
         [Pure]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static JsDate AsDate(this JsValue value)
         public static JsDate AsDate(this JsValue value)

+ 1 - 1
Jint/Native/FinalizationRegistry/FinalizationRegistryInstance.cs

@@ -4,7 +4,7 @@ using Jint.Runtime;
 
 
 namespace Jint.Native.FinalizationRegistry;
 namespace Jint.Native.FinalizationRegistry;
 
 
-internal sealed record Cell(JsValue WeakRefTarget, JsValue HeldValue, ObjectInstance? UnregisterToken);
+internal sealed record Cell(JsValue WeakRefTarget, JsValue HeldValue, JsValue? UnregisterToken);
 
 
 internal sealed class FinalizationRegistryInstance : ObjectInstance
 internal sealed class FinalizationRegistryInstance : ObjectInstance
 {
 {

+ 6 - 6
Jint/Native/FinalizationRegistry/FinalizationRegistryPrototype.cs

@@ -51,9 +51,9 @@ internal sealed class FinalizationRegistryPrototype : Prototype
         var heldValue = arguments.At(1);
         var heldValue = arguments.At(1);
         var unregisterToken = arguments.At(2);
         var unregisterToken = arguments.At(2);
 
 
-        if (target is not ObjectInstance)
+        if (!target.CanBeHeldWeakly(_engine.GlobalSymbolRegistry))
         {
         {
-            ExceptionHelper.ThrowTypeError(_realm, "target must be an object");
+            ExceptionHelper.ThrowTypeError(_realm, "target must be an object or symbol");
         }
         }
 
 
         if (SameValue(target, heldValue))
         if (SameValue(target, heldValue))
@@ -61,7 +61,7 @@ internal sealed class FinalizationRegistryPrototype : Prototype
             ExceptionHelper.ThrowTypeError(_realm, "target and holdings must not be same");
             ExceptionHelper.ThrowTypeError(_realm, "target and holdings must not be same");
         }
         }
 
 
-        if (unregisterToken is not ObjectInstance oi)
+        if (!unregisterToken.CanBeHeldWeakly(_engine.GlobalSymbolRegistry))
         {
         {
             if (!unregisterToken.IsUndefined())
             if (!unregisterToken.IsUndefined())
             {
             {
@@ -69,7 +69,7 @@ internal sealed class FinalizationRegistryPrototype : Prototype
             }
             }
 
 
         }
         }
-        var cell = new Cell(target, heldValue, unregisterToken as ObjectInstance);
+        var cell = new Cell(target, heldValue, unregisterToken);
         finalizationRegistry.AddCell(cell);
         finalizationRegistry.AddCell(cell);
         return Undefined;
         return Undefined;
     }
     }
@@ -83,9 +83,9 @@ internal sealed class FinalizationRegistryPrototype : Prototype
 
 
         var unregisterToken = arguments.At(0);
         var unregisterToken = arguments.At(0);
 
 
-        if (unregisterToken is not ObjectInstance oi)
+        if (!unregisterToken.CanBeHeldWeakly(_engine.GlobalSymbolRegistry))
         {
         {
-            ExceptionHelper.ThrowTypeError(_realm, unregisterToken + " must be an object");
+            ExceptionHelper.ThrowTypeError(_realm, unregisterToken + " must be an object or symbol");
         }
         }
 
 
         return finalizationRegistry.Remove(unregisterToken);
         return finalizationRegistry.Remove(unregisterToken);

+ 37 - 33
Jint/Native/Symbol/GlobalSymbolRegistry.cs

@@ -1,42 +1,46 @@
 using System.Diagnostics.CodeAnalysis;
 using System.Diagnostics.CodeAnalysis;
 
 
-namespace Jint.Native.Symbol
+namespace Jint.Native.Symbol;
+
+public sealed class GlobalSymbolRegistry
 {
 {
-    public sealed class GlobalSymbolRegistry
-    {
-        public static readonly JsSymbol AsyncIterator = new JsSymbol("Symbol.asyncIterator");
-        public static readonly JsSymbol HasInstance = new JsSymbol("Symbol.hasInstance");
-        public static readonly JsSymbol IsConcatSpreadable = new JsSymbol("Symbol.isConcatSpreadable");
-        public static readonly JsSymbol Iterator = new JsSymbol("Symbol.iterator");
-        public static readonly JsSymbol Match = new JsSymbol("Symbol.match");
-        public static readonly JsSymbol MatchAll = new JsSymbol("Symbol.matchAll");
-        public static readonly JsSymbol Replace = new JsSymbol("Symbol.replace");
-        public static readonly JsSymbol Search = new JsSymbol("Symbol.search");
-        public static readonly JsSymbol Species = new JsSymbol("Symbol.species");
-        public static readonly JsSymbol Split = new JsSymbol("Symbol.split");
-        public static readonly JsSymbol ToPrimitive = new JsSymbol("Symbol.toPrimitive");
-        public static readonly JsSymbol ToStringTag = new JsSymbol("Symbol.toStringTag");
-        public static readonly JsSymbol Unscopables = new JsSymbol("Symbol.unscopables");
+    public static readonly JsSymbol AsyncIterator = new JsSymbol("Symbol.asyncIterator");
+    public static readonly JsSymbol HasInstance = new JsSymbol("Symbol.hasInstance");
+    public static readonly JsSymbol IsConcatSpreadable = new JsSymbol("Symbol.isConcatSpreadable");
+    public static readonly JsSymbol Iterator = new JsSymbol("Symbol.iterator");
+    public static readonly JsSymbol Match = new JsSymbol("Symbol.match");
+    public static readonly JsSymbol MatchAll = new JsSymbol("Symbol.matchAll");
+    public static readonly JsSymbol Replace = new JsSymbol("Symbol.replace");
+    public static readonly JsSymbol Search = new JsSymbol("Symbol.search");
+    public static readonly JsSymbol Species = new JsSymbol("Symbol.species");
+    public static readonly JsSymbol Split = new JsSymbol("Symbol.split");
+    public static readonly JsSymbol ToPrimitive = new JsSymbol("Symbol.toPrimitive");
+    public static readonly JsSymbol ToStringTag = new JsSymbol("Symbol.toStringTag");
+    public static readonly JsSymbol Unscopables = new JsSymbol("Symbol.unscopables");
+
+    // engine-specific created by scripts
+    private Dictionary<JsValue, JsSymbol>? _customSymbolLookup;
 
 
-        // engine-specific created by scripts
-        private Dictionary<JsValue, JsSymbol>? _customSymbolLookup;
+    internal bool TryGetSymbol(JsValue key, [NotNullWhen(true)] out JsSymbol? symbol)
+    {
+        symbol = null;
+        return _customSymbolLookup != null
+               && _customSymbolLookup.TryGetValue(key, out symbol);
+    }
 
 
-        internal bool TryGetSymbol(JsValue key, [NotNullWhen(true)] out JsSymbol? symbol)
-        {
-            symbol = null;
-            return _customSymbolLookup != null
-                   && _customSymbolLookup.TryGetValue(key, out symbol);
-        }
+    internal void Add(JsSymbol symbol)
+    {
+        _customSymbolLookup ??= new Dictionary<JsValue, JsSymbol>();
+        _customSymbolLookup[symbol._value] = symbol;
+    }
 
 
-        internal void Add(JsSymbol symbol)
-        {
-            _customSymbolLookup ??= new Dictionary<JsValue, JsSymbol>();
-            _customSymbolLookup[symbol._value] = symbol;
-        }
+    internal static JsSymbol CreateSymbol(JsValue description)
+    {
+        return new JsSymbol(description);
+    }
 
 
-        internal JsSymbol CreateSymbol(JsValue description)
-        {
-            return new JsSymbol(description);
-        }
+    internal bool ContainsCustom(JsValue value)
+    {
+        return value is JsSymbol symbol && _customSymbolLookup?.ContainsKey(symbol._value) == true;
     }
     }
 }
 }

+ 2 - 2
Jint/Native/Symbol/SymbolConstructor.cs

@@ -66,7 +66,7 @@ namespace Jint.Native.Symbol
                 ? Undefined
                 ? Undefined
                 : TypeConverter.ToJsString(description);
                 : TypeConverter.ToJsString(description);
 
 
-            var value = _engine.GlobalSymbolRegistry.CreateSymbol(descString);
+            var value = GlobalSymbolRegistry.CreateSymbol(descString);
             return value;
             return value;
         }
         }
 
 
@@ -81,7 +81,7 @@ namespace Jint.Native.Symbol
 
 
             if (!_engine.GlobalSymbolRegistry.TryGetSymbol(stringKey, out var symbol))
             if (!_engine.GlobalSymbolRegistry.TryGetSymbol(stringKey, out var symbol))
             {
             {
-                symbol = _engine.GlobalSymbolRegistry.CreateSymbol(stringKey);
+                symbol = GlobalSymbolRegistry.CreateSymbol(stringKey);
                 _engine.GlobalSymbolRegistry.Add(symbol);
                 _engine.GlobalSymbolRegistry.Add(symbol);
             }
             }
 
 

+ 1 - 1
Jint/Native/WeakMap/WeakMapInstance.cs

@@ -26,7 +26,7 @@ internal sealed class WeakMapInstance : ObjectInstance
 
 
     internal void WeakMapSet(JsValue key, JsValue value)
     internal void WeakMapSet(JsValue key, JsValue value)
     {
     {
-        if (key.IsPrimitive())
+        if (!key.CanBeHeldWeakly(_engine.GlobalSymbolRegistry))
         {
         {
             ExceptionHelper.ThrowTypeError(_engine.Realm, "WeakMap key must be an object, got " + key);
             ExceptionHelper.ThrowTypeError(_engine.Realm, "WeakMap key must be an object, got " + key);
         }
         }

+ 60 - 61
Jint/Native/WeakMap/WeakMapPrototype.cs

@@ -5,80 +5,79 @@ using Jint.Runtime;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
 using Jint.Runtime.Interop;
 
 
-namespace Jint.Native.WeakMap
+namespace Jint.Native.WeakMap;
+
+/// <summary>
+/// https://tc39.es/ecma262/#sec-weakmap-objects
+/// </summary>
+internal sealed class WeakMapPrototype : Prototype
 {
 {
-    /// <summary>
-    /// https://tc39.es/ecma262/#sec-weakmap-objects
-    /// </summary>
-    internal sealed class WeakMapPrototype : Prototype
+    private readonly WeakMapConstructor _constructor;
+
+    internal WeakMapPrototype(
+        Engine engine,
+        Realm realm,
+        WeakMapConstructor constructor,
+        ObjectPrototype prototype) : base(engine, realm)
     {
     {
-        private readonly WeakMapConstructor _constructor;
+        _prototype = prototype;
+        _constructor = constructor;
+    }
 
 
-        internal WeakMapPrototype(
-            Engine engine,
-            Realm realm,
-            WeakMapConstructor constructor,
-            ObjectPrototype prototype) : base(engine, realm)
+    protected override void Initialize()
+    {
+        const PropertyFlag propertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
+        var properties = new PropertyDictionary(6, checkExistingKeys: false)
         {
         {
-            _prototype = prototype;
-            _constructor = constructor;
-        }
+            ["length"] = new PropertyDescriptor(0, PropertyFlag.Configurable),
+            ["constructor"] = new PropertyDescriptor(_constructor, PropertyFlag.NonEnumerable),
+            ["delete"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "delete", Delete, 1, PropertyFlag.Configurable), propertyFlags),
+            ["get"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "get", Get, 1, PropertyFlag.Configurable), propertyFlags),
+            ["has"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "has", Has, 1, PropertyFlag.Configurable), propertyFlags),
+            ["set"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "set", Set, 2, PropertyFlag.Configurable), propertyFlags),
+        };
+        SetProperties(properties);
 
 
-        protected override void Initialize()
+        var symbols = new SymbolDictionary(1)
         {
         {
-            const PropertyFlag propertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
-            var properties = new PropertyDictionary(6, checkExistingKeys: false)
-            {
-                ["length"] = new PropertyDescriptor(0, PropertyFlag.Configurable),
-                ["constructor"] = new PropertyDescriptor(_constructor, PropertyFlag.NonEnumerable),
-                ["delete"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "delete", Delete, 1, PropertyFlag.Configurable), propertyFlags),
-                ["get"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "get", Get, 1, PropertyFlag.Configurable), propertyFlags),
-                ["has"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "has", Has, 1, PropertyFlag.Configurable), propertyFlags),
-                ["set"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "set", Set, 2, PropertyFlag.Configurable), propertyFlags),
-            };
-            SetProperties(properties);
+            [GlobalSymbolRegistry.ToStringTag] = new PropertyDescriptor("WeakMap", false, false, true)
+        };
+        SetSymbols(symbols);
+    }
 
 
-            var symbols = new SymbolDictionary(1)
-            {
-                [GlobalSymbolRegistry.ToStringTag] = new PropertyDescriptor("WeakMap", false, false, true)
-            };
-            SetSymbols(symbols);
-        }
+    private JsValue Get(JsValue thisObj, JsValue[] arguments)
+    {
+        var map = AssertWeakMapInstance(thisObj);
+        return map.WeakMapGet(arguments.At(0));
+    }
 
 
-        private JsValue Get(JsValue thisObj, JsValue[] arguments)
-        {
-            var map = AssertWeakMapInstance(thisObj);
-            return map.WeakMapGet(arguments.At(0));
-        }
+    private JsValue Delete(JsValue thisObj, JsValue[] arguments)
+    {
+        var map = AssertWeakMapInstance(thisObj);
+        return arguments.Length > 0 && map.WeakMapDelete(arguments.At(0)) ? JsBoolean.True : JsBoolean.False;
+    }
 
 
-        private JsValue Delete(JsValue thisObj, JsValue[] arguments)
-        {
-            var map = AssertWeakMapInstance(thisObj);
-            return (arguments.Length > 0 && map.WeakMapDelete(arguments.At(0))) ? JsBoolean.True : JsBoolean.False;
-        }
+    private JsValue Set(JsValue thisObj, JsValue[] arguments)
+    {
+        var map = AssertWeakMapInstance(thisObj);
+        map.WeakMapSet(arguments.At(0), arguments.At(1));
+        return thisObj;
+    }
 
 
-        private JsValue Set(JsValue thisObj, JsValue[] arguments)
-        {
-            var map = AssertWeakMapInstance(thisObj);
-            map.WeakMapSet(arguments.At(0), arguments.At(1));
-            return thisObj;
-        }
+    private JsValue Has(JsValue thisObj, JsValue[] arguments)
+    {
+        var map = AssertWeakMapInstance(thisObj);
+        return map.WeakMapHas(arguments.At(0)) ? JsBoolean.True : JsBoolean.False;
+    }
 
 
-        private JsValue Has(JsValue thisObj, JsValue[] arguments)
+    private WeakMapInstance AssertWeakMapInstance(JsValue thisObj)
+    {
+        var map = thisObj as WeakMapInstance;
+        if (map is null)
         {
         {
-            var map = AssertWeakMapInstance(thisObj);
-            return map.WeakMapHas(arguments.At(0)) ? JsBoolean.True : JsBoolean.False;
+            ExceptionHelper.ThrowTypeError(_realm, "object must be a WeakMap");
         }
         }
 
 
-        private WeakMapInstance AssertWeakMapInstance(JsValue thisObj)
-        {
-            var map = thisObj as WeakMapInstance;
-            if (map is null)
-            {
-                ExceptionHelper.ThrowTypeError(_realm, "object must be a WeakMap");
-            }
-
-            return map;
-        }
+        return map;
     }
     }
 }
 }

+ 3 - 3
Jint/Native/WeakRef/WeakRefConstructor.cs

@@ -42,15 +42,15 @@ internal sealed class WeakRefConstructor : FunctionInstance, IConstructor
 
 
         var target = arguments.At(0);
         var target = arguments.At(0);
 
 
-        if (target is not ObjectInstance)
+        if (!target.CanBeHeldWeakly(_engine.GlobalSymbolRegistry))
         {
         {
-            ExceptionHelper.ThrowTypeError(_realm, "WeakRef: target must be an object");
+            ExceptionHelper.ThrowTypeError(_realm, "WeakRef: target must be an object or symbol");
         }
         }
 
 
         var weakRef = OrdinaryCreateFromConstructor(
         var weakRef = OrdinaryCreateFromConstructor(
             newTarget,
             newTarget,
             static intrinsics => intrinsics.WeakRef.PrototypeObject,
             static intrinsics => intrinsics.WeakRef.PrototypeObject,
-            static (Engine engine, Realm _, object? t) => new WeakRefInstance(engine, (ObjectInstance) t!),
+            static (engine, _, target) => new WeakRefInstance(engine, target!),
             target);
             target);
 
 
         _engine.AddToKeptObjects(target);
         _engine.AddToKeptObjects(target);

+ 3 - 3
Jint/Native/WeakRef/WeakRefInstance.cs

@@ -7,11 +7,11 @@ namespace Jint.Native.WeakRef;
 /// </summary>
 /// </summary>
 internal sealed class WeakRefInstance : ObjectInstance
 internal sealed class WeakRefInstance : ObjectInstance
 {
 {
-    private readonly WeakReference<ObjectInstance> _weakRefTarget;
+    private readonly WeakReference<JsValue> _weakRefTarget;
 
 
-    public WeakRefInstance(Engine engine, ObjectInstance target) : base(engine)
+    public WeakRefInstance(Engine engine, JsValue target) : base(engine)
     {
     {
-        _weakRefTarget = new WeakReference<ObjectInstance>(target);
+        _weakRefTarget = new WeakReference<JsValue>(target);
     }
     }
 
 
     public JsValue WeakRefDeref()
     public JsValue WeakRefDeref()

+ 3 - 3
Jint/Native/WeakSet/WeakSetInstance.cs

@@ -1,6 +1,7 @@
 using System.Runtime.CompilerServices;
 using System.Runtime.CompilerServices;
 
 
 using Jint.Native.Object;
 using Jint.Native.Object;
+using Jint.Native.Symbol;
 using Jint.Runtime;
 using Jint.Runtime;
 
 
 namespace Jint.Native.WeakSet;
 namespace Jint.Native.WeakSet;
@@ -26,9 +27,9 @@ internal sealed class WeakSetInstance : ObjectInstance
 
 
     internal void WeakSetAdd(JsValue value)
     internal void WeakSetAdd(JsValue value)
     {
     {
-        if (value.IsPrimitive())
+        if (!value.CanBeHeldWeakly(_engine.GlobalSymbolRegistry))
         {
         {
-            ExceptionHelper.ThrowTypeError(_engine.Realm, "WeakSet value must be an object, got " + value);
+            ExceptionHelper.ThrowTypeError(_engine.Realm, "WeakSet value must be an object or symbol, got " + value);
         }
         }
 
 
 #if NETSTANDARD2_1_OR_GREATER
 #if NETSTANDARD2_1_OR_GREATER
@@ -38,5 +39,4 @@ internal sealed class WeakSetInstance : ObjectInstance
         _table.Add(value, Undefined);
         _table.Add(value, Undefined);
 #endif
 #endif
     }
     }
-
 }
 }

+ 57 - 58
Jint/Native/WeakSet/WeakSetPrototype.cs

@@ -5,76 +5,75 @@ using Jint.Runtime;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
 using Jint.Runtime.Interop;
 
 
-namespace Jint.Native.WeakSet
+namespace Jint.Native.WeakSet;
+
+/// <summary>
+/// https://tc39.es/ecma262/#sec-weakset-objects
+/// </summary>
+internal sealed class WeakSetPrototype : Prototype
 {
 {
-    /// <summary>
-    /// https://tc39.es/ecma262/#sec-weakset-objects
-    /// </summary>
-    internal sealed class WeakSetPrototype : Prototype
+    private readonly WeakSetConstructor _constructor;
+    internal ClrFunctionInstance _originalAddFunction = null!;
+
+    internal WeakSetPrototype(
+        Engine engine,
+        Realm realm,
+        WeakSetConstructor constructor,
+        ObjectPrototype prototype) : base(engine, realm)
     {
     {
-        private readonly WeakSetConstructor _constructor;
-        internal ClrFunctionInstance _originalAddFunction = null!;
+        _prototype = prototype;
+        _constructor = constructor;
+    }
 
 
-        internal WeakSetPrototype(
-            Engine engine,
-            Realm realm,
-            WeakSetConstructor constructor,
-            ObjectPrototype prototype) : base(engine, realm)
-        {
-            _prototype = prototype;
-            _constructor = constructor;
-        }
+    protected override void Initialize()
+    {
+        _originalAddFunction = new ClrFunctionInstance(Engine, "add", Add, 1, PropertyFlag.Configurable);
 
 
-        protected override void Initialize()
+        const PropertyFlag PropertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
+        var properties = new PropertyDictionary(5, checkExistingKeys: false)
         {
         {
-            _originalAddFunction = new ClrFunctionInstance(Engine, "add", Add, 1, PropertyFlag.Configurable);
+            ["length"] = new(0, PropertyFlag.Configurable),
+            ["constructor"] = new(_constructor, PropertyFlag.NonEnumerable),
+            ["delete"] = new(new ClrFunctionInstance(Engine, "delete", Delete, 1, PropertyFlag.Configurable), PropertyFlags),
+            ["add"] = new(_originalAddFunction, PropertyFlags),
+            ["has"] = new(new ClrFunctionInstance(Engine, "has", Has, 1, PropertyFlag.Configurable), PropertyFlags),
+        };
+        SetProperties(properties);
 
 
-            const PropertyFlag PropertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
-            var properties = new PropertyDictionary(5, checkExistingKeys: false)
-            {
-                ["length"] = new(0, PropertyFlag.Configurable),
-                ["constructor"] = new(_constructor, PropertyFlag.NonEnumerable),
-                ["delete"] = new(new ClrFunctionInstance(Engine, "delete", Delete, 1, PropertyFlag.Configurable), PropertyFlags),
-                ["add"] = new(_originalAddFunction, PropertyFlags),
-                ["has"] = new(new ClrFunctionInstance(Engine, "has", Has, 1, PropertyFlag.Configurable), PropertyFlags),
-            };
-            SetProperties(properties);
+        var symbols = new SymbolDictionary(1)
+        {
+            [GlobalSymbolRegistry.ToStringTag] = new("WeakSet", false, false, true)
+        };
+        SetSymbols(symbols);
+    }
 
 
-            var symbols = new SymbolDictionary(1)
-            {
-                [GlobalSymbolRegistry.ToStringTag] = new("WeakSet", false, false, true)
-            };
-            SetSymbols(symbols);
-        }
+    private JsValue Add(JsValue thisObj, JsValue[] arguments)
+    {
+        var set = AssertWeakSetInstance(thisObj);
+        set.WeakSetAdd(arguments.At(0));
+        return thisObj;
+    }
 
 
-        private JsValue Add(JsValue thisObj, JsValue[] arguments)
-        {
-            var set = AssertWeakSetInstance(thisObj);
-            set.WeakSetAdd(arguments.At(0));
-            return thisObj;
-        }
+    private JsValue Delete(JsValue thisObj, JsValue[] arguments)
+    {
+        var set = AssertWeakSetInstance(thisObj);
+        return set.WeakSetDelete(arguments.At(0)) ? JsBoolean.True : JsBoolean.False;
+    }
 
 
-        private JsValue Delete(JsValue thisObj, JsValue[] arguments)
-        {
-            var set = AssertWeakSetInstance(thisObj);
-            return set.WeakSetDelete(arguments.At(0)) ? JsBoolean.True : JsBoolean.False;
-        }
+    private JsValue Has(JsValue thisObj, JsValue[] arguments)
+    {
+        var set = AssertWeakSetInstance(thisObj);
+        return set.WeakSetHas(arguments.At(0)) ? JsBoolean.True : JsBoolean.False;
+    }
 
 
-        private JsValue Has(JsValue thisObj, JsValue[] arguments)
+    private WeakSetInstance AssertWeakSetInstance(JsValue thisObj)
+    {
+        var set = thisObj as WeakSetInstance;
+        if (set is null)
         {
         {
-            var set = AssertWeakSetInstance(thisObj);
-            return set.WeakSetHas(arguments.At(0)) ? JsBoolean.True : JsBoolean.False;
+            ExceptionHelper.ThrowTypeError(_realm, "object must be a WeakSet");
         }
         }
 
 
-        private WeakSetInstance AssertWeakSetInstance(JsValue thisObj)
-        {
-            var set = thisObj as WeakSetInstance;
-            if (set is null)
-            {
-                ExceptionHelper.ThrowTypeError(_realm, "object must be a WeakSet");
-            }
-
-            return set;
-        }
+        return set;
     }
     }
 }
 }

+ 1 - 0
README.md

@@ -111,6 +111,7 @@ The entire execution engine was rebuild with performance in mind, in many cases
 - ✔ Array find from last
 - ✔ Array find from last
 - ✔ Array.group and Array.groupToMap
 - ✔ Array.group and Array.groupToMap
 - ✔ ShadowRealm
 - ✔ ShadowRealm
+- ✔ Symbols as WeakMap keys
 
 
 #### Other
 #### Other