Browse Source

Implement SharedArrayBuffer (#1708)

Marko Lahma 1 year ago
parent
commit
5ad54b1b92

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

@@ -17,7 +17,6 @@
     "regexp-lookbehind",
     "regexp-lookbehind",
     "regexp-unicode-property-escapes",
     "regexp-unicode-property-escapes",
     "regexp-v-flag",
     "regexp-v-flag",
-    "SharedArrayBuffer",
     "tail-call-optimization",
     "tail-call-optimization",
     "Temporal",
     "Temporal",
     "u180e"
     "u180e"

+ 480 - 462
Jint/JsValueExtensions.cs

@@ -11,621 +11,639 @@ using Jint.Native.Symbol;
 using Jint.Native.TypedArray;
 using Jint.Native.TypedArray;
 using Jint.Runtime;
 using Jint.Runtime;
 
 
-namespace Jint
+namespace Jint;
+
+public static class JsValueExtensions
 {
 {
-    public static class JsValueExtensions
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsPrimitive(this JsValue value)
     {
     {
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsPrimitive(this JsValue value)
-        {
-            return (value._type & (InternalTypes.Primitive | InternalTypes.Undefined | InternalTypes.Null)) != InternalTypes.Empty;
-        }
+        return (value._type & (InternalTypes.Primitive | InternalTypes.Undefined | InternalTypes.Null)) != InternalTypes.Empty;
+    }
 
 
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsUndefined(this JsValue value)
-        {
-            return value._type == InternalTypes.Undefined;
-        }
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsUndefined(this JsValue value)
+    {
+        return value._type == InternalTypes.Undefined;
+    }
 
 
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        internal static bool IsNullOrUndefined(this JsValue value)
-        {
-            return value._type < InternalTypes.Boolean;
-        }
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    internal static bool IsNullOrUndefined(this JsValue value)
+    {
+        return value._type < InternalTypes.Boolean;
+    }
+
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsDate(this JsValue value)
+    {
+        return value is JsDate;
+    }
+
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsPromise(this JsValue value)
+    {
+        return value is JsPromise;
+    }
 
 
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsDate(this JsValue value)
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsPrivateName(this JsValue value) => value._type == InternalTypes.PrivateName;
+
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsRegExp(this JsValue value)
+    {
+        if (value is not ObjectInstance oi)
         {
         {
-            return value is JsDate;
+            return false;
         }
         }
 
 
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsPromise(this JsValue value)
+        var matcher = oi.Get(GlobalSymbolRegistry.Match);
+        if (!matcher.IsUndefined())
         {
         {
-            return value is JsPromise;
+            return TypeConverter.ToBoolean(matcher);
         }
         }
 
 
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsPrivateName(this JsValue value) => value._type == InternalTypes.PrivateName;
+        return value is JsRegExp;
+    }
 
 
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsRegExp(this JsValue value)
-        {
-            if (value is not ObjectInstance oi)
-            {
-                return false;
-            }
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsObject(this JsValue value)
+    {
+        return (value._type & InternalTypes.Object) != InternalTypes.Empty;
+    }
 
 
-            var matcher = oi.Get(GlobalSymbolRegistry.Match);
-            if (!matcher.IsUndefined())
-            {
-                return TypeConverter.ToBoolean(matcher);
-            }
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsString(this JsValue value)
+    {
+        return (value._type & InternalTypes.String) != InternalTypes.Empty;
+    }
 
 
-            return value is JsRegExp;
-        }
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsNumber(this JsValue value)
+    {
+        return (value._type & (InternalTypes.Number | InternalTypes.Integer)) != InternalTypes.Empty;
+    }
 
 
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsObject(this JsValue value)
-        {
-            return (value._type & InternalTypes.Object) != InternalTypes.Empty;
-        }
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsBigInt(this JsValue value)
+    {
+        return (value._type & InternalTypes.BigInt) != InternalTypes.Empty;
+    }
 
 
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsString(this JsValue value)
-        {
-            return (value._type & InternalTypes.String) != InternalTypes.Empty;
-        }
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    internal static bool IsInteger(this JsValue value)
+    {
+        return value._type == InternalTypes.Integer;
+    }
+
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsBoolean(this JsValue value)
+    {
+        return value._type == InternalTypes.Boolean;
+    }
+
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsNull(this JsValue value)
+    {
+        return value._type == InternalTypes.Null;
+    }
+
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsSymbol(this JsValue value)
+    {
+        return value._type == InternalTypes.Symbol;
+    }
 
 
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsNumber(this JsValue value)
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    internal static bool CanBeHeldWeakly(this JsValue value, GlobalSymbolRegistry symbolRegistry)
+    {
+        return value.IsObject() || (value.IsSymbol() && !symbolRegistry.ContainsCustom(value));
+    }
+
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static JsDate AsDate(this JsValue value)
+    {
+        if (!value.IsDate())
         {
         {
-            return (value._type & (InternalTypes.Number | InternalTypes.Integer)) != InternalTypes.Empty;
+            ExceptionHelper.ThrowArgumentException("The value is not a date");
         }
         }
 
 
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsBigInt(this JsValue value)
+        return (JsDate) value;
+    }
+
+    [Pure]
+    public static JsRegExp AsRegExp(this JsValue value)
+    {
+        if (!value.IsRegExp())
         {
         {
-            return (value._type & InternalTypes.BigInt) != InternalTypes.Empty;
+            ExceptionHelper.ThrowArgumentException("The value is not a regex");
         }
         }
 
 
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        internal static bool IsInteger(this JsValue value)
+        return (JsRegExp) value;
+    }
+
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static ObjectInstance AsObject(this JsValue value)
+    {
+        if (!value.IsObject())
         {
         {
-            return value._type == InternalTypes.Integer;
+            ExceptionHelper.ThrowArgumentException("The value is not an object");
         }
         }
 
 
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsBoolean(this JsValue value)
+        return (ObjectInstance) value;
+    }
+
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static TInstance AsInstance<TInstance>(this JsValue value) where TInstance : class
+    {
+        if (!value.IsObject())
         {
         {
-            return value._type == InternalTypes.Boolean;
+            ExceptionHelper.ThrowArgumentException("The value is not an object");
         }
         }
 
 
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsNull(this JsValue value)
+        return (value as TInstance)!;
+    }
+
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static JsArray AsArray(this JsValue value)
+    {
+        if (!value.IsArray())
         {
         {
-            return value._type == InternalTypes.Null;
+            ExceptionHelper.ThrowArgumentException("The value is not an array");
         }
         }
 
 
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsSymbol(this JsValue value)
+        return (JsArray) value;
+    }
+
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool AsBoolean(this JsValue value)
+    {
+        if (value._type != InternalTypes.Boolean)
         {
         {
-            return value._type == InternalTypes.Symbol;
+            ThrowWrongTypeException(value, "boolean");
         }
         }
 
 
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        internal static bool CanBeHeldWeakly(this JsValue value, GlobalSymbolRegistry symbolRegistry)
+        return ((JsBoolean) value)._value;
+    }
+
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static double AsNumber(this JsValue value)
+    {
+        if (!value.IsNumber())
         {
         {
-            return value.IsObject() || (value.IsSymbol() && !symbolRegistry.ContainsCustom(value));
+            ThrowWrongTypeException(value, "number");
         }
         }
 
 
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static JsDate AsDate(this JsValue value)
-        {
-            if (!value.IsDate())
-            {
-                ExceptionHelper.ThrowArgumentException("The value is not a date");
-            }
+        return ((JsNumber) value)._value;
+    }
 
 
-            return (JsDate) value;
-        }
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    internal static int AsInteger(this JsValue value)
+    {
+        return (int) ((JsNumber) value)._value;
+    }
 
 
-        [Pure]
-        public static JsRegExp AsRegExp(this JsValue value)
-        {
-            if (!value.IsRegExp())
-            {
-                ExceptionHelper.ThrowArgumentException("The value is not a regex");
-            }
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    internal static BigInteger AsBigInt(this JsValue value)
+    {
+        return ((JsBigInt) value)._value;
+    }
 
 
-            return (JsRegExp) value;
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static string AsString(this JsValue value)
+    {
+        if (!value.IsString())
+        {
+            ThrowWrongTypeException(value, "string");
         }
         }
 
 
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static ObjectInstance AsObject(this JsValue value)
-        {
-            if (!value.IsObject())
-            {
-                ExceptionHelper.ThrowArgumentException("The value is not an object");
-            }
+        return value.ToString();
+    }
 
 
-            return (ObjectInstance) value;
-        }
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsUint8Array(this JsValue value)
+    {
+        return value is JsTypedArray { _arrayElementType: TypedArrayElementType.Uint8 };
+    }
 
 
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static TInstance AsInstance<TInstance>(this JsValue value) where TInstance : class
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static byte[] AsUint8Array(this JsValue value)
+    {
+        if (!value.IsUint8Array())
         {
         {
-            if (!value.IsObject())
-            {
-                ExceptionHelper.ThrowArgumentException("The value is not an object");
-            }
-
-            return (value as TInstance)!;
+            ThrowWrongTypeException(value, "Uint8Array");
         }
         }
 
 
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static JsArray AsArray(this JsValue value)
-        {
-            if (!value.IsArray())
-            {
-                ExceptionHelper.ThrowArgumentException("The value is not an array");
-            }
+        return ((JsTypedArray) value).ToNativeArray<byte>();
+    }
 
 
-            return (JsArray) value;
-        }
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsUint8ClampedArray(this JsValue value)
+    {
+        return value is JsTypedArray { _arrayElementType: TypedArrayElementType.Uint8C };
+    }
 
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool AsBoolean(this JsValue value)
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static byte[] AsUint8ClampedArray(this JsValue value)
+    {
+        if (!value.IsUint8ClampedArray())
         {
         {
-            if (value._type != InternalTypes.Boolean)
-            {
-                ThrowWrongTypeException(value, "boolean");
-            }
-
-            return ((JsBoolean) value)._value;
+            ThrowWrongTypeException(value, "Uint8ClampedArray");
         }
         }
 
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static double AsNumber(this JsValue value)
-        {
-            if (!value.IsNumber())
-            {
-                ThrowWrongTypeException(value, "number");
-            }
+        return ((JsTypedArray) value).ToNativeArray<byte>();
+    }
 
 
-            return ((JsNumber) value)._value;
-        }
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsInt8Array(this JsValue value)
+    {
+        return value is JsTypedArray { _arrayElementType: TypedArrayElementType.Int8 };
+    }
 
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        internal static int AsInteger(this JsValue value)
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static sbyte[] AsInt8Array(this JsValue value)
+    {
+        if (!value.IsInt8Array())
         {
         {
-            return (int) ((JsNumber) value)._value;
+            ThrowWrongTypeException(value, "Int8Array");
         }
         }
 
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        internal static BigInteger AsBigInt(this JsValue value)
+        return ((JsTypedArray) value).ToNativeArray<sbyte>();
+    }
+
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsInt16Array(this JsValue value)
+    {
+        return value is JsTypedArray { _arrayElementType: TypedArrayElementType.Int16 };
+    }
+
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static short[] AsInt16Array(this JsValue value)
+    {
+        if (!value.IsInt16Array())
         {
         {
-            return ((JsBigInt) value)._value;
+            ThrowWrongTypeException(value, "Int16Array");
         }
         }
 
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static string AsString(this JsValue value)
-        {
-            if (!value.IsString())
-            {
-                ThrowWrongTypeException(value, "string");
-            }
+        return ((JsTypedArray) value).ToNativeArray<short>();
+    }
 
 
-            return value.ToString();
-        }
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsUint16Array(this JsValue value)
+    {
+        return value is JsTypedArray { _arrayElementType: TypedArrayElementType.Uint16 };
+    }
 
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsUint8Array(this JsValue value)
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static ushort[] AsUint16Array(this JsValue value)
+    {
+        if (!value.IsUint16Array())
         {
         {
-            return value is JsTypedArray { _arrayElementType: TypedArrayElementType.Uint8 };
+            ThrowWrongTypeException(value, "Uint16Array");
         }
         }
 
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static byte[] AsUint8Array(this JsValue value)
-        {
-            if (!value.IsUint8Array())
-            {
-                ThrowWrongTypeException(value, "Uint8Array");
-            }
+        return ((JsTypedArray) value).ToNativeArray<ushort>();
+    }
 
 
-            return ((JsTypedArray) value).ToNativeArray<byte>();
-        }
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsInt32Array(this JsValue value)
+    {
+        return value is JsTypedArray { _arrayElementType: TypedArrayElementType.Int32 };
+    }
 
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsUint8ClampedArray(this JsValue value)
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static int[] AsInt32Array(this JsValue value)
+    {
+        if (!value.IsInt32Array())
         {
         {
-            return value is JsTypedArray { _arrayElementType: TypedArrayElementType.Uint8C };
+            ThrowWrongTypeException(value, "Int32Array");
         }
         }
 
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static byte[] AsUint8ClampedArray(this JsValue value)
-        {
-            if (!value.IsUint8ClampedArray())
-            {
-                ThrowWrongTypeException(value, "Uint8ClampedArray");
-            }
+        return ((JsTypedArray) value).ToNativeArray<int>();
+    }
 
 
-            return ((JsTypedArray) value).ToNativeArray<byte>();
-        }
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsUint32Array(this JsValue value)
+    {
+        return value is JsTypedArray { _arrayElementType: TypedArrayElementType.Uint32 };
+    }
 
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsInt8Array(this JsValue value)
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static uint[] AsUint32Array(this JsValue value)
+    {
+        if (!value.IsUint32Array())
         {
         {
-            return value is JsTypedArray { _arrayElementType: TypedArrayElementType.Int8 };
+            ThrowWrongTypeException(value, "Uint32Array");
         }
         }
 
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static sbyte[] AsInt8Array(this JsValue value)
-        {
-            if (!value.IsInt8Array())
-            {
-                ThrowWrongTypeException(value, "Int8Array");
-            }
+        return ((JsTypedArray) value).ToNativeArray<uint>();
+    }
 
 
-            return ((JsTypedArray) value).ToNativeArray<sbyte>();
-        }
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsBigInt64Array(this JsValue value)
+    {
+        return value is JsTypedArray { _arrayElementType: TypedArrayElementType.BigInt64 };
+    }
 
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsInt16Array(this JsValue value)
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static long[] AsBigInt64Array(this JsValue value)
+    {
+        if (!value.IsBigInt64Array())
         {
         {
-            return value is JsTypedArray { _arrayElementType: TypedArrayElementType.Int16 };
+            ThrowWrongTypeException(value, "BigInt64Array");
         }
         }
 
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static short[] AsInt16Array(this JsValue value)
-        {
-            if (!value.IsInt16Array())
-            {
-                ThrowWrongTypeException(value, "Int16Array");
-            }
+        return ((JsTypedArray) value).ToNativeArray<long>();
+    }
 
 
-            return ((JsTypedArray) value).ToNativeArray<short>();
-        }
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsBigUint64Array(this JsValue value)
+    {
+        return value is JsTypedArray { _arrayElementType: TypedArrayElementType.BigUint64 };
+    }
 
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsUint16Array(this JsValue value)
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static ulong[] AsBigUint64Array(this JsValue value)
+    {
+        if (!value.IsBigUint64Array())
         {
         {
-            return value is JsTypedArray { _arrayElementType: TypedArrayElementType.Uint16 };
+            ThrowWrongTypeException(value, "BigUint64Array");
         }
         }
 
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static ushort[] AsUint16Array(this JsValue value)
-        {
-            if (!value.IsUint16Array())
-            {
-                ThrowWrongTypeException(value, "Uint16Array");
-            }
+        return ((JsTypedArray) value).ToNativeArray<ulong>();
+    }
 
 
-            return ((JsTypedArray) value).ToNativeArray<ushort>();
-        }
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsFloat32Array(this JsValue value)
+    {
+        return value is JsTypedArray { _arrayElementType: TypedArrayElementType.Float32 };
+    }
 
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsInt32Array(this JsValue value)
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static float[] AsFloat32Array(this JsValue value)
+    {
+        if (!value.IsFloat32Array())
         {
         {
-            return value is JsTypedArray { _arrayElementType: TypedArrayElementType.Int32 };
+            ThrowWrongTypeException(value, "Float32Array");
         }
         }
 
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static int[] AsInt32Array(this JsValue value)
-        {
-            if (!value.IsInt32Array())
-            {
-                ThrowWrongTypeException(value, "Int32Array");
-            }
+        return ((JsTypedArray) value).ToNativeArray<float>();
+    }
 
 
-            return ((JsTypedArray) value).ToNativeArray<int>();
-        }
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsFloat64Array(this JsValue value)
+    {
+        return value is JsTypedArray { _arrayElementType: TypedArrayElementType.Float64 };
+    }
 
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsUint32Array(this JsValue value)
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static double[] AsFloat64Array(this JsValue value)
+    {
+        if (!value.IsFloat64Array())
         {
         {
-            return value is JsTypedArray { _arrayElementType: TypedArrayElementType.Uint32 };
+            ThrowWrongTypeException(value, "Float64Array");
         }
         }
 
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static uint[] AsUint32Array(this JsValue value)
-        {
-            if (!value.IsUint32Array())
-            {
-                ThrowWrongTypeException(value, "Uint32Array");
-            }
+        return ((JsTypedArray) value).ToNativeArray<double>();
+    }
 
 
-            return ((JsTypedArray) value).ToNativeArray<uint>();
-        }
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static T? TryCast<T>(this JsValue value) where T : class
+    {
+        return value as T;
+    }
 
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsBigInt64Array(this JsValue value)
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static T? TryCast<T>(this JsValue value, Action<JsValue> fail) where T : class
+    {
+        if (value is T o)
         {
         {
-            return value is JsTypedArray { _arrayElementType: TypedArrayElementType.BigInt64 };
+            return o;
         }
         }
 
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static long[] AsBigInt64Array(this JsValue value)
-        {
-            if (!value.IsBigInt64Array())
-            {
-                ThrowWrongTypeException(value, "BigInt64Array");
-            }
+        fail.Invoke(value);
 
 
-            return ((JsTypedArray) value).ToNativeArray<long>();
-        }
+        return null;
+    }
 
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsBigUint64Array(this JsValue value)
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static T? As<T>(this JsValue value) where T : ObjectInstance
+    {
+        if (value.IsObject())
         {
         {
-            return value is JsTypedArray { _arrayElementType: TypedArrayElementType.BigUint64 };
+            return value as T;
         }
         }
 
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static ulong[] AsBigUint64Array(this JsValue value)
-        {
-            if (!value.IsBigUint64Array())
-            {
-                ThrowWrongTypeException(value, "BigUint64Array");
-            }
+        return null;
+    }
 
 
-            return ((JsTypedArray) value).ToNativeArray<ulong>();
-        }
-        
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsFloat32Array(this JsValue value)
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static FunctionInstance AsFunctionInstance(this JsValue value)
+    {
+        if (value is not FunctionInstance instance)
         {
         {
-            return value is JsTypedArray { _arrayElementType: TypedArrayElementType.Float32 };
+            ThrowWrongTypeException(value, "FunctionInstance");
+            return null!;
         }
         }
-        
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static float[] AsFloat32Array(this JsValue value)
-        {
-            if (!value.IsFloat32Array())
-            {
-                ThrowWrongTypeException(value, "Float32Array");
-            }
 
 
-            return ((JsTypedArray) value).ToNativeArray<float>();
-        }
-        
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsFloat64Array(this JsValue value)
+        return instance;
+    }
+
+    [Pure]
+    public static JsValue Call(this JsValue value)
+    {
+        if (value is ObjectInstance objectInstance)
         {
         {
-            return value is JsTypedArray { _arrayElementType: TypedArrayElementType.Float64 };
+            var engine = objectInstance.Engine;
+            return engine.Call(value, Array.Empty<JsValue>());
         }
         }
-        
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static double[] AsFloat64Array(this JsValue value)
-        {
-            if (!value.IsFloat64Array())
-            {
-                ThrowWrongTypeException(value, "Float64Array");
-            }
 
 
-            return ((JsTypedArray) value).ToNativeArray<double>();
-        }
+        return ThrowNotObject(value);
+    }
 
 
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static T? TryCast<T>(this JsValue value) where T : class
+    [Pure]
+    public static JsValue Call(this JsValue value, JsValue arg1)
+    {
+        if (value is ObjectInstance objectInstance)
         {
         {
-            return value as T;
+            var engine = objectInstance.Engine;
+            var arguments = engine._jsValueArrayPool.RentArray(1);
+            arguments[0] = arg1;
+            var result = engine.Call(value, arguments);
+            engine._jsValueArrayPool.ReturnArray(arguments);
+            return result;
         }
         }
 
 
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static T? TryCast<T>(this JsValue value, Action<JsValue> fail) where T : class
-        {
-            if (value is T o)
-            {
-                return o;
-            }
-
-            fail.Invoke(value);
-
-            return null;
-        }
+        return ThrowNotObject(value);
+    }
 
 
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static T? As<T>(this JsValue value) where T : ObjectInstance
+    [Pure]
+    public static JsValue Call(this JsValue value, JsValue arg1, JsValue arg2)
+    {
+        if (value is ObjectInstance objectInstance)
         {
         {
-            if (value.IsObject())
-            {
-                return value as T;
-            }
-
-            return null;
+            var engine = objectInstance.Engine;
+            var arguments = engine._jsValueArrayPool.RentArray(2);
+            arguments[0] = arg1;
+            arguments[1] = arg2;
+            var result = engine.Call(value, arguments);
+            engine._jsValueArrayPool.ReturnArray(arguments);
+            return result;
         }
         }
 
 
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static FunctionInstance AsFunctionInstance(this JsValue value)
-        {
-            if (value is not FunctionInstance instance)
-            {
-                ThrowWrongTypeException(value, "FunctionInstance");
-                return null!;
-            }
-
-            return instance;
-        }
+        return ThrowNotObject(value);
+    }
 
 
-        [Pure]
-        public static JsValue Call(this JsValue value)
+    [Pure]
+    public static JsValue Call(this JsValue value, JsValue arg1, JsValue arg2, JsValue arg3)
+    {
+        if (value is ObjectInstance objectInstance)
         {
         {
-            if (value is ObjectInstance objectInstance)
-            {
-                var engine = objectInstance.Engine;
-                return engine.Call(value, Array.Empty<JsValue>());
-            }
-
-            return ThrowNotObject(value);
+            var engine = objectInstance.Engine;
+            var arguments = engine._jsValueArrayPool.RentArray(3);
+            arguments[0] = arg1;
+            arguments[1] = arg2;
+            arguments[2] = arg3;
+            var result = engine.Call(value, arguments);
+            engine._jsValueArrayPool.ReturnArray(arguments);
+            return result;
         }
         }
 
 
-        [Pure]
-        public static JsValue Call(this JsValue value, JsValue arg1)
-        {
-            if (value is ObjectInstance objectInstance)
-            {
-                var engine = objectInstance.Engine;
-                var arguments = engine._jsValueArrayPool.RentArray(1);
-                arguments[0] = arg1;
-                var result = engine.Call(value, arguments);
-                engine._jsValueArrayPool.ReturnArray(arguments);
-                return result;
-            }
+        return ThrowNotObject(value);
+    }
 
 
-            return ThrowNotObject(value);
+    [Pure]
+    public static JsValue Call(this JsValue value, params JsValue[] arguments)
+    {
+        if (value is ObjectInstance objectInstance)
+        {
+            return objectInstance.Engine.Call(value, arguments);
         }
         }
 
 
-        [Pure]
-        public static JsValue Call(this JsValue value, JsValue arg1, JsValue arg2)
-        {
-            if (value is ObjectInstance objectInstance)
-            {
-                var engine = objectInstance.Engine;
-                var arguments = engine._jsValueArrayPool.RentArray(2);
-                arguments[0] = arg1;
-                arguments[1] = arg2;
-                var result = engine.Call(value, arguments);
-                engine._jsValueArrayPool.ReturnArray(arguments);
-                return result;
-            }
+        return ThrowNotObject(value);
+    }
 
 
-            return ThrowNotObject(value);
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static JsValue Call(this JsValue value, JsValue thisObj, JsValue[] arguments)
+    {
+        if (value is ObjectInstance objectInstance)
+        {
+            return objectInstance.Engine.Call(value, thisObj, arguments);
         }
         }
 
 
-        [Pure]
-        public static JsValue Call(this JsValue value, JsValue arg1, JsValue arg2, JsValue arg3)
-        {
-            if (value is ObjectInstance objectInstance)
-            {
-                var engine = objectInstance.Engine;
-                var arguments = engine._jsValueArrayPool.RentArray(3);
-                arguments[0] = arg1;
-                arguments[1] = arg2;
-                arguments[2] = arg3;
-                var result = engine.Call(value, arguments);
-                engine._jsValueArrayPool.ReturnArray(arguments);
-                return result;
-            }
+        return ThrowNotObject(value);
+    }
 
 
-            return ThrowNotObject(value);
-        }
+    [MethodImpl(MethodImplOptions.NoInlining)]
+    private static JsValue ThrowNotObject(JsValue value)
+    {
+        ExceptionHelper.ThrowArgumentException(value + " is not object");
+        return null;
+    }
 
 
-        [Pure]
-        public static JsValue Call(this JsValue value, params JsValue[] arguments)
+    /// <summary>
+    /// If the value is a Promise
+    ///     1. If "Fulfilled" returns the value it was fulfilled with
+    ///     2. If "Rejected" throws "PromiseRejectedException" with the rejection reason
+    ///     3. If "Pending" throws "InvalidOperationException". Should be called only in "Settled" state
+    /// Else
+    ///     returns the value intact
+    /// </summary>
+    /// <param name="value">value to unwrap</param>
+    /// <returns>inner value if Promise the value itself otherwise</returns>
+    public static JsValue UnwrapIfPromise(this JsValue value)
+    {
+        if (value is JsPromise promise)
         {
         {
-            if (value is ObjectInstance objectInstance)
+            switch (promise.State)
             {
             {
-                return objectInstance.Engine.Call(value, arguments);
+                case PromiseState.Pending:
+                    ExceptionHelper.ThrowInvalidOperationException("'UnwrapIfPromise' called before Promise was settled");
+                    return null;
+                case PromiseState.Fulfilled:
+                    return promise.Value;
+                case PromiseState.Rejected:
+                    ExceptionHelper.ThrowPromiseRejectedException(promise.Value);
+                    return null;
+                default:
+                    ExceptionHelper.ThrowArgumentOutOfRangeException();
+                    return null;
             }
             }
-
-            return ThrowNotObject(value);
         }
         }
 
 
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static JsValue Call(this JsValue value, JsValue thisObj, JsValue[] arguments)
-        {
-            if (value is ObjectInstance objectInstance)
-            {
-                return objectInstance.Engine.Call(value, thisObj, arguments);
-            }
+        return value;
+    }
 
 
-            return ThrowNotObject(value);
-        }
+    [MethodImpl(MethodImplOptions.NoInlining)]
+    private static void ThrowWrongTypeException(JsValue value, string expectedType)
+    {
+        ExceptionHelper.ThrowArgumentException($"Expected {expectedType} but got {value._type}");
+    }
 
 
-        [MethodImpl(MethodImplOptions.NoInlining)]
-        private static JsValue ThrowNotObject(JsValue value)
+    internal static BigInteger ToBigInteger(this JsValue value, Engine engine)
+    {
+        try
         {
         {
-            ExceptionHelper.ThrowArgumentException(value + " is not object");
-            return null;
+            return TypeConverter.ToBigInt(value);
         }
         }
-
-        /// <summary>
-        /// If the value is a Promise
-        ///     1. If "Fulfilled" returns the value it was fulfilled with
-        ///     2. If "Rejected" throws "PromiseRejectedException" with the rejection reason
-        ///     3. If "Pending" throws "InvalidOperationException". Should be called only in "Settled" state
-        /// Else
-        ///     returns the value intact
-        /// </summary>
-        /// <param name="value">value to unwrap</param>
-        /// <returns>inner value if Promise the value itself otherwise</returns>
-        public static JsValue UnwrapIfPromise(this JsValue value)
+        catch (ParserException ex)
         {
         {
-            if (value is JsPromise promise)
-            {
-                switch (promise.State)
-                {
-                    case PromiseState.Pending:
-                        ExceptionHelper.ThrowInvalidOperationException("'UnwrapIfPromise' called before Promise was settled");
-                        return null;
-                    case PromiseState.Fulfilled:
-                        return promise.Value;
-                    case PromiseState.Rejected:
-                        ExceptionHelper.ThrowPromiseRejectedException(promise.Value);
-                        return null;
-                    default:
-                        ExceptionHelper.ThrowArgumentOutOfRangeException();
-                        return null;
-                }
-            }
-
-            return value;
+            ExceptionHelper.ThrowSyntaxError(engine.Realm, ex.Message);
+            return default;
         }
         }
+    }
 
 
-        [MethodImpl(MethodImplOptions.NoInlining)]
-        private static void ThrowWrongTypeException(JsValue value, string expectedType)
+    internal static ICallable GetCallable(this JsValue source, Realm realm)
+    {
+        if (source is ICallable callable)
         {
         {
-            ExceptionHelper.ThrowArgumentException($"Expected {expectedType} but got {value._type}");
+            return callable;
         }
         }
 
 
-        internal static BigInteger ToBigInteger(this JsValue value, Engine engine)
+        ExceptionHelper.ThrowTypeError(realm, "Argument must be callable");
+        return null;
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-getarraybuffermaxbytelengthoption
+    /// </summary>
+    internal static uint? GetArrayBufferMaxByteLengthOption(this JsValue options)
+    {
+        if (options is not JsObject oi)
         {
         {
-            try
-            {
-                return TypeConverter.ToBigInt(value);
-            }
-            catch (ParserException ex)
-            {
-                ExceptionHelper.ThrowSyntaxError(engine.Realm, ex.Message);
-                return default;
-            }
+            return null;
         }
         }
 
 
-        internal static ICallable GetCallable(this JsValue source, Realm realm)
+        var maxByteLength = options.Get("maxByteLength");
+        if (maxByteLength.IsUndefined())
         {
         {
-            if (source is ICallable callable)
-            {
-                return callable;
-            }
-
-            ExceptionHelper.ThrowTypeError(realm, "Argument must be callable");
             return null;
             return null;
         }
         }
+
+        return TypeConverter.ToIndex(oi.Engine.Realm, maxByteLength);
     }
     }
 }
 }

+ 6 - 22
Jint/Native/ArrayBuffer/ArrayBufferConstructor.cs

@@ -76,29 +76,10 @@ internal sealed class ArrayBufferConstructor : Constructor
         var options = arguments.At(1);
         var options = arguments.At(1);
 
 
         var byteLength = TypeConverter.ToIndex(_realm, length);
         var byteLength = TypeConverter.ToIndex(_realm, length);
-        var requestedMaxByteLength = GetArrayBufferMaxByteLengthOption(options);
+        var requestedMaxByteLength = options.GetArrayBufferMaxByteLengthOption();
         return AllocateArrayBuffer(newTarget, byteLength, requestedMaxByteLength);
         return AllocateArrayBuffer(newTarget, byteLength, requestedMaxByteLength);
     }
     }
 
 
