Skip to content
27 changes: 24 additions & 3 deletions core/engine/src/builtins/typed_array/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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 )
Expand All @@ -295,8 +315,9 @@ pub(crate) fn typed_array_exotic_prevent_extensions(
.downcast_ref::<TypedArray>()
.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 {
Expand Down
21 changes: 21 additions & 0 deletions core/engine/src/builtins/typed_array/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)"),
]);
}