From 5bd4bbfb8d5b73bb3081047660b6c11c8fadc9ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20Sj=C3=B6green?= Date: Sun, 3 Nov 2024 23:50:44 +0100 Subject: [PATCH 1/9] feat(ecmascript): Implement dataview `get` and `set` methods --- .../src/ecmascript/builtins/array_buffer.rs | 4 +- .../array_buffer/abstract_operations.rs | 78 +++- .../builtins/data_view/abstract_operations.rs | 171 +++++++- .../data_view_objects/data_view_prototype.rs | 385 +++++++++++++----- .../src/ecmascript/types/language/bigint.rs | 18 + nova_vm/src/ecmascript/types/spec.rs | 2 +- .../src/ecmascript/types/spec/data_block.rs | 288 ++++++++++++- 7 files changed, 802 insertions(+), 144 deletions(-) diff --git a/nova_vm/src/ecmascript/builtins/array_buffer.rs b/nova_vm/src/ecmascript/builtins/array_buffer.rs index 220cc4f3d..8c1c3070a 100644 --- a/nova_vm/src/ecmascript/builtins/array_buffer.rs +++ b/nova_vm/src/ecmascript/builtins/array_buffer.rs @@ -20,8 +20,8 @@ use crate::{ }; pub(crate) use abstract_operations::{ - allocate_array_buffer, array_buffer_byte_length, is_detached_buffer, - is_fixed_length_array_buffer, Ordering, + allocate_array_buffer, array_buffer_byte_length, get_value_from_buffer, is_detached_buffer, + is_fixed_length_array_buffer, set_value_in_buffer, Ordering, }; pub use data::ArrayBufferHeapData; use std::ops::{Index, IndexMut}; diff --git a/nova_vm/src/ecmascript/builtins/array_buffer/abstract_operations.rs b/nova_vm/src/ecmascript/builtins/array_buffer/abstract_operations.rs index 5fd63b4c2..b65ebfde9 100644 --- a/nova_vm/src/ecmascript/builtins/array_buffer/abstract_operations.rs +++ b/nova_vm/src/ecmascript/builtins/array_buffer/abstract_operations.rs @@ -3,6 +3,7 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. use super::{ArrayBuffer, ArrayBufferHeapData}; +use crate::ecmascript::types::Viewable; use crate::engine::context::GcScope; use crate::{ ecmascript::{ @@ -314,7 +315,11 @@ pub(crate) const fn is_no_tear_configuration(r#type: (), order: Ordering) -> boo /// The abstract operation RawBytesToNumeric takes arguments type (a /// TypedArray element type), rawBytes (a List of byte values), and /// isLittleEndian (a Boolean) and returns a Number or a BigInt. -pub(crate) const fn raw_bytes_to_numeric(_type: (), _raw_bytes: &[u8], _is_little_endian: bool) { +pub(crate) fn raw_bytes_to_numeric( + agent: &mut Agent, + raw_bytes: T, + is_little_endian: bool, +) -> Value { // 1. Let elementSize be the Element Size value specified in Table 71 for Element Type type. // 2. If isLittleEndian is false, reverse the order of the elements of rawBytes. // 3. If type is FLOAT32, then @@ -331,6 +336,11 @@ pub(crate) const fn raw_bytes_to_numeric(_type: (), _raw_bytes: &[u8], _is_littl // a. Let intValue be the byte elements of rawBytes concatenated and interpreted as a bit string encoding of a binary little-endian two's complement number of bit length elementSize × 8. // 7. If IsBigIntElementType(type) is true, return the BigInt value that corresponds to intValue. // 8. Otherwise, return the Number value that corresponds to intValue. + if is_little_endian { + raw_bytes.into_le_value(agent) + } else { + raw_bytes.into_be_value(agent) + } } /// ### [25.1.3.14 GetRawBytesFromSharedBlock ( block, byteIndex, type, isTypedArray, order )](https://tc39.es/ecma262/#sec-getrawbytesfromsharedblock) @@ -366,26 +376,36 @@ pub(crate) fn get_raw_bytes_from_shared_block( /// integer), type (a TypedArray element type), isTypedArray (a Boolean), /// and order (SEQ-CST or UNORDERED) and optional argument isLittleEndian /// (a Boolean) and returns a Number or a BigInt. -pub(crate) fn get_value_from_buffer( - _array_buffer: ArrayBuffer, - _byte_index: u32, - _type: (), +pub(crate) fn get_value_from_buffer( + agent: &mut Agent, + array_buffer: ArrayBuffer, + byte_index: usize, _is_typed_array: bool, _order: Ordering, - _is_little_endian: Option, -) { + is_little_endian: Option, +) -> Value { // 1. Assert: IsDetachedBuffer(arrayBuffer) is false. + debug_assert!(!array_buffer.is_detached(agent)); // 2. Assert: There are sufficient bytes in arrayBuffer starting at byteIndex to represent a value of type. - // 3. Let block be arrayBuffer.[[ArrayBufferData]]. // 4. Let elementSize be the Element Size value specified in Table 71 for Element Type type. + // 3. Let block be arrayBuffer.[[ArrayBufferData]]. + let block = agent[array_buffer].get_data_block(); // 5. If IsSharedArrayBuffer(arrayBuffer) is true, then // a. Assert: block is a Shared Data Block. // b. Let rawValue be GetRawBytesFromSharedBlock(block, byteIndex, type, isTypedArray, order). // 6. Else, // a. Let rawValue be a List whose elements are bytes from block at indices in the interval from byteIndex (inclusive) to byteIndex + elementSize (exclusive). // 7. Assert: The number of elements in rawValue is elementSize. + // TODO: Add [[LittleEndian]] to the agent record. // 8. If isLittleEndian is not present, set isLittleEndian to the value of the [[LittleEndian]] field of the surrounding agent's Agent Record. + let is_little_endian = is_little_endian.unwrap_or(false); + // 9. Return RawBytesToNumeric(type, rawValue, isLittleEndian). + raw_bytes_to_numeric::( + agent, + block.get_offset_by_byte::(byte_index).unwrap(), + is_little_endian, + ) } /// ### [25.1.3.16 NumericToRawBytes ( type, value, isLittleEndian )](https://tc39.es/ecma262/#sec-numerictorawbytes) @@ -393,12 +413,12 @@ pub(crate) fn get_value_from_buffer( /// The abstract operation NumericToRawBytes takes arguments type (a /// TypedArray element type), value (a Number or a BigInt), and /// isLittleEndian (a Boolean) and returns a List of byte values. -pub(crate) fn numeric_to_raw_bytes( - _array_buffer: ArrayBuffer, - _type: (), - _value: Number, - _is_little_endian: bool, -) { +pub(crate) fn numeric_to_raw_bytes( + agent: &mut Agent, + gc: GcScope<'_, '_>, + value: Value, + is_little_endian: bool, +) -> T { // 1. If type is FLOAT32, then // a. 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. 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. // 2. Else if type is FLOAT64, then @@ -413,6 +433,11 @@ pub(crate) fn numeric_to_raw_bytes( // i. Let rawBytes be a List whose elements are the n-byte binary two's complement encoding of intValue. The bytes are ordered in little endian order. // 4. If isLittleEndian is false, reverse the order of the elements of rawBytes. // 5. Return rawBytes. + if is_little_endian { + T::from_le_value(agent, gc, value) + } else { + T::from_be_value(agent, gc, value) + } } /// ### [25.1.3.17 SetValueInBuffer ( arrayBuffer, byteIndex, type, value, isTypedArray, order \[ , isLittleEndian \] )](https://tc39.es/ecma262/#sec-setvalueinbuffer) @@ -422,29 +447,40 @@ pub(crate) fn numeric_to_raw_bytes( /// type (a TypedArray element type), value (a Number or a BigInt), /// isTypedArray (a Boolean), and order (SEQ-CST, UNORDERED, or INIT) and /// optional argument isLittleEndian (a Boolean) and returns UNUSED. -pub(crate) fn set_value_in_buffer( - _array_buffer: ArrayBuffer, - _byte_index: u32, - _type: (), - _value: Value, +#[allow(clippy::too_many_arguments)] +pub(crate) fn set_value_in_buffer( + agent: &mut Agent, + gc: GcScope<'_, '_>, + array_buffer: ArrayBuffer, + byte_index: usize, + value: Value, _is_typed_array: bool, _order: Ordering, - _is_little_endian: Option, + is_little_endian: Option, ) { // 1. Assert: IsDetachedBuffer(arrayBuffer) is false. + debug_assert!(!array_buffer.is_detached(agent)); // 2. Assert: There are sufficient bytes in arrayBuffer starting at byteIndex to represent a value of type. // 3. Assert: value is a BigInt if IsBigIntElementType(type) is true; otherwise, value is a Number. - // 4. Let block be arrayBuffer.[[ArrayBufferData]]. + // 5. Let elementSize be the Element Size value specified in Table 71 for Element Type type. // 6. If isLittleEndian is not present, set isLittleEndian to the value of the [[LittleEndian]] field of the surrounding agent's Agent Record. + let is_little_endian = is_little_endian.unwrap_or(false); + // 7. Let rawBytes be NumericToRawBytes(type, value, isLittleEndian). + let raw_bytes = numeric_to_raw_bytes::(agent, gc, value, is_little_endian); // 8. If IsSharedArrayBuffer(arrayBuffer) is true, then // a. Let execution be the [[CandidateExecution]] field of the surrounding agent's Agent Record. // b. Let eventsRecord be the Agent Events Record of 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 eventsRecord.[[EventList]]. // 9. Else, + + // 4. Let block be arrayBuffer.[[ArrayBufferData]]. + let block = agent[array_buffer].get_data_block_mut(); + // a. Store the individual bytes of rawBytes into block, starting at block[byteIndex]. + block.set_offset_by_byte::(byte_index, raw_bytes); // 10. Return UNUSED. } diff --git a/nova_vm/src/ecmascript/builtins/data_view/abstract_operations.rs b/nova_vm/src/ecmascript/builtins/data_view/abstract_operations.rs index 6eeac1a57..22c2a8041 100644 --- a/nova_vm/src/ecmascript/builtins/data_view/abstract_operations.rs +++ b/nova_vm/src/ecmascript/builtins/data_view/abstract_operations.rs @@ -1,6 +1,17 @@ -use crate::ecmascript::{ - builtins::array_buffer::{array_buffer_byte_length, is_fixed_length_array_buffer, Ordering}, - execution::Agent, +use crate::{ + ecmascript::{ + abstract_operations::type_conversion::{to_big_int, to_boolean, to_index, to_number}, + builtins::{ + array_buffer::{ + array_buffer_byte_length, get_value_from_buffer, is_fixed_length_array_buffer, + set_value_in_buffer, Ordering, + }, + structured_data::data_view_objects::data_view_prototype::require_internal_slot_data_view, + }, + execution::{agent::ExceptionType, Agent, JsResult}, + types::{IntoValue, Value, Viewable}, + }, + engine::context::GcScope, }; use super::DataView; @@ -65,7 +76,7 @@ pub(crate) fn make_data_view_with_buffer_witness_record( pub(crate) fn get_view_byte_length( agent: &Agent, view_record: &DataViewWithBufferWitnessRecord, -) -> i64 { +) -> usize { // 1. Assert: IsViewOutOfBounds(viewRecord) is false. assert!(!is_view_out_of_bounds(agent, view_record)); @@ -74,7 +85,7 @@ pub(crate) fn get_view_byte_length( // 3. If view.[[ByteLength]] is not auto, return view.[[ByteLength]]. if let Some(byte_length) = view.byte_length(agent) { - return byte_length as i64; + return byte_length; } // NOTE: This assert seems to not be guarding anything important, so it's @@ -94,7 +105,7 @@ pub(crate) fn get_view_byte_length( let byte_length = view_record.cached_buffer_byte_length.0; // 8. Return byteLength - byteOffset. - (byte_length - byte_offset) as i64 + byte_length - byte_offset } /// ### [25.3.1.4 IsViewOutOfBounds ( viewRecord )](https://tc39.es/ecma262/#sec-isviewoutofbounds) @@ -143,3 +154,151 @@ pub(crate) fn is_view_out_of_bounds( // 10. Return false. false } + +/// ### [25.3.1.5 GetViewValue ( view, requestIndex, isLittleEndian, type )](https://tc39.es/ecma262/#sec-getviewvalue) +/// +/// The abstract operation GetViewValue takes arguments view (an ECMAScript +/// language value), requestIndex (an ECMAScript language value), isLittleEndian +/// (an ECMAScript language value), and type (a TypedArray element type) and +/// returns either a normal completion containing either a Number or a BigInt, +/// or a throw completion. It is used by functions on DataView instances to +/// retrieve values from the view's buffer. +pub(crate) fn get_view_value( + agent: &mut Agent, + gc: GcScope<'_, '_>, + view: Value, + request_index: Value, + is_little_endian: Value, +) -> JsResult { + // 1. Perform ? RequireInternalSlot(view, [[DataView]]). + // 2. Assert: view has a [[ViewedArrayBuffer]] internal slot. + let view = require_internal_slot_data_view(agent, view)?; + + // 3. Let getIndex be ? ToIndex(requestIndex). + let get_index = to_index(agent, gc, request_index)? as usize; + // 4. Set isLittleEndian to ToBoolean(isLittleEndian). + let is_little_endian = to_boolean(agent, is_little_endian); + + // 5. Let viewOffset be view.[[ByteOffset]]. + let view_offset = view.byte_offset(agent); + + // 6. Let viewRecord be MakeDataViewWithBufferWitnessRecord(view, unordered). + let view_record = make_data_view_with_buffer_witness_record(agent, view, Ordering::Unordered); + + // 7. NOTE: Bounds checking is not a synchronizing operation when view's backing buffer is a growable SharedArrayBuffer. + // 8. If IsViewOutOfBounds(viewRecord) is true, throw a TypeError exception. + if is_view_out_of_bounds(agent, &view_record) { + return Err(agent.throw_exception_with_static_message( + ExceptionType::TypeError, + "DataView is out of bounds", + )); + } + + // 9. Let viewSize be GetViewByteLength(viewRecord). + let view_size = get_view_byte_length(agent, &view_record); + + // 10. Let elementSize be the Element Size value specified in Table 69 for Element Type type. + let element_size = size_of::(); + + // 11. If getIndex + elementSize > viewSize, throw a RangeError exception. + if get_index + element_size > view_size { + return Err(agent.throw_exception_with_static_message( + ExceptionType::RangeError, + "Index out of bounds", + )); + } + + // 12. Let bufferIndex be getIndex + viewOffset. + let buffer_index = get_index + view_offset; + + // 13. Return GetValueFromBuffer(view.[[ViewedArrayBuffer]], bufferIndex, type, false, unordered, isLittleEndian). + Ok(get_value_from_buffer::( + agent, + view.get_viewed_array_buffer(agent), + buffer_index, + false, + Ordering::Unordered, + Some(is_little_endian), + )) +} + +/// ### [25.3.1.6 SetViewValue ( view, requestIndex, isLittleEndian, type, value )](https://tc39.es/ecma262/#sec-setviewvalue) +/// +/// The abstract operation SetViewValue takes arguments view (an ECMAScript +/// language value), requestIndex (an ECMAScript language value), isLittleEndian +/// (an ECMAScript language value), type (a TypedArray element type), and value +/// (an ECMAScript language value) and returns either a normal completion +/// containing undefined or a throw completion. It is used by functions on +/// DataView instances to store values into the view's buffer. +pub(crate) fn set_view_value( + agent: &mut Agent, + mut gc: GcScope<'_, '_>, + view: Value, + request_index: Value, + is_little_endian: Value, + value: Value, +) -> JsResult { + // 1. Perform ? RequireInternalSlot(view, [[DataView]]). + // 2. Assert: view has a [[ViewedArrayBuffer]] internal slot. + let view = require_internal_slot_data_view(agent, view)?; + + // 3. Let getIndex be ? ToIndex(requestIndex). + let get_index = to_index(agent, gc.reborrow(), request_index)? as usize; + + // 4. If IsBigIntElementType(type) is true, let numberValue be ? ToBigInt(value). + let number_value = if T::is_bigint_type() { + to_big_int(agent, gc.reborrow(), value)?.into_value() + } else { + // 5. Otherwise, let numberValue be ? ToNumber(value). + to_number(agent, gc.reborrow(), value)?.into_value() + }; + + // 6. Set isLittleEndian to ToBoolean(isLittleEndian). + let is_little_endian = to_boolean(agent, is_little_endian); + + // 7. Let viewOffset be view.[[ByteOffset]]. + let view_offset = view.byte_offset(agent); + + // 8. Let viewRecord be MakeDataViewWithBufferWitnessRecord(view, unordered). + let view_record = make_data_view_with_buffer_witness_record(agent, view, Ordering::Unordered); + + // 9. NOTE: Bounds checking is not a synchronizing operation when view's backing buffer is a growable SharedArrayBuffer. + // 10. If IsViewOutOfBounds(viewRecord) is true, throw a TypeError exception. + if is_view_out_of_bounds(agent, &view_record) { + return Err(agent.throw_exception_with_static_message( + ExceptionType::TypeError, + "DataView is out of bounds", + )); + } + + // 11. Let viewSize be GetViewByteLength(viewRecord). + let view_size = get_view_byte_length(agent, &view_record); + + // 12. Let elementSize be the Element Size value specified in Table 69 for Element Type type. + let element_size = size_of::(); + // 13. If getIndex + elementSize > viewSize, throw a RangeError exception. + if get_index + element_size > view_size { + return Err(agent.throw_exception_with_static_message( + ExceptionType::RangeError, + "Index out of bounds", + )); + } + + // 14. Let bufferIndex be getIndex + viewOffset. + let buffer_index = get_index + view_offset; + + // 15. Perform SetValueInBuffer(view.[[ViewedArrayBuffer]], bufferIndex, type, numberValue, false, unordered, isLittleEndian). + set_value_in_buffer::( + agent, + gc, + view.get_viewed_array_buffer(agent), + buffer_index, + number_value, + false, + Ordering::Unordered, + Some(is_little_endian), + ); + + // 16. Return undefined. + Ok(Value::Undefined) +} diff --git a/nova_vm/src/ecmascript/builtins/structured_data/data_view_objects/data_view_prototype.rs b/nova_vm/src/ecmascript/builtins/structured_data/data_view_objects/data_view_prototype.rs index 7ea44b0b1..1087bea36 100644 --- a/nova_vm/src/ecmascript/builtins/structured_data/data_view_objects/data_view_prototype.rs +++ b/nova_vm/src/ecmascript/builtins/structured_data/data_view_objects/data_view_prototype.rs @@ -2,6 +2,7 @@ // 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 crate::ecmascript::builtins::data_view::abstract_operations::{get_view_value, set_view_value}; use crate::engine::context::GcScope; use crate::{ ecmascript::{ @@ -215,7 +216,7 @@ impl DataViewPrototype { )); } // 6. Let size be GetViewByteLength(viewRecord). - let size = get_view_byte_length(agent, &view_record); + let size = get_view_byte_length(agent, &view_record) as i64; // 7. Return 𝔽(size). Ok(Number::from(SmallInteger::try_from(size).unwrap()).into_value()) } @@ -248,184 +249,364 @@ impl DataViewPrototype { Ok(Number::from(SmallInteger::try_from(o.byte_offset(agent) as i64).unwrap()).into_value()) } + /// ### [25.3.4.5 DataView.prototype.getBigInt64 ( byteOffset \[ , littleEndian \] )](https://tc39.es/ecma262/#sec-dataview.prototype.getbigint64) fn get_big_int64( - _agent: &mut Agent, - _gc: GcScope<'_, '_>, - _this_value: Value, - _arguments: ArgumentsList, + agent: &mut Agent, + gc: GcScope<'_, '_>, + this_value: Value, + arguments: ArgumentsList, ) -> JsResult { - todo!() + let byte_offset = arguments.get(0); + let little_endian = arguments.get(1); + // 1. Let v be the this value. + // 2. Return ? GetViewValue(v, byteOffset, littleEndian, bigint64). + get_view_value::(agent, gc, this_value, byte_offset, little_endian) } + /// ### [25.3.4.6 DataView.prototype.getBigUint64 ( byteOffset \[ , littleEndian \] )](https://tc39.es/ecma262/#sec-dataview.prototype.getbiguint64) fn get_big_uint64( - _agent: &mut Agent, - _gc: GcScope<'_, '_>, - _this_value: Value, - _: ArgumentsList, + agent: &mut Agent, + gc: GcScope<'_, '_>, + this_value: Value, + arguments: ArgumentsList, ) -> JsResult { - todo!() + let byte_offset = arguments.get(0); + let little_endian = arguments.get(1); + // 1. Let v be the this value. + // 2. Return ? GetViewValue(v, byteOffset, littleEndian, biguint64). + get_view_value::(agent, gc, this_value, byte_offset, little_endian) } + /// ### [25.3.4.7 DataView.prototype.getFloat32 ( byteOffset \[ , littleEndian \] )](https://tc39.es/ecma262/#sec-dataview.prototype.getfloat32) fn get_float32( - _agent: &mut Agent, - _gc: GcScope<'_, '_>, - _this_value: Value, - _: ArgumentsList, + agent: &mut Agent, + gc: GcScope<'_, '_>, + this_value: Value, + arguments: ArgumentsList, ) -> JsResult { - todo!() + let byte_offset = arguments.get(0); + // 2. If littleEndian is not present, set littleEndian to false. + let little_endian = if arguments.len() > 1 { + arguments.get(1) + } else { + Value::Boolean(false) + }; + // 1. Let v be the this value. + // 3. Return ? GetViewValue(v, byteOffset, littleEndian, float32). + get_view_value::(agent, gc, this_value, byte_offset, little_endian) } + /// ### [25.3.4.8 DataView.prototype.getFloat64 ( byteOffset \[ , littleEndian \] )](https://tc39.es/ecma262/#sec-dataview.prototype.getfloat64) fn get_float64( - _agent: &mut Agent, - _gc: GcScope<'_, '_>, - _this_value: Value, - _: ArgumentsList, + agent: &mut Agent, + gc: GcScope<'_, '_>, + this_value: Value, + arguments: ArgumentsList, ) -> JsResult { - todo!() + let byte_offset = arguments.get(0); + // 2. If littleEndian is not present, set littleEndian to false. + let little_endian = if arguments.len() > 1 { + arguments.get(1) + } else { + Value::Boolean(false) + }; + // 1. Let v be the this value. + // 3. Return ? GetViewValue(v, byteOffset, littleEndian, float64). + get_view_value::(agent, gc, this_value, byte_offset, little_endian) } + /// ### [25.3.4.9 DataView.prototype.getInt8 ( byteOffset )](https://tc39.es/ecma262/#sec-dataview.prototype.getint8) fn get_int8( - _agent: &mut Agent, - _gc: GcScope<'_, '_>, - _this_value: Value, - _: ArgumentsList, + agent: &mut Agent, + gc: GcScope<'_, '_>, + this_value: Value, + arguments: ArgumentsList, ) -> JsResult { - todo!() + let byte_offset = arguments.get(0); + // 1. Let v be the this value. + // 2. Return ? GetViewValue(v, byteOffset, true, int8). + get_view_value::(agent, gc, this_value, byte_offset, Value::Boolean(true)) } + /// ### [25.3.4.10 DataView.prototype.getInt16 ( byteOffset \[ , littleEndian \] )](https://tc39.es/ecma262/#sec-dataview.prototype.getint16) fn get_int16( - _agent: &mut Agent, - _gc: GcScope<'_, '_>, - _this_value: Value, - _: ArgumentsList, + agent: &mut Agent, + gc: GcScope<'_, '_>, + this_value: Value, + arguments: ArgumentsList, ) -> JsResult { - todo!() + let byte_offset = arguments.get(0); + // 2. If littleEndian is not present, set littleEndian to false. + let little_endian = if arguments.len() > 1 { + arguments.get(1) + } else { + Value::Boolean(false) + }; + // 1. Let v be the this value. + // 3. Return ? GetViewValue(v, byteOffset, littleEndian, int16). + get_view_value::(agent, gc, this_value, byte_offset, little_endian) } + /// ### [25.3.4.11 DataView.prototype.getInt32 ( byteOffset \[ , littleEndian \] )](https://tc39.es/ecma262/#sec-dataview.prototype.getint32) fn get_int32( - _agent: &mut Agent, - _gc: GcScope<'_, '_>, - _this_value: Value, - _: ArgumentsList, + agent: &mut Agent, + gc: GcScope<'_, '_>, + this_value: Value, + arguments: ArgumentsList, ) -> JsResult { - todo!() + let byte_offset = arguments.get(0); + // 2. If littleEndian is not present, set littleEndian to false. + let little_endian = if arguments.len() > 1 { + arguments.get(1) + } else { + Value::Boolean(false) + }; + // 1. Let v be the this value. + // 3. Return ? GetViewValue(v, byteOffset, littleEndian, int32). + get_view_value::(agent, gc, this_value, byte_offset, little_endian) } + /// ### [25.3.4.12 DataView.prototype.getUint8 ( byteOffset )](https://tc39.es/ecma262/#sec-dataview.prototype.getuint8) fn get_uint8( - _agent: &mut Agent, - _gc: GcScope<'_, '_>, - _this_value: Value, - _: ArgumentsList, + agent: &mut Agent, + gc: GcScope<'_, '_>, + this_value: Value, + arguments: ArgumentsList, ) -> JsResult { - todo!() + let byte_offset = arguments.get(0); + // 1. Let v be the this value. + // 2. Return ? GetViewValue(v, byteOffset, true, uint8). + get_view_value::(agent, gc, this_value, byte_offset, Value::Boolean(true)) } + /// ### [25.3.4.13 DataView.prototype.getUint16 ( byteOffset \[ , littleEndian \] )](https://tc39.es/ecma262/#sec-dataview.prototype.getuint16) fn get_uint16( - _agent: &mut Agent, - _gc: GcScope<'_, '_>, - _this_value: Value, - _: ArgumentsList, + agent: &mut Agent, + gc: GcScope<'_, '_>, + this_value: Value, + arguments: ArgumentsList, ) -> JsResult { - todo!() + let byte_offset = arguments.get(0); + // 2. If littleEndian is not present, set littleEndian to false. + let little_endian = if arguments.len() > 1 { + arguments.get(1) + } else { + Value::Boolean(false) + }; + // 1. Let v be the this value. + // 3. Return ? GetViewValue(v, byteOffset, littleEndian, uint16). + get_view_value::(agent, gc, this_value, byte_offset, little_endian) } + /// ### [25.3.4.14 DataView.prototype.getUint32 ( byteOffset \[ , littleEndian \] )](https://tc39.es/ecma262/#sec-dataview.prototype.getuint32) fn get_uint32( - _agent: &mut Agent, - _gc: GcScope<'_, '_>, - _this_value: Value, - _: ArgumentsList, + agent: &mut Agent, + gc: GcScope<'_, '_>, + this_value: Value, + arguments: ArgumentsList, ) -> JsResult { - todo!() + let byte_offset = arguments.get(0); + // 2. If littleEndian is not present, set littleEndian to false. + let little_endian = if arguments.len() > 1 { + arguments.get(1) + } else { + Value::Boolean(false) + }; + // 1. Let v be the this value. + // 3. Return ? GetViewValue(v, byteOffset, littleEndian, uint32). + get_view_value::(agent, gc, this_value, byte_offset, little_endian) } + /// ### [25.3.4.15 DataView.prototype.setBigInt64 ( byteOffset, value \[ , littleEndian \] )](https://tc39.es/ecma262/#sec-dataview.prototype.setbigint64) fn set_big_int64( - _agent: &mut Agent, - _gc: GcScope<'_, '_>, - _this_value: Value, - _: ArgumentsList, + agent: &mut Agent, + gc: GcScope<'_, '_>, + this_value: Value, + arguments: ArgumentsList, ) -> JsResult { - todo!() + let byte_offset = arguments.get(0); + let value = arguments.get(1); + let little_endian = arguments.get(2); + // 1. Let v be the this value. + // 2. Return ? SetViewValue(v, byteOffset, littleEndian, bigint64, value). + set_view_value::(agent, gc, this_value, byte_offset, little_endian, value) } + /// ### [25.3.4.16 DataView.prototype.setBigUint64 ( byteOffset, value \[ , littleEndian \] )](https://tc39.es/ecma262/#sec-dataview.prototype.setbiguint64) fn set_big_uint64( - _agent: &mut Agent, - _gc: GcScope<'_, '_>, - _this_value: Value, - _: ArgumentsList, + agent: &mut Agent, + gc: GcScope<'_, '_>, + this_value: Value, + arguments: ArgumentsList, ) -> JsResult { - todo!() + let byte_offset = arguments.get(0); + let value = arguments.get(1); + let little_endian = arguments.get(2); + // 1. Let v be the this value. + // 2. Return ? SetViewValue(v, byteOffset, littleEndian, biguint64, value). + set_view_value::(agent, gc, this_value, byte_offset, little_endian, value) } + /// ### [25.3.4.17 DataView.prototype.setFloat32 ( byteOffset, value \[ , littleEndian \] )](https://tc39.es/ecma262/#sec-dataview.prototype.setfloat32) fn set_float32( - _agent: &mut Agent, - _gc: GcScope<'_, '_>, - _this_value: Value, - _: ArgumentsList, + agent: &mut Agent, + gc: GcScope<'_, '_>, + this_value: Value, + arguments: ArgumentsList, ) -> JsResult { - todo!() + let byte_offset = arguments.get(0); + let value = arguments.get(1); + // 2. If littleEndian is not present, set littleEndian to false. + let little_endian = if arguments.len() > 2 { + arguments.get(2) + } else { + Value::Boolean(false) + }; + // 1. Let v be the this value. + // 2. Return ? SetViewValue(v, byteOffset, littleEndian, float32, value). + set_view_value::(agent, gc, this_value, byte_offset, little_endian, value) } + /// ### [25.3.4.18 DataView.prototype.setFloat64 ( byteOffset, value \[ , littleEndian \] )](https://tc39.es/ecma262/#sec-dataview.prototype.setfloat64) fn set_float64( - _agent: &mut Agent, - _gc: GcScope<'_, '_>, - _this_value: Value, - _: ArgumentsList, + agent: &mut Agent, + gc: GcScope<'_, '_>, + this_value: Value, + arguments: ArgumentsList, ) -> JsResult { - todo!() + let byte_offset = arguments.get(0); + let value = arguments.get(1); + // 2. If littleEndian is not present, set littleEndian to false. + let little_endian = if arguments.len() > 2 { + arguments.get(2) + } else { + Value::Boolean(false) + }; + // 1. Let v be the this value. + // 2. Return ? SetViewValue(v, byteOffset, littleEndian, float64, value). + set_view_value::(agent, gc, this_value, byte_offset, little_endian, value) } + /// ### [25.3.4.19 DataView.prototype.setInt8 ( byteOffset, value )](https://tc39.es/ecma262/#sec-dataview.prototype.setint8) fn set_int8( - _agent: &mut Agent, - _gc: GcScope<'_, '_>, - _this_value: Value, - _: ArgumentsList, + agent: &mut Agent, + gc: GcScope<'_, '_>, + this_value: Value, + arguments: ArgumentsList, ) -> JsResult { - todo!() + let byte_offset = arguments.get(0); + let value = arguments.get(1); + // 1. Let v be the this value. + // 2. Return ? SetViewValue(v, byteOffset, true, int8, value). + set_view_value::( + agent, + gc, + this_value, + byte_offset, + Value::Boolean(true), + value, + ) } + /// ### [25.3.4.20 DataView.prototype.setInt16 ( byteOffset, value \[ , littleEndian \] )](https://tc39.es/ecma262/#sec-dataview.prototype.setint16) fn set_int16( - _agent: &mut Agent, - _gc: GcScope<'_, '_>, - _this_value: Value, - _: ArgumentsList, + agent: &mut Agent, + gc: GcScope<'_, '_>, + this_value: Value, + arguments: ArgumentsList, ) -> JsResult { - todo!() + let byte_offset = arguments.get(0); + let value = arguments.get(1); + // 2. If littleEndian is not present, set littleEndian to false. + let little_endian = if arguments.len() > 2 { + arguments.get(2) + } else { + Value::Boolean(false) + }; + // 1. Let v be the this value. + // 2. Return ? SetViewValue(v, byteOffset, littleEndian, int16, value). + set_view_value::(agent, gc, this_value, byte_offset, little_endian, value) } + /// ### [25.3.4.21 DataView.prototype.setInt32 ( byteOffset, value \[ , littleEndian \] )](https://tc39.es/ecma262/#sec-dataview.prototype.setint32) fn set_int32( - _agent: &mut Agent, - _gc: GcScope<'_, '_>, - _this_value: Value, - _: ArgumentsList, + agent: &mut Agent, + gc: GcScope<'_, '_>, + this_value: Value, + arguments: ArgumentsList, ) -> JsResult { - todo!() + let byte_offset = arguments.get(0); + let value = arguments.get(1); + // 2. If littleEndian is not present, set littleEndian to false. + let little_endian = if arguments.len() > 2 { + arguments.get(2) + } else { + Value::Boolean(false) + }; + // 1. Let v be the this value. + // 2. Return ? SetViewValue(v, byteOffset, littleEndian, int32, value). + set_view_value::(agent, gc, this_value, byte_offset, little_endian, value) } + /// ### [25.3.4.22 DataView.prototype.setUint8 ( byteOffset, value )](https://tc39.es/ecma262/#sec-dataview.prototype.setuint8) fn set_uint8( - _agent: &mut Agent, - _gc: GcScope<'_, '_>, - _this_value: Value, - _: ArgumentsList, + agent: &mut Agent, + gc: GcScope<'_, '_>, + this_value: Value, + arguments: ArgumentsList, ) -> JsResult { - todo!() + let byte_offset = arguments.get(0); + let value = arguments.get(1); + // 1. Let v be the this value. + // 2. Return ? SetViewValue(v, byteOffset, true, uint8, value). + set_view_value::( + agent, + gc, + this_value, + byte_offset, + Value::Boolean(true), + value, + ) } + /// ### [25.3.4.23 DataView.prototype.setUint16 ( byteOffset, value \[ , littleEndian \] )](https://tc39.es/ecma262/#sec-dataview.prototype.setuint16) fn set_uint16( - _agent: &mut Agent, - _gc: GcScope<'_, '_>, - _this_value: Value, - _: ArgumentsList, + agent: &mut Agent, + gc: GcScope<'_, '_>, + this_value: Value, + arguments: ArgumentsList, ) -> JsResult { - todo!() + let byte_offset = arguments.get(0); + let value = arguments.get(1); + // 2. If littleEndian is not present, set littleEndian to false. + let little_endian = if arguments.len() > 2 { + arguments.get(2) + } else { + Value::Boolean(false) + }; + // 1. Let v be the this value. + // 2. Return ? SetViewValue(v, byteOffset, littleEndian, uint16, value). + set_view_value::(agent, gc, this_value, byte_offset, little_endian, value) } + /// ### [25.3.4.24 DataView.prototype.setUint32 ( byteOffset, value \[ , littleEndian \] )](https://tc39.es/ecma262/#sec-dataview.prototype.setuint32) fn set_uint32( - _agent: &mut Agent, - _gc: GcScope<'_, '_>, - _this_value: Value, - _: ArgumentsList, + agent: &mut Agent, + gc: GcScope<'_, '_>, + this_value: Value, + arguments: ArgumentsList, ) -> JsResult { - todo!() + let byte_offset = arguments.get(0); + let value = arguments.get(1); + // 2. If littleEndian is not present, set littleEndian to false. + let little_endian = if arguments.len() > 2 { + arguments.get(2) + } else { + Value::Boolean(false) + }; + // 1. Let v be the this value. + // 2. Return ? SetViewValue(v, byteOffset, littleEndian, uint32, value). + set_view_value::(agent, gc, this_value, byte_offset, little_endian, value) } pub(crate) fn create_intrinsic(agent: &mut Agent, realm: RealmIdentifier) { @@ -474,7 +655,7 @@ impl DataViewPrototype { } #[inline] -fn require_internal_slot_data_view(agent: &mut Agent, o: Value) -> JsResult { +pub(crate) fn require_internal_slot_data_view(agent: &mut Agent, o: Value) -> JsResult { match o { // 1. Perform ? RequireInternalSlot(O, [[DataView]]). Value::DataView(array_buffer) => Ok(array_buffer), diff --git a/nova_vm/src/ecmascript/types/language/bigint.rs b/nova_vm/src/ecmascript/types/language/bigint.rs index fde6647f0..f93fcb9b8 100644 --- a/nova_vm/src/ecmascript/types/language/bigint.rs +++ b/nova_vm/src/ecmascript/types/language/bigint.rs @@ -167,6 +167,15 @@ impl TryFrom for SmallBigInt { } } +impl TryFrom for SmallBigInt { + type Error = (); + + #[inline(always)] + fn try_from(value: u64) -> Result { + Ok(Self(value.try_into()?)) + } +} + impl TryFrom<&num_bigint::BigInt> for SmallBigInt { type Error = (); @@ -211,6 +220,15 @@ impl BigInt { } } + #[inline] + pub fn from_u64(agent: &mut Agent, value: u64) -> Self { + if let Ok(result) = SmallBigInt::try_from(value) { + Self::SmallBigInt(result) + } else { + agent.heap.create(BigIntHeapData { data: value.into() }) + } + } + #[inline] pub(crate) fn from_num_bigint(agent: &mut Agent, value: num_bigint::BigInt) -> Self { if let Ok(result) = SmallBigInt::try_from(&value) { diff --git a/nova_vm/src/ecmascript/types/spec.rs b/nova_vm/src/ecmascript/types/spec.rs index c1f8e97cc..bd7811602 100644 --- a/nova_vm/src/ecmascript/types/spec.rs +++ b/nova_vm/src/ecmascript/types/spec.rs @@ -6,6 +6,6 @@ mod data_block; mod property_descriptor; mod reference; #[cfg(feature = "array-buffer")] -pub(crate) use data_block::DataBlock; +pub(crate) use data_block::{DataBlock, Viewable}; pub use property_descriptor::PropertyDescriptor; pub(crate) use reference::*; diff --git a/nova_vm/src/ecmascript/types/spec/data_block.rs b/nova_vm/src/ecmascript/types/spec/data_block.rs index 753739486..f51c98d94 100644 --- a/nova_vm/src/ecmascript/types/spec/data_block.rs +++ b/nova_vm/src/ecmascript/types/spec/data_block.rs @@ -9,7 +9,13 @@ use std::{ ptr::{self, read_unaligned, write_unaligned, NonNull}, }; -use crate::ecmascript::execution::{agent::ExceptionType, Agent, JsResult}; +use crate::{ + ecmascript::{ + execution::{agent::ExceptionType, Agent, JsResult}, + types::{BigInt, IntoValue, Value}, + }, + engine::context::GcScope, +}; /// Sentinel pointer for a detached data block. /// @@ -61,18 +67,248 @@ mod private { impl Sealed for f64 {} } -pub trait Viewable: private::Sealed {} +pub trait Viewable: private::Sealed + Copy { + fn is_bigint_type() -> bool; + fn into_be_value(self, agent: &mut Agent) -> Value; + fn into_le_value(self, agent: &mut Agent) -> Value; + fn from_le_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self; + fn from_be_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self; +} + +impl Viewable for u8 { + fn is_bigint_type() -> bool { + false + } + + fn into_be_value(self, _: &mut Agent) -> Value { + Value::from(self.to_be()) + } + + fn into_le_value(self, _: &mut Agent) -> Value { + Value::from(self.to_le()) + } + + fn from_be_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { + value.to_real(agent, gc).unwrap() as Self + } + + fn from_le_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { + value.to_real(agent, gc).unwrap() as Self + } +} +impl Viewable for i8 { + fn is_bigint_type() -> bool { + false + } + + fn into_be_value(self, _: &mut Agent) -> Value { + Value::from(self.to_be()) + } + + fn into_le_value(self, _: &mut Agent) -> Value { + Value::from(self.to_le()) + } + + fn from_be_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { + value.to_real(agent, gc).unwrap() as Self + } + + fn from_le_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { + value.to_real(agent, gc).unwrap() as Self + } +} +impl Viewable for u16 { + fn is_bigint_type() -> bool { + false + } + + fn into_be_value(self, _: &mut Agent) -> Value { + Value::from(self.to_be()) + } + + fn into_le_value(self, _: &mut Agent) -> Value { + Value::from(self.to_le()) + } + + fn from_be_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { + (value.to_real(agent, gc).unwrap() as Self).to_be() + } + + fn from_le_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { + (value.to_real(agent, gc).unwrap() as Self).to_le() + } +} +impl Viewable for i16 { + fn is_bigint_type() -> bool { + false + } + + fn into_be_value(self, _: &mut Agent) -> Value { + Value::from(self.to_be()) + } -impl Viewable for u8 {} -impl Viewable for i8 {} -impl Viewable for u16 {} -impl Viewable for i16 {} -impl Viewable for u32 {} -impl Viewable for i32 {} -impl Viewable for u64 {} -impl Viewable for i64 {} -impl Viewable for f32 {} -impl Viewable for f64 {} + fn into_le_value(self, _: &mut Agent) -> Value { + Value::from(self.to_le()) + } + + fn from_be_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { + (value.to_real(agent, gc).unwrap() as Self).to_be() + } + + fn from_le_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { + (value.to_real(agent, gc).unwrap() as Self).to_le() + } +} +impl Viewable for u32 { + fn is_bigint_type() -> bool { + false + } + + fn into_be_value(self, _: &mut Agent) -> Value { + Value::from(self.to_be()) + } + + fn into_le_value(self, _: &mut Agent) -> Value { + Value::from(self.to_le()) + } + + fn from_be_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { + (value.to_real(agent, gc).unwrap() as Self).to_be() + } + + fn from_le_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { + (value.to_real(agent, gc).unwrap() as Self).to_le() + } +} +impl Viewable for i32 { + fn is_bigint_type() -> bool { + false + } + + fn into_be_value(self, _: &mut Agent) -> Value { + Value::from(self.to_be()) + } + + fn into_le_value(self, _: &mut Agent) -> Value { + Value::from(self.to_le()) + } + + fn from_be_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { + (value.to_real(agent, gc).unwrap() as Self).to_be() + } + + fn from_le_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { + (value.to_real(agent, gc).unwrap() as Self).to_le() + } +} +impl Viewable for u64 { + fn is_bigint_type() -> bool { + true + } + + fn into_be_value(self, agent: &mut Agent) -> Value { + BigInt::from_u64(agent, self.to_be()).into_value() + } + + fn into_le_value(self, agent: &mut Agent) -> Value { + BigInt::from_u64(agent, self.to_le()).into_value() + } + + fn from_be_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { + match value.to_bigint(agent, gc).unwrap() { + BigInt::SmallBigInt(value) => (value.into_i64() as Self).to_be(), + BigInt::BigInt(value) => { + let value: Self = agent[value].data.clone().try_into().unwrap(); + value.to_be() + } + } + } + + fn from_le_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { + match value.to_bigint(agent, gc).unwrap() { + BigInt::SmallBigInt(value) => (value.into_i64() as Self).to_le(), + BigInt::BigInt(value) => { + let value: Self = agent[value].data.clone().try_into().unwrap(); + value.to_le() + } + } + } +} +impl Viewable for i64 { + fn is_bigint_type() -> bool { + true + } + + fn into_be_value(self, agent: &mut Agent) -> Value { + BigInt::from_i64(agent, self.to_be()).into_value() + } + + fn into_le_value(self, agent: &mut Agent) -> Value { + BigInt::from_i64(agent, self.to_le()).into_value() + } + + fn from_be_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { + match value.to_bigint(agent, gc).unwrap() { + BigInt::SmallBigInt(value) => value.into_i64().to_be(), + BigInt::BigInt(value) => { + let value: Self = agent[value].data.clone().try_into().unwrap(); + value.to_be() + } + } + } + + fn from_le_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { + match value.to_bigint(agent, gc).unwrap() { + BigInt::SmallBigInt(value) => value.into_i64().to_le(), + BigInt::BigInt(value) => { + let value: Self = agent[value].data.clone().try_into().unwrap(); + value.to_le() + } + } + } +} +impl Viewable for f32 { + fn is_bigint_type() -> bool { + false + } + + fn into_be_value(self, _: &mut Agent) -> Value { + Value::from(Self::from_ne_bytes(self.to_be_bytes())) + } + + fn into_le_value(self, _: &mut Agent) -> Value { + Value::from(Self::from_ne_bytes(self.to_le_bytes())) + } + + fn from_be_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { + Self::from_ne_bytes((value.to_real(agent, gc).unwrap() as Self).to_be_bytes()) + } + + fn from_le_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { + Self::from_ne_bytes((value.to_real(agent, gc).unwrap() as Self).to_le_bytes()) + } +} +impl Viewable for f64 { + fn is_bigint_type() -> bool { + false + } + + fn into_be_value(self, agent: &mut Agent) -> Value { + Value::from_f64(agent, Self::from_ne_bytes(self.to_be_bytes())) + } + + fn into_le_value(self, agent: &mut Agent) -> Value { + Value::from_f64(agent, Self::from_ne_bytes(self.to_le_bytes())) + } + + fn from_be_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { + Self::from_ne_bytes((value.to_real(agent, gc).unwrap() as Self).to_be_bytes()) + } + + fn from_le_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { + Self::from_ne_bytes((value.to_real(agent, gc).unwrap() as Self).to_le_bytes()) + } +} impl DataBlock { /// Sentinel value for detached DataBlocks. @@ -162,6 +398,20 @@ impl DataBlock { } } + pub fn get_offset_by_byte(&self, byte_offset: usize) -> Option { + let size = std::mem::size_of::(); + let end_byte_offset = byte_offset + size; + if end_byte_offset > self.byte_length { + None + } else { + self.ptr.map(|data| { + // SAFETY: The data is properly initialized, and the T being read is + // checked to be fully within the length of the data allocation. + unsafe { read_unaligned(data.as_ptr().byte_add(byte_offset).cast()) } + }) + } + } + pub fn set(&mut self, offset: usize, value: T) { let size = std::mem::size_of::(); if let Some(data) = self.ptr { @@ -176,6 +426,20 @@ impl DataBlock { } } + pub fn set_offset_by_byte(&mut self, byte_offset: usize, value: T) { + let size = std::mem::size_of::(); + if let Some(data) = self.ptr { + // Note: We have to check offset + 1 to ensure that the write does + // not reach data beyond the end of the DataBlock allocation. + let end_byte_offset = byte_offset + size; + if end_byte_offset <= self.byte_length { + // SAFETY: The data is properly initialized, and the T being written is + // checked to be fully within the length of the data allocation. + unsafe { write_unaligned(data.as_ptr().byte_add(byte_offset).cast(), value) } + } + } + } + pub fn set_from( &mut self, dst_offset: usize, From 62511424f61a2a369b8c726f85b5177e8acc57a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20Sj=C3=B6green?= Date: Sun, 3 Nov 2024 23:51:05 +0100 Subject: [PATCH 2/9] chore: Update metrics --- tests/expectations.json | 222 ---------------------------------------- tests/metrics.json | 6 +- 2 files changed, 3 insertions(+), 225 deletions(-) diff --git a/tests/expectations.json b/tests/expectations.json index 9394b005b..c4efcbae2 100644 --- a/tests/expectations.json +++ b/tests/expectations.json @@ -580,7 +580,6 @@ "built-ins/Array/prototype/with/this-value-nullish.js": "CRASH", "built-ins/ArrayBuffer/allocation-limit.js": "CRASH", "built-ins/ArrayBuffer/data-allocation-after-object-creation.js": "CRASH", - "built-ins/ArrayBuffer/init-zero.js": "CRASH", "built-ins/ArrayBuffer/isView/arg-is-typedarray-buffer.js": "CRASH", "built-ins/ArrayBuffer/isView/arg-is-typedarray-subclass-instance.js": "CRASH", "built-ins/ArrayBuffer/isView/arg-is-typedarray.js": "CRASH", @@ -1234,39 +1233,13 @@ "built-ins/DataView/prototype/getBigInt64/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getBigInt64/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getBigInt64/detached-buffer.js": "CRASH", - "built-ins/DataView/prototype/getBigInt64/index-is-out-of-range.js": "CRASH", - "built-ins/DataView/prototype/getBigInt64/negative-byteoffset-throws.js": "CRASH", - "built-ins/DataView/prototype/getBigInt64/resizable-buffer.js": "CRASH", - "built-ins/DataView/prototype/getBigInt64/return-abrupt-from-tonumber-byteoffset-symbol.js": "CRASH", - "built-ins/DataView/prototype/getBigInt64/return-abrupt-from-tonumber-byteoffset.js": "CRASH", - "built-ins/DataView/prototype/getBigInt64/return-value-clean-arraybuffer.js": "CRASH", - "built-ins/DataView/prototype/getBigInt64/return-values-custom-offset.js": "CRASH", - "built-ins/DataView/prototype/getBigInt64/return-values.js": "CRASH", "built-ins/DataView/prototype/getBigInt64/this-has-no-dataview-internal.js": "CRASH", - "built-ins/DataView/prototype/getBigInt64/this-is-not-object.js": "CRASH", "built-ins/DataView/prototype/getBigInt64/to-boolean-littleendian.js": "CRASH", - "built-ins/DataView/prototype/getBigInt64/toindex-byteoffset-errors.js": "CRASH", - "built-ins/DataView/prototype/getBigInt64/toindex-byteoffset-toprimitive.js": "CRASH", - "built-ins/DataView/prototype/getBigInt64/toindex-byteoffset-wrapped-values.js": "CRASH", - "built-ins/DataView/prototype/getBigInt64/toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getBigUint64/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getBigUint64/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getBigUint64/detached-buffer.js": "CRASH", - "built-ins/DataView/prototype/getBigUint64/index-is-out-of-range.js": "CRASH", - "built-ins/DataView/prototype/getBigUint64/negative-byteoffset-throws.js": "CRASH", - "built-ins/DataView/prototype/getBigUint64/resizable-buffer.js": "CRASH", - "built-ins/DataView/prototype/getBigUint64/return-abrupt-from-tonumber-byteoffset-symbol.js": "CRASH", - "built-ins/DataView/prototype/getBigUint64/return-abrupt-from-tonumber-byteoffset.js": "CRASH", - "built-ins/DataView/prototype/getBigUint64/return-value-clean-arraybuffer.js": "CRASH", - "built-ins/DataView/prototype/getBigUint64/return-values-custom-offset.js": "CRASH", - "built-ins/DataView/prototype/getBigUint64/return-values.js": "CRASH", "built-ins/DataView/prototype/getBigUint64/this-has-no-dataview-internal.js": "CRASH", - "built-ins/DataView/prototype/getBigUint64/this-is-not-object.js": "CRASH", "built-ins/DataView/prototype/getBigUint64/to-boolean-littleendian.js": "CRASH", - "built-ins/DataView/prototype/getBigUint64/toindex-byteoffset-errors.js": "CRASH", - "built-ins/DataView/prototype/getBigUint64/toindex-byteoffset-toprimitive.js": "CRASH", - "built-ins/DataView/prototype/getBigUint64/toindex-byteoffset-wrapped-values.js": "CRASH", - "built-ins/DataView/prototype/getBigUint64/toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getFloat16/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getFloat16/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getFloat16/detached-buffer.js": "CRASH", @@ -1289,158 +1262,58 @@ "built-ins/DataView/prototype/getFloat32/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getFloat32/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getFloat32/detached-buffer.js": "CRASH", - "built-ins/DataView/prototype/getFloat32/index-is-out-of-range.js": "CRASH", - "built-ins/DataView/prototype/getFloat32/minus-zero.js": "CRASH", - "built-ins/DataView/prototype/getFloat32/negative-byteoffset-throws.js": "CRASH", "built-ins/DataView/prototype/getFloat32/resizable-buffer.js": "CRASH", - "built-ins/DataView/prototype/getFloat32/return-abrupt-from-tonumber-byteoffset-symbol.js": "CRASH", - "built-ins/DataView/prototype/getFloat32/return-abrupt-from-tonumber-byteoffset.js": "CRASH", - "built-ins/DataView/prototype/getFloat32/return-infinity.js": "CRASH", - "built-ins/DataView/prototype/getFloat32/return-nan.js": "CRASH", "built-ins/DataView/prototype/getFloat32/return-value-clean-arraybuffer.js": "CRASH", "built-ins/DataView/prototype/getFloat32/return-values-custom-offset.js": "CRASH", "built-ins/DataView/prototype/getFloat32/return-values.js": "CRASH", "built-ins/DataView/prototype/getFloat32/this-has-no-dataview-internal.js": "CRASH", - "built-ins/DataView/prototype/getFloat32/this-is-not-object.js": "CRASH", "built-ins/DataView/prototype/getFloat32/to-boolean-littleendian.js": "CRASH", "built-ins/DataView/prototype/getFloat32/toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getFloat64/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getFloat64/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getFloat64/detached-buffer.js": "CRASH", - "built-ins/DataView/prototype/getFloat64/index-is-out-of-range.js": "CRASH", "built-ins/DataView/prototype/getFloat64/minus-zero.js": "CRASH", - "built-ins/DataView/prototype/getFloat64/negative-byteoffset-throws.js": "CRASH", - "built-ins/DataView/prototype/getFloat64/resizable-buffer.js": "CRASH", - "built-ins/DataView/prototype/getFloat64/return-abrupt-from-tonumber-byteoffset-symbol.js": "CRASH", - "built-ins/DataView/prototype/getFloat64/return-abrupt-from-tonumber-byteoffset.js": "CRASH", - "built-ins/DataView/prototype/getFloat64/return-infinity.js": "CRASH", - "built-ins/DataView/prototype/getFloat64/return-nan.js": "CRASH", - "built-ins/DataView/prototype/getFloat64/return-value-clean-arraybuffer.js": "CRASH", - "built-ins/DataView/prototype/getFloat64/return-values-custom-offset.js": "CRASH", - "built-ins/DataView/prototype/getFloat64/return-values.js": "CRASH", "built-ins/DataView/prototype/getFloat64/this-has-no-dataview-internal.js": "CRASH", - "built-ins/DataView/prototype/getFloat64/this-is-not-object.js": "CRASH", - "built-ins/DataView/prototype/getFloat64/to-boolean-littleendian.js": "CRASH", - "built-ins/DataView/prototype/getFloat64/toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getInt16/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getInt16/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getInt16/detached-buffer.js": "CRASH", - "built-ins/DataView/prototype/getInt16/index-is-out-of-range.js": "CRASH", - "built-ins/DataView/prototype/getInt16/negative-byteoffset-throws.js": "CRASH", - "built-ins/DataView/prototype/getInt16/resizable-buffer.js": "CRASH", - "built-ins/DataView/prototype/getInt16/return-abrupt-from-tonumber-byteoffset-symbol.js": "CRASH", - "built-ins/DataView/prototype/getInt16/return-abrupt-from-tonumber-byteoffset.js": "CRASH", - "built-ins/DataView/prototype/getInt16/return-value-clean-arraybuffer.js": "CRASH", - "built-ins/DataView/prototype/getInt16/return-values-custom-offset.js": "CRASH", - "built-ins/DataView/prototype/getInt16/return-values.js": "CRASH", "built-ins/DataView/prototype/getInt16/this-has-no-dataview-internal.js": "CRASH", - "built-ins/DataView/prototype/getInt16/this-is-not-object.js": "CRASH", - "built-ins/DataView/prototype/getInt16/to-boolean-littleendian.js": "CRASH", - "built-ins/DataView/prototype/getInt16/toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getInt32/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getInt32/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getInt32/detached-buffer.js": "CRASH", "built-ins/DataView/prototype/getInt32/index-is-out-of-range-sab.js": "CRASH", - "built-ins/DataView/prototype/getInt32/index-is-out-of-range.js": "CRASH", "built-ins/DataView/prototype/getInt32/negative-byteoffset-throws-sab.js": "CRASH", - "built-ins/DataView/prototype/getInt32/negative-byteoffset-throws.js": "CRASH", - "built-ins/DataView/prototype/getInt32/resizable-buffer.js": "CRASH", "built-ins/DataView/prototype/getInt32/return-abrupt-from-tonumber-byteoffset-sab.js": "CRASH", "built-ins/DataView/prototype/getInt32/return-abrupt-from-tonumber-byteoffset-symbol-sab.js": "CRASH", - "built-ins/DataView/prototype/getInt32/return-abrupt-from-tonumber-byteoffset-symbol.js": "CRASH", - "built-ins/DataView/prototype/getInt32/return-abrupt-from-tonumber-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getInt32/return-value-clean-arraybuffer-sab.js": "CRASH", - "built-ins/DataView/prototype/getInt32/return-value-clean-arraybuffer.js": "CRASH", "built-ins/DataView/prototype/getInt32/return-values-custom-offset-sab.js": "CRASH", - "built-ins/DataView/prototype/getInt32/return-values-custom-offset.js": "CRASH", "built-ins/DataView/prototype/getInt32/return-values-sab.js": "CRASH", - "built-ins/DataView/prototype/getInt32/return-values.js": "CRASH", "built-ins/DataView/prototype/getInt32/this-has-no-dataview-internal-sab.js": "CRASH", "built-ins/DataView/prototype/getInt32/this-has-no-dataview-internal.js": "CRASH", - "built-ins/DataView/prototype/getInt32/this-is-not-object.js": "CRASH", "built-ins/DataView/prototype/getInt32/to-boolean-littleendian-sab.js": "CRASH", - "built-ins/DataView/prototype/getInt32/to-boolean-littleendian.js": "CRASH", "built-ins/DataView/prototype/getInt32/toindex-byteoffset-sab.js": "CRASH", - "built-ins/DataView/prototype/getInt32/toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getInt8/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getInt8/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getInt8/detached-buffer.js": "CRASH", - "built-ins/DataView/prototype/getInt8/index-is-out-of-range.js": "CRASH", - "built-ins/DataView/prototype/getInt8/negative-byteoffset-throws.js": "CRASH", - "built-ins/DataView/prototype/getInt8/resizable-buffer.js": "CRASH", - "built-ins/DataView/prototype/getInt8/return-abrupt-from-tonumber-byteoffset-symbol.js": "CRASH", - "built-ins/DataView/prototype/getInt8/return-abrupt-from-tonumber-byteoffset.js": "CRASH", - "built-ins/DataView/prototype/getInt8/return-value-clean-arraybuffer.js": "CRASH", - "built-ins/DataView/prototype/getInt8/return-values-custom-offset.js": "CRASH", - "built-ins/DataView/prototype/getInt8/return-values.js": "CRASH", "built-ins/DataView/prototype/getInt8/this-has-no-dataview-internal.js": "CRASH", - "built-ins/DataView/prototype/getInt8/this-is-not-object.js": "CRASH", - "built-ins/DataView/prototype/getInt8/toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getUint16/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getUint16/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getUint16/detached-buffer.js": "CRASH", - "built-ins/DataView/prototype/getUint16/index-is-out-of-range.js": "CRASH", - "built-ins/DataView/prototype/getUint16/negative-byteoffset-throws.js": "CRASH", - "built-ins/DataView/prototype/getUint16/resizable-buffer.js": "CRASH", - "built-ins/DataView/prototype/getUint16/return-abrupt-from-tonumber-byteoffset-symbol.js": "CRASH", - "built-ins/DataView/prototype/getUint16/return-abrupt-from-tonumber-byteoffset.js": "CRASH", - "built-ins/DataView/prototype/getUint16/return-value-clean-arraybuffer.js": "CRASH", - "built-ins/DataView/prototype/getUint16/return-values-custom-offset.js": "CRASH", - "built-ins/DataView/prototype/getUint16/return-values.js": "CRASH", "built-ins/DataView/prototype/getUint16/this-has-no-dataview-internal.js": "CRASH", - "built-ins/DataView/prototype/getUint16/this-is-not-object.js": "CRASH", - "built-ins/DataView/prototype/getUint16/to-boolean-littleendian.js": "CRASH", - "built-ins/DataView/prototype/getUint16/toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getUint32/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getUint32/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getUint32/detached-buffer.js": "CRASH", - "built-ins/DataView/prototype/getUint32/index-is-out-of-range.js": "CRASH", - "built-ins/DataView/prototype/getUint32/negative-byteoffset-throws.js": "CRASH", - "built-ins/DataView/prototype/getUint32/resizable-buffer.js": "CRASH", - "built-ins/DataView/prototype/getUint32/return-abrupt-from-tonumber-byteoffset-symbol.js": "CRASH", - "built-ins/DataView/prototype/getUint32/return-abrupt-from-tonumber-byteoffset.js": "CRASH", - "built-ins/DataView/prototype/getUint32/return-value-clean-arraybuffer.js": "CRASH", - "built-ins/DataView/prototype/getUint32/return-values-custom-offset.js": "CRASH", - "built-ins/DataView/prototype/getUint32/return-values.js": "CRASH", "built-ins/DataView/prototype/getUint32/this-has-no-dataview-internal.js": "CRASH", - "built-ins/DataView/prototype/getUint32/this-is-not-object.js": "CRASH", - "built-ins/DataView/prototype/getUint32/to-boolean-littleendian.js": "CRASH", - "built-ins/DataView/prototype/getUint32/toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getUint8/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getUint8/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/getUint8/detached-buffer.js": "CRASH", - "built-ins/DataView/prototype/getUint8/index-is-out-of-range.js": "CRASH", - "built-ins/DataView/prototype/getUint8/negative-byteoffset-throws.js": "CRASH", - "built-ins/DataView/prototype/getUint8/resizable-buffer.js": "CRASH", - "built-ins/DataView/prototype/getUint8/return-abrupt-from-tonumber-byteoffset-symbol.js": "CRASH", - "built-ins/DataView/prototype/getUint8/return-abrupt-from-tonumber-byteoffset.js": "CRASH", - "built-ins/DataView/prototype/getUint8/return-value-clean-arraybuffer.js": "CRASH", - "built-ins/DataView/prototype/getUint8/return-values-custom-offset.js": "CRASH", - "built-ins/DataView/prototype/getUint8/return-values.js": "CRASH", "built-ins/DataView/prototype/getUint8/this-has-no-dataview-internal.js": "CRASH", - "built-ins/DataView/prototype/getUint8/this-is-not-object.js": "CRASH", - "built-ins/DataView/prototype/getUint8/toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setBigInt64/detached-buffer-after-bigint-value.js": "CRASH", "built-ins/DataView/prototype/setBigInt64/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setBigInt64/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setBigInt64/detached-buffer.js": "CRASH", - "built-ins/DataView/prototype/setBigInt64/index-check-before-value-conversion.js": "CRASH", - "built-ins/DataView/prototype/setBigInt64/index-is-out-of-range.js": "CRASH", - "built-ins/DataView/prototype/setBigInt64/negative-byteoffset-throws.js": "CRASH", - "built-ins/DataView/prototype/setBigInt64/no-value-arg.js": "CRASH", - "built-ins/DataView/prototype/setBigInt64/range-check-after-value-conversion.js": "CRASH", - "built-ins/DataView/prototype/setBigInt64/resizable-buffer.js": "CRASH", - "built-ins/DataView/prototype/setBigInt64/return-abrupt-from-tobigint-value-symbol.js": "CRASH", - "built-ins/DataView/prototype/setBigInt64/return-abrupt-from-tobigint-value.js": "CRASH", - "built-ins/DataView/prototype/setBigInt64/return-abrupt-from-tonumber-byteoffset-symbol.js": "CRASH", - "built-ins/DataView/prototype/setBigInt64/return-abrupt-from-tonumber-byteoffset.js": "CRASH", - "built-ins/DataView/prototype/setBigInt64/set-values-little-endian-order.js": "CRASH", "built-ins/DataView/prototype/setBigInt64/set-values-return-undefined.js": "CRASH", "built-ins/DataView/prototype/setBigInt64/this-has-no-dataview-internal.js": "CRASH", - "built-ins/DataView/prototype/setBigInt64/this-is-not-object.js": "CRASH", - "built-ins/DataView/prototype/setBigInt64/to-boolean-littleendian.js": "CRASH", - "built-ins/DataView/prototype/setBigInt64/toindex-byteoffset.js": "CRASH", - "built-ins/DataView/prototype/setBigUint64/resizable-buffer.js": "CRASH", "built-ins/DataView/prototype/setFloat16/detached-buffer-after-number-value.js": "CRASH", "built-ins/DataView/prototype/setFloat16/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setFloat16/detached-buffer-before-outofrange-byteoffset.js": "CRASH", @@ -1465,157 +1338,62 @@ "built-ins/DataView/prototype/setFloat32/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setFloat32/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setFloat32/detached-buffer.js": "CRASH", - "built-ins/DataView/prototype/setFloat32/index-check-before-value-conversion.js": "CRASH", "built-ins/DataView/prototype/setFloat32/index-is-out-of-range.js": "CRASH", "built-ins/DataView/prototype/setFloat32/negative-byteoffset-throws.js": "CRASH", - "built-ins/DataView/prototype/setFloat32/no-value-arg.js": "CRASH", - "built-ins/DataView/prototype/setFloat32/range-check-after-value-conversion.js": "CRASH", - "built-ins/DataView/prototype/setFloat32/resizable-buffer.js": "CRASH", - "built-ins/DataView/prototype/setFloat32/return-abrupt-from-tonumber-byteoffset-symbol.js": "CRASH", - "built-ins/DataView/prototype/setFloat32/return-abrupt-from-tonumber-byteoffset.js": "CRASH", - "built-ins/DataView/prototype/setFloat32/return-abrupt-from-tonumber-value-symbol.js": "CRASH", - "built-ins/DataView/prototype/setFloat32/return-abrupt-from-tonumber-value.js": "CRASH", "built-ins/DataView/prototype/setFloat32/set-values-little-endian-order.js": "CRASH", "built-ins/DataView/prototype/setFloat32/set-values-return-undefined.js": "CRASH", "built-ins/DataView/prototype/setFloat32/this-has-no-dataview-internal.js": "CRASH", - "built-ins/DataView/prototype/setFloat32/this-is-not-object.js": "CRASH", "built-ins/DataView/prototype/setFloat32/to-boolean-littleendian.js": "CRASH", "built-ins/DataView/prototype/setFloat32/toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setFloat64/detached-buffer-after-number-value.js": "CRASH", "built-ins/DataView/prototype/setFloat64/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setFloat64/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setFloat64/detached-buffer.js": "CRASH", - "built-ins/DataView/prototype/setFloat64/index-check-before-value-conversion.js": "CRASH", - "built-ins/DataView/prototype/setFloat64/index-is-out-of-range.js": "CRASH", - "built-ins/DataView/prototype/setFloat64/negative-byteoffset-throws.js": "CRASH", - "built-ins/DataView/prototype/setFloat64/no-value-arg.js": "CRASH", - "built-ins/DataView/prototype/setFloat64/range-check-after-value-conversion.js": "CRASH", - "built-ins/DataView/prototype/setFloat64/resizable-buffer.js": "CRASH", - "built-ins/DataView/prototype/setFloat64/return-abrupt-from-tonumber-byteoffset-symbol.js": "CRASH", - "built-ins/DataView/prototype/setFloat64/return-abrupt-from-tonumber-byteoffset.js": "CRASH", - "built-ins/DataView/prototype/setFloat64/return-abrupt-from-tonumber-value-symbol.js": "CRASH", - "built-ins/DataView/prototype/setFloat64/return-abrupt-from-tonumber-value.js": "CRASH", - "built-ins/DataView/prototype/setFloat64/set-values-little-endian-order.js": "CRASH", "built-ins/DataView/prototype/setFloat64/set-values-return-undefined.js": "CRASH", "built-ins/DataView/prototype/setFloat64/this-has-no-dataview-internal.js": "CRASH", - "built-ins/DataView/prototype/setFloat64/this-is-not-object.js": "CRASH", - "built-ins/DataView/prototype/setFloat64/to-boolean-littleendian.js": "CRASH", - "built-ins/DataView/prototype/setFloat64/toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setInt16/detached-buffer-after-number-value.js": "CRASH", "built-ins/DataView/prototype/setInt16/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setInt16/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setInt16/detached-buffer.js": "CRASH", - "built-ins/DataView/prototype/setInt16/index-check-before-value-conversion.js": "CRASH", - "built-ins/DataView/prototype/setInt16/index-is-out-of-range.js": "CRASH", - "built-ins/DataView/prototype/setInt16/negative-byteoffset-throws.js": "CRASH", - "built-ins/DataView/prototype/setInt16/no-value-arg.js": "CRASH", - "built-ins/DataView/prototype/setInt16/range-check-after-value-conversion.js": "CRASH", - "built-ins/DataView/prototype/setInt16/resizable-buffer.js": "CRASH", - "built-ins/DataView/prototype/setInt16/return-abrupt-from-tonumber-byteoffset-symbol.js": "CRASH", - "built-ins/DataView/prototype/setInt16/return-abrupt-from-tonumber-byteoffset.js": "CRASH", - "built-ins/DataView/prototype/setInt16/return-abrupt-from-tonumber-value-symbol.js": "CRASH", - "built-ins/DataView/prototype/setInt16/return-abrupt-from-tonumber-value.js": "CRASH", "built-ins/DataView/prototype/setInt16/set-values-little-endian-order.js": "CRASH", "built-ins/DataView/prototype/setInt16/set-values-return-undefined.js": "CRASH", "built-ins/DataView/prototype/setInt16/this-has-no-dataview-internal.js": "CRASH", - "built-ins/DataView/prototype/setInt16/this-is-not-object.js": "CRASH", - "built-ins/DataView/prototype/setInt16/to-boolean-littleendian.js": "CRASH", - "built-ins/DataView/prototype/setInt16/toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setInt32/detached-buffer-after-number-value.js": "CRASH", "built-ins/DataView/prototype/setInt32/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setInt32/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setInt32/detached-buffer.js": "CRASH", - "built-ins/DataView/prototype/setInt32/index-check-before-value-conversion.js": "CRASH", - "built-ins/DataView/prototype/setInt32/index-is-out-of-range.js": "CRASH", - "built-ins/DataView/prototype/setInt32/negative-byteoffset-throws.js": "CRASH", - "built-ins/DataView/prototype/setInt32/no-value-arg.js": "CRASH", - "built-ins/DataView/prototype/setInt32/range-check-after-value-conversion.js": "CRASH", - "built-ins/DataView/prototype/setInt32/resizable-buffer.js": "CRASH", - "built-ins/DataView/prototype/setInt32/return-abrupt-from-tonumber-byteoffset-symbol.js": "CRASH", - "built-ins/DataView/prototype/setInt32/return-abrupt-from-tonumber-byteoffset.js": "CRASH", - "built-ins/DataView/prototype/setInt32/return-abrupt-from-tonumber-value-symbol.js": "CRASH", - "built-ins/DataView/prototype/setInt32/return-abrupt-from-tonumber-value.js": "CRASH", "built-ins/DataView/prototype/setInt32/set-values-little-endian-order.js": "CRASH", "built-ins/DataView/prototype/setInt32/set-values-return-undefined.js": "CRASH", "built-ins/DataView/prototype/setInt32/this-has-no-dataview-internal.js": "CRASH", - "built-ins/DataView/prototype/setInt32/this-is-not-object.js": "CRASH", - "built-ins/DataView/prototype/setInt32/to-boolean-littleendian.js": "CRASH", - "built-ins/DataView/prototype/setInt32/toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setInt8/detached-buffer-after-number-value.js": "CRASH", "built-ins/DataView/prototype/setInt8/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setInt8/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setInt8/detached-buffer.js": "CRASH", - "built-ins/DataView/prototype/setInt8/index-check-before-value-conversion.js": "CRASH", - "built-ins/DataView/prototype/setInt8/index-is-out-of-range.js": "CRASH", - "built-ins/DataView/prototype/setInt8/negative-byteoffset-throws.js": "CRASH", - "built-ins/DataView/prototype/setInt8/no-value-arg.js": "CRASH", - "built-ins/DataView/prototype/setInt8/range-check-after-value-conversion.js": "CRASH", - "built-ins/DataView/prototype/setInt8/resizable-buffer.js": "CRASH", - "built-ins/DataView/prototype/setInt8/return-abrupt-from-tonumber-byteoffset-symbol.js": "CRASH", - "built-ins/DataView/prototype/setInt8/return-abrupt-from-tonumber-byteoffset.js": "CRASH", - "built-ins/DataView/prototype/setInt8/return-abrupt-from-tonumber-value-symbol.js": "CRASH", - "built-ins/DataView/prototype/setInt8/return-abrupt-from-tonumber-value.js": "CRASH", "built-ins/DataView/prototype/setInt8/set-values-return-undefined.js": "CRASH", "built-ins/DataView/prototype/setInt8/this-has-no-dataview-internal.js": "CRASH", - "built-ins/DataView/prototype/setInt8/this-is-not-object.js": "CRASH", - "built-ins/DataView/prototype/setInt8/toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setUint16/detached-buffer-after-number-value.js": "CRASH", "built-ins/DataView/prototype/setUint16/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setUint16/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setUint16/detached-buffer.js": "CRASH", - "built-ins/DataView/prototype/setUint16/index-check-before-value-conversion.js": "CRASH", - "built-ins/DataView/prototype/setUint16/index-is-out-of-range.js": "CRASH", - "built-ins/DataView/prototype/setUint16/negative-byteoffset-throws.js": "CRASH", - "built-ins/DataView/prototype/setUint16/no-value-arg.js": "CRASH", - "built-ins/DataView/prototype/setUint16/range-check-after-value-conversion.js": "CRASH", - "built-ins/DataView/prototype/setUint16/resizable-buffer.js": "CRASH", - "built-ins/DataView/prototype/setUint16/return-abrupt-from-tonumber-byteoffset-symbol.js": "CRASH", - "built-ins/DataView/prototype/setUint16/return-abrupt-from-tonumber-byteoffset.js": "CRASH", - "built-ins/DataView/prototype/setUint16/return-abrupt-from-tonumber-value-symbol.js": "CRASH", - "built-ins/DataView/prototype/setUint16/return-abrupt-from-tonumber-value.js": "CRASH", "built-ins/DataView/prototype/setUint16/set-values-little-endian-order.js": "CRASH", "built-ins/DataView/prototype/setUint16/set-values-return-undefined.js": "CRASH", "built-ins/DataView/prototype/setUint16/this-has-no-dataview-internal.js": "CRASH", - "built-ins/DataView/prototype/setUint16/this-is-not-object.js": "CRASH", - "built-ins/DataView/prototype/setUint16/to-boolean-littleendian.js": "CRASH", - "built-ins/DataView/prototype/setUint16/toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setUint32/detached-buffer-after-number-value.js": "CRASH", "built-ins/DataView/prototype/setUint32/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setUint32/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setUint32/detached-buffer.js": "CRASH", - "built-ins/DataView/prototype/setUint32/index-check-before-value-conversion.js": "CRASH", - "built-ins/DataView/prototype/setUint32/index-is-out-of-range.js": "CRASH", - "built-ins/DataView/prototype/setUint32/negative-byteoffset-throws.js": "CRASH", - "built-ins/DataView/prototype/setUint32/no-value-arg.js": "CRASH", - "built-ins/DataView/prototype/setUint32/range-check-after-value-conversion.js": "CRASH", - "built-ins/DataView/prototype/setUint32/resizable-buffer.js": "CRASH", - "built-ins/DataView/prototype/setUint32/return-abrupt-from-tonumber-byteoffset-symbol.js": "CRASH", - "built-ins/DataView/prototype/setUint32/return-abrupt-from-tonumber-byteoffset.js": "CRASH", - "built-ins/DataView/prototype/setUint32/return-abrupt-from-tonumber-value-symbol.js": "CRASH", - "built-ins/DataView/prototype/setUint32/return-abrupt-from-tonumber-value.js": "CRASH", "built-ins/DataView/prototype/setUint32/set-values-little-endian-order.js": "CRASH", "built-ins/DataView/prototype/setUint32/set-values-return-undefined.js": "CRASH", "built-ins/DataView/prototype/setUint32/this-has-no-dataview-internal.js": "CRASH", - "built-ins/DataView/prototype/setUint32/this-is-not-object.js": "CRASH", - "built-ins/DataView/prototype/setUint32/to-boolean-littleendian.js": "CRASH", - "built-ins/DataView/prototype/setUint32/toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setUint8/detached-buffer-after-number-value.js": "CRASH", "built-ins/DataView/prototype/setUint8/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setUint8/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setUint8/detached-buffer.js": "CRASH", - "built-ins/DataView/prototype/setUint8/index-check-before-value-conversion.js": "CRASH", "built-ins/DataView/prototype/setUint8/index-is-out-of-range.js": "CRASH", "built-ins/DataView/prototype/setUint8/negative-byteoffset-throws.js": "CRASH", "built-ins/DataView/prototype/setUint8/no-value-arg.js": "CRASH", - "built-ins/DataView/prototype/setUint8/range-check-after-value-conversion.js": "CRASH", - "built-ins/DataView/prototype/setUint8/resizable-buffer.js": "CRASH", - "built-ins/DataView/prototype/setUint8/return-abrupt-from-tonumber-byteoffset-symbol.js": "CRASH", - "built-ins/DataView/prototype/setUint8/return-abrupt-from-tonumber-byteoffset.js": "CRASH", - "built-ins/DataView/prototype/setUint8/return-abrupt-from-tonumber-value-symbol.js": "CRASH", - "built-ins/DataView/prototype/setUint8/return-abrupt-from-tonumber-value.js": "CRASH", "built-ins/DataView/prototype/setUint8/set-values-return-undefined.js": "CRASH", "built-ins/DataView/prototype/setUint8/this-has-no-dataview-internal.js": "CRASH", - "built-ins/DataView/prototype/setUint8/this-is-not-object.js": "CRASH", "built-ins/DataView/prototype/setUint8/toindex-byteoffset.js": "CRASH", "built-ins/DataView/return-abrupt-tonumber-bytelength-sab.js": "CRASH", "built-ins/DataView/return-abrupt-tonumber-bytelength-symbol-sab.js": "CRASH", diff --git a/tests/metrics.json b/tests/metrics.json index 68e1e8200..3966f8467 100644 --- a/tests/metrics.json +++ b/tests/metrics.json @@ -1,8 +1,8 @@ { "results": { - "crash": 16114, - "fail": 8357, - "pass": 20777, + "crash": 15859, + "fail": 8390, + "pass": 20999, "skip": 40, "timeout": 3, "unresolved": 0 From 6a14de3735cc87a51ce7d983a798a37b9bc1a9a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20Sj=C3=B6green?= Date: Mon, 4 Nov 2024 13:41:55 +0100 Subject: [PATCH 3/9] fix: PR comments and `to_*` usage in `Viewable` trait --- .../abstract_operations/type_conversion.rs | 63 +++++++++++ .../array_buffer/abstract_operations.rs | 23 +++- .../builtins/data_view/abstract_operations.rs | 16 +-- .../data_view_objects/data_view_prototype.rs | 103 ++++-------------- .../src/ecmascript/types/language/bigint.rs | 1 - .../src/ecmascript/types/spec/data_block.rs | 102 ++++++----------- 6 files changed, 141 insertions(+), 167 deletions(-) diff --git a/nova_vm/src/ecmascript/abstract_operations/type_conversion.rs b/nova_vm/src/ecmascript/abstract_operations/type_conversion.rs index 47bab5a61..37c0b699e 100644 --- a/nova_vm/src/ecmascript/abstract_operations/type_conversion.rs +++ b/nova_vm/src/ecmascript/abstract_operations/type_conversion.rs @@ -707,6 +707,69 @@ pub(crate) fn string_to_big_int(_agent: &mut Agent, _argument: String) -> Option todo!("string_to_big_int: Implement BigInts") } +/// ### [7.1.15 ToBigInt64 ( argument )](https://tc39.es/ecma262/#sec-tobigint64) +/// +/// The abstract operation ToBigInt64 takes argument argument (an ECMAScript +/// language value) and returns either a normal completion containing a BigInt +/// or a throw completion. It converts argument to one of 2**64 BigInt values +/// in the inclusive interval from ℤ(-2**63) to ℤ(2**63 - 1). +#[inline(always)] +pub(crate) fn to_big_int64( + agent: &mut Agent, + gc: GcScope<'_, '_>, + + argument: Value, +) -> JsResult { + // 1. Let n be ? ToBigInt(argument). + let n = to_big_int(agent, gc, argument)?; + + // 2. Let int64bit be ℝ(n) modulo 2**64. + match n { + BigInt::BigInt(heap_big_int) => { + let int64bit = agent[heap_big_int].data.clone() % u64::MAX; + // 3. If int64bit ≥ 2**63, return ℤ(int64bit - 2**64); otherwise return ℤ(int64bit). + if int64bit >= i64::MAX.into() { + Ok((int64bit - u64::MAX).try_into().unwrap()) + } else { + Ok(int64bit.try_into().unwrap()) + } + } + BigInt::SmallBigInt(small_big_int) => { + let int64bit = small_big_int.into_i64(); + Ok(int64bit) + } + } +} + +/// ### [7.1.16 ToBigUint64 ( argument )](https://tc39.es/ecma262/#sec-tobiguint64) +/// +/// The abstract operation ToBigUint64 takes argument argument (an ECMAScript +/// language value) and returns either a normal completion containing a BigInt +/// or a throw completion. It converts argument to one of 2**64 BigInt values +/// in the inclusive interval from 0ℤ to ℤ(2**64 - 1). +#[inline(always)] +pub(crate) fn to_big_uint64( + agent: &mut Agent, + gc: GcScope<'_, '_>, + + argument: Value, +) -> JsResult { + // 1. Let n be ? ToBigInt(argument). + let n = to_big_int(agent, gc, argument)?; + + // 2. Let int64bit be ℝ(n) modulo 2**64. + match n { + BigInt::BigInt(heap_big_int) => { + let int64bit = agent[heap_big_int].data.clone() % u64::MAX; + Ok(int64bit.try_into().unwrap()) + } + BigInt::SmallBigInt(small_big_int) => { + let int64bit = small_big_int.into_i64(); + Ok(int64bit as u64) + } + } +} + /// ### [7.1.17 ToString ( argument )](https://tc39.es/ecma262/#sec-tostring) pub(crate) fn to_string( agent: &mut Agent, diff --git a/nova_vm/src/ecmascript/builtins/array_buffer/abstract_operations.rs b/nova_vm/src/ecmascript/builtins/array_buffer/abstract_operations.rs index b65ebfde9..93a9edaa0 100644 --- a/nova_vm/src/ecmascript/builtins/array_buffer/abstract_operations.rs +++ b/nova_vm/src/ecmascript/builtins/array_buffer/abstract_operations.rs @@ -396,9 +396,17 @@ pub(crate) fn get_value_from_buffer( // 6. Else, // a. Let rawValue be a List whose elements are bytes from block at indices in the interval from byteIndex (inclusive) to byteIndex + elementSize (exclusive). // 7. Assert: The number of elements in rawValue is elementSize. - // TODO: Add [[LittleEndian]] to the agent record. // 8. If isLittleEndian is not present, set isLittleEndian to the value of the [[LittleEndian]] field of the surrounding agent's Agent Record. - let is_little_endian = is_little_endian.unwrap_or(false); + let is_little_endian = is_little_endian.unwrap_or({ + #[cfg(target_endian = "little")] + { + true + } + #[cfg(target_endian = "big")] + { + false + } + }); // 9. Return RawBytesToNumeric(type, rawValue, isLittleEndian). raw_bytes_to_numeric::( @@ -465,7 +473,16 @@ pub(crate) fn set_value_in_buffer( // 5. Let elementSize be the Element Size value specified in Table 71 for Element Type type. // 6. If isLittleEndian is not present, set isLittleEndian to the value of the [[LittleEndian]] field of the surrounding agent's Agent Record. - let is_little_endian = is_little_endian.unwrap_or(false); + let is_little_endian = is_little_endian.unwrap_or({ + #[cfg(target_endian = "little")] + { + true + } + #[cfg(target_endian = "big")] + { + false + } + }); // 7. Let rawBytes be NumericToRawBytes(type, value, isLittleEndian). let raw_bytes = numeric_to_raw_bytes::(agent, gc, value, is_little_endian); diff --git a/nova_vm/src/ecmascript/builtins/data_view/abstract_operations.rs b/nova_vm/src/ecmascript/builtins/data_view/abstract_operations.rs index 22c2a8041..303901b30 100644 --- a/nova_vm/src/ecmascript/builtins/data_view/abstract_operations.rs +++ b/nova_vm/src/ecmascript/builtins/data_view/abstract_operations.rs @@ -1,6 +1,6 @@ use crate::{ ecmascript::{ - abstract_operations::type_conversion::{to_big_int, to_boolean, to_index, to_number}, + abstract_operations::type_conversion::{to_big_int, to_index, to_number}, builtins::{ array_buffer::{ array_buffer_byte_length, get_value_from_buffer, is_fixed_length_array_buffer, @@ -168,7 +168,8 @@ pub(crate) fn get_view_value( gc: GcScope<'_, '_>, view: Value, request_index: Value, - is_little_endian: Value, + // 4. Set isLittleEndian to ToBoolean(isLittleEndian). + is_little_endian: bool, ) -> JsResult { // 1. Perform ? RequireInternalSlot(view, [[DataView]]). // 2. Assert: view has a [[ViewedArrayBuffer]] internal slot. @@ -176,9 +177,6 @@ pub(crate) fn get_view_value( // 3. Let getIndex be ? ToIndex(requestIndex). let get_index = to_index(agent, gc, request_index)? as usize; - // 4. Set isLittleEndian to ToBoolean(isLittleEndian). - let is_little_endian = to_boolean(agent, is_little_endian); - // 5. Let viewOffset be view.[[ByteOffset]]. let view_offset = view.byte_offset(agent); @@ -235,7 +233,8 @@ pub(crate) fn set_view_value( mut gc: GcScope<'_, '_>, view: Value, request_index: Value, - is_little_endian: Value, + // 6. Set isLittleEndian to ToBoolean(isLittleEndian). + is_little_endian: bool, value: Value, ) -> JsResult { // 1. Perform ? RequireInternalSlot(view, [[DataView]]). @@ -246,16 +245,13 @@ pub(crate) fn set_view_value( let get_index = to_index(agent, gc.reborrow(), request_index)? as usize; // 4. If IsBigIntElementType(type) is true, let numberValue be ? ToBigInt(value). - let number_value = if T::is_bigint_type() { + let number_value = if T::IS_BIGINT { to_big_int(agent, gc.reborrow(), value)?.into_value() } else { // 5. Otherwise, let numberValue be ? ToNumber(value). to_number(agent, gc.reborrow(), value)?.into_value() }; - // 6. Set isLittleEndian to ToBoolean(isLittleEndian). - let is_little_endian = to_boolean(agent, is_little_endian); - // 7. Let viewOffset be view.[[ByteOffset]]. let view_offset = view.byte_offset(agent); diff --git a/nova_vm/src/ecmascript/builtins/structured_data/data_view_objects/data_view_prototype.rs b/nova_vm/src/ecmascript/builtins/structured_data/data_view_objects/data_view_prototype.rs index 1087bea36..b3f7add19 100644 --- a/nova_vm/src/ecmascript/builtins/structured_data/data_view_objects/data_view_prototype.rs +++ b/nova_vm/src/ecmascript/builtins/structured_data/data_view_objects/data_view_prototype.rs @@ -2,6 +2,7 @@ // 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 crate::ecmascript::abstract_operations::type_conversion::to_boolean; use crate::ecmascript::builtins::data_view::abstract_operations::{get_view_value, set_view_value}; use crate::engine::context::GcScope; use crate::{ @@ -257,7 +258,7 @@ impl DataViewPrototype { arguments: ArgumentsList, ) -> JsResult { let byte_offset = arguments.get(0); - let little_endian = arguments.get(1); + let little_endian = to_boolean(agent, arguments.get(1)); // 1. Let v be the this value. // 2. Return ? GetViewValue(v, byteOffset, littleEndian, bigint64). get_view_value::(agent, gc, this_value, byte_offset, little_endian) @@ -271,7 +272,7 @@ impl DataViewPrototype { arguments: ArgumentsList, ) -> JsResult { let byte_offset = arguments.get(0); - let little_endian = arguments.get(1); + let little_endian = to_boolean(agent, arguments.get(1)); // 1. Let v be the this value. // 2. Return ? GetViewValue(v, byteOffset, littleEndian, biguint64). get_view_value::(agent, gc, this_value, byte_offset, little_endian) @@ -286,11 +287,7 @@ impl DataViewPrototype { ) -> JsResult { let byte_offset = arguments.get(0); // 2. If littleEndian is not present, set littleEndian to false. - let little_endian = if arguments.len() > 1 { - arguments.get(1) - } else { - Value::Boolean(false) - }; + let little_endian = to_boolean(agent, arguments.get(1)); // 1. Let v be the this value. // 3. Return ? GetViewValue(v, byteOffset, littleEndian, float32). get_view_value::(agent, gc, this_value, byte_offset, little_endian) @@ -305,11 +302,7 @@ impl DataViewPrototype { ) -> JsResult { let byte_offset = arguments.get(0); // 2. If littleEndian is not present, set littleEndian to false. - let little_endian = if arguments.len() > 1 { - arguments.get(1) - } else { - Value::Boolean(false) - }; + let little_endian = to_boolean(agent, arguments.get(1)); // 1. Let v be the this value. // 3. Return ? GetViewValue(v, byteOffset, littleEndian, float64). get_view_value::(agent, gc, this_value, byte_offset, little_endian) @@ -325,7 +318,7 @@ impl DataViewPrototype { let byte_offset = arguments.get(0); // 1. Let v be the this value. // 2. Return ? GetViewValue(v, byteOffset, true, int8). - get_view_value::(agent, gc, this_value, byte_offset, Value::Boolean(true)) + get_view_value::(agent, gc, this_value, byte_offset, true) } /// ### [25.3.4.10 DataView.prototype.getInt16 ( byteOffset \[ , littleEndian \] )](https://tc39.es/ecma262/#sec-dataview.prototype.getint16) @@ -337,11 +330,7 @@ impl DataViewPrototype { ) -> JsResult { let byte_offset = arguments.get(0); // 2. If littleEndian is not present, set littleEndian to false. - let little_endian = if arguments.len() > 1 { - arguments.get(1) - } else { - Value::Boolean(false) - }; + let little_endian = to_boolean(agent, arguments.get(1)); // 1. Let v be the this value. // 3. Return ? GetViewValue(v, byteOffset, littleEndian, int16). get_view_value::(agent, gc, this_value, byte_offset, little_endian) @@ -356,11 +345,7 @@ impl DataViewPrototype { ) -> JsResult { let byte_offset = arguments.get(0); // 2. If littleEndian is not present, set littleEndian to false. - let little_endian = if arguments.len() > 1 { - arguments.get(1) - } else { - Value::Boolean(false) - }; + let little_endian = to_boolean(agent, arguments.get(1)); // 1. Let v be the this value. // 3. Return ? GetViewValue(v, byteOffset, littleEndian, int32). get_view_value::(agent, gc, this_value, byte_offset, little_endian) @@ -376,7 +361,7 @@ impl DataViewPrototype { let byte_offset = arguments.get(0); // 1. Let v be the this value. // 2. Return ? GetViewValue(v, byteOffset, true, uint8). - get_view_value::(agent, gc, this_value, byte_offset, Value::Boolean(true)) + get_view_value::(agent, gc, this_value, byte_offset, true) } /// ### [25.3.4.13 DataView.prototype.getUint16 ( byteOffset \[ , littleEndian \] )](https://tc39.es/ecma262/#sec-dataview.prototype.getuint16) @@ -388,11 +373,7 @@ impl DataViewPrototype { ) -> JsResult { let byte_offset = arguments.get(0); // 2. If littleEndian is not present, set littleEndian to false. - let little_endian = if arguments.len() > 1 { - arguments.get(1) - } else { - Value::Boolean(false) - }; + let little_endian = to_boolean(agent, arguments.get(1)); // 1. Let v be the this value. // 3. Return ? GetViewValue(v, byteOffset, littleEndian, uint16). get_view_value::(agent, gc, this_value, byte_offset, little_endian) @@ -407,11 +388,7 @@ impl DataViewPrototype { ) -> JsResult { let byte_offset = arguments.get(0); // 2. If littleEndian is not present, set littleEndian to false. - let little_endian = if arguments.len() > 1 { - arguments.get(1) - } else { - Value::Boolean(false) - }; + let little_endian = to_boolean(agent, arguments.get(1)); // 1. Let v be the this value. // 3. Return ? GetViewValue(v, byteOffset, littleEndian, uint32). get_view_value::(agent, gc, this_value, byte_offset, little_endian) @@ -426,7 +403,7 @@ impl DataViewPrototype { ) -> JsResult { let byte_offset = arguments.get(0); let value = arguments.get(1); - let little_endian = arguments.get(2); + let little_endian = to_boolean(agent, arguments.get(2)); // 1. Let v be the this value. // 2. Return ? SetViewValue(v, byteOffset, littleEndian, bigint64, value). set_view_value::(agent, gc, this_value, byte_offset, little_endian, value) @@ -441,7 +418,7 @@ impl DataViewPrototype { ) -> JsResult { let byte_offset = arguments.get(0); let value = arguments.get(1); - let little_endian = arguments.get(2); + let little_endian = to_boolean(agent, arguments.get(2)); // 1. Let v be the this value. // 2. Return ? SetViewValue(v, byteOffset, littleEndian, biguint64, value). set_view_value::(agent, gc, this_value, byte_offset, little_endian, value) @@ -457,11 +434,7 @@ impl DataViewPrototype { let byte_offset = arguments.get(0); let value = arguments.get(1); // 2. If littleEndian is not present, set littleEndian to false. - let little_endian = if arguments.len() > 2 { - arguments.get(2) - } else { - Value::Boolean(false) - }; + let little_endian = to_boolean(agent, arguments.get(2)); // 1. Let v be the this value. // 2. Return ? SetViewValue(v, byteOffset, littleEndian, float32, value). set_view_value::(agent, gc, this_value, byte_offset, little_endian, value) @@ -477,11 +450,7 @@ impl DataViewPrototype { let byte_offset = arguments.get(0); let value = arguments.get(1); // 2. If littleEndian is not present, set littleEndian to false. - let little_endian = if arguments.len() > 2 { - arguments.get(2) - } else { - Value::Boolean(false) - }; + let little_endian = to_boolean(agent, arguments.get(2)); // 1. Let v be the this value. // 2. Return ? SetViewValue(v, byteOffset, littleEndian, float64, value). set_view_value::(agent, gc, this_value, byte_offset, little_endian, value) @@ -498,14 +467,7 @@ impl DataViewPrototype { let value = arguments.get(1); // 1. Let v be the this value. // 2. Return ? SetViewValue(v, byteOffset, true, int8, value). - set_view_value::( - agent, - gc, - this_value, - byte_offset, - Value::Boolean(true), - value, - ) + set_view_value::(agent, gc, this_value, byte_offset, true, value) } /// ### [25.3.4.20 DataView.prototype.setInt16 ( byteOffset, value \[ , littleEndian \] )](https://tc39.es/ecma262/#sec-dataview.prototype.setint16) @@ -518,11 +480,7 @@ impl DataViewPrototype { let byte_offset = arguments.get(0); let value = arguments.get(1); // 2. If littleEndian is not present, set littleEndian to false. - let little_endian = if arguments.len() > 2 { - arguments.get(2) - } else { - Value::Boolean(false) - }; + let little_endian = to_boolean(agent, arguments.get(2)); // 1. Let v be the this value. // 2. Return ? SetViewValue(v, byteOffset, littleEndian, int16, value). set_view_value::(agent, gc, this_value, byte_offset, little_endian, value) @@ -538,11 +496,7 @@ impl DataViewPrototype { let byte_offset = arguments.get(0); let value = arguments.get(1); // 2. If littleEndian is not present, set littleEndian to false. - let little_endian = if arguments.len() > 2 { - arguments.get(2) - } else { - Value::Boolean(false) - }; + let little_endian = to_boolean(agent, arguments.get(2)); // 1. Let v be the this value. // 2. Return ? SetViewValue(v, byteOffset, littleEndian, int32, value). set_view_value::(agent, gc, this_value, byte_offset, little_endian, value) @@ -559,14 +513,7 @@ impl DataViewPrototype { let value = arguments.get(1); // 1. Let v be the this value. // 2. Return ? SetViewValue(v, byteOffset, true, uint8, value). - set_view_value::( - agent, - gc, - this_value, - byte_offset, - Value::Boolean(true), - value, - ) + set_view_value::(agent, gc, this_value, byte_offset, true, value) } /// ### [25.3.4.23 DataView.prototype.setUint16 ( byteOffset, value \[ , littleEndian \] )](https://tc39.es/ecma262/#sec-dataview.prototype.setuint16) @@ -579,11 +526,7 @@ impl DataViewPrototype { let byte_offset = arguments.get(0); let value = arguments.get(1); // 2. If littleEndian is not present, set littleEndian to false. - let little_endian = if arguments.len() > 2 { - arguments.get(2) - } else { - Value::Boolean(false) - }; + let little_endian = to_boolean(agent, arguments.get(2)); // 1. Let v be the this value. // 2. Return ? SetViewValue(v, byteOffset, littleEndian, uint16, value). set_view_value::(agent, gc, this_value, byte_offset, little_endian, value) @@ -599,11 +542,7 @@ impl DataViewPrototype { let byte_offset = arguments.get(0); let value = arguments.get(1); // 2. If littleEndian is not present, set littleEndian to false. - let little_endian = if arguments.len() > 2 { - arguments.get(2) - } else { - Value::Boolean(false) - }; + let little_endian = to_boolean(agent, arguments.get(2)); // 1. Let v be the this value. // 2. Return ? SetViewValue(v, byteOffset, littleEndian, uint32, value). set_view_value::(agent, gc, this_value, byte_offset, little_endian, value) diff --git a/nova_vm/src/ecmascript/types/language/bigint.rs b/nova_vm/src/ecmascript/types/language/bigint.rs index f93fcb9b8..c9ee08d9f 100644 --- a/nova_vm/src/ecmascript/types/language/bigint.rs +++ b/nova_vm/src/ecmascript/types/language/bigint.rs @@ -520,7 +520,6 @@ impl BigInt { } } - /// ### [ /// ### [6.1.6.2.13 BigInt::equal ( x, y )](https://tc39.es/ecma262/#sec-numeric-types-bigint-equal) /// /// The abstract operation BigInt::equal takes arguments x (a BigInt) and y diff --git a/nova_vm/src/ecmascript/types/spec/data_block.rs b/nova_vm/src/ecmascript/types/spec/data_block.rs index f51c98d94..91c96cecc 100644 --- a/nova_vm/src/ecmascript/types/spec/data_block.rs +++ b/nova_vm/src/ecmascript/types/spec/data_block.rs @@ -11,6 +11,10 @@ use std::{ use crate::{ ecmascript::{ + abstract_operations::type_conversion::{ + to_big_int64, to_big_uint64, to_int16, to_int32, to_int8, to_uint16, to_uint32, + to_uint8, + }, execution::{agent::ExceptionType, Agent, JsResult}, types::{BigInt, IntoValue, Value}, }, @@ -68,7 +72,7 @@ mod private { } pub trait Viewable: private::Sealed + Copy { - fn is_bigint_type() -> bool; + const IS_BIGINT: bool; fn into_be_value(self, agent: &mut Agent) -> Value; fn into_le_value(self, agent: &mut Agent) -> Value; fn from_le_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self; @@ -76,9 +80,7 @@ pub trait Viewable: private::Sealed + Copy { } impl Viewable for u8 { - fn is_bigint_type() -> bool { - false - } + const IS_BIGINT: bool = false; fn into_be_value(self, _: &mut Agent) -> Value { Value::from(self.to_be()) @@ -89,17 +91,15 @@ impl Viewable for u8 { } fn from_be_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { - value.to_real(agent, gc).unwrap() as Self + to_uint8(agent, gc, value).unwrap().to_be() } fn from_le_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { - value.to_real(agent, gc).unwrap() as Self + to_uint8(agent, gc, value).unwrap().to_le() } } impl Viewable for i8 { - fn is_bigint_type() -> bool { - false - } + const IS_BIGINT: bool = false; fn into_be_value(self, _: &mut Agent) -> Value { Value::from(self.to_be()) @@ -110,17 +110,15 @@ impl Viewable for i8 { } fn from_be_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { - value.to_real(agent, gc).unwrap() as Self + to_int8(agent, gc, value).unwrap().to_be() } fn from_le_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { - value.to_real(agent, gc).unwrap() as Self + to_int8(agent, gc, value).unwrap().to_le() } } impl Viewable for u16 { - fn is_bigint_type() -> bool { - false - } + const IS_BIGINT: bool = false; fn into_be_value(self, _: &mut Agent) -> Value { Value::from(self.to_be()) @@ -131,17 +129,15 @@ impl Viewable for u16 { } fn from_be_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { - (value.to_real(agent, gc).unwrap() as Self).to_be() + to_uint16(agent, gc, value).unwrap().to_be() } fn from_le_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { - (value.to_real(agent, gc).unwrap() as Self).to_le() + to_uint16(agent, gc, value).unwrap().to_le() } } impl Viewable for i16 { - fn is_bigint_type() -> bool { - false - } + const IS_BIGINT: bool = false; fn into_be_value(self, _: &mut Agent) -> Value { Value::from(self.to_be()) @@ -152,17 +148,15 @@ impl Viewable for i16 { } fn from_be_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { - (value.to_real(agent, gc).unwrap() as Self).to_be() + to_int16(agent, gc, value).unwrap().to_be() } fn from_le_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { - (value.to_real(agent, gc).unwrap() as Self).to_le() + to_int16(agent, gc, value).unwrap().to_le() } } impl Viewable for u32 { - fn is_bigint_type() -> bool { - false - } + const IS_BIGINT: bool = false; fn into_be_value(self, _: &mut Agent) -> Value { Value::from(self.to_be()) @@ -173,17 +167,15 @@ impl Viewable for u32 { } fn from_be_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { - (value.to_real(agent, gc).unwrap() as Self).to_be() + to_uint32(agent, gc, value).unwrap().to_be() } fn from_le_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { - (value.to_real(agent, gc).unwrap() as Self).to_le() + to_uint32(agent, gc, value).unwrap().to_le() } } impl Viewable for i32 { - fn is_bigint_type() -> bool { - false - } + const IS_BIGINT: bool = false; fn into_be_value(self, _: &mut Agent) -> Value { Value::from(self.to_be()) @@ -194,17 +186,15 @@ impl Viewable for i32 { } fn from_be_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { - (value.to_real(agent, gc).unwrap() as Self).to_be() + to_int32(agent, gc, value).unwrap().to_be() } fn from_le_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { - (value.to_real(agent, gc).unwrap() as Self).to_le() + to_int32(agent, gc, value).unwrap().to_le() } } impl Viewable for u64 { - fn is_bigint_type() -> bool { - true - } + const IS_BIGINT: bool = true; fn into_be_value(self, agent: &mut Agent) -> Value { BigInt::from_u64(agent, self.to_be()).into_value() @@ -215,29 +205,15 @@ impl Viewable for u64 { } fn from_be_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { - match value.to_bigint(agent, gc).unwrap() { - BigInt::SmallBigInt(value) => (value.into_i64() as Self).to_be(), - BigInt::BigInt(value) => { - let value: Self = agent[value].data.clone().try_into().unwrap(); - value.to_be() - } - } + to_big_uint64(agent, gc, value).unwrap().to_be() } fn from_le_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { - match value.to_bigint(agent, gc).unwrap() { - BigInt::SmallBigInt(value) => (value.into_i64() as Self).to_le(), - BigInt::BigInt(value) => { - let value: Self = agent[value].data.clone().try_into().unwrap(); - value.to_le() - } - } + to_big_uint64(agent, gc, value).unwrap().to_le() } } impl Viewable for i64 { - fn is_bigint_type() -> bool { - true - } + const IS_BIGINT: bool = true; fn into_be_value(self, agent: &mut Agent) -> Value { BigInt::from_i64(agent, self.to_be()).into_value() @@ -248,29 +224,15 @@ impl Viewable for i64 { } fn from_be_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { - match value.to_bigint(agent, gc).unwrap() { - BigInt::SmallBigInt(value) => value.into_i64().to_be(), - BigInt::BigInt(value) => { - let value: Self = agent[value].data.clone().try_into().unwrap(); - value.to_be() - } - } + to_big_int64(agent, gc, value).unwrap().to_be() } fn from_le_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self { - match value.to_bigint(agent, gc).unwrap() { - BigInt::SmallBigInt(value) => value.into_i64().to_le(), - BigInt::BigInt(value) => { - let value: Self = agent[value].data.clone().try_into().unwrap(); - value.to_le() - } - } + to_big_int64(agent, gc, value).unwrap().to_le() } } impl Viewable for f32 { - fn is_bigint_type() -> bool { - false - } + const IS_BIGINT: bool = false; fn into_be_value(self, _: &mut Agent) -> Value { Value::from(Self::from_ne_bytes(self.to_be_bytes())) @@ -289,9 +251,7 @@ impl Viewable for f32 { } } impl Viewable for f64 { - fn is_bigint_type() -> bool { - false - } + const IS_BIGINT: bool = false; fn into_be_value(self, agent: &mut Agent) -> Value { Value::from_f64(agent, Self::from_ne_bytes(self.to_be_bytes())) From 0cd1dcb946c8f5ea09f8c1772c15e94966f09dd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20Sj=C3=B6green?= Date: Mon, 4 Nov 2024 13:42:10 +0100 Subject: [PATCH 4/9] chore: Update metrics --- tests/expectations.json | 9 --------- tests/metrics.json | 4 ++-- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/tests/expectations.json b/tests/expectations.json index c4efcbae2..3f6c5b7ae 100644 --- a/tests/expectations.json +++ b/tests/expectations.json @@ -1355,35 +1355,26 @@ "built-ins/DataView/prototype/setInt16/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setInt16/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setInt16/detached-buffer.js": "CRASH", - "built-ins/DataView/prototype/setInt16/set-values-little-endian-order.js": "CRASH", - "built-ins/DataView/prototype/setInt16/set-values-return-undefined.js": "CRASH", "built-ins/DataView/prototype/setInt16/this-has-no-dataview-internal.js": "CRASH", "built-ins/DataView/prototype/setInt32/detached-buffer-after-number-value.js": "CRASH", "built-ins/DataView/prototype/setInt32/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setInt32/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setInt32/detached-buffer.js": "CRASH", - "built-ins/DataView/prototype/setInt32/set-values-little-endian-order.js": "CRASH", - "built-ins/DataView/prototype/setInt32/set-values-return-undefined.js": "CRASH", "built-ins/DataView/prototype/setInt32/this-has-no-dataview-internal.js": "CRASH", "built-ins/DataView/prototype/setInt8/detached-buffer-after-number-value.js": "CRASH", "built-ins/DataView/prototype/setInt8/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setInt8/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setInt8/detached-buffer.js": "CRASH", - "built-ins/DataView/prototype/setInt8/set-values-return-undefined.js": "CRASH", "built-ins/DataView/prototype/setInt8/this-has-no-dataview-internal.js": "CRASH", "built-ins/DataView/prototype/setUint16/detached-buffer-after-number-value.js": "CRASH", "built-ins/DataView/prototype/setUint16/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setUint16/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setUint16/detached-buffer.js": "CRASH", - "built-ins/DataView/prototype/setUint16/set-values-little-endian-order.js": "CRASH", - "built-ins/DataView/prototype/setUint16/set-values-return-undefined.js": "CRASH", "built-ins/DataView/prototype/setUint16/this-has-no-dataview-internal.js": "CRASH", "built-ins/DataView/prototype/setUint32/detached-buffer-after-number-value.js": "CRASH", "built-ins/DataView/prototype/setUint32/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setUint32/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setUint32/detached-buffer.js": "CRASH", - "built-ins/DataView/prototype/setUint32/set-values-little-endian-order.js": "CRASH", - "built-ins/DataView/prototype/setUint32/set-values-return-undefined.js": "CRASH", "built-ins/DataView/prototype/setUint32/this-has-no-dataview-internal.js": "CRASH", "built-ins/DataView/prototype/setUint8/detached-buffer-after-number-value.js": "CRASH", "built-ins/DataView/prototype/setUint8/detached-buffer-after-toindex-byteoffset.js": "CRASH", diff --git a/tests/metrics.json b/tests/metrics.json index 3966f8467..a9d3c0873 100644 --- a/tests/metrics.json +++ b/tests/metrics.json @@ -1,8 +1,8 @@ { "results": { "crash": 15859, - "fail": 8390, - "pass": 20999, + "fail": 8381, + "pass": 21008, "skip": 40, "timeout": 3, "unresolved": 0 From a8cae0bd7ad5a3c95fdcb0e0bdf7249864c8abdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20Sj=C3=B6green?= Date: Mon, 4 Nov 2024 13:43:44 +0100 Subject: [PATCH 5/9] chore: write comment --- nova_vm/src/ecmascript/types/spec/data_block.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nova_vm/src/ecmascript/types/spec/data_block.rs b/nova_vm/src/ecmascript/types/spec/data_block.rs index 91c96cecc..94526879f 100644 --- a/nova_vm/src/ecmascript/types/spec/data_block.rs +++ b/nova_vm/src/ecmascript/types/spec/data_block.rs @@ -77,6 +77,10 @@ pub trait Viewable: private::Sealed + Copy { fn into_le_value(self, agent: &mut Agent) -> Value; fn from_le_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self; fn from_be_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self; + + // TODO: Consider adding the following methods if needed + // fn into_ne_value(self, agent: &mut Agent) -> Value; + // fn from_ne_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self; } impl Viewable for u8 { From 9e01e108787eb03341664b89be3e7a092baaab52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20Sj=C3=B6green?= Date: Mon, 4 Nov 2024 14:13:21 +0100 Subject: [PATCH 6/9] fix: Behaviour of `BigInt` --- .../bigint_objects/bigint_constructor.rs | 9 ++++++++- nova_vm/src/ecmascript/types/language/number.rs | 8 ++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/nova_vm/src/ecmascript/builtins/numbers_and_dates/bigint_objects/bigint_constructor.rs b/nova_vm/src/ecmascript/builtins/numbers_and_dates/bigint_objects/bigint_constructor.rs index f51f9d711..67e1e6dd9 100644 --- a/nova_vm/src/ecmascript/builtins/numbers_and_dates/bigint_objects/bigint_constructor.rs +++ b/nova_vm/src/ecmascript/builtins/numbers_and_dates/bigint_objects/bigint_constructor.rs @@ -77,7 +77,14 @@ impl BigIntConstructor { let value = arguments.get(0); let prim = to_primitive(agent, gc.reborrow(), value, Some(PreferredType::Number))?; if let Ok(prim) = Number::try_from(prim) { - Ok(prim.into_value()) + if !prim.is_integer(agent) { + return Err(agent.throw_exception_with_static_message( + ExceptionType::RangeError, + "Can't convert number to BigInt because it isn't an integer", + )); + } + + Ok(BigInt::from_i64(agent, prim.into_i64(agent)).into_value()) } else { to_big_int(agent, gc.reborrow(), value).map(|result| result.into_value()) } diff --git a/nova_vm/src/ecmascript/types/language/number.rs b/nova_vm/src/ecmascript/types/language/number.rs index ec41fbdc1..02332ce67 100644 --- a/nova_vm/src/ecmascript/types/language/number.rs +++ b/nova_vm/src/ecmascript/types/language/number.rs @@ -311,6 +311,14 @@ impl Number { } } + pub fn is_integer(self, agent: &impl Index) -> bool { + match self { + Number::Number(n) => agent[n].fract() == 0.0, + Number::Integer(_) => true, + Number::SmallF64(n) => n.into_f64().fract() == 0.0, + } + } + pub fn is_nonzero(self, agent: &impl Index) -> bool { match self { Number::Number(n) => 0.0 != agent[n], From f09e4ef655af4980d6f5f55e3605b1857f50fc0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20Sj=C3=B6green?= Date: Mon, 4 Nov 2024 14:17:04 +0100 Subject: [PATCH 7/9] chore: update expectations --- tests/expectations.json | 9 --------- tests/metrics.json | 4 ++-- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/tests/expectations.json b/tests/expectations.json index 3f6c5b7ae..bcbe30f9e 100644 --- a/tests/expectations.json +++ b/tests/expectations.json @@ -1173,7 +1173,6 @@ "built-ins/BigInt/asUintN/bigint-tobigint-toprimitive.js": "CRASH", "built-ins/BigInt/asUintN/bigint-tobigint-wrapped-values.js": "FAIL", "built-ins/BigInt/asUintN/bigint-tobigint.js": "CRASH", - "built-ins/BigInt/call-value-of-when-to-string-present.js": "FAIL", "built-ins/BigInt/constructor-coercion.js": "FAIL", "built-ins/BigInt/constructor-empty-string.js": "CRASH", "built-ins/BigInt/constructor-from-binary-string.js": "CRASH", @@ -1181,11 +1180,7 @@ "built-ins/BigInt/constructor-from-hex-string.js": "CRASH", "built-ins/BigInt/constructor-from-octal-string.js": "CRASH", "built-ins/BigInt/constructor-from-string-syntax-errors.js": "CRASH", - "built-ins/BigInt/constructor-integer.js": "FAIL", "built-ins/BigInt/constructor-trailing-leading-spaces.js": "CRASH", - "built-ins/BigInt/infinity-throws-rangeerror.js": "FAIL", - "built-ins/BigInt/nan-throws-rangeerror.js": "FAIL", - "built-ins/BigInt/negative-infinity-throws.rangeerror.js": "FAIL", "built-ins/BigInt/non-integer-rangeerror.js": "FAIL", "built-ins/BigInt/prototype/toString/a-z.js": "FAIL", "built-ins/BigInt/prototype/toString/default-radix.js": "CRASH", @@ -1312,7 +1307,6 @@ "built-ins/DataView/prototype/setBigInt64/detached-buffer-after-toindex-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setBigInt64/detached-buffer-before-outofrange-byteoffset.js": "CRASH", "built-ins/DataView/prototype/setBigInt64/detached-buffer.js": "CRASH", - "built-ins/DataView/prototype/setBigInt64/set-values-return-undefined.js": "CRASH", "built-ins/DataView/prototype/setBigInt64/this-has-no-dataview-internal.js": "CRASH", "built-ins/DataView/prototype/setFloat16/detached-buffer-after-number-value.js": "CRASH", "built-ins/DataView/prototype/setFloat16/detached-buffer-after-toindex-byteoffset.js": "CRASH", @@ -2919,9 +2913,7 @@ "built-ins/Object/prototype/toString/symbol-tag-array-builtin.js": "CRASH", "built-ins/Object/prototype/toString/symbol-tag-generators-builtin.js": "FAIL", "built-ins/Object/prototype/toString/symbol-tag-map-builtin.js": "CRASH", - "built-ins/Object/prototype/toString/symbol-tag-non-str-bigint.js": "FAIL", "built-ins/Object/prototype/toString/symbol-tag-non-str-proxy-function.js": "CRASH", - "built-ins/Object/prototype/toString/symbol-tag-override-bigint.js": "FAIL", "built-ins/Object/prototype/toString/symbol-tag-override-instances.js": "FAIL", "built-ins/Object/prototype/toString/symbol-tag-override-primitives.js": "FAIL", "built-ins/Object/prototype/toString/symbol-tag-set-builtin.js": "CRASH", @@ -18179,7 +18171,6 @@ "language/expressions/template-literal/tv-template-tail.js": "CRASH", "language/expressions/template-literal/tv-utf16-escape-sequence.js": "CRASH", "language/expressions/template-literal/tv-zwnbsp.js": "CRASH", - "language/expressions/typeof/bigint.js": "FAIL", "language/expressions/typeof/built-in-exotic-objects-no-call.js": "CRASH", "language/expressions/typeof/null.js": "CRASH", "language/expressions/typeof/proxy.js": "CRASH", diff --git a/tests/metrics.json b/tests/metrics.json index a9d3c0873..69284a0e3 100644 --- a/tests/metrics.json +++ b/tests/metrics.json @@ -1,8 +1,8 @@ { "results": { "crash": 15859, - "fail": 8381, - "pass": 21008, + "fail": 8372, + "pass": 21017, "skip": 40, "timeout": 3, "unresolved": 0 From 2a43b41ed192d3de1740044839a81e6ec73000cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20Sj=C3=B6green?= Date: Sat, 9 Nov 2024 13:59:39 +0100 Subject: [PATCH 8/9] feat: Wrangle the bigints to wrapping i64 and u64 respectively --- .../abstract_operations/type_conversion.rs | 28 +++++++++++++------ .../src/ecmascript/types/spec/data_block.rs | 1 + 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/nova_vm/src/ecmascript/abstract_operations/type_conversion.rs b/nova_vm/src/ecmascript/abstract_operations/type_conversion.rs index 37c0b699e..488dc44c8 100644 --- a/nova_vm/src/ecmascript/abstract_operations/type_conversion.rs +++ b/nova_vm/src/ecmascript/abstract_operations/type_conversion.rs @@ -14,6 +14,8 @@ //! The BigInt type has no implicit conversions in the ECMAScript language; //! programmers must call BigInt explicitly to convert values from other types. +use num_bigint::Sign; + use crate::engine::context::GcScope; use crate::{ ecmascript::{ @@ -717,7 +719,6 @@ pub(crate) fn string_to_big_int(_agent: &mut Agent, _argument: String) -> Option pub(crate) fn to_big_int64( agent: &mut Agent, gc: GcScope<'_, '_>, - argument: Value, ) -> JsResult { // 1. Let n be ? ToBigInt(argument). @@ -726,13 +727,16 @@ pub(crate) fn to_big_int64( // 2. Let int64bit be ℝ(n) modulo 2**64. match n { BigInt::BigInt(heap_big_int) => { - let int64bit = agent[heap_big_int].data.clone() % u64::MAX; // 3. If int64bit ≥ 2**63, return ℤ(int64bit - 2**64); otherwise return ℤ(int64bit). - if int64bit >= i64::MAX.into() { - Ok((int64bit - u64::MAX).try_into().unwrap()) + let big_int = &agent[heap_big_int].data; + let int64bit = big_int.iter_u64_digits().next().unwrap_or(0); + let int64bit = if big_int.sign() == Sign::Minus { + u64::MAX - int64bit + 1 } else { - Ok(int64bit.try_into().unwrap()) - } + int64bit + }; + let int64bit = i64::from_ne_bytes(int64bit.to_ne_bytes()); + Ok(int64bit) } BigInt::SmallBigInt(small_big_int) => { let int64bit = small_big_int.into_i64(); @@ -751,7 +755,6 @@ pub(crate) fn to_big_int64( pub(crate) fn to_big_uint64( agent: &mut Agent, gc: GcScope<'_, '_>, - argument: Value, ) -> JsResult { // 1. Let n be ? ToBigInt(argument). @@ -760,8 +763,15 @@ pub(crate) fn to_big_uint64( // 2. Let int64bit be ℝ(n) modulo 2**64. match n { BigInt::BigInt(heap_big_int) => { - let int64bit = agent[heap_big_int].data.clone() % u64::MAX; - Ok(int64bit.try_into().unwrap()) + // https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=7d82adfe85f7d0ed44ab37a7b2cdf092 + let big_int = &agent[heap_big_int].data; + let int64bit = big_int.iter_u64_digits().next().unwrap_or(0); + let int64bit = if big_int.sign() == Sign::Minus { + u64::MAX - int64bit + 1 + } else { + int64bit + }; + Ok(int64bit) } BigInt::SmallBigInt(small_big_int) => { let int64bit = small_big_int.into_i64(); diff --git a/nova_vm/src/ecmascript/types/spec/data_block.rs b/nova_vm/src/ecmascript/types/spec/data_block.rs index 94526879f..e8c445497 100644 --- a/nova_vm/src/ecmascript/types/spec/data_block.rs +++ b/nova_vm/src/ecmascript/types/spec/data_block.rs @@ -73,6 +73,7 @@ mod private { pub trait Viewable: private::Sealed + Copy { const IS_BIGINT: bool; + fn into_be_value(self, agent: &mut Agent) -> Value; fn into_le_value(self, agent: &mut Agent) -> Value; fn from_le_value(agent: &mut Agent, gc: GcScope<'_, '_>, value: Value) -> Self; From 6e35cafc4536f1d18cb70a4ab7ac9b99842a7b7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20Sj=C3=B6green?= Date: Sat, 9 Nov 2024 14:07:35 +0100 Subject: [PATCH 9/9] chore: Update metrics --- tests/metrics.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/metrics.json b/tests/metrics.json index 69284a0e3..7cc01e30b 100644 --- a/tests/metrics.json +++ b/tests/metrics.json @@ -1,8 +1,8 @@ { "results": { - "crash": 15859, + "crash": 15846, "fail": 8372, - "pass": 21017, + "pass": 21030, "skip": 40, "timeout": 3, "unresolved": 0