diff --git a/core/engine/src/builtins/typed_array/object.rs b/core/engine/src/builtins/typed_array/object.rs index 500071e8be2..57087cc1350 100644 --- a/core/engine/src/builtins/typed_array/object.rs +++ b/core/engine/src/builtins/typed_array/object.rs @@ -4,7 +4,7 @@ use std::sync::atomic::Ordering; use crate::{ Context, JsExpect, JsNativeError, JsResult, JsString, JsValue, - builtins::array_buffer::BufferObject, + builtins::array_buffer::{BufferObject, BufferRef}, object::{ JsData, JsObject, internal_methods::{ @@ -279,6 +279,26 @@ impl TypedArray { // 4. Return true. Some(index) } + + /// Abstract operation `IsTypedArrayFixedLength ( O )`. + /// + /// More information: + /// - [ECMAScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-istypedarrayfixedlength + fn is_fixed_length(&self) -> bool { + // 1. If O.[[ArrayLength]] is auto, return false. + if self.is_auto_length() { + return false; + } + + // 2. Let buffer be O.[[ViewedArrayBuffer]]. + match self.viewed_array_buffer().as_buffer() { + // 3. If IsFixedLengthArrayBuffer(buffer) is false and IsSharedArrayBuffer(buffer) is false, return false. + BufferRef::Buffer(buf) => buf.is_fixed_len(), + BufferRef::SharedBuffer(_) => true, + } + } } // Integer-Indexed Exotic Objects [[PreventExtensions]] ( O ) @@ -295,8 +315,9 @@ pub(crate) fn typed_array_exotic_prevent_extensions( .downcast_ref::() .js_expect("must be a TypedArray")?; - ta.viewed_array_buffer().as_buffer().is_fixed_len() - }; + ta.is_fixed_length() + }; // Note: this block ensures that the borrow of obj is dropped + // so it may be re-borrowed in step 3 // 1. If IsTypedArrayFixedLength(O) is false, return false. if !is_fixed_length { diff --git a/core/engine/src/builtins/typed_array/tests.rs b/core/engine/src/builtins/typed_array/tests.rs index a9c978c2750..547dc4dff94 100644 --- a/core/engine/src/builtins/typed_array/tests.rs +++ b/core/engine/src/builtins/typed_array/tests.rs @@ -161,3 +161,24 @@ fn typedarray_conversion_mismatch_throws() { ), ]); } + +#[test] +fn typedarray_exotic_prevent_extensions() { + // ref: https://github.com/tc39/test262/blob/main/test/staging/built-ins/Object/preventExtensions/preventExtensions-variable-length-typed-arrays.js + run_test_actions([ + TestAction::run("const gsab = new SharedArrayBuffer(4, { maxByteLength: 8 });"), + TestAction::run("const fixedLength = new Uint8Array(gsab, 0, 4);"), + TestAction::run("const fixedLengthWithOffset = new Uint8Array(gsab, 2, 2);"), + TestAction::run("Object.preventExtensions(fixedLength);"), + TestAction::run("Object.preventExtensions(fixedLengthWithOffset);"), + TestAction::assert("!Object.isExtensible(fixedLength)"), + TestAction::assert("!Object.isExtensible(fixedLengthWithOffset)"), + TestAction::run("const rab = new ArrayBuffer(4);"), + TestAction::run("const fixedLength1 = new Uint8Array(rab, 0, 4);"), + TestAction::run("const fixedLengthWithOffset1 = new Uint8Array(rab, 2, 2);"), + TestAction::run("Object.preventExtensions(fixedLength1);"), + TestAction::run("Object.preventExtensions(fixedLengthWithOffset1);"), + TestAction::assert("!Object.isExtensible(fixedLength1)"), + TestAction::assert("!Object.isExtensible(fixedLengthWithOffset1)"), + ]); +}