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 | |
18 | namespace v8 { |
19 | namespace internal { |
20 | |
21 | OBJECT_CONSTRUCTORS_IMPL(JSArrayBuffer, JSObject) |
22 | OBJECT_CONSTRUCTORS_IMPL(JSArrayBufferView, JSObject) |
23 | OBJECT_CONSTRUCTORS_IMPL(JSTypedArray, JSArrayBufferView) |
24 | OBJECT_CONSTRUCTORS_IMPL(JSDataView, JSArrayBufferView) |
25 | |
26 | CAST_ACCESSOR(JSArrayBuffer) |
27 | CAST_ACCESSOR(JSArrayBufferView) |
28 | CAST_ACCESSOR(JSTypedArray) |
29 | CAST_ACCESSOR(JSDataView) |
30 | |
31 | size_t JSArrayBuffer::byte_length() const { |
32 | return READ_UINTPTR_FIELD(*this, kByteLengthOffset); |
33 | } |
34 | |
35 | void JSArrayBuffer::set_byte_length(size_t value) { |
36 | WRITE_UINTPTR_FIELD(*this, kByteLengthOffset, value); |
37 | } |
38 | |
39 | void* JSArrayBuffer::backing_store() const { |
40 | intptr_t ptr = READ_INTPTR_FIELD(*this, kBackingStoreOffset); |
41 | return reinterpret_cast<void*>(ptr); |
42 | } |
43 | |
44 | void 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 | |
49 | size_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 | |
64 | void* 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 | |
79 | bool JSArrayBuffer::is_wasm_memory() const { |
80 | return IsWasmMemoryBit::decode(bit_field()); |
81 | } |
82 | |
83 | void JSArrayBuffer::set_is_wasm_memory(bool is_wasm_memory) { |
84 | set_bit_field(IsWasmMemoryBit::update(bit_field(), is_wasm_memory)); |
85 | } |
86 | |
87 | void 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 | |
95 | void JSArrayBuffer::set_bit_field(uint32_t bits) { |
96 | WRITE_UINT32_FIELD(*this, kBitFieldOffset, bits); |
97 | } |
98 | |
99 | uint32_t JSArrayBuffer::bit_field() const { |
100 | return READ_UINT32_FIELD(*this, kBitFieldOffset); |
101 | } |
102 | |
103 | // |bit_field| fields. |
104 | BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, is_external, |
105 | JSArrayBuffer::IsExternalBit) |
106 | BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, is_detachable, |
107 | JSArrayBuffer::IsDetachableBit) |
108 | BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, was_detached, |
109 | JSArrayBuffer::WasDetachedBit) |
110 | BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, is_shared, |
111 | JSArrayBuffer::IsSharedBit) |
112 | |
113 | size_t JSArrayBufferView::byte_offset() const { |
114 | return READ_UINTPTR_FIELD(*this, kByteOffsetOffset); |
115 | } |
116 | |
117 | void JSArrayBufferView::set_byte_offset(size_t value) { |
118 | WRITE_UINTPTR_FIELD(*this, kByteOffsetOffset, value); |
119 | } |
120 | |
121 | size_t JSArrayBufferView::byte_length() const { |
122 | return READ_UINTPTR_FIELD(*this, kByteLengthOffset); |
123 | } |
124 | |
125 | void JSArrayBufferView::set_byte_length(size_t value) { |
126 | WRITE_UINTPTR_FIELD(*this, kByteLengthOffset, value); |
127 | } |
128 | |
129 | ACCESSORS(JSArrayBufferView, buffer, Object, kBufferOffset) |
130 | |
131 | bool JSArrayBufferView::WasDetached() const { |
132 | return JSArrayBuffer::cast(buffer())->was_detached(); |
133 | } |
134 | |
135 | size_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 | |
142 | void 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 | |
148 | bool 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 |
157 | MaybeHandle<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 | |
178 | ACCESSORS(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 | |