/src/serenity/Userland/Libraries/LibJS/Runtime/DataView.cpp
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #include <LibJS/Runtime/DataView.h> |
8 | | |
9 | | namespace JS { |
10 | | |
11 | | JS_DEFINE_ALLOCATOR(DataView); |
12 | | |
13 | | NonnullGCPtr<DataView> DataView::create(Realm& realm, ArrayBuffer* viewed_buffer, ByteLength byte_length, size_t byte_offset) |
14 | 0 | { |
15 | 0 | return realm.heap().allocate<DataView>(realm, viewed_buffer, move(byte_length), byte_offset, realm.intrinsics().data_view_prototype()); |
16 | 0 | } |
17 | | |
18 | | DataView::DataView(ArrayBuffer* viewed_buffer, ByteLength byte_length, size_t byte_offset, Object& prototype) |
19 | 0 | : Object(ConstructWithPrototypeTag::Tag, prototype) |
20 | 0 | , m_viewed_array_buffer(viewed_buffer) |
21 | 0 | , m_byte_length(move(byte_length)) |
22 | 0 | , m_byte_offset(byte_offset) |
23 | 0 | { |
24 | 0 | } |
25 | | |
26 | | void DataView::visit_edges(Visitor& visitor) |
27 | 0 | { |
28 | 0 | Base::visit_edges(visitor); |
29 | 0 | visitor.visit(m_viewed_array_buffer); |
30 | 0 | } |
31 | | |
32 | | // 25.3.1.2 MakeDataViewWithBufferWitnessRecord ( obj, order ), https://tc39.es/ecma262/#sec-makedataviewwithbufferwitnessrecord |
33 | | DataViewWithBufferWitness make_data_view_with_buffer_witness_record(DataView const& data_view, ArrayBuffer::Order order) |
34 | 0 | { |
35 | | // 1. Let buffer be obj.[[ViewedArrayBuffer]]. |
36 | 0 | auto* buffer = data_view.viewed_array_buffer(); |
37 | |
|
38 | 0 | ByteLength byte_length { 0 }; |
39 | | |
40 | | // 2. If IsDetachedBuffer(buffer) is true, then |
41 | 0 | if (buffer->is_detached()) { |
42 | | // a. Let byteLength be detached. |
43 | 0 | byte_length = ByteLength::detached(); |
44 | 0 | } |
45 | | // 3. Else, |
46 | 0 | else { |
47 | | // a. Let byteLength be ArrayBufferByteLength(buffer, order). |
48 | 0 | byte_length = array_buffer_byte_length(*buffer, order); |
49 | 0 | } |
50 | | |
51 | | // 4. Return the DataView With Buffer Witness Record { [[Object]]: obj, [[CachedBufferByteLength]]: byteLength }. |
52 | 0 | return { .object = data_view, .cached_buffer_byte_length = move(byte_length) }; |
53 | 0 | } |
54 | | |
55 | | // 25.3.1.3 GetViewByteLength ( viewRecord ), https://tc39.es/ecma262/#sec-getviewbytelength |
56 | | u32 get_view_byte_length(DataViewWithBufferWitness const& view_record) |
57 | 0 | { |
58 | | // 1. Assert: IsViewOutOfBounds(viewRecord) is false. |
59 | 0 | VERIFY(!is_view_out_of_bounds(view_record)); |
60 | | |
61 | | // 2. Let view be viewRecord.[[Object]]. |
62 | 0 | auto const& view = *view_record.object; |
63 | | |
64 | | // 3. If view.[[ByteLength]] is not auto, return view.[[ByteLength]]. |
65 | 0 | if (!view.byte_length().is_auto()) |
66 | 0 | return view.byte_length().length(); |
67 | | |
68 | | // 4. Assert: IsFixedLengthArrayBuffer(view.[[ViewedArrayBuffer]]) is false. |
69 | 0 | VERIFY(!view.viewed_array_buffer()->is_fixed_length()); |
70 | | |
71 | | // 5. Let byteOffset be view.[[ByteOffset]]. |
72 | 0 | auto byte_offset = view.byte_offset(); |
73 | | |
74 | | // 6. Let byteLength be viewRecord.[[CachedBufferByteLength]]. |
75 | 0 | auto const& byte_length = view_record.cached_buffer_byte_length; |
76 | | |
77 | | // 7. Assert: byteLength is not detached. |
78 | 0 | VERIFY(!byte_length.is_detached()); |
79 | | |
80 | | // 8. Return byteLength - byteOffset. |
81 | 0 | return byte_length.length() - byte_offset; |
82 | 0 | } |
83 | | |
84 | | // 25.3.1.4 IsViewOutOfBounds ( viewRecord ), https://tc39.es/ecma262/#sec-isviewoutofbounds |
85 | | bool is_view_out_of_bounds(DataViewWithBufferWitness const& view_record) |
86 | 0 | { |
87 | | // 1. Let view be viewRecord.[[Object]]. |
88 | 0 | auto const& view = *view_record.object; |
89 | | |
90 | | // 2. Let bufferByteLength be viewRecord.[[CachedBufferByteLength]]. |
91 | 0 | auto const& buffer_byte_length = view_record.cached_buffer_byte_length; |
92 | | |
93 | | // 3. Assert: IsDetachedBuffer(view.[[ViewedArrayBuffer]]) is true if and only if bufferByteLength is detached. |
94 | 0 | VERIFY(view.viewed_array_buffer()->is_detached() == buffer_byte_length.is_detached()); |
95 | | |
96 | | // 4. If bufferByteLength is detached, return true. |
97 | 0 | if (buffer_byte_length.is_detached()) |
98 | 0 | return true; |
99 | | |
100 | | // 5. Let byteOffsetStart be view.[[ByteOffset]]. |
101 | 0 | auto byte_offset_start = view.byte_offset(); |
102 | 0 | u32 byte_offset_end = 0; |
103 | | |
104 | | // 6. If view.[[ByteLength]] is auto, then |
105 | 0 | if (view.byte_length().is_auto()) { |
106 | | // a. Let byteOffsetEnd be bufferByteLength. |
107 | 0 | byte_offset_end = buffer_byte_length.length(); |
108 | 0 | } |
109 | | // 7. Else, |
110 | 0 | else { |
111 | | // a. Let byteOffsetEnd be byteOffsetStart + view.[[ByteLength]]. |
112 | 0 | byte_offset_end = byte_offset_start + view.byte_length().length(); |
113 | 0 | } |
114 | | |
115 | | // 8. If byteOffsetStart > bufferByteLength or byteOffsetEnd > bufferByteLength, return true. |
116 | 0 | if ((byte_offset_start > buffer_byte_length.length()) || (byte_offset_end > buffer_byte_length.length())) |
117 | 0 | return true; |
118 | | |
119 | | // 9. NOTE: 0-length DataViews are not considered out-of-bounds. |
120 | | // 10. Return false. |
121 | 0 | return false; |
122 | 0 | } |
123 | | |
124 | | } |