Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ use crate::{
SmallInteger,
ecmascript::{
abstract_operations::{
operations_on_objects::{get, length_of_array_like, set, try_set},
operations_on_objects::{construct, get, length_of_array_like, set, try_set},
type_conversion::{to_big_int, to_index, to_number},
},
builtins::{
ArrayBuffer,
ArgumentsList, ArrayBuffer,
array_buffer::{
Ordering, ViewedArrayBufferByteLength, allocate_array_buffer,
array_buffer_byte_length, clone_array_buffer, get_value_from_buffer,
Expand All @@ -25,8 +25,8 @@ use crate::{
},
execution::{Agent, JsResult, ProtoIntrinsics, agent::ExceptionType},
types::{
BigInt, Function, InternalSlots, IntoFunction, IntoNumeric, IntoObject, Number,
Numeric, Object, PropertyKey, U8Clamped, Value, Viewable,
BigInt, Function, InternalSlots, IntoFunction, IntoNumeric, IntoObject, IntoValue,
Number, Numeric, Object, PropertyKey, U8Clamped, Value, Viewable,
},
},
engine::{
Expand Down Expand Up @@ -1158,3 +1158,161 @@ pub(crate) fn allocate_typed_array_buffer<T: Viewable>(
// 9. Return unused.
Ok(())
}

/// ### [23.2.4.2 TypedArrayCreateFromConstructor ( constructor, argumentList )](https://tc39.es/ecma262/multipage/indexed-collections.html#sec-typedarraycreatefromconstructor)
///
/// ### NOTE
/// This method implements steps 2 onwards of the TypedArrayCreateFromConstructor abstract operation.
fn typed_array_create_from_constructor_internal<'a>(
agent: &mut Agent,
new_typed_array: Object<'_>,
length: Option<i64>,
gc: NoGcScope<'a, '_>,
) -> JsResult<TypedArray<'a>> {
// 2. Let taRecord be ? ValidateTypedArray(newTypedArray, seq-cst).
let ta_record =
validate_typed_array(agent, new_typed_array.into_value(), Ordering::SeqCst, gc)?;
let o = ta_record.object;
// 3. If the number of elements in argumentList is 1 and argumentList[0] is a Number, then
if let Some(first_arg) = length {
// a. If IsTypedArrayOutOfBounds(taRecord) is true, throw a TypeError exception.
if match o {
TypedArray::Int8Array(_) => is_typed_array_out_of_bounds::<i8>(agent, &ta_record, gc),
TypedArray::Uint8Array(_) => is_typed_array_out_of_bounds::<u8>(agent, &ta_record, gc),
TypedArray::Uint8ClampedArray(_) => {
is_typed_array_out_of_bounds::<U8Clamped>(agent, &ta_record, gc)
}
TypedArray::Int16Array(_) => is_typed_array_out_of_bounds::<i16>(agent, &ta_record, gc),
TypedArray::Uint16Array(_) => {
is_typed_array_out_of_bounds::<u16>(agent, &ta_record, gc)
}
TypedArray::Int32Array(_) => is_typed_array_out_of_bounds::<i32>(agent, &ta_record, gc),
TypedArray::Uint32Array(_) => {
is_typed_array_out_of_bounds::<u32>(agent, &ta_record, gc)
}
TypedArray::BigInt64Array(_) => {
is_typed_array_out_of_bounds::<i64>(agent, &ta_record, gc)
}
TypedArray::BigUint64Array(_) => {
is_typed_array_out_of_bounds::<u64>(agent, &ta_record, gc)
}
#[cfg(feature = "proposal-float16array")]
TypedArray::Float16Array(_) => {
is_typed_array_out_of_bounds::<f16>(agent, &ta_record, gc)
}
TypedArray::Float32Array(_) => {
is_typed_array_out_of_bounds::<f32>(agent, &ta_record, gc)
}
TypedArray::Float64Array(_) => {
is_typed_array_out_of_bounds::<f64>(agent, &ta_record, gc)
}
} {
return Err(agent.throw_exception_with_static_message(
ExceptionType::TypeError,
"TypedArray out of bounds",
gc,
));
}
// b. Let length be TypedArrayLength(taRecord).
let len = match o {
TypedArray::Int8Array(_) => typed_array_length::<i8>(agent, &ta_record, gc),
TypedArray::Uint8Array(_) => typed_array_length::<u8>(agent, &ta_record, gc),
TypedArray::Uint8ClampedArray(_) => {
typed_array_length::<U8Clamped>(agent, &ta_record, gc)
}
TypedArray::Int16Array(_) => typed_array_length::<i16>(agent, &ta_record, gc),
TypedArray::Uint16Array(_) => typed_array_length::<u16>(agent, &ta_record, gc),
TypedArray::Int32Array(_) => typed_array_length::<i32>(agent, &ta_record, gc),
TypedArray::Uint32Array(_) => typed_array_length::<u32>(agent, &ta_record, gc),
TypedArray::BigInt64Array(_) => typed_array_length::<i64>(agent, &ta_record, gc),
TypedArray::BigUint64Array(_) => typed_array_length::<u64>(agent, &ta_record, gc),
#[cfg(feature = "proposal-float16array")]
TypedArray::Float16Array(_) => typed_array_length::<f16>(agent, &ta_record, gc),
TypedArray::Float32Array(_) => typed_array_length::<f32>(agent, &ta_record, gc),
TypedArray::Float64Array(_) => typed_array_length::<f64>(agent, &ta_record, gc),
} as i64;
// c. If length < ℝ(argumentList[0]), throw a TypeError exception.
if len < first_arg {
return Err(agent.throw_exception_with_static_message(
ExceptionType::TypeError,
"TypedArray out of bounds",
gc,
));
};
}
// 4. Return newTypedArray.
Ok(o)
}

/// ### [23.2.4.2 TypedArrayCreateFromConstructor ( constructor, argumentList )](https://tc39.es/ecma262/multipage/indexed-collections.html#sec-typedarraycreatefromconstructor)
/// The abstract operation TypedArrayCreateFromConstructor takes arguments constructor (a constructor)
/// and argumentList (a List of ECMAScript language values)
/// and returns either a normal completion containing a TypedArray or a throw completion.
/// It is used to specify the creation of a new TypedArray using a constructor function.
pub(crate) fn typed_array_create_from_constructor_with_length<'a>(
agent: &mut Agent,
constructor: Function,
length: i64,
mut gc: GcScope<'a, '_>,
) -> JsResult<TypedArray<'a>> {
let constructor = constructor.bind(gc.nogc());
// 1. Let newTypedArray be ? Construct(constructor, argumentList).
let new_typed_array = construct(
agent,
constructor.unbind(),
Some(ArgumentsList::from_mut_value(
&mut Value::try_from(length).unwrap(),
)),
None,
gc.reborrow(),
)?;
typed_array_create_from_constructor_internal(
agent,
new_typed_array.unbind(),
Some(length),
gc.into_nogc(),
)
}

