1// Copyright 2018 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_OBJECTS_JS_ARRAY_BUFFER_INL_H_
6#define V8_OBJECTS_JS_ARRAY_BUFFER_INL_H_
7
8#include "src/objects/js-array-buffer.h"
9
10#include "src/heap/heap-write-barrier-inl.h"
11#include "src/objects-inl.h"
12#include "src/objects/js-objects-inl.h"
13#include "src/wasm/wasm-engine.h"
14
15// Has to be the last include (doesn't have include guards):
16#include "src/objects/object-macros.h"
17
18namespace v8 {
19namespace internal {
20
21OBJECT_CONSTRUCTORS_IMPL(JSArrayBuffer, JSObject)
22OBJECT_CONSTRUCTORS_IMPL(JSArrayBufferView, JSObject)
23OBJECT_CONSTRUCTORS_IMPL(JSTypedArray, JSArrayBufferView)
24OBJECT_CONSTRUCTORS_IMPL(JSDataView, JSArrayBufferView)
25
26CAST_ACCESSOR(JSArrayBuffer)
27CAST_ACCESSOR(JSArrayBufferView)
28CAST_ACCESSOR(JSTypedArray)
29CAST_ACCESSOR(JSDataView)
30
31size_t JSArrayBuffer::byte_length() const {
32 return READ_UINTPTR_FIELD(*this, kByteLengthOffset);
33}
34
35void JSArrayBuffer::set_byte_length(size_t value) {
36 WRITE_UINTPTR_FIELD(*this, kByteLengthOffset, value);
37}
38
39void* JSArrayBuffer::backing_store() const {
40 intptr_t ptr = READ_INTPTR_FIELD(*this, kBackingStoreOffset);
41 return reinterpret_cast<void*>(ptr);
42}
43
44void JSArrayBuffer::set_backing_store(void* value, WriteBarrierMode mode) {
45 intptr_t ptr = reinterpret_cast<intptr_t>(value);
46 WRITE_INTPTR_FIELD(*this, kBackingStoreOffset, ptr);
47}
48
49size_t JSArrayBuffer::allocation_length() const {
50 if (backing_store() == nullptr) {
51 return 0;
52 }
53 // If this buffer is managed by the WasmMemoryTracker
54 if (is_wasm_memory()) {
55 const auto* data =
56 GetIsolate()->wasm_engine()->memory_tracker()->FindAllocationData(
57 backing_store());
58 DCHECK_NOT_NULL(data);
59 return data->allocation_length;
60 }
61 return byte_length();
62}
63
64void* JSArrayBuffer::allocation_base() const {
65 if (backing_store() == nullptr) {
66 return nullptr;
67 }
68 // If this buffer is managed by the WasmMemoryTracker
69 if (is_wasm_memory()) {
70 const auto* data =
71 GetIsolate()->wasm_engine()->memory_tracker()->FindAllocationData(
72 backing_store());
73 DCHECK_NOT_NULL(data);
74 return data->allocation_base;
75 }
76 return backing_store();
77}
78
79bool JSArrayBuffer::is_wasm_memory() const {
80 return IsWasmMemoryBit::decode(bit_field());
81}
82
83void JSArrayBuffer::set_is_wasm_memory(bool is_wasm_memory) {
84 set_bit_field(IsWasmMemoryBit::update(bit_field(), is_wasm_memory));
85}
86
87void JSArrayBuffer::clear_padding() {
88 if (FIELD_SIZE(kOptionalPaddingOffset) != 0) {
89 DCHECK_EQ(4, FIELD_SIZE(kOptionalPaddingOffset));
90 memset(reinterpret_cast<void*>(address() + kOptionalPaddingOffset), 0,
91 FIELD_SIZE(kOptionalPaddingOffset));
92 }
93}
94
95void JSArrayBuffer::set_bit_field(uint32_t bits) {
96 WRITE_UINT32_FIELD(*this, kBitFieldOffset, bits);
97}
98
99uint32_t JSArrayBuffer::bit_field() const {
100 return READ_UINT32_FIELD(*this, kBitFieldOffset);
101}
102
103// |bit_field| fields.
104BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, is_external,
105 JSArrayBuffer::IsExternalBit)
106BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, is_detachable,
107 JSArrayBuffer::IsDetachableBit)
108BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, was_detached,
109 JSArrayBuffer::WasDetachedBit)
110BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, is_shared,
111 JSArrayBuffer::IsSharedBit)
112
113size_t JSArrayBufferView::byte_offset() const {
114 return READ_UINTPTR_FIELD(*this, kByteOffsetOffset);
115}
116
117void JSArrayBufferView::set_byte_offset(size_t value) {
118 WRITE_UINTPTR_FIELD(*this, kByteOffsetOffset, value);
119}
120
121size_t JSArrayBufferView::byte_length() const {
122 return READ_UINTPTR_FIELD(*this, kByteLengthOffset);
123}
124
125void JSArrayBufferView::set_byte_length(size_t value) {
126 WRITE_UINTPTR_FIELD(*this, kByteLengthOffset, value);
127}
128
129ACCESSORS(JSArrayBufferView, buffer, Object, kBufferOffset)
130
131bool JSArrayBufferView::WasDetached() const {
132 return JSArrayBuffer::cast(buffer())->was_detached();
133}
134
135size_t JSTypedArray::length() const {
136 // TODO(bmeurer, v8:4153): Change this to size_t later.
137 int length = Smi::cast(raw_length())->value();
138 DCHECK_LE(0, length);
139 return length;
140}
141
142void JSTypedArray::set_length(size_t value) {
143 // TODO(bmeurer, v8:4153): Change this to size_t later.
144 CHECK_LE(value, Smi::kMaxValue);
145 set_raw_length(Smi::FromInt(static_cast<int>(value)), SKIP_WRITE_BARRIER);
146}
147
148bool JSTypedArray::is_on_heap() const {
149 DisallowHeapAllocation no_gc;
150 // Checking that buffer()->backing_store() is not nullptr is not sufficient;
151 // it will be nullptr when byte_length is 0 as well.
152 FixedTypedArrayBase fta = FixedTypedArrayBase::cast(elements());
153 return fta->base_pointer()->ptr() == fta.ptr();
154}
155
156// static
157MaybeHandle<JSTypedArray> JSTypedArray::Validate(Isolate* isolate,
158 Handle<Object> receiver,
159 const char* method_name) {
160 if (V8_UNLIKELY(!receiver->IsJSTypedArray())) {
161 const MessageTemplate message = MessageTemplate::kNotTypedArray;
162 THROW_NEW_ERROR(isolate, NewTypeError(message), JSTypedArray);
163 }
164
165 Handle<JSTypedArray> array = Handle<JSTypedArray>::cast(receiver);
166 if (V8_UNLIKELY(array->WasDetached())) {
167 const MessageTemplate message = MessageTemplate::kDetachedOperation;
168 Handle<String> operation =
169 isolate->factory()->NewStringFromAsciiChecked(method_name);
170 THROW_NEW_ERROR(isolate, NewTypeError(message, operation), JSTypedArray);
171 }
172
173 // spec describes to return `buffer`, but it may disrupt current
174 // implementations, and it's much useful to return array for now.
175 return array;
176}
177
178ACCESSORS(JSTypedArray, raw_length, Object, kLengthOffset)
179
180} // namespace internal
181} // namespace v8
182
183#include "src/objects/object-macros-undef.h"
184
185#endif // V8_OBJECTS_JS_ARRAY_BUFFER_INL_H_
186