2020-12-02 20:49:31 +00:00
/*
2021-10-09 12:31:13 +01:00
* Copyright ( c ) 2020 - 2021 , Linus Groh < linusg @ serenityos . org >
2022-03-02 11:44:32 -05:00
* Copyright ( c ) 2022 , the SerenityOS developers .
2020-12-02 20:49:31 +00:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-12-02 20:49:31 +00:00
*/
2021-10-09 12:31:13 +01:00
# include <LibJS/Runtime/AbstractOperations.h>
2020-12-02 20:49:31 +00:00
# include <LibJS/Runtime/ArrayBuffer.h>
# include <LibJS/Runtime/GlobalObject.h>
namespace JS {
2022-02-07 13:34:32 +01:00
ThrowCompletionOr < ArrayBuffer * > ArrayBuffer : : create ( GlobalObject & global_object , size_t byte_length )
2020-12-02 20:49:31 +00:00
{
2021-10-09 12:31:13 +01:00
auto buffer = ByteBuffer : : create_zeroed ( byte_length ) ;
2022-02-07 13:34:32 +01:00
if ( buffer . is_error ( ) )
return global_object . vm ( ) . throw_completion < RangeError > ( global_object , ErrorType : : NotEnoughMemoryToAllocate , byte_length ) ;
2021-09-05 14:43:15 +04:30
return global_object . heap ( ) . allocate < ArrayBuffer > ( global_object , buffer . release_value ( ) , * global_object . array_buffer_prototype ( ) ) ;
2020-12-02 20:49:31 +00:00
}
2021-12-13 22:05:42 +00:00
ArrayBuffer * ArrayBuffer : : create ( GlobalObject & global_object , ByteBuffer buffer )
{
return global_object . heap ( ) . allocate < ArrayBuffer > ( global_object , move ( buffer ) , * global_object . array_buffer_prototype ( ) ) ;
}
2021-05-17 21:39:31 +04:30
ArrayBuffer * ArrayBuffer : : create ( GlobalObject & global_object , ByteBuffer * buffer )
{
return global_object . heap ( ) . allocate < ArrayBuffer > ( global_object , buffer , * global_object . array_buffer_prototype ( ) ) ;
}
2021-09-05 14:43:15 +04:30
ArrayBuffer : : ArrayBuffer ( ByteBuffer buffer , Object & prototype )
2020-12-02 20:49:31 +00:00
: Object ( prototype )
2021-09-05 14:43:15 +04:30
, m_buffer ( move ( buffer ) )
2021-06-10 22:44:17 +03:00
, m_detach_key ( js_undefined ( ) )
2020-12-02 20:49:31 +00:00
{
}
2021-05-17 21:39:31 +04:30
ArrayBuffer : : ArrayBuffer ( ByteBuffer * buffer , Object & prototype )
: Object ( prototype )
, m_buffer ( buffer )
2021-06-10 22:44:17 +03:00
, m_detach_key ( js_undefined ( ) )
2021-05-17 21:39:31 +04:30
{
}
2022-03-02 11:45:26 -05:00
// 1.1.5 IsResizableArrayBuffer ( arrayBuffer ), https://tc39.es/proposal-resizablearraybuffer/#sec-isresizablearraybuffer
bool ArrayBuffer : : is_resizable_array_buffer ( ) const
{
// 1. Assert: Type(arrayBuffer) is Object and arrayBuffer has an [[ArrayBufferData]] internal slot.
// 2. If buffer has an [[ArrayBufferMaxByteLength]] internal slot, return true.
// 3. Return false.
return m_max_byte_length . has_value ( ) ;
}
2021-06-11 00:59:24 +03:00
void ArrayBuffer : : visit_edges ( Cell : : Visitor & visitor )
{
2021-09-11 14:05:12 +02:00
Base : : visit_edges ( visitor ) ;
2021-06-11 00:59:24 +03:00
visitor . visit ( m_detach_key ) ;
}
2021-10-09 12:31:13 +01:00
// 25.1.2.1 AllocateArrayBuffer ( constructor, byteLength ), https://tc39.es/ecma262/#sec-allocatearraybuffer
2022-03-02 11:44:32 -05:00
// 1.1.2 AllocateArrayBuffer ( constructor, byteLength [, maxByteLength ] ), https://tc39.es/proposal-resizablearraybuffer/#sec-allocatearraybuffer
ThrowCompletionOr < ArrayBuffer * > allocate_array_buffer ( GlobalObject & global_object , FunctionObject & constructor , size_t byte_length , Optional < size_t > max_byte_length )
2021-10-09 12:31:13 +01:00
{
2022-02-19 23:31:59 -05:00
// 1. Let slots be « [[ArrayBufferData]], [[ArrayBufferByteLength]], [[ArrayBufferDetachKey]] ».
// 2. If maxByteLength is present, append [[ArrayBufferMaxByteLength]] to slots.
// 3. Let obj be ? OrdinaryCreateFromConstructor(constructor, "%ArrayBuffer.prototype%", slots).
2021-10-09 12:31:13 +01:00
auto * obj = TRY ( ordinary_create_from_constructor < ArrayBuffer > ( global_object , constructor , & GlobalObject : : array_buffer_prototype , nullptr ) ) ;
2022-02-19 23:31:59 -05:00
// 4. Let block be ? CreateByteDataBlock(byteLength).
2021-10-09 12:31:13 +01:00
auto block = ByteBuffer : : create_zeroed ( byte_length ) ;
2022-01-20 17:47:39 +00:00
if ( block . is_error ( ) )
2021-10-09 12:31:13 +01:00
return global_object . vm ( ) . throw_completion < RangeError > ( global_object , ErrorType : : NotEnoughMemoryToAllocate , byte_length ) ;
2022-02-19 23:31:59 -05:00
// 5. Set obj.[[ArrayBufferData]] to block.
2022-01-20 17:47:39 +00:00
obj - > set_buffer ( block . release_value ( ) ) ;
2021-10-09 12:31:13 +01:00
2022-02-19 23:31:59 -05:00
// 6. Set obj.[[ArrayBufferByteLength]] to byteLength.
// 7. If maxByteLength is present, then
if ( max_byte_length . has_value ( ) ) {
// a. Assert: byteLength ≤ maxByteLength.
VERIFY ( byte_length < = * max_byte_length ) ;
// b. If it is not possible to create a Data Block block consisting of maxByteLength bytes, throw a RangeError exception.
// c. NOTE: Resizable ArrayBuffers are designed to be implementable with in-place growth. Implementations reserve the right to throw if, for example, virtual memory cannot be reserved up front.
// d. Set obj.[[ArrayBufferMaxByteLength]] to maxByteLength.
obj - > set_max_byte_length ( * max_byte_length ) ;
}
2021-10-09 12:31:13 +01:00
2022-02-19 23:31:59 -05:00
// 8. Return obj.
2021-10-09 12:31:13 +01:00
return obj ;
}
2022-02-08 21:36:48 +02:00
// 25.1.2.4 CloneArrayBuffer ( srcBuffer, srcByteOffset, srcLength, cloneConstructor ), https://tc39.es/ecma262/#sec-clonearraybuffer
ThrowCompletionOr < ArrayBuffer * > clone_array_buffer ( GlobalObject & global_object , ArrayBuffer & source_buffer , size_t source_byte_offset , size_t source_length , FunctionObject & clone_constructor )
{
auto & vm = global_object . vm ( ) ;
// 1. Let targetBuffer be ? AllocateArrayBuffer(cloneConstructor, srcLength).
auto * target_buffer = TRY ( allocate_array_buffer ( global_object , clone_constructor , source_length ) ) ;
// 2. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError exception.
if ( source_buffer . is_detached ( ) )
return vm . throw_completion < TypeError > ( global_object , ErrorType : : DetachedArrayBuffer ) ;
// 3. Let srcBlock be srcBuffer.[[ArrayBufferData]].
auto & source_block = source_buffer . buffer ( ) ;
// 4. Let targetBlock be targetBuffer.[[ArrayBufferData]].
auto & target_block = target_buffer - > buffer ( ) ;
// 5. Perform CopyDataBlockBytes(targetBlock, 0, srcBlock, srcByteOffset, srcLength).
// FIXME: This is only correct for ArrayBuffers, once SharedArrayBuffer is implemented, the AO has to be implemented
target_block . overwrite ( 0 , source_block . offset_pointer ( source_byte_offset ) , source_length ) ;
// 6. Return targetBuffer.
return target_buffer ;
}
2020-12-02 20:49:31 +00:00
}