/// ### [23.2.4.2 TypedArrayCreateFromConstructor ( constructor, argumentList )](https://tc39.es/ecma262/multipage/indexed-collections.html#sec-typedarraycreatefromconstructor)
/// The abstract operation TypedArrayCreateFromConstructor takes arguments constructor (a constructor)
/// and argumentList (a List of ECMAScript language values)
/// and returns either a normal completion containing a TypedArray or a throw completion.
/// It is used to specify the creation of a new TypedArray using a constructor function.
pub(crate) fn typed_array_create_from_constructor_with_buffer<'a>(
agent: &mut Agent,
constructor: Function,
array_buffer: ArrayBuffer,
byte_offset: i64,
length: Option<i64>,
mut gc: GcScope<'a, '_>,
) -> JsResult<TypedArray<'a>> {
let constructor = constructor.bind(gc.nogc());
let array_buffer = array_buffer.bind(gc.nogc());
let args: &mut [Value] = if let Some(length) = length {
&mut [
array_buffer.into_value().unbind(),
Value::try_from(byte_offset).unwrap(),
Value::try_from(length).unwrap(),
]
} else {
&mut [
array_buffer.into_value().unbind(),
Value::try_from(byte_offset).unwrap(),
]
};
// 1. Let newTypedArray be ? Construct(constructor, argumentList).
let new_typed_array = construct(
agent,
constructor.unbind(),
Some(ArgumentsList::from_mut_slice(args)),
None,
gc.reborrow(),
)?;
typed_array_create_from_constructor_internal(
agent,
new_typed_array.unbind(),
length,
gc.into_nogc(),
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use num_traits::ToPrimitive;

use crate::{
SmallInteger,
ecmascript::{
abstract_operations::{
operations_on_objects::{call_function, try_get},
testing_and_comparison::{is_array, is_callable, same_value_zero},
operations_on_objects::{call_function, set, try_get},
testing_and_comparison::{is_array, is_callable, is_constructor, same_value_zero},
type_conversion::{
to_boolean, to_integer_or_infinity, to_string, try_to_integer_or_infinity,
try_to_string,
Expand Down Expand Up @@ -44,7 +46,8 @@ use crate::{

use super::abstract_operations::{
is_typed_array_out_of_bounds, make_typed_array_with_buffer_witness_record,
typed_array_byte_length, typed_array_length, validate_typed_array,
typed_array_byte_length, typed_array_create_from_constructor_with_length, typed_array_length,
validate_typed_array,
};

pub struct TypedArrayIntrinsicObject;
Expand All @@ -68,7 +71,7 @@ struct TypedArrayOf;
impl Builtin for TypedArrayOf {
const BEHAVIOUR: Behaviour = Behaviour::Regular(TypedArrayIntrinsicObject::of);
const LENGTH: u8 = 0;
const NAME: String<'static> = BUILTIN_STRING_MEMORY.fromCodePoint;
const NAME: String<'static> = BUILTIN_STRING_MEMORY.of;
}
struct TypedArrayGetSpecies;
impl Builtin for TypedArrayGetSpecies {
Expand Down Expand Up @@ -112,13 +115,56 @@ impl TypedArrayIntrinsicObject {
is_array(agent, arguments.get(0), gc.nogc()).map(Value::Boolean)
}

/// ### [23.2.2.2 %TypedArray%.of ( ...items )](https://tc39.es/ecma262/multipage/indexed-collections.html#sec-properties-of-the-%typedarray%-intrinsic-object)
fn of<'gc>(
_agent: &mut Agent,
_this_value: Value,
_arguments: ArgumentsList,
_gc: GcScope<'gc, '_>,
agent: &mut Agent,
this_value: Value,
arguments: ArgumentsList,
mut gc: GcScope<'gc, '_>,
) -> JsResult<Value<'gc>> {
todo!();
// 1. Let len be the number of elements in items.
let len = arguments.len();
// 2. Let C be the this value.
let c = this_value;
// 3. If IsConstructor(C) is false, throw a TypeError exception.
let Some(c) = is_constructor(agent, c) else {
return Err(agent.throw_exception_with_static_message(
ExceptionType::TypeError,
"Not a constructor",
gc.nogc(),
));
};
// 4. Let newObj be ? TypedArrayCreateFromConstructor(C, « 𝔽(len) »).
let len = len.to_i64().unwrap();
let c = c.scope(agent, gc.nogc());
let new_obj = typed_array_create_from_constructor_with_length(
agent,
c.get(agent),
len,
gc.reborrow(),
)?
.unbind()
.bind(gc.nogc());
// 5. Let k be 0.
// 6. Repeat, while k < len,
let scoped_new_obj = new_obj.scope(agent, gc.nogc());
for (k, &k_value) in arguments.iter().enumerate() {
// a. Let kValue be items[k].
// b. Let Pk be ! ToString(𝔽(k)).
let pk = PropertyKey::try_from(k).unwrap();
// c. Perform ? Set(newObj, Pk, kValue, true).
set(
agent,
scoped_new_obj.get(agent).into_object(),
pk,
k_value,
true,
gc.reborrow(),
)?
// d. Set k to k + 1.
}
// 7. Return newObj.
Ok(scoped_new_obj.get(agent).into_value())
}

fn get_species<'gc>(
Expand Down
16 changes: 0 additions & 16 deletions tests/expectations.json
Original file line number Diff line number Diff line change
Expand Up @@ -8791,11 +8791,6 @@
"built-ins/TypedArray/from/iterated-array-changed-by-tonumber.js": "CRASH",
"built-ins/TypedArray/from/mapfn-is-not-callable.js": "CRASH",
"built-ins/TypedArray/from/this-is-not-constructor.js": "CRASH",
"built-ins/TypedArray/of/length.js": "FAIL",
"built-ins/TypedArray/of/name.js": "FAIL",
"built-ins/TypedArray/of/not-a-constructor.js": "FAIL",
"built-ins/TypedArray/of/prop-desc.js": "FAIL",
"built-ins/TypedArray/of/resized-with-out-of-bounds-and-in-bounds-indices.js": "FAIL",
"built-ins/TypedArray/prototype/byteLength/resized-out-of-bounds-1.js": "CRASH",
"built-ins/TypedArray/prototype/byteLength/resized-out-of-bounds-2.js": "CRASH",
"built-ins/TypedArray/prototype/byteOffset/resized-out-of-bounds.js": "CRASH",
Expand Down Expand Up @@ -9708,20 +9703,9 @@
"built-ins/TypedArrayConstructors/internals/Set/key-is-minus-zero.js": "FAIL",
"built-ins/TypedArrayConstructors/internals/Set/key-is-not-integer.js": "FAIL",
"built-ins/TypedArrayConstructors/internals/Set/tonumber-value-throws.js": "FAIL",
"built-ins/TypedArrayConstructors/of/BigInt/argument-number-value-throws.js": "FAIL",
"built-ins/TypedArrayConstructors/of/BigInt/custom-ctor-returns-other-instance.js": "FAIL",
"built-ins/TypedArrayConstructors/of/BigInt/custom-ctor.js": "FAIL",
"built-ins/TypedArrayConstructors/of/BigInt/new-instance-empty.js": "FAIL",
"built-ins/TypedArrayConstructors/of/BigInt/new-instance-using-custom-ctor.js": "FAIL",
"built-ins/TypedArrayConstructors/of/BigInt/new-instance.js": "FAIL",
"built-ins/TypedArrayConstructors/of/argument-number-value-throws.js": "FAIL",
"built-ins/TypedArrayConstructors/of/custom-ctor-returns-other-instance.js": "FAIL",
"built-ins/TypedArrayConstructors/of/custom-ctor.js": "FAIL",
"built-ins/TypedArrayConstructors/of/nan-conversion.js": "FAIL",
"built-ins/TypedArrayConstructors/of/new-instance-empty.js": "FAIL",
"built-ins/TypedArrayConstructors/of/new-instance-from-zero.js": "FAIL",
"built-ins/TypedArrayConstructors/of/new-instance-using-custom-ctor.js": "FAIL",
"built-ins/TypedArrayConstructors/of/new-instance.js": "FAIL",
"built-ins/Uint8Array/fromBase64/alphabet.js": "FAIL",
"built-ins/Uint8Array/fromBase64/descriptor.js": "FAIL",
"built-ins/Uint8Array/fromBase64/ignores-receiver.js": "FAIL",
Expand Down
6 changes: 3 additions & 3 deletions tests/metrics.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"results": {
"crash": 12092,
"fail": 7472,
"pass": 27172,
"crash": 12097,
"fail": 7451,
"pass": 27188,
"skip": 65,
"timeout": 0,
"unresolved": 0
Expand Down