-    /// <summary>
-    /// https://tc39.es/ecma262/#sec-getarraybuffermaxbytelengthoption
-    /// </summary>
-    private uint? GetArrayBufferMaxByteLengthOption(JsValue options)
-    {
-        if (options is not ObjectInstance)
-        {
-            return null;
-        }
-
-        var maxByteLength = options.Get("maxByteLength");
-        if (maxByteLength.IsUndefined())
-        {
-            return null;
-        }
-
-        return TypeConverter.ToIndex(_realm, maxByteLength);
-    }
-
     /// <summary>
     /// <summary>
     /// https://tc39.es/ecma262/#sec-allocatearraybuffer
     /// https://tc39.es/ecma262/#sec-allocatearraybuffer
     /// </summary>
     /// </summary>
@@ -114,8 +95,11 @@ internal sealed class ArrayBufferConstructor : Constructor
         var obj = OrdinaryCreateFromConstructor(
         var obj = OrdinaryCreateFromConstructor(
             constructor,
             constructor,
             static intrinsics => intrinsics.ArrayBuffer.PrototypeObject,
             static intrinsics => intrinsics.ArrayBuffer.PrototypeObject,
-            static (engine, _, state) => new JsArrayBuffer(engine, state!.Item1, state.Item2),
-            new Tuple<ulong, uint?>(byteLength, maxByteLength));
+            static (engine, _, state) => new JsArrayBuffer(engine, state!.Item1),
+            new Tuple<uint?>(maxByteLength));
+
+        var block = byteLength > 0 ? JsArrayBuffer.CreateByteDataBlock(_realm, byteLength) : System.Array.Empty<byte>();
+        obj._arrayBufferData = block;
 
 
         return obj;
         return obj;
     }
     }

+ 6 - 36
Jint/Native/ArrayBuffer/ArrayBufferPrototype.cs

@@ -47,16 +47,11 @@ internal sealed class ArrayBufferPrototype : Prototype
     private JsValue Detached(JsValue thisObject, JsValue[] arguments)
     private JsValue Detached(JsValue thisObject, JsValue[] arguments)
     {
     {
         var o = thisObject as JsArrayBuffer;
         var o = thisObject as JsArrayBuffer;
-        if (o is null)
+        if (o is null || o.IsSharedArrayBuffer)
         {
         {
             ExceptionHelper.ThrowTypeError(_realm, "Method ArrayBuffer.prototype.detached called on incompatible receiver " + thisObject);
             ExceptionHelper.ThrowTypeError(_realm, "Method ArrayBuffer.prototype.detached called on incompatible receiver " + thisObject);
         }
         }
 
 
-        if (o.IsSharedArrayBuffer)
-        {
-            ExceptionHelper.ThrowTypeError(_realm);
-        }
-
         return o.IsDetachedBuffer;
         return o.IsDetachedBuffer;
     }
     }
 
 
@@ -66,16 +61,11 @@ internal sealed class ArrayBufferPrototype : Prototype
     private JsValue MaxByteLength(JsValue thisObject, JsValue[] arguments)
     private JsValue MaxByteLength(JsValue thisObject, JsValue[] arguments)
     {
     {
         var o = thisObject as JsArrayBuffer;
         var o = thisObject as JsArrayBuffer;
-        if (o is null)
+        if (o is null || o.IsSharedArrayBuffer)
         {
         {
             ExceptionHelper.ThrowTypeError(_realm, "Method ArrayBuffer.prototype.maxByteLength called on incompatible receiver " + thisObject);
             ExceptionHelper.ThrowTypeError(_realm, "Method ArrayBuffer.prototype.maxByteLength called on incompatible receiver " + thisObject);
         }
         }
 
 
-        if (o.IsSharedArrayBuffer)
-        {
-            ExceptionHelper.ThrowTypeError(_realm);
-        }
-
         if (o.IsDetachedBuffer)
         if (o.IsDetachedBuffer)
         {
         {
             return JsNumber.PositiveZero;
             return JsNumber.PositiveZero;
@@ -94,16 +84,11 @@ internal sealed class ArrayBufferPrototype : Prototype
     private JsValue Resizable(JsValue thisObject, JsValue[] arguments)
     private JsValue Resizable(JsValue thisObject, JsValue[] arguments)
     {
     {
         var o = thisObject as JsArrayBuffer;
         var o = thisObject as JsArrayBuffer;
-        if (o is null)
+        if (o is null || o.IsSharedArrayBuffer)
         {
         {
             ExceptionHelper.ThrowTypeError(_realm, "Method ArrayBuffer.prototype.resizable called on incompatible receiver " + thisObject);
             ExceptionHelper.ThrowTypeError(_realm, "Method ArrayBuffer.prototype.resizable called on incompatible receiver " + thisObject);
         }
         }
 
 
-        if (o.IsSharedArrayBuffer)
-        {
-            ExceptionHelper.ThrowTypeError(_realm);
-        }
-
         return !o.IsFixedLengthArrayBuffer;
         return !o.IsFixedLengthArrayBuffer;
     }
     }
 
 
@@ -113,16 +98,11 @@ internal sealed class ArrayBufferPrototype : Prototype
     private JsValue Resize(JsValue thisObject, JsValue[] arguments)
     private JsValue Resize(JsValue thisObject, JsValue[] arguments)
     {
     {
         var o = thisObject as JsArrayBuffer;
         var o = thisObject as JsArrayBuffer;
-        if (o is null)
+        if (o is null || o.IsSharedArrayBuffer)
         {
         {
             ExceptionHelper.ThrowTypeError(_realm, "Method ArrayBuffer.prototype.resize called on incompatible receiver " + thisObject);
             ExceptionHelper.ThrowTypeError(_realm, "Method ArrayBuffer.prototype.resize called on incompatible receiver " + thisObject);
         }
         }
 
 
-        if (o.IsSharedArrayBuffer)
-        {
-            ExceptionHelper.ThrowTypeError(_realm);
-        }
-
         var newLength = arguments.At(0);
         var newLength = arguments.At(0);
         var newByteLength = TypeConverter.ToIndex(_realm, newLength);
         var newByteLength = TypeConverter.ToIndex(_realm, newLength);
 
 
@@ -139,16 +119,11 @@ internal sealed class ArrayBufferPrototype : Prototype
     private JsValue ByteLength(JsValue thisObject, JsValue[] arguments)
     private JsValue ByteLength(JsValue thisObject, JsValue[] arguments)
     {
     {
         var o = thisObject as JsArrayBuffer;
         var o = thisObject as JsArrayBuffer;
-        if (o is null)
+        if (o is null || o.IsSharedArrayBuffer)
         {
         {
             ExceptionHelper.ThrowTypeError(_realm, "Method ArrayBuffer.prototype.byteLength called on incompatible receiver " + thisObject);
             ExceptionHelper.ThrowTypeError(_realm, "Method ArrayBuffer.prototype.byteLength called on incompatible receiver " + thisObject);
         }
         }
 
 
-        if (o.IsSharedArrayBuffer)
-        {
-            ExceptionHelper.ThrowTypeError(_realm);
-        }
-
         if (o.IsDetachedBuffer)
         if (o.IsDetachedBuffer)
         {
         {
             return JsNumber.PositiveZero;
             return JsNumber.PositiveZero;
@@ -163,16 +138,11 @@ internal sealed class ArrayBufferPrototype : Prototype
     private JsValue Slice(JsValue thisObject, JsValue[] arguments)
     private JsValue Slice(JsValue thisObject, JsValue[] arguments)
     {
     {
         var o = thisObject as JsArrayBuffer;
         var o = thisObject as JsArrayBuffer;
-        if (o is null)
+        if (o is null || o.IsSharedArrayBuffer)
         {
         {
             ExceptionHelper.ThrowTypeError(_realm, "Method ArrayBuffer.prototype.slice called on incompatible receiver " + thisObject);
             ExceptionHelper.ThrowTypeError(_realm, "Method ArrayBuffer.prototype.slice called on incompatible receiver " + thisObject);
         }
         }
 
 
-        if (o.IsSharedArrayBuffer)
-        {
-            ExceptionHelper.ThrowTypeError(_realm);
-        }
-
         o.AssertNotDetached();
         o.AssertNotDetached();
 
 
         var start = arguments.At(0);
         var start = arguments.At(0);

+ 228 - 259
Jint/Native/ArrayBuffer/JsArrayBuffer.cs

@@ -2,345 +2,314 @@ using Jint.Native.Object;
 using Jint.Native.TypedArray;
 using Jint.Native.TypedArray;
 using Jint.Runtime;
 using Jint.Runtime;
 
 
-namespace Jint.Native.ArrayBuffer
+namespace Jint.Native.ArrayBuffer;
+
+/// <summary>
+/// https://tc39.es/ecma262/#sec-arraybuffer-objects
+/// </summary>
+public class JsArrayBuffer : ObjectInstance
 {
 {
-    /// <summary>
-    /// https://tc39.es/ecma262/#sec-arraybuffer-objects
-    /// </summary>
-    public sealed class JsArrayBuffer : ObjectInstance
-    {
-        // so that we don't need to allocate while or reading setting values
-        private readonly byte[] _workBuffer = new byte[8];
+    // so that we don't need to allocate while or reading setting values
+    private readonly byte[] _workBuffer = new byte[8];
 
 
-        private byte[]? _arrayBufferData;
-        internal readonly uint? _arrayBufferMaxByteLength;
+    internal byte[]? _arrayBufferData;
+    internal readonly int? _arrayBufferMaxByteLength;
 
 
-        private readonly JsValue _arrayBufferDetachKey = Undefined;
+    private readonly JsValue _arrayBufferDetachKey = Undefined;
 
 
-        internal JsArrayBuffer(
-            Engine engine,
-            ulong byteLength,
-            uint? arrayBufferMaxByteLength = null) : base(engine)
+    internal JsArrayBuffer(
+        Engine engine,
+        uint? arrayBufferMaxByteLength = null) : base(engine)
+    {
+        if (arrayBufferMaxByteLength is > int.MaxValue)
         {
         {
-            _arrayBufferMaxByteLength = arrayBufferMaxByteLength;
-            var block = byteLength > 0 ? CreateByteDataBlock(byteLength) : System.Array.Empty<byte>();
-            _arrayBufferData = block;
+            ExceptionHelper.ThrowRangeError(engine.Realm, "arrayBufferMaxByteLength cannot be larger than int32.MaxValue");
         }
         }
 
 
-        private byte[] CreateByteDataBlock(ulong byteLength)
-        {
-            if (byteLength > int.MaxValue)
-            {
-                ExceptionHelper.ThrowRangeError(_engine.Realm, "Array buffer allocation failed");
-            }
+        _arrayBufferMaxByteLength = (int?) arrayBufferMaxByteLength;
+    }
 
 
-            return new byte[byteLength];
+    internal static byte[] CreateByteDataBlock(Realm realm, ulong byteLength)
+    {
+        if (byteLength > int.MaxValue)
+        {
+            ExceptionHelper.ThrowRangeError(realm, "Array buffer allocation failed");
         }
         }
 
 
-        internal int ArrayBufferByteLength => _arrayBufferData?.Length ?? 0;
-        internal byte[]? ArrayBufferData => _arrayBufferData;
+        return new byte[byteLength];
+    }
 
 
-        internal bool IsDetachedBuffer => _arrayBufferData is null;
+    internal virtual int ArrayBufferByteLength => _arrayBufferData?.Length ?? 0;
+    internal byte[]? ArrayBufferData => _arrayBufferData;
 
 
-        internal bool IsFixedLengthArrayBuffer => _arrayBufferMaxByteLength is null;
+    internal bool IsDetachedBuffer => _arrayBufferData is null;
 
 
-#pragma warning disable CA1822
-        internal bool IsSharedArrayBuffer => false; // TODO SharedArrayBuffer
-#pragma warning restore CA1822
+    internal bool IsFixedLengthArrayBuffer => _arrayBufferMaxByteLength is null;
 
 
-        /// <summary>
-        /// https://tc39.es/ecma262/#sec-detacharraybuffer
-        /// </summary>
-        internal void DetachArrayBuffer(JsValue? key = null)
-        {
-            key ??= Undefined;
+    internal virtual bool IsSharedArrayBuffer => false;
 
 
-            if (!SameValue(_arrayBufferDetachKey, key))
-            {
-                ExceptionHelper.ThrowTypeError(_engine.Realm);
-            }
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-detacharraybuffer
+    /// </summary>
+    internal void DetachArrayBuffer(JsValue? key = null)
+    {
+        key ??= Undefined;
 
 
-            _arrayBufferData = null;
+        if (!SameValue(_arrayBufferDetachKey, key))
+        {
+            ExceptionHelper.ThrowTypeError(_engine.Realm);
         }
         }
 
 
-        /// <summary>
-        /// https://tc39.es/ecma262/#sec-clonearraybuffer
-        /// </summary>
-        internal JsArrayBuffer CloneArrayBuffer(
-            ArrayBufferConstructor constructor,
-            int srcByteOffset,
-            uint srcLength)
-        {
-            var targetBuffer = constructor.AllocateArrayBuffer(_engine.Realm.Intrinsics.ArrayBuffer, srcLength);
-            AssertNotDetached();
+        _arrayBufferData = null;
+    }
 
 
-            var srcBlock = _arrayBufferData!;
-            var targetBlock = targetBuffer.ArrayBufferData!;
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-clonearraybuffer
+    /// </summary>
+    internal JsArrayBuffer CloneArrayBuffer(
+        ArrayBufferConstructor constructor,
+        int srcByteOffset,
+        uint srcLength)
+    {
+        var targetBuffer = constructor.AllocateArrayBuffer(_engine.Realm.Intrinsics.ArrayBuffer, srcLength);
+        AssertNotDetached();
 
 
-            // TODO SharedArrayBuffer would use this
-            //CopyDataBlockBytes(targetBlock, 0, srcBlock, srcByteOffset, srcLength).
+        var srcBlock = _arrayBufferData!;
+        var targetBlock = targetBuffer.ArrayBufferData!;
 
 
-            System.Array.Copy(srcBlock, srcByteOffset, targetBlock, 0, srcLength);
+        // TODO SharedArrayBuffer would use this
+        //CopyDataBlockBytes(targetBlock, 0, srcBlock, srcByteOffset, srcLength).
 
 
-            return targetBuffer;
-        }
+        System.Array.Copy(srcBlock, srcByteOffset, targetBlock, 0, srcLength);
 
 
-        /// <summary>
-        /// https://tc39.es/ecma262/#sec-getvaluefrombuffer
-        /// </summary>
-        internal TypedArrayValue GetValueFromBuffer(
-            int byteIndex,
-            TypedArrayElementType type,
-            bool isTypedArray,
-            ArrayBufferOrder order,
-            bool? isLittleEndian = null)
-        {
-            if (!IsSharedArrayBuffer)
-            {
-                // If isLittleEndian is not present, set isLittleEndian to the value of the [[LittleEndian]] field of the surrounding agent's Agent Record.
-                return RawBytesToNumeric(type, byteIndex, isLittleEndian ?? BitConverter.IsLittleEndian);
-            }
+        return targetBuffer;
+    }
 
 
-            /*
-                Let execution be the [[CandidateExecution]] field of the surrounding agent's Agent EsprimaExtensions.Record.
-                b. Let eventList be the [[EventList]] field of the element in execution.[[EventsRecords]] whose [[AgentSignifier]] is AgentSignifier().
-                c. If isTypedArray is true and IsNoTearConfiguration(type, order) is true, let noTear be true; otherwise let noTear be false.
-                d. Let rawValue be a List of length elementSize whose elements are nondeterministically chosen byte values.
-                e. NOTE: In implementations, rawValue is the result of a non-atomic or atomic read instruction on the underlying hardware. The nondeterminism is a semantic prescription of the memory model to describe observable behaviour of hardware with weak consistency.
-                f. Let readEvent be ReadSharedMemory { [[Order]]: order, [[NoTear]]: noTear, [[Block]]: block, [[ByteIndex]]: byteIndex, [[ElementSize]]: elementSize }.
-                g. Append readEvent to eventList.
-                h. Append Chosen Value EsprimaExtensions.Record { [[Event]]: readEvent, [[ChosenValue]]: rawValue } to execution.[[ChosenValues]].
-            */
-            ExceptionHelper.ThrowNotImplementedException("SharedArrayBuffer not implemented");
-            return default;
-        }
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-getvaluefrombuffer
+    /// </summary>
+    internal TypedArrayValue GetValueFromBuffer(
+        int byteIndex,
+        TypedArrayElementType type,
+        bool isTypedArray,
+        ArrayBufferOrder order,
+        bool? isLittleEndian = null)
+    {
+        return RawBytesToNumeric(type, byteIndex, isLittleEndian ?? BitConverter.IsLittleEndian);
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-rawbytestonumeric
+    /// </summary>
+    internal TypedArrayValue RawBytesToNumeric(TypedArrayElementType type, int byteIndex, bool isLittleEndian)
+    {
+        var elementSize = type.GetElementSize();
+        var rawBytes = _arrayBufferData!;
+
+        // 8 byte values require a little more at the moment
+        var needsReverse = !isLittleEndian
+                           && elementSize > 1
+                           && type is TypedArrayElementType.Float32 or TypedArrayElementType.Float64 or TypedArrayElementType.BigInt64 or TypedArrayElementType.BigUint64;
 
 
-        /// <summary>
-        /// https://tc39.es/ecma262/#sec-rawbytestonumeric
-        /// </summary>
-        internal TypedArrayValue RawBytesToNumeric(TypedArrayElementType type, int byteIndex, bool isLittleEndian)
+        if (needsReverse)
         {
         {
-            var elementSize = type.GetElementSize();
-            var rawBytes = _arrayBufferData!;
+            System.Array.Copy(rawBytes, byteIndex, _workBuffer, 0, elementSize);
+            byteIndex = 0;
+            System.Array.Reverse(_workBuffer, 0, elementSize);
+            rawBytes = _workBuffer;
+        }
 
 
-            // 8 byte values require a little more at the moment
-            var needsReverse = !isLittleEndian
-                               && elementSize > 1
-                               && type is TypedArrayElementType.Float32 or TypedArrayElementType.Float64 or TypedArrayElementType.BigInt64 or TypedArrayElementType.BigUint64;
+        if (type == TypedArrayElementType.Float32)
+        {
+            // rawBytes concatenated and interpreted as a little-endian bit string encoding of an IEEE 754-2019 binary32 value.
+            var value = BitConverter.ToSingle(rawBytes, byteIndex);
 
 
-            if (needsReverse)
+            // If value is an IEEE 754-2019 binary32 NaN value, return the NaN Number value.
+            if (float.IsNaN(value))
             {
             {
-                System.Array.Copy(rawBytes, byteIndex, _workBuffer, 0, elementSize);
-                byteIndex = 0;
-                System.Array.Reverse(_workBuffer, 0, elementSize);
-                rawBytes = _workBuffer;
+                return double.NaN;
             }
             }
 
 
-            if (type == TypedArrayElementType.Float32)
-            {
-                // rawBytes concatenated and interpreted as a little-endian bit string encoding of an IEEE 754-2019 binary32 value.
-                var value = BitConverter.ToSingle(rawBytes, byteIndex);
-
-                // If value is an IEEE 754-2019 binary32 NaN value, return the NaN Number value.
-                if (float.IsNaN(value))
-                {
-                    return double.NaN;
-                }
-
-                return value;
-            }
+            return value;
+        }
 
 
-            if (type == TypedArrayElementType.Float64)
-            {
-                // rawBytes concatenated and interpreted as a little-endian bit string encoding of an IEEE 754-2019 binary64 value.
-                var value = BitConverter.ToDouble(rawBytes, byteIndex);
-                return value;
-            }
+        if (type == TypedArrayElementType.Float64)
+        {
+            // rawBytes concatenated and interpreted as a little-endian bit string encoding of an IEEE 754-2019 binary64 value.
+            var value = BitConverter.ToDouble(rawBytes, byteIndex);
+            return value;
+        }
 
 
-            if (type == TypedArrayElementType.BigUint64)
-            {
-                var value = BitConverter.ToUInt64(rawBytes, byteIndex);
-                return value;
-            }
+        if (type == TypedArrayElementType.BigUint64)
+        {
+            var value = BitConverter.ToUInt64(rawBytes, byteIndex);
+            return value;
+        }
 
 
-            if (type == TypedArrayElementType.BigInt64)
-            {
-                var value = BitConverter.ToInt64(rawBytes, byteIndex);
-                return value;
-            }
+        if (type == TypedArrayElementType.BigInt64)
+        {
+            var value = BitConverter.ToInt64(rawBytes, byteIndex);
+            return value;
+        }
 
 
-            TypedArrayValue? arrayValue = type switch
-            {
-                TypedArrayElementType.Int8 => ((sbyte) rawBytes[byteIndex]),
-                TypedArrayElementType.Uint8 => (rawBytes[byteIndex]),
-                TypedArrayElementType.Uint8C =>(rawBytes[byteIndex]),
-                TypedArrayElementType.Int16 => (isLittleEndian
+        TypedArrayValue? arrayValue = type switch
+        {
+            TypedArrayElementType.Int8 => ((sbyte) rawBytes[byteIndex]),
+            TypedArrayElementType.Uint8 => (rawBytes[byteIndex]),
+            TypedArrayElementType.Uint8C =>(rawBytes[byteIndex]),
+            TypedArrayElementType.Int16 => (isLittleEndian
                     ? (short) (rawBytes[byteIndex] | (rawBytes[byteIndex + 1] << 8))
                     ? (short) (rawBytes[byteIndex] | (rawBytes[byteIndex + 1] << 8))
                     : (short) (rawBytes[byteIndex + 1] | (rawBytes[byteIndex] << 8))
                     : (short) (rawBytes[byteIndex + 1] | (rawBytes[byteIndex] << 8))
                 ),
                 ),
-                TypedArrayElementType.Uint16 => (isLittleEndian
+            TypedArrayElementType.Uint16 => (isLittleEndian
                     ? (ushort) (rawBytes[byteIndex] | (rawBytes[byteIndex + 1] << 8))
                     ? (ushort) (rawBytes[byteIndex] | (rawBytes[byteIndex + 1] << 8))
                     : (ushort) (rawBytes[byteIndex + 1] | (rawBytes[byteIndex] << 8))
                     : (ushort) (rawBytes[byteIndex + 1] | (rawBytes[byteIndex] << 8))
                 ),
                 ),
-                TypedArrayElementType.Int32 => (isLittleEndian
+            TypedArrayElementType.Int32 => (isLittleEndian
                     ? rawBytes[byteIndex] | (rawBytes[byteIndex + 1] << 8) | (rawBytes[byteIndex + 2] << 16) | (rawBytes[byteIndex + 3] << 24)
                     ? rawBytes[byteIndex] | (rawBytes[byteIndex + 1] << 8) | (rawBytes[byteIndex + 2] << 16) | (rawBytes[byteIndex + 3] << 24)
                     : rawBytes[byteIndex + 3] | (rawBytes[byteIndex + 2] << 8) | (rawBytes[byteIndex + 1] << 16) | (rawBytes[byteIndex + 0] << 24)
                     : rawBytes[byteIndex + 3] | (rawBytes[byteIndex + 2] << 8) | (rawBytes[byteIndex + 1] << 16) | (rawBytes[byteIndex + 0] << 24)
                 ),
                 ),
-                TypedArrayElementType.Uint32 => (isLittleEndian
+            TypedArrayElementType.Uint32 => (isLittleEndian
                     ? (uint) (rawBytes[byteIndex] | (rawBytes[byteIndex + 1] << 8) | (rawBytes[byteIndex + 2] << 16) | (rawBytes[byteIndex + 3] << 24))
                     ? (uint) (rawBytes[byteIndex] | (rawBytes[byteIndex + 1] << 8) | (rawBytes[byteIndex + 2] << 16) | (rawBytes[byteIndex + 3] << 24))
                     : (uint) (rawBytes[byteIndex + 3] | (rawBytes[byteIndex + 2] << 8) | (rawBytes[byteIndex + 1] << 16) | (rawBytes[byteIndex] << 24))
                     : (uint) (rawBytes[byteIndex + 3] | (rawBytes[byteIndex + 2] << 8) | (rawBytes[byteIndex + 1] << 16) | (rawBytes[byteIndex] << 24))
                 ),
                 ),
-                _ => null
-            };
-
-            if (arrayValue is null)
-            {
-                ExceptionHelper.ThrowArgumentOutOfRangeException(nameof(type), type.ToString());
-            }
+            _ => null
+        };
 
 
-            return arrayValue.Value;
+        if (arrayValue is null)
+        {
+            ExceptionHelper.ThrowArgumentOutOfRangeException(nameof(type), type.ToString());
         }
         }
 
 
-        /// <summary>
-        /// https://tc39.es/ecma262/#sec-setvalueinbuffer
-        /// </summary>
-        internal void SetValueInBuffer(
-            int byteIndex,
-            TypedArrayElementType type,
-            TypedArrayValue value,
-            bool isTypedArray,
-            ArrayBufferOrder order,
-            bool? isLittleEndian = null)
+        return arrayValue.Value;
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-setvalueinbuffer
+    /// </summary>
+    internal void SetValueInBuffer(
+        int byteIndex,
+        TypedArrayElementType type,
+        TypedArrayValue value,
+        bool isTypedArray,
+        ArrayBufferOrder order,
+        bool? isLittleEndian = null)
+    {
+        var block = _arrayBufferData!;
+        // If isLittleEndian is not present, set isLittleEndian to the value of the [[LittleEndian]] field of the surrounding agent's Agent Record.
+        var rawBytes = NumericToRawBytes(type, value, isLittleEndian ?? BitConverter.IsLittleEndian);
+        System.Array.Copy(rawBytes, 0, block,  byteIndex, type.GetElementSize());
+    }
+
+    private byte[] NumericToRawBytes(TypedArrayElementType type, TypedArrayValue value, bool isLittleEndian)
+    {
+        byte[] rawBytes;
+        if (type == TypedArrayElementType.Float32)
         {
         {
-            var block = _arrayBufferData!;
-            if (!IsSharedArrayBuffer)
-            {
-                // If isLittleEndian is not present, set isLittleEndian to the value of the [[LittleEndian]] field of the surrounding agent's Agent Record.
-                var rawBytes = NumericToRawBytes(type, value, isLittleEndian ?? BitConverter.IsLittleEndian);
-                System.Array.Copy(rawBytes, 0, block,  byteIndex, type.GetElementSize());
-            }
-            else
-            {
-                /*
-                    a. Let execution be the [[CandidateExecution]] field of the surrounding agent's Agent Record.
-                    b. Let eventList be the [[EventList]] field of the element in execution.[[EventsRecords]] whose [[AgentSignifier]] is AgentSignifier().
-                    c. If isTypedArray is true and IsNoTearConfiguration(type, order) is true, let noTear be true; otherwise let noTear be false.
-                    d. Append WriteSharedMemory { [[Order]]: order, [[NoTear]]: noTear, [[Block]]: block, [[ByteIndex]]: byteIndex, [[ElementSize]]: elementSize, [[Payload]]: rawBytes } to eventList.
-                */
-                ExceptionHelper.ThrowNotImplementedException("SharedArrayBuffer not implemented");
-            }
+            // Let rawBytes be a List whose elements are the 4 bytes that are the result of converting value to IEEE 754-2019 binary32 format using roundTiesToEven mode. If isLittleEndian is false, the bytes are arranged in big endian order. Otherwise, the bytes are arranged in little endian order. If value is NaN, rawBytes may be set to any implementation chosen IEEE 754-2019 binary32 format Not-a-Number encoding. An implementation must always choose the same encoding for each implementation distinguishable NaN value.
+            rawBytes = BitConverter.GetBytes((float) value.DoubleValue);
         }
         }
-
-        private byte[] NumericToRawBytes(TypedArrayElementType type, TypedArrayValue value, bool isLittleEndian)
+        else if (type == TypedArrayElementType.Float64)
         {
         {
-            byte[] rawBytes;
-            if (type == TypedArrayElementType.Float32)
-            {
-                // Let rawBytes be a List whose elements are the 4 bytes that are the result of converting value to IEEE 754-2019 binary32 format using roundTiesToEven mode. If isLittleEndian is false, the bytes are arranged in big endian order. Otherwise, the bytes are arranged in little endian order. If value is NaN, rawBytes may be set to any implementation chosen IEEE 754-2019 binary32 format Not-a-Number encoding. An implementation must always choose the same encoding for each implementation distinguishable NaN value.
-                rawBytes = BitConverter.GetBytes((float) value.DoubleValue);
-            }
-            else if (type == TypedArrayElementType.Float64)
-            {
-                // Let rawBytes be a List whose elements are the 8 bytes that are the IEEE 754-2019 binary64 format encoding of value. If isLittleEndian is false, the bytes are arranged in big endian order. Otherwise, the bytes are arranged in little endian order. If value is NaN, rawBytes may be set to any implementation chosen IEEE 754-2019 binary64 format Not-a-Number encoding. An implementation must always choose the same encoding for each implementation distinguishable NaN value.
-                rawBytes = BitConverter.GetBytes(value.DoubleValue);
-            }
-            else if (type == TypedArrayElementType.BigInt64)
-            {
-                rawBytes = BitConverter.GetBytes(TypeConverter.ToBigInt64(value.BigInteger));
-            }
-            else if (type == TypedArrayElementType.BigUint64)
-            {
-                rawBytes = BitConverter.GetBytes(TypeConverter.ToBigUint64(value.BigInteger));
-            }
-            else
+            // Let rawBytes be a List whose elements are the 8 bytes that are the IEEE 754-2019 binary64 format encoding of value. If isLittleEndian is false, the bytes are arranged in big endian order. Otherwise, the bytes are arranged in little endian order. If value is NaN, rawBytes may be set to any implementation chosen IEEE 754-2019 binary64 format Not-a-Number encoding. An implementation must always choose the same encoding for each implementation distinguishable NaN value.
+            rawBytes = BitConverter.GetBytes(value.DoubleValue);
+        }
+        else if (type == TypedArrayElementType.BigInt64)
+        {
+            rawBytes = BitConverter.GetBytes(TypeConverter.ToBigInt64(value.BigInteger));
+        }
+        else if (type == TypedArrayElementType.BigUint64)
+        {
+            rawBytes = BitConverter.GetBytes(TypeConverter.ToBigUint64(value.BigInteger));
+        }
+        else
+        {
+            // inlined conversion for faster speed instead of getting the method in spec
+            var doubleValue  = value.DoubleValue;
+            var intValue = double.IsNaN(doubleValue) || doubleValue == 0 || double.IsInfinity(doubleValue)
+                ? 0
+                : (long) doubleValue;
+
+            rawBytes = _workBuffer;
+            switch (type)
             {
             {
-                // inlined conversion for faster speed instead of getting the method in spec
-                var doubleValue  = value.DoubleValue;
-                var intValue = double.IsNaN(doubleValue) || doubleValue == 0 || double.IsInfinity(doubleValue)
-                    ? 0
-                    : (long) doubleValue;
-
-                rawBytes = _workBuffer;
-                switch (type)
-                {
-                    case TypedArrayElementType.Int8:
-                        rawBytes[0] = (byte) (sbyte) intValue;
-                        break;
-                    case TypedArrayElementType.Uint8:
-                        rawBytes[0] = (byte) intValue;
-                        break;
-                    case TypedArrayElementType.Uint8C:
-                        rawBytes[0] = (byte) TypeConverter.ToUint8Clamp(value.DoubleValue);
-                        break;
-                    case TypedArrayElementType.Int16:
+                case TypedArrayElementType.Int8:
+                    rawBytes[0] = (byte) (sbyte) intValue;
+                    break;
+                case TypedArrayElementType.Uint8:
+                    rawBytes[0] = (byte) intValue;
+                    break;
+                case TypedArrayElementType.Uint8C:
+                    rawBytes[0] = (byte) TypeConverter.ToUint8Clamp(value.DoubleValue);
+                    break;
+                case TypedArrayElementType.Int16:
 #if !NETSTANDARD2_1
 #if !NETSTANDARD2_1
-                        rawBytes = BitConverter.GetBytes((short) intValue);
+                    rawBytes = BitConverter.GetBytes((short) intValue);
 #else
 #else
                         BitConverter.TryWriteBytes(rawBytes, (short) intValue);
                         BitConverter.TryWriteBytes(rawBytes, (short) intValue);
 #endif
 #endif
-                        break;
-                    case TypedArrayElementType.Uint16:
+                    break;
+                case TypedArrayElementType.Uint16:
 #if !NETSTANDARD2_1
 #if !NETSTANDARD2_1
-                        rawBytes = BitConverter.GetBytes((ushort) intValue);
+                    rawBytes = BitConverter.GetBytes((ushort) intValue);
 #else
 #else
                         BitConverter.TryWriteBytes(rawBytes, (ushort) intValue);
                         BitConverter.TryWriteBytes(rawBytes, (ushort) intValue);
 #endif
 #endif
-                        break;
-                    case TypedArrayElementType.Int32:
+                    break;
+                case TypedArrayElementType.Int32:
 #if !NETSTANDARD2_1
 #if !NETSTANDARD2_1
-                        rawBytes = BitConverter.GetBytes((uint) intValue);
+                    rawBytes = BitConverter.GetBytes((uint) intValue);
 #else
 #else
                         BitConverter.TryWriteBytes(rawBytes, (uint) intValue);
                         BitConverter.TryWriteBytes(rawBytes, (uint) intValue);
 #endif
 #endif
-                        break;
-                    case TypedArrayElementType.Uint32:
+                    break;
+                case TypedArrayElementType.Uint32:
 #if !NETSTANDARD2_1
 #if !NETSTANDARD2_1
-                        rawBytes = BitConverter.GetBytes((uint) intValue);
+                    rawBytes = BitConverter.GetBytes((uint) intValue);
 #else
 #else
                         BitConverter.TryWriteBytes(rawBytes, (uint) intValue);
                         BitConverter.TryWriteBytes(rawBytes, (uint) intValue);
 #endif
 #endif
-                        break;
-                    default:
-                        ExceptionHelper.ThrowArgumentOutOfRangeException();
-                        return null;
-                }
+                    break;
+                default:
+                    ExceptionHelper.ThrowArgumentOutOfRangeException();
+                    return null;
             }
             }
-
-            var elementSize = type.GetElementSize();
-            if (!isLittleEndian && elementSize > 1)
-            {
-                System.Array.Reverse(rawBytes, 0, elementSize);
-            }
-
-            return rawBytes;
         }
         }
 
 
-        internal void Resize(uint newByteLength)
+        var elementSize = type.GetElementSize();
+        if (!isLittleEndian && elementSize > 1)
         {
         {
-            if (_arrayBufferMaxByteLength is null)
-            {
-                ExceptionHelper.ThrowTypeError(_engine.Realm);
-            }
+            System.Array.Reverse(rawBytes, 0, elementSize);
+        }
 
 
-            if (newByteLength > _arrayBufferMaxByteLength)
-            {
-                ExceptionHelper.ThrowRangeError(_engine.Realm);
-            }
+        return rawBytes;
+    }
 
 
-            var oldBlock = _arrayBufferData ?? System.Array.Empty<byte>();
-            var newBlock = CreateByteDataBlock(newByteLength);
-            var copyLength = System.Math.Min(newByteLength, ArrayBufferByteLength);
+    internal void Resize(uint newByteLength)
+    {
+        if (_arrayBufferMaxByteLength is null)
+        {
+            ExceptionHelper.ThrowTypeError(_engine.Realm);
+        }
 
 
-            System.Array.Copy(oldBlock, newBlock, copyLength);
-            _arrayBufferData = newBlock;
+        if (newByteLength > _arrayBufferMaxByteLength)
+        {
+            ExceptionHelper.ThrowRangeError(_engine.Realm);
         }
         }
 
 
-        internal void AssertNotDetached()
+        var oldBlock = _arrayBufferData ?? System.Array.Empty<byte>();
+        var newBlock = CreateByteDataBlock(_engine.Realm, newByteLength);
+        var copyLength = System.Math.Min(newByteLength, ArrayBufferByteLength);
+
+        System.Array.Copy(oldBlock, newBlock, copyLength);
+        _arrayBufferData = newBlock;
+    }
+
+    internal void AssertNotDetached()
+    {
+        if (IsDetachedBuffer)
         {
         {
-            if (IsDetachedBuffer)
-            {
-                ExceptionHelper.ThrowTypeError(_engine.Realm, "ArrayBuffer has been detached");
-            }
+            ExceptionHelper.ThrowTypeError(_engine.Realm, "ArrayBuffer has been detached");
         }
         }
     }
     }
 }
 }

+ 1 - 1
Jint/Native/Global/GlobalObject.Properties.cs

@@ -114,7 +114,7 @@ public partial class GlobalObject
         properties.AddDangerous(propertyRegExp, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.RegExp, PropertyFlags));
         properties.AddDangerous(propertyRegExp, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.RegExp, PropertyFlags));
         properties.AddDangerous(propertySet, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Set, PropertyFlags));
         properties.AddDangerous(propertySet, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Set, PropertyFlags));
         properties.AddDangerous(propertyShadowRealm, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.ShadowRealm, PropertyFlags));
         properties.AddDangerous(propertyShadowRealm, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.ShadowRealm, PropertyFlags));
-        properties.AddDangerous(propertySharedArrayBuffer, new LazyPropertyDescriptor(this, static state => Undefined, PropertyFlags));
+        properties.AddDangerous(propertySharedArrayBuffer, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.SharedArrayBuffer, PropertyFlags));
         properties.AddDangerous(propertyString, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.String, PropertyFlags));
         properties.AddDangerous(propertyString, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.String, PropertyFlags));
         properties.AddDangerous(propertySymbol, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Symbol, PropertyFlags));
         properties.AddDangerous(propertySymbol, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Symbol, PropertyFlags));
         properties.AddDangerous(propertySyntaxError, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.SyntaxError, PropertyFlags));
         properties.AddDangerous(propertySyntaxError, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.SyntaxError, PropertyFlags));

+ 41 - 0
Jint/Native/SharedArrayBuffer/JsSharedArrayBuffer.cs

@@ -0,0 +1,41 @@
+using Jint.Native.ArrayBuffer;
+using Jint.Runtime;
+
+namespace Jint.Native.SharedArrayBuffer;
+
+/// <summary>
+/// https://tc39.es/ecma262/#sec-sharedarraybuffer-objects
+/// </summary>
+internal sealed class JsSharedArrayBuffer : JsArrayBuffer
+{
+    private readonly int _arrayBufferByteLengthData;
+
+    internal JsSharedArrayBuffer(
+        Engine engine,
+        uint? arrayBufferMaxByteLength,
+        uint arrayBufferByteLengthData) : base(engine, arrayBufferMaxByteLength)
+    {
+        if (arrayBufferByteLengthData > int.MaxValue)
+        {
+            ExceptionHelper.ThrowRangeError(engine.Realm, "arrayBufferByteLengthData cannot be larger than int32.MaxValue");
+        }
+        this._arrayBufferByteLengthData = (int) arrayBufferByteLengthData;
+    }
+
+    internal override int ArrayBufferByteLength => _arrayBufferByteLengthData;
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-createsharedbytedatablock
+    /// </summary>
+    internal static byte[] CreateSharedByteDataBlock(Realm realm, ulong byteLength)
+    {
+        if (byteLength > int.MaxValue)
+        {
+            ExceptionHelper.ThrowRangeError(realm, "Array buffer allocation failed");
+        }
+
+        return new byte[byteLength];
+    }
+
+    internal override bool IsSharedArrayBuffer => true;
+}

+ 111 - 0
Jint/Native/SharedArrayBuffer/SharedArrayBufferConstructor.cs

@@ -0,0 +1,111 @@
+using Jint.Collections;
+using Jint.Native.DataView;
+using Jint.Native.Function;
+using Jint.Native.Object;
+using Jint.Native.Symbol;
+using Jint.Native.TypedArray;
+using Jint.Runtime;
+using Jint.Runtime.Descriptors;
+using Jint.Runtime.Interop;
+
+namespace Jint.Native.SharedArrayBuffer;
+
+/// <summary>
+/// https://tc39.es/ecma262/#sec-sharedarraybuffer-constructor
+/// </summary>
+internal sealed class SharedArrayBufferConstructor : Constructor
+{
+    private static readonly JsString _functionName = new("SharedArrayBuffer");
+
+    internal SharedArrayBufferConstructor(
+        Engine engine,
+        Realm realm,
+        FunctionPrototype functionPrototype,
+        ObjectPrototype objectPrototype)
+        : base(engine, realm, _functionName)
+    {
+        _prototype = functionPrototype;
+        PrototypeObject = new SharedArrayBufferPrototype(engine, this, objectPrototype);
+        _length = new PropertyDescriptor(1, PropertyFlag.Configurable);
+        _prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
+    }
+
+    private SharedArrayBufferPrototype PrototypeObject { get; }
+
+    protected override void Initialize()
+    {
+        const PropertyFlag lengthFlags = PropertyFlag.Configurable;
+        var properties = new PropertyDictionary(1, checkExistingKeys: false)
+        {
+            ["isView"] = new PropertyDescriptor(new PropertyDescriptor(new ClrFunctionInstance(Engine, "isView", IsView, 1, lengthFlags), PropertyFlag.Configurable | PropertyFlag.Writable)),
+        };
+        SetProperties(properties);
+
+        var symbols = new SymbolDictionary(1)
+        {
+            [GlobalSymbolRegistry.Species] = new GetSetPropertyDescriptor(get: new ClrFunctionInstance(Engine, "get [Symbol.species]", Species, 0, lengthFlags), set: Undefined,PropertyFlag.Configurable),
+        };
+        SetSymbols(symbols);
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-arraybuffer.isview
+    /// </summary>
+    private static JsValue IsView(JsValue thisObject, JsValue[] arguments)
+    {
+        var arg = arguments.At(0);
+        return arg is JsDataView or JsTypedArray;
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-get-arraybuffer-@@species
+    /// </summary>
+    private static JsValue Species(JsValue thisObject, JsValue[] arguments)
+    {
+        return thisObject;
+    }
+
+    protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
+    {
+        ExceptionHelper.ThrowTypeError(_realm, "Constructor SharedArrayBuffer requires 'new'");
+        return Undefined;
+    }
+
+    public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
+    {
+        if (newTarget.IsUndefined())
+        {
+            ExceptionHelper.ThrowTypeError(_realm);
+        }
+
+        var length = arguments.At(0);
+        var options = arguments.At(1);
+
+        var byteLength = TypeConverter.ToIndex(_realm, length);
+        var requestedMaxByteLength = options.GetArrayBufferMaxByteLengthOption();
+
+        return AllocateSharedArrayBuffer(newTarget, byteLength, requestedMaxByteLength);
+    }
+
+    private JsSharedArrayBuffer AllocateSharedArrayBuffer(JsValue constructor, uint byteLength, uint? maxByteLength  = null)
+    {
+        var allocatingGrowableBuffer = maxByteLength != null;
+
+        if (allocatingGrowableBuffer && byteLength > maxByteLength)
+        {
+            ExceptionHelper.ThrowRangeError(_realm);
+        }
+
+        var obj = OrdinaryCreateFromConstructor(
+            constructor,
+            static intrinsics => intrinsics.SharedArrayBuffer.PrototypeObject,
+            static (engine, _, state) => new JsSharedArrayBuffer(engine, state!.Item1, state.Item2),
+            new Tuple<uint?, uint>(maxByteLength, byteLength));
+
+        var allocLength = maxByteLength.GetValueOrDefault(byteLength);
+        var block = JsSharedArrayBuffer.CreateSharedByteDataBlock(_realm, allocLength);
+        obj._arrayBufferData = block;
+
+        return obj;
+    }
+}

+ 199 - 0
Jint/Native/SharedArrayBuffer/SharedArrayBufferPrototype.cs

@@ -0,0 +1,199 @@
+using Jint.Collections;
+using Jint.Native.Object;
+using Jint.Native.Symbol;
+using Jint.Runtime;
+using Jint.Runtime.Descriptors;
+using Jint.Runtime.Interop;
+
+namespace Jint.Native.SharedArrayBuffer;
+
+/// <summary>
+/// https://tc39.es/ecma262/#sec-properties-of-the-sharedarraybuffer-prototype-object
+/// </summary>
+internal sealed class SharedArrayBufferPrototype : Prototype
+{
+    private readonly SharedArrayBufferConstructor _constructor;
+
+    internal SharedArrayBufferPrototype(
+        Engine engine,
+        SharedArrayBufferConstructor constructor,
+        ObjectPrototype objectPrototype) : base(engine, engine.Realm)
+    {
+        _prototype = objectPrototype;
+        _constructor = constructor;
+    }
+
+    protected override void Initialize()
+    {
+        const PropertyFlag lengthFlags = PropertyFlag.Configurable;
+        var properties = new PropertyDictionary(3, checkExistingKeys: false)
+        {
+            ["byteLength"] = new GetSetPropertyDescriptor(new ClrFunctionInstance(_engine, "get byteLength", ByteLength, 0, lengthFlags), Undefined, PropertyFlag.Configurable),
+            [KnownKeys.Constructor] = new PropertyDescriptor(_constructor, PropertyFlag.NonEnumerable),
+            ["growable"] = new GetSetPropertyDescriptor(new ClrFunctionInstance(_engine, "get growable", Growable, 0, lengthFlags), Undefined, PropertyFlag.Configurable),
+            ["grow"] = new PropertyDescriptor(new ClrFunctionInstance(_engine, "grow", Grow, 1, lengthFlags), PropertyFlag.NonEnumerable),
+            ["maxByteLength"] = new GetSetPropertyDescriptor(new ClrFunctionInstance(_engine, "get maxByteLength", MaxByteLength, 0, lengthFlags), Undefined, PropertyFlag.Configurable),
+            ["slice"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "slice", Slice, 2, lengthFlags), PropertyFlag.Configurable | PropertyFlag.Writable)
+        };
+        SetProperties(properties);
+
+        var symbols = new SymbolDictionary(1) { [GlobalSymbolRegistry.ToStringTag] = new PropertyDescriptor("SharedArrayBuffer", PropertyFlag.Configurable) };
+        SetSymbols(symbols);
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-get-sharedarraybuffer.prototype.bytelength
+    /// </summary>
+    private JsNumber ByteLength(JsValue thisObj, JsValue[] arguments)
+    {
+        var o = thisObj as JsSharedArrayBuffer;
+        if (o is null || !o.IsSharedArrayBuffer)
+        {
+            ExceptionHelper.ThrowTypeError(_realm, "Method prototype.byteLength called on incompatible receiver " + thisObj);
+        }
+
+        return JsNumber.Create(o.ArrayBufferByteLength);
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-sharedarraybuffer.prototype.slice
+    /// </summary>
+    private JsSharedArrayBuffer Slice(JsValue thisObj, JsValue[] arguments)
+    {
+        var o = thisObj as JsSharedArrayBuffer;
+        if (o is null || !o.IsSharedArrayBuffer)
+        {
+            ExceptionHelper.ThrowTypeError(_realm, "Method prototype.slice called on incompatible receiver " + thisObj);
+        }
+
+        o.AssertNotDetached();
+
+        var start = arguments.At(0);
+        var end = arguments.At(1);
+
+        var len = o.ArrayBufferByteLength;
+        var relativeStart = TypeConverter.ToIntegerOrInfinity(start);
+        var first = relativeStart switch
+        {
+            double.NegativeInfinity => 0,
+            < 0 => (int) System.Math.Max(len + relativeStart, 0),
+            _ => (int) System.Math.Min(relativeStart, len)
+        };
+
+        double relativeEnd;
+        if (end.IsUndefined())
+        {
+            relativeEnd = len;
+        }
+        else
+        {
+            relativeEnd = TypeConverter.ToIntegerOrInfinity(end);
+        }
+
+        var final = relativeEnd switch
+        {
+            double.NegativeInfinity => 0,
+            < 0 => (int) System.Math.Max(len + relativeEnd, 0),
+            _ => (int) System.Math.Min(relativeEnd, len)
+        };
+
+        var newLen = System.Math.Max(final - first, 0);
+        var ctor = SpeciesConstructor(o, _realm.Intrinsics.SharedArrayBuffer);
+        var bufferInstance = Construct(ctor, new JsValue[] { JsNumber.Create(newLen) }) as JsSharedArrayBuffer;
+
+        if (bufferInstance is null)
+        {
+            ExceptionHelper.ThrowTypeError(_realm);
+        }
+
+        if (!bufferInstance.IsSharedArrayBuffer)
+        {
+            ExceptionHelper.ThrowTypeError(_realm);
+        }
+
+        if (bufferInstance.IsDetachedBuffer)
+        {
+            ExceptionHelper.ThrowTypeError(_realm);
+        }
+
+        if (ReferenceEquals(bufferInstance, o))
+        {
+            ExceptionHelper.ThrowTypeError(_realm);
+        }
+
+        if (bufferInstance.ArrayBufferByteLength < newLen)
+        {
+            ExceptionHelper.ThrowTypeError(_realm);
+        }
+
+        // NOTE: Side-effects of the above steps may have detached O.
+
+        if (bufferInstance.IsDetachedBuffer)
+        {
+            ExceptionHelper.ThrowTypeError(_realm);
+        }
+
+        var fromBuf = o.ArrayBufferData!;
+        var toBuf = bufferInstance.ArrayBufferData!;
+        System.Array.Copy(fromBuf, first, toBuf, 0, newLen);
+        return bufferInstance;
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-get-sharedarraybuffer.prototype.growable
+    /// </summary>
+    private JsValue Growable(JsValue thisObject, JsValue[] arguments)
+    {
+        var o = thisObject as JsSharedArrayBuffer;
+        if (o is null || !o.IsSharedArrayBuffer)
+        {
+            ExceptionHelper.ThrowTypeError(_realm, "Method SharedArrayBuffer.prototype.growable called on incompatible receiver " + thisObject);
+        }
+
+        return !o.IsFixedLengthArrayBuffer;
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-sharedarraybuffer.prototype.grow
+    /// </summary>
+    private JsValue Grow(JsValue thisObject, JsValue[] arguments)
+    {
+        var o = thisObject as JsSharedArrayBuffer;
+        if (o is null || !o.IsSharedArrayBuffer)
+        {
+            ExceptionHelper.ThrowTypeError(_realm, "Method SharedArrayBuffer.prototype.grow called on incompatible receiver " + thisObject);
+        }
+
+        var newLength = arguments.At(0);
+        var newByteLength = TypeConverter.ToIndex(_realm, newLength);
+
+        o.AssertNotDetached();
+
+        o.Resize(newByteLength);
+
+        return Undefined;
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-get-sharedarraybuffer.prototype.maxbytelength
+    /// </summary>
+    private JsValue MaxByteLength(JsValue thisObject, JsValue[] arguments)
+    {
+        var o = thisObject as JsSharedArrayBuffer;
+        if (o is null || !o.IsSharedArrayBuffer)
+        {
+            ExceptionHelper.ThrowTypeError(_realm, "Method SharedArrayBuffer.prototype.maxByteLength called on incompatible receiver " + thisObject);
+        }
+
+        if (o.IsDetachedBuffer)
+        {
+            return JsNumber.PositiveZero;
+        }
+
+        long length = o.IsFixedLengthArrayBuffer
+            ? o.ArrayBufferByteLength
+            : o._arrayBufferMaxByteLength.GetValueOrDefault();
+
+        return length;
+    }
+}

+ 0 - 1
Jint/Native/String/StringPrototype.cs

@@ -1,6 +1,5 @@
 #pragma warning disable CA1859 // Use concrete types when possible for improved performance -- most of prototype methods return JsValue
 #pragma warning disable CA1859 // Use concrete types when possible for improved performance -- most of prototype methods return JsValue
 
 
-using System;
 using System.Globalization;
 using System.Globalization;
 using System.Runtime.CompilerServices;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Runtime.InteropServices;

+ 1 - 12
Jint/Native/TypedArray/IntrinsicTypedArrayPrototype.cs

@@ -1051,18 +1051,7 @@ namespace Jint.Native.TypedArray
                 ExceptionHelper.ThrowTypeError(_realm, "Content type mismatch");
                 ExceptionHelper.ThrowTypeError(_realm, "Content type mismatch");
             }
             }
 
 
-            bool same;
-            if (srcBuffer.IsSharedArrayBuffer && targetBuffer.IsSharedArrayBuffer)
-            {
-                // a. If srcBuffer.[[ArrayBufferData]] and targetBuffer.[[ArrayBufferData]] are the same Shared Data Block values, let same be true; else let same be false.
-                ExceptionHelper.ThrowNotImplementedException("SharedBuffer not implemented");
-                same = false;
-            }
-            else
-            {
-                same = SameValue(srcBuffer, targetBuffer);
-            }
-
+            var same = SameValue(srcBuffer, targetBuffer);
             int srcByteIndex;
             int srcByteIndex;
             if (same)
             if (same)
             {
             {

+ 4 - 1
Jint/Native/TypedArray/JsTypedArray.cs

@@ -28,7 +28,10 @@ namespace Jint.Native.TypedArray
             uint length) : base(engine)
             uint length) : base(engine)
         {
         {
             _intrinsics = intrinsics;
             _intrinsics = intrinsics;
-            _viewedArrayBuffer = new JsArrayBuffer(engine, 0);
+            _viewedArrayBuffer = new JsArrayBuffer(engine)
+            {
+                _arrayBufferData = System.Array.Empty<byte>()
+            };
 
 
             _arrayElementType = type;
             _arrayElementType = type;
             _contentType = type != TypedArrayElementType.BigInt64 && type != TypedArrayElementType.BigUint64
             _contentType = type != TypedArrayElementType.BigInt64 && type != TypedArrayElementType.BigUint64

+ 5 - 0
Jint/Runtime/Intrinsics.cs

@@ -23,6 +23,7 @@ using Jint.Native.Reflect;
 using Jint.Native.RegExp;
 using Jint.Native.RegExp;
 using Jint.Native.Set;
 using Jint.Native.Set;
 using Jint.Native.ShadowRealm;
 using Jint.Native.ShadowRealm;
+using Jint.Native.SharedArrayBuffer;
 using Jint.Native.String;
 using Jint.Native.String;
 using Jint.Native.Symbol;
 using Jint.Native.Symbol;
 using Jint.Native.TypedArray;
 using Jint.Native.TypedArray;
@@ -82,6 +83,7 @@ namespace Jint.Runtime
         private ArrayIteratorPrototype? _arrayIteratorPrototype;
         private ArrayIteratorPrototype? _arrayIteratorPrototype;
         private BooleanConstructor? _boolean;
         private BooleanConstructor? _boolean;
         private ArrayBufferConstructor? _arrayBufferConstructor;
         private ArrayBufferConstructor? _arrayBufferConstructor;
+        private SharedArrayBufferConstructor? _sharedArrayBufferConstructor;
         private DataViewConstructor? _dataView;
         private DataViewConstructor? _dataView;
         private AsyncFunctionConstructor? _asyncFunction;
         private AsyncFunctionConstructor? _asyncFunction;
         private FinalizationRegistryConstructor? _finalizationRegistry;
         private FinalizationRegistryConstructor? _finalizationRegistry;
@@ -141,6 +143,9 @@ namespace Jint.Runtime
         internal ArrayBufferConstructor ArrayBuffer =>
         internal ArrayBufferConstructor ArrayBuffer =>
             _arrayBufferConstructor ??= new ArrayBufferConstructor(_engine, _realm, Function.PrototypeObject, Object.PrototypeObject);
             _arrayBufferConstructor ??= new ArrayBufferConstructor(_engine, _realm, Function.PrototypeObject, Object.PrototypeObject);
 
 
+        internal SharedArrayBufferConstructor SharedArrayBuffer =>
+            _sharedArrayBufferConstructor ??= new SharedArrayBufferConstructor(_engine, _realm, Function.PrototypeObject, Object.PrototypeObject);
+
         internal IntrinsicTypedArrayConstructor TypedArray =>
         internal IntrinsicTypedArrayConstructor TypedArray =>
             _typedArray ??= new IntrinsicTypedArrayConstructor(_engine, _realm, Function.PrototypeObject, Object.PrototypeObject, "TypedArray");
             _typedArray ??= new IntrinsicTypedArrayConstructor(_engine, _realm, Function.PrototypeObject, Object.PrototypeObject, "TypedArray");
 
 

+ 2 - 1
README.md

@@ -55,7 +55,8 @@ Following features are supported in version 3.x.
 
 
 - ✔ `Promise.prototype.finally`
 - ✔ `Promise.prototype.finally`
 - ✔ RegExp named capture groups
 - ✔ RegExp named capture groups
-- ✔ Rest/spread operators for object literals (`...identifier`),
+- ✔ Rest/spread operators for object literals (`...identifier`)
+- ✔ SharedArrayBuffer
 
 
 #### ECMAScript 2019
 #### ECMAScript 2019