2020-12-02 20:49:31 +00:00
/*
2022-05-02 18:54:39 +00:00
* Copyright ( c ) 2020 - 2022 , Linus Groh < linusg @ serenityos . org >
2020-12-02 20:49:31 +00:00
*
2021-04-22 08:24:48 +00:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-12-02 20:49:31 +00:00
*/
# pragma once
# include <AK/ByteBuffer.h>
2021-07-11 12:57:54 +00:00
# include <AK/Function.h>
2021-05-17 17:09:31 +00:00
# include <AK/Variant.h>
2023-01-28 16:26:03 +00:00
# include <LibJS/Runtime/BigInt.h>
2021-10-09 11:31:13 +00:00
# include <LibJS/Runtime/Completion.h>
2021-06-13 22:57:15 +00:00
# include <LibJS/Runtime/GlobalObject.h>
2020-12-02 20:49:31 +00:00
# include <LibJS/Runtime/Object.h>
namespace JS {
2021-06-16 23:43:24 +00:00
struct ClampedU8 {
} ;
2021-07-11 12:57:54 +00:00
// 25.1.1 Notation (read-modify-write modification function), https://tc39.es/ecma262/#sec-arraybuffer-notation
using ReadWriteModifyFunction = Function < ByteBuffer ( ByteBuffer , ByteBuffer ) > ;
2023-06-30 17:00:56 +00:00
enum class PreserveResizability {
FixedLength ,
PreserveResizability
} ;
2023-09-11 08:35:03 +00:00
// 6.2.9 Data Blocks, https://tc39.es/ecma262/#sec-data-blocks
struct DataBlock {
enum class Shared {
No ,
Yes ,
} ;
ByteBuffer & buffer ( )
{
ByteBuffer * ptr { nullptr } ;
byte_buffer . visit ( [ & ] ( Empty ) { VERIFY_NOT_REACHED ( ) ; } , [ & ] ( auto * pointer ) { ptr = pointer ; } , [ & ] ( auto & value ) { ptr = & value ; } ) ;
return * ptr ;
}
ByteBuffer const & buffer ( ) const { return const_cast < DataBlock * > ( this ) - > buffer ( ) ; }
2024-02-27 16:00:44 +00:00
size_t size ( ) const
{
return byte_buffer . visit (
[ ] ( Empty ) - > size_t { return 0u ; } ,
[ ] ( ByteBuffer const & buffer ) { return buffer . size ( ) ; } ,
[ ] ( ByteBuffer const * buffer ) { return buffer - > size ( ) ; } ) ;
}
2023-09-11 08:35:03 +00:00
Variant < Empty , ByteBuffer , ByteBuffer * > byte_buffer ;
Shared is_shared = { Shared : : No } ;
} ;
2020-12-02 20:49:31 +00:00
class ArrayBuffer : public Object {
JS_OBJECT ( ArrayBuffer , Object ) ;
2024-11-14 15:01:23 +00:00
GC_DECLARE_ALLOCATOR ( ArrayBuffer ) ;
2020-12-02 20:49:31 +00:00
public :
2024-11-14 15:01:23 +00:00
static ThrowCompletionOr < GC : : Ref < ArrayBuffer > > create ( Realm & , size_t ) ;
static GC : : Ref < ArrayBuffer > create ( Realm & , ByteBuffer ) ;
static GC : : Ref < ArrayBuffer > create ( Realm & , ByteBuffer * ) ;
2020-12-02 20:49:31 +00:00
2022-03-14 16:25:06 +00:00
virtual ~ ArrayBuffer ( ) override = default ;
2020-12-02 20:49:31 +00:00
2024-02-27 16:00:44 +00:00
size_t byte_length ( ) const { return m_data_block . size ( ) ; }
2023-06-28 06:27:43 +00:00
// [[ArrayBufferData]]
2023-09-11 08:35:03 +00:00
ByteBuffer & buffer ( ) { return m_data_block . buffer ( ) ; }
ByteBuffer const & buffer ( ) const { return m_data_block . buffer ( ) ; }
2020-12-02 20:49:31 +00:00
2023-10-14 23:10:55 +00:00
// [[ArrayBufferMaxByteLength]]
size_t max_byte_length ( ) const { return m_max_byte_length . value ( ) ; }
void set_max_byte_length ( size_t max_byte_length ) { m_max_byte_length = max_byte_length ; }
2021-10-09 11:31:13 +00:00
// Used by allocate_array_buffer() to attach the data block after construction
2023-09-11 08:35:03 +00:00
void set_data_block ( DataBlock block ) { m_data_block = move ( block ) ; }
2021-10-09 11:31:13 +00:00
2021-06-10 19:44:17 +00:00
Value detach_key ( ) const { return m_detach_key ; }
2021-06-10 21:59:24 +00:00
void set_detach_key ( Value detach_key ) { m_detach_key = detach_key ; }
2023-09-11 08:35:03 +00:00
void detach_buffer ( ) { m_data_block . byte_buffer = Empty { } ; }
2023-06-28 05:20:44 +00:00
2024-08-20 14:29:45 +00:00
// 25.1.3.4 IsDetachedBuffer ( arrayBuffer ), https://tc39.es/ecma262/#sec-isdetachedbuffer
2023-06-28 05:20:44 +00:00
bool is_detached ( ) const
{
// 1. If arrayBuffer.[[ArrayBufferData]] is null, return true.
2023-09-11 08:35:03 +00:00
if ( m_data_block . byte_buffer . has < Empty > ( ) )
2023-06-28 05:20:44 +00:00
return true ;
// 2. Return false.
return false ;
}
2021-06-10 19:44:17 +00:00
2024-08-20 14:29:45 +00:00
// 25.1.3.9 IsFixedLengthArrayBuffer ( arrayBuffer ), https://tc39.es/ecma262/#sec-isfixedlengtharraybuffer
2023-10-14 23:10:55 +00:00
bool is_fixed_length ( ) const
{
// 1. If arrayBuffer has an [[ArrayBufferMaxByteLength]] internal slot, return false.
if ( m_max_byte_length . has_value ( ) )
return false ;
// 2. Return true.
return true ;
}
2023-10-14 15:20:23 +00:00
// 25.2.2.2 IsSharedArrayBuffer ( obj ), https://tc39.es/ecma262/#sec-issharedarraybuffer
2023-09-11 08:35:03 +00:00
bool is_shared_array_buffer ( ) const
{
// 1. Let bufferData be obj.[[ArrayBufferData]].
// 2. If bufferData is null, return false.
if ( m_data_block . byte_buffer . has < Empty > ( ) )
return false ;
// 3. If bufferData is a Data Block, return false.
if ( m_data_block . is_shared = = DataBlock : : Shared : : No )
return false ;
// 4. Assert: bufferData is a Shared Data Block.
VERIFY ( m_data_block . is_shared = = DataBlock : : Shared : : Yes ) ;
// 5. Return true.
return true ;
}
2021-06-13 22:57:15 +00:00
enum Order {
SeqCst ,
Unordered
} ;
template < typename type >
2023-11-26 09:33:56 +00:00
Value get_value ( size_t byte_index , bool is_typed_array , Order , bool is_little_endian = true ) ;
2021-06-13 23:02:53 +00:00
template < typename type >
2023-11-26 09:33:56 +00:00
void set_value ( size_t byte_index , Value value , bool is_typed_array , Order , bool is_little_endian = true ) ;
2021-07-11 12:57:54 +00:00
template < typename T >
2023-11-26 09:33:56 +00:00
Value get_modify_set_value ( size_t byte_index , Value value , ReadWriteModifyFunction operation , bool is_little_endian = true ) ;
2021-06-13 22:57:15 +00:00
2020-12-02 20:49:31 +00:00
private :
2022-08-28 21:51:28 +00:00
ArrayBuffer ( ByteBuffer buffer , Object & prototype ) ;
ArrayBuffer ( ByteBuffer * buffer , Object & prototype ) ;
2021-06-10 21:59:24 +00:00
virtual void visit_edges ( Visitor & ) override ;
2023-09-11 08:35:03 +00:00
DataBlock m_data_block ;
2023-10-14 23:10:55 +00:00
Optional < size_t > m_max_byte_length ;
2021-06-10 19:44:17 +00:00
// The various detach related members of ArrayBuffer are not used by any ECMA262 functionality,
// but are required to be available for the use of various harnesses like the Test262 test runner.
Value m_detach_key ;
2020-12-02 20:49:31 +00:00
} ;
2023-09-11 08:35:03 +00:00
ThrowCompletionOr < DataBlock > create_byte_data_block ( VM & vm , size_t size ) ;
2023-09-12 00:03:42 +00:00
void copy_data_block_bytes ( ByteBuffer & to_block , u64 to_index , ByteBuffer const & from_block , u64 from_index , u64 count ) ;
2023-10-14 23:10:55 +00:00
ThrowCompletionOr < ArrayBuffer * > allocate_array_buffer ( VM & , FunctionObject & constructor , size_t byte_length , Optional < size_t > const & max_byte_length = { } ) ;
2024-08-20 14:29:45 +00:00
ThrowCompletionOr < ArrayBuffer * > array_buffer_copy_and_detach ( VM & , ArrayBuffer & array_buffer , Value new_length , PreserveResizability preserve_resizability ) ;
2022-08-21 16:25:31 +00:00
ThrowCompletionOr < void > detach_array_buffer ( VM & , ArrayBuffer & array_buffer , Optional < Value > key = { } ) ;
2023-10-14 23:10:55 +00:00
ThrowCompletionOr < Optional < size_t > > get_array_buffer_max_byte_length_option ( VM & , Value options ) ;
2022-08-21 16:25:31 +00:00
ThrowCompletionOr < ArrayBuffer * > clone_array_buffer ( VM & , ArrayBuffer & source_buffer , size_t source_byte_offset , size_t source_length ) ;
2024-11-14 15:01:23 +00:00
ThrowCompletionOr < GC : : Ref < ArrayBuffer > > allocate_shared_array_buffer ( VM & , FunctionObject & constructor , size_t byte_length ) ;
2021-10-09 11:31:13 +00:00
2024-02-27 14:19:58 +00:00
// 25.1.3.2 ArrayBufferByteLength ( arrayBuffer, order ), https://tc39.es/ecma262/#sec-arraybufferbytelength
inline size_t array_buffer_byte_length ( ArrayBuffer const & array_buffer , ArrayBuffer : : Order )
{
// FIXME: 1. If IsSharedArrayBuffer(arrayBuffer) is true and arrayBuffer has an [[ArrayBufferByteLengthData]] internal slot, then
// FIXME: a. Let bufferByteLengthBlock be arrayBuffer.[[ArrayBufferByteLengthData]].
// FIXME: b. Let rawLength be GetRawBytesFromSharedBlock(bufferByteLengthBlock, 0, biguint64, true, order).
// FIXME: c. Let isLittleEndian be the value of the [[LittleEndian]] field of the surrounding agent's Agent Record.
// FIXME: d. Return ℝ (RawBytesToNumeric(biguint64, rawLength, isLittleEndian)).
// 2. Assert: IsDetachedBuffer(arrayBuffer) is false.
VERIFY ( ! array_buffer . is_detached ( ) ) ;
// 3. Return arrayBuffer.[[ArrayBufferByteLength]].
return array_buffer . byte_length ( ) ;
}
2024-08-20 14:29:45 +00:00
// 25.1.3.14 RawBytesToNumeric ( type, rawBytes, isLittleEndian ), https://tc39.es/ecma262/#sec-rawbytestonumeric
2024-11-09 21:29:03 +00:00
// 5 RawBytesToNumeric ( type, rawBytes, isLittleEndian ), https://tc39.es/proposal-float16array/#sec-rawbytestonumeric
2021-06-13 22:57:15 +00:00
template < typename T >
2023-10-05 09:53:56 +00:00
static Value raw_bytes_to_numeric ( VM & vm , Bytes raw_value , bool is_little_endian )
2021-06-13 22:57:15 +00:00
{
2023-06-29 06:13:49 +00:00
// 1. Let elementSize be the Element Size value specified in Table 70 for Element Type type.
2024-11-09 21:29:03 +00:00
// NOTE: Used in step 7, but not needed with our implementation of that step.
2023-06-29 06:13:49 +00:00
// 2. If isLittleEndian is false, reverse the order of the elements of rawBytes.
2021-06-13 22:57:15 +00:00
if ( ! is_little_endian ) {
VERIFY ( raw_value . size ( ) % 2 = = 0 ) ;
for ( size_t i = 0 ; i < raw_value . size ( ) / 2 ; + + i )
swap ( raw_value [ i ] , raw_value [ raw_value . size ( ) - 1 - i ] ) ;
}
2023-06-29 06:13:49 +00:00
2021-06-16 23:43:24 +00:00
using UnderlyingBufferDataType = Conditional < IsSame < ClampedU8 , T > , u8 , T > ;
2024-11-09 21:29:03 +00:00
// 3. If type is Float16, then
if constexpr ( IsSame < UnderlyingBufferDataType , f16 > ) {
// a. Let value be the byte elements of rawBytes concatenated and interpreted as a little-endian bit string encoding of an IEEE 754-2019 binary16 value.
f16 value ;
raw_value . copy_to ( { & value , sizeof ( f16 ) } ) ;
// b. If value is an IEEE 754-2019 binary16 NaN value, return the NaN Number value.
if ( isnan ( static_cast < double > ( value ) ) )
return js_nan ( ) ;
// c. Return the Number value that corresponds to value.
return Value ( value ) ;
}
// 4. If type is Float32, then
2021-06-16 23:43:24 +00:00
if constexpr ( IsSame < UnderlyingBufferDataType , float > ) {
2023-06-29 06:13:49 +00:00
// a. Let value be the byte elements of rawBytes concatenated and interpreted as a little-endian bit string encoding of an IEEE 754-2019 binary32 value.
2021-06-13 22:57:15 +00:00
float value ;
2023-10-05 09:53:56 +00:00
raw_value . copy_to ( { & value , sizeof ( float ) } ) ;
2023-06-29 06:13:49 +00:00
// b. If value is an IEEE 754-2019 binary32 NaN value, return the NaN Number value.
2021-06-13 22:57:15 +00:00
if ( isnan ( value ) )
return js_nan ( ) ;
2023-06-29 06:13:49 +00:00
// c. Return the Number value that corresponds to value.
2021-06-13 22:57:15 +00:00
return Value ( value ) ;
}
2023-06-29 06:13:49 +00:00
2024-11-09 21:29:03 +00:00
// 5. If type is Float64, then
2021-06-16 23:43:24 +00:00
if constexpr ( IsSame < UnderlyingBufferDataType , double > ) {
2023-06-29 06:13:49 +00:00
// a. Let value be the byte elements of rawBytes concatenated and interpreted as a little-endian bit string encoding of an IEEE 754-2019 binary64 value.
2021-06-13 22:57:15 +00:00
double value ;
2023-10-05 09:53:56 +00:00
raw_value . copy_to ( { & value , sizeof ( double ) } ) ;
2023-06-29 06:13:49 +00:00
// b. If value is an IEEE 754-2019 binary64 NaN value, return the NaN Number value.
2021-06-13 22:57:15 +00:00
if ( isnan ( value ) )
return js_nan ( ) ;
2023-06-29 06:13:49 +00:00
// c. Return the Number value that corresponds to value.
2021-06-13 22:57:15 +00:00
return Value ( value ) ;
}
2023-06-29 06:13:49 +00:00
// NOTE: Not in spec, sanity check for steps below.
2021-06-16 23:43:24 +00:00
if constexpr ( ! IsIntegral < UnderlyingBufferDataType > )
2021-06-13 22:57:15 +00:00
VERIFY_NOT_REACHED ( ) ;
2023-06-29 06:13:49 +00:00
2024-11-09 21:29:03 +00:00
// 6. If IsUnsignedElementType(type) is true, then
2023-06-29 06:13:49 +00:00
// a. Let intValue be the byte elements of rawBytes concatenated and interpreted as a bit string encoding of an unsigned little-endian binary number.
2024-11-09 21:29:03 +00:00
// 7. Else,
2023-06-29 06:13:49 +00:00
// 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.
//
// NOTE: The signed/unsigned logic above is implemented in step 7 by the IsSigned<> check, and in step 8 by JS::Value constructor overloads.
2021-06-16 23:43:24 +00:00
UnderlyingBufferDataType int_value = 0 ;
2023-10-05 09:53:56 +00:00
raw_value . copy_to ( { & int_value , sizeof ( UnderlyingBufferDataType ) } ) ;
2023-06-29 06:13:49 +00:00
2024-11-09 21:29:03 +00:00
// 8. If IsBigIntElementType(type) is true, return the BigInt value that corresponds to intValue.
2021-06-16 23:43:24 +00:00
if constexpr ( sizeof ( UnderlyingBufferDataType ) = = 8 ) {
2022-08-25 22:49:50 +00:00
if constexpr ( IsSigned < UnderlyingBufferDataType > ) {
static_assert ( IsSame < UnderlyingBufferDataType , i64 > ) ;
2022-12-06 22:03:52 +00:00
return BigInt : : create ( vm , Crypto : : SignedBigInteger { int_value } ) ;
2022-08-25 22:49:50 +00:00
} else {
static_assert ( IsOneOf < UnderlyingBufferDataType , u64 , double > ) ;
2022-12-06 22:03:52 +00:00
return BigInt : : create ( vm , Crypto : : SignedBigInteger { Crypto : : UnsignedBigInteger { int_value } } ) ;
2022-08-25 22:49:50 +00:00
}
2023-06-29 06:13:49 +00:00
}
2024-11-09 21:29:03 +00:00
// 9. Otherwise, return the Number value that corresponds to intValue.
2023-06-29 06:13:49 +00:00
else {
2021-06-13 22:57:15 +00:00
return Value ( int_value ) ;
}
}
2024-08-20 14:29:45 +00:00
// 25.1.3.16 GetValueFromBuffer ( arrayBuffer, byteIndex, type, isTypedArray, order [ , isLittleEndian ] ), https://tc39.es/ecma262/#sec-getvaluefrombuffer
2021-06-13 22:57:15 +00:00
template < typename T >
2023-11-26 09:33:56 +00:00
Value ArrayBuffer : : get_value ( size_t byte_index , [ [ maybe_unused ] ] bool is_typed_array , Order , bool is_little_endian )
2021-06-13 22:57:15 +00:00
{
2022-08-21 16:25:31 +00:00
auto & vm = this - > vm ( ) ;
2023-06-29 05:52:17 +00:00
// 1. Assert: IsDetachedBuffer(arrayBuffer) is false.
VERIFY ( ! is_detached ( ) ) ;
2022-08-21 16:25:31 +00:00
2023-06-29 05:52:17 +00:00
// 2. Assert: There are sufficient bytes in arrayBuffer starting at byteIndex to represent a value of type.
2023-09-11 08:35:03 +00:00
VERIFY ( m_data_block . buffer ( ) . bytes ( ) . slice ( byte_index ) . size ( ) > = sizeof ( T ) ) ;
2023-06-29 05:52:17 +00:00
// 3. Let block be arrayBuffer.[[ArrayBufferData]].
2023-09-11 08:35:03 +00:00
auto & block = m_data_block . buffer ( ) ;
2023-06-29 05:52:17 +00:00
// 4. Let elementSize be the Element Size value specified in Table 70 for Element Type type.
2021-06-13 22:57:15 +00:00
auto element_size = sizeof ( T ) ;
2023-10-05 09:53:56 +00:00
AK : : Array < u8 , sizeof ( T ) > raw_value { } ;
2023-06-29 05:52:17 +00:00
// FIXME: 5. If IsSharedArrayBuffer(arrayBuffer) is true, then
if ( false ) {
// FIXME: a. Let execution be the [[CandidateExecution]] field of the surrounding agent's Agent Record.
// FIXME: b. Let eventsRecord be the Agent Events Record of execution.[[EventsRecords]] whose [[AgentSignifier]] is AgentSignifier().
// FIXME: c. If isTypedArray is true and IsNoTearConfiguration(type, order) is true, let noTear be true; otherwise let noTear be false.
// FIXME: d. Let rawValue be a List of length elementSize whose elements are nondeterministically chosen byte values.
// FIXME: e. NOTE: In implementations, rawValue is the result of a non-atomic or atomic read instruction on the underlying hardware. The nondeterminism is a semantic prescription of the memory model to describe observable behaviour of hardware with weak consistency.
// FIXME: f. Let readEvent be ReadSharedMemory { [[Order]]: order, [[NoTear]]: noTear, [[Block]]: block, [[ByteIndex]]: byteIndex, [[ElementSize]]: elementSize }.
// FIXME: g. Append readEvent to eventsRecord.[[EventList]].
// FIXME: h. Append Chosen Value Record { [[Event]]: readEvent, [[ChosenValue]]: rawValue } to execution.[[ChosenValues]].
}
// 6. Else,
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).
2023-10-05 09:53:56 +00:00
block . bytes ( ) . slice ( byte_index , element_size ) . copy_to ( raw_value ) ;
2023-06-29 05:52:17 +00:00
}
// 7. Assert: The number of elements in rawValue is elementSize.
VERIFY ( raw_value . size ( ) = = element_size ) ;
// 8. If isLittleEndian is not present, set isLittleEndian to the value of the [[LittleEndian]] field of the surrounding agent's Agent Record.
// NOTE: Done by default parameter at declaration of this function.
2021-06-13 22:57:15 +00:00
2023-06-29 05:52:17 +00:00
// 9. Return RawBytesToNumeric(type, rawValue, isLittleEndian).
2023-10-05 09:53:56 +00:00
return raw_bytes_to_numeric < T > ( vm , raw_value , is_little_endian ) ;
2021-06-13 22:57:15 +00:00
}
2024-08-20 14:29:45 +00:00
// 25.1.3.17 NumericToRawBytes ( type, value, isLittleEndian ), https://tc39.es/ecma262/#sec-numerictorawbytes
2024-11-09 21:29:03 +00:00
// 6 NumericToRawBytes ( type, value, isLittleEndian ), https://tc39.es/proposal-float16array/#sec-numerictorawbytes
2021-06-13 23:02:53 +00:00
template < typename T >
2023-10-05 10:38:15 +00:00
static void numeric_to_raw_bytes ( VM & vm , Value value , bool is_little_endian , Bytes raw_bytes )
2021-06-13 23:02:53 +00:00
{
2021-10-16 18:56:14 +00:00
VERIFY ( value . is_number ( ) | | value . is_bigint ( ) ) ;
2021-06-16 23:43:24 +00:00
using UnderlyingBufferDataType = Conditional < IsSame < ClampedU8 , T > , u8 , T > ;
2023-10-05 10:38:15 +00:00
VERIFY ( raw_bytes . size ( ) = = sizeof ( UnderlyingBufferDataType ) ) ;
2021-06-13 23:02:53 +00:00
auto flip_if_needed = [ & ] ( ) {
if ( is_little_endian )
return ;
2021-06-16 23:43:24 +00:00
VERIFY ( sizeof ( UnderlyingBufferDataType ) % 2 = = 0 ) ;
for ( size_t i = 0 ; i < sizeof ( UnderlyingBufferDataType ) / 2 ; + + i )
swap ( raw_bytes [ i ] , raw_bytes [ sizeof ( UnderlyingBufferDataType ) - 1 - i ] ) ;
2021-06-13 23:02:53 +00:00
} ;
2024-11-09 21:29:03 +00:00
if constexpr ( IsSame < UnderlyingBufferDataType , f16 > ) {
auto raw_value = static_cast < f16 > ( MUST ( value . to_double ( vm ) ) ) ;
ReadonlyBytes { & raw_value , sizeof ( f16 ) } . copy_to ( raw_bytes ) ;
flip_if_needed ( ) ;
return ;
}
2021-06-16 23:43:24 +00:00
if constexpr ( IsSame < UnderlyingBufferDataType , float > ) {
2022-08-21 13:00:56 +00:00
float raw_value = MUST ( value . to_double ( vm ) ) ;
2021-06-13 23:02:53 +00:00
ReadonlyBytes { & raw_value , sizeof ( float ) } . copy_to ( raw_bytes ) ;
flip_if_needed ( ) ;
2023-10-05 10:38:15 +00:00
return ;
2021-06-13 23:02:53 +00:00
}
2021-06-16 23:43:24 +00:00
if constexpr ( IsSame < UnderlyingBufferDataType , double > ) {
2022-08-21 13:00:56 +00:00
double raw_value = MUST ( value . to_double ( vm ) ) ;
2021-06-13 23:02:53 +00:00
ReadonlyBytes { & raw_value , sizeof ( double ) } . copy_to ( raw_bytes ) ;
flip_if_needed ( ) ;
2023-10-05 10:38:15 +00:00
return ;
2021-06-13 23:02:53 +00:00
}
2021-06-16 23:43:24 +00:00
if constexpr ( ! IsIntegral < UnderlyingBufferDataType > )
2021-06-13 23:02:53 +00:00
VERIFY_NOT_REACHED ( ) ;
2021-06-16 23:43:24 +00:00
if constexpr ( sizeof ( UnderlyingBufferDataType ) = = 8 ) {
UnderlyingBufferDataType int_value ;
if constexpr ( IsSigned < UnderlyingBufferDataType > )
2022-08-21 13:00:56 +00:00
int_value = MUST ( value . to_bigint_int64 ( vm ) ) ;
2021-06-16 23:43:24 +00:00
else
2022-08-21 13:00:56 +00:00
int_value = MUST ( value . to_bigint_uint64 ( vm ) ) ;
2021-06-16 23:43:24 +00:00
ReadonlyBytes { & int_value , sizeof ( UnderlyingBufferDataType ) } . copy_to ( raw_bytes ) ;
2021-06-13 23:02:53 +00:00
flip_if_needed ( ) ;
2023-10-05 10:38:15 +00:00
return ;
2021-06-13 23:02:53 +00:00
} else {
2021-06-16 23:43:24 +00:00
UnderlyingBufferDataType int_value ;
if constexpr ( IsSigned < UnderlyingBufferDataType > ) {
if constexpr ( sizeof ( UnderlyingBufferDataType ) = = 4 )
2022-08-21 13:00:56 +00:00
int_value = MUST ( value . to_i32 ( vm ) ) ;
2021-06-16 23:43:24 +00:00
else if constexpr ( sizeof ( UnderlyingBufferDataType ) = = 2 )
2022-08-21 13:00:56 +00:00
int_value = MUST ( value . to_i16 ( vm ) ) ;
2021-06-16 23:43:24 +00:00
else
2022-08-21 13:00:56 +00:00
int_value = MUST ( value . to_i8 ( vm ) ) ;
2021-06-16 23:43:24 +00:00
} else {
if constexpr ( sizeof ( UnderlyingBufferDataType ) = = 4 )
2022-08-21 13:00:56 +00:00
int_value = MUST ( value . to_u32 ( vm ) ) ;
2021-06-16 23:43:24 +00:00
else if constexpr ( sizeof ( UnderlyingBufferDataType ) = = 2 )
2022-08-21 13:00:56 +00:00
int_value = MUST ( value . to_u16 ( vm ) ) ;
2021-06-16 23:43:24 +00:00
else if constexpr ( ! IsSame < T , ClampedU8 > )
2022-08-21 13:00:56 +00:00
int_value = MUST ( value . to_u8 ( vm ) ) ;
2021-06-16 23:43:24 +00:00
else
2022-08-21 13:00:56 +00:00
int_value = MUST ( value . to_u8_clamp ( vm ) ) ;
2021-06-16 23:43:24 +00:00
}
ReadonlyBytes { & int_value , sizeof ( UnderlyingBufferDataType ) } . copy_to ( raw_bytes ) ;
if constexpr ( sizeof ( UnderlyingBufferDataType ) % 2 = = 0 )
flip_if_needed ( ) ;
2023-10-05 10:38:15 +00:00
return ;
2021-06-13 23:02:53 +00:00
}
}
2024-08-20 14:29:45 +00:00
// 25.1.3.18 SetValueInBuffer ( arrayBuffer, byteIndex, type, value, isTypedArray, order [ , isLittleEndian ] ), https://tc39.es/ecma262/#sec-setvalueinbuffer
2021-06-13 23:02:53 +00:00
template < typename T >
2023-11-26 09:33:56 +00:00
void ArrayBuffer : : set_value ( size_t byte_index , Value value , [ [ maybe_unused ] ] bool is_typed_array , Order , bool is_little_endian )
2021-06-13 23:02:53 +00:00
{
2022-08-21 16:25:31 +00:00
auto & vm = this - > vm ( ) ;
2023-06-28 06:28:39 +00:00
// 1. Assert: IsDetachedBuffer(arrayBuffer) is false.
VERIFY ( ! is_detached ( ) ) ;
// 2. Assert: There are sufficient bytes in arrayBuffer starting at byteIndex to represent a value of type.
2023-09-11 08:35:03 +00:00
VERIFY ( m_data_block . buffer ( ) . bytes ( ) . slice ( byte_index ) . size ( ) > = sizeof ( T ) ) ;
2023-06-28 06:28:39 +00:00
// 3. Assert: value is a BigInt if IsBigIntElementType(type) is true; otherwise, value is a Number.
if constexpr ( IsIntegral < T > & & sizeof ( T ) = = 8 )
VERIFY ( value . is_bigint ( ) ) ;
else
VERIFY ( value . is_number ( ) ) ;
// 4. Let block be arrayBuffer.[[ArrayBufferData]].
2023-09-11 08:35:03 +00:00
auto & block = m_data_block . buffer ( ) ;
2023-06-28 06:28:39 +00:00
// FIXME: 5. Let elementSize be the Element Size value specified in Table 70 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.
// NOTE: Done by default parameter at declaration of this function.
// 7. Let rawBytes be NumericToRawBytes(type, value, isLittleEndian).
2023-10-05 10:38:15 +00:00
AK : : Array < u8 , sizeof ( T ) > raw_bytes ;
numeric_to_raw_bytes < T > ( vm , value , is_little_endian , raw_bytes ) ;
2021-06-13 23:02:53 +00:00
2023-06-28 06:28:39 +00:00
// FIXME 8. If IsSharedArrayBuffer(arrayBuffer) is true, then
if ( false ) {
// FIXME: a. Let execution be the [[CandidateExecution]] field of the surrounding agent's Agent Record.
// FIXME: b. Let eventsRecord be the Agent Events Record of execution.[[EventsRecords]] whose [[AgentSignifier]] is AgentSignifier().
// FIXME: c. If isTypedArray is true and IsNoTearConfiguration(type, order) is true, let noTear be true; otherwise let noTear be false.
// FIXME: d. Append WriteSharedMemory { [[Order]]: order, [[NoTear]]: noTear, [[Block]]: block, [[ByteIndex]]: byteIndex, [[ElementSize]]: elementSize, [[Payload]]: rawBytes } to eventsRecord.[[EventList]].
}
// 9. Else,
else {
// a. Store the individual bytes of rawBytes into block, starting at block[byteIndex].
raw_bytes . span ( ) . copy_to ( block . span ( ) . slice ( byte_index ) ) ;
}
2021-06-13 23:02:53 +00:00
2023-06-28 06:28:39 +00:00
// 10. Return unused.
2021-06-13 23:02:53 +00:00
}
2024-08-20 14:29:45 +00:00
// 25.1.3.19 GetModifySetValueInBuffer ( arrayBuffer, byteIndex, type, value, op [ , isLittleEndian ] ), https://tc39.es/ecma262/#sec-getmodifysetvalueinbuffer
2021-07-11 12:57:54 +00:00
template < typename T >
2023-11-26 09:33:56 +00:00
Value ArrayBuffer : : get_modify_set_value ( size_t byte_index , Value value , ReadWriteModifyFunction operation , bool is_little_endian )
2021-07-11 12:57:54 +00:00
{
2022-08-21 16:25:31 +00:00
auto & vm = this - > vm ( ) ;
2023-10-05 10:38:15 +00:00
auto raw_bytes = MUST ( ByteBuffer : : create_uninitialized ( sizeof ( T ) ) ) ;
numeric_to_raw_bytes < T > ( vm , value , is_little_endian , raw_bytes ) ;
2021-07-11 12:57:54 +00:00
// FIXME: Check for shared buffer
2023-10-05 10:38:15 +00:00
auto raw_bytes_read = MUST ( ByteBuffer : : create_uninitialized ( sizeof ( T ) ) ) ;
m_data_block . buffer ( ) . bytes ( ) . slice ( byte_index , sizeof ( T ) ) . copy_to ( raw_bytes_read ) ;
2021-07-11 12:57:54 +00:00
auto raw_bytes_modified = operation ( raw_bytes_read , raw_bytes ) ;
2023-09-11 08:35:03 +00:00
raw_bytes_modified . span ( ) . copy_to ( m_data_block . buffer ( ) . span ( ) . slice ( byte_index ) ) ;
2021-07-11 12:57:54 +00:00
2022-08-21 16:25:31 +00:00
return raw_bytes_to_numeric < T > ( vm , raw_bytes_read , is_little_endian ) ;
2021-07-11 12:57:54 +00:00
}
2020-12-02 20:49:31 +00:00
}