blob: 0376f9fa50848f35a4f236509e396b99e7e5bec4 [file]
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_OBJECTS_JS_ARRAY_BUFFER_H_
#define V8_OBJECTS_JS_ARRAY_BUFFER_H_
#include "include/v8-array-buffer.h"
#include "include/v8-typed-array.h"
#include "src/base/bit-field.h"
#include "src/handles/maybe-handles.h"
#include "src/objects/backing-store.h"
#include "src/objects/js-function.h"
#include "src/objects/js-objects.h"
#include "src/sandbox/check.h"
#include "src/sandbox/external-pointer.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
class ArrayBufferExtension;
V8_OBJECT class JSArrayBuffer : public JSAPIObjectWithEmbedderSlots {
public:
// The maximum length for JSArrayBuffer's supported by V8.
// On 32-bit architectures we limit this to 2GiB, so that
// we can continue to use CheckBounds with the Unsigned31
// restriction for the length.
#if V8_ENABLE_SANDBOX
static constexpr size_t kMaxByteLength = kMaxSafeBufferSizeForSandbox;
#elif V8_HOST_ARCH_32_BIT
static constexpr size_t kMaxByteLength = kMaxInt;
#else
static constexpr size_t kMaxByteLength = kMaxSafeInteger;
#endif
// [byte_length]: length in bytes
inline size_t byte_length() const;
inline void set_byte_length(size_t value);
inline size_t byte_length_unchecked() const;
// [max_byte_length]: maximum length in bytes
inline size_t max_byte_length() const;
inline void set_max_byte_length(size_t value);
// [backing_store]: backing memory for this array
// It should not be assumed that this will be nullptr for empty ArrayBuffers.
inline void* backing_store() const;
inline void* backing_store(PtrComprCageBase cage_base) const;
inline void set_backing_store(Isolate* isolate, void* value);
// [extension]: extension object used for GC
inline ArrayBufferExtension* extension() const;
inline void set_extension(ArrayBufferExtension* value);
inline void init_extension();
// Returns the current extension and resets it to nullptr. Expects a witness
// DisallowGarbageCollection to make sure the returned extension isn't freed
// while a pointer to it is held on stack.
inline ArrayBufferExtension* extract_extension(
Isolate* isolate,
const DisallowGarbageCollection& disallow_gc V8_LIFETIME_BOUND);
// [bit_field]: boolean flags
inline uint32_t bit_field() const;
inline void set_bit_field(uint32_t value);
// Clear uninitialized padding space. This ensures that the snapshot content
// is deterministic. Depending on the V8 build mode there could be no padding.
V8_INLINE void clear_padding();
// Bit positions for [bit_field].
using IsExternalBit = base::BitField<bool, 0, 1, uint32_t>;
using IsDetachableBit = IsExternalBit::Next<bool, 1>;
using WasDetachedBit = IsDetachableBit::Next<bool, 1>;
using IsSharedBit = WasDetachedBit::Next<SharedFlag, 1>;
using IsResizableByJsBit = IsSharedBit::Next<ResizableFlag, 1>;
using IsImmutableBit = IsResizableByJsBit::Next<ImmutableFlag, 1>;
enum Flag : uint32_t {
kNone = 0,
kIsExternal = IsExternalBit::kMask,
kIsDetachable = IsDetachableBit::kMask,
kWasDetached = WasDetachedBit::kMask,
kIsShared = IsSharedBit::kMask,
kIsResizableByJs = IsResizableByJsBit::kMask,
kIsImmutable = IsImmutableBit::kMask,
};
using Flags = base::Flags<Flag>;
static constexpr int kFlagCount = 6;
// [is_external]: true indicates that the embedder is in charge of freeing the
// backing_store, while is_external == false means that v8 will free the
// memory block once all ArrayBuffers referencing it are collected by the GC.
DECL_BOOLEAN_ACCESSORS(is_external)
// [is_detachable]: false => this buffer cannot be detached.
DECL_BOOLEAN_ACCESSORS(is_detachable)
// [was_detached]: true => the buffer was previously detached.
DECL_BOOLEAN_ACCESSORS(was_detached)
inline bool was_detached(AcquireLoadTag) const;
inline void set_was_detached(bool value, ReleaseStoreTag);
// [is_shared]: true if this is a SharedArrayBuffer or a
// GrowableSharedArrayBuffer.
inline SharedFlag is_shared() const;
inline void set_is_shared(SharedFlag value);
// [is_resizable_by_js]: true if this is a ResizableArrayBuffer or a
// GrowableSharedArrayBuffer.
inline ResizableFlag is_resizable_by_js() const;
inline void set_is_resizable_by_js(ResizableFlag value);
// [is_immutable]: true if this is an ImmutableArrayBuffer.
inline bool is_immutable() const;
inline void set_is_immutable(ImmutableFlag value);
V8_EXPORT_PRIVATE void MakeImmutable(Isolate* isolate);
// An ArrayBuffer is empty if its BackingStore is empty or if there is none.
// An empty ArrayBuffer will have a byte_length of zero but not necessarily a
// nullptr backing_store. An ArrayBuffer with a byte_length of zero may not
// necessarily be empty though, as it may be a GrowableSharedArrayBuffer.
// An ArrayBuffer with a size greater than zero is never empty.
inline bool IsEmpty() const;
inline Tagged<MaybeObject> views_or_detach_key() const;
inline void set_views_or_detach_key(
Tagged<MaybeObject> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline Tagged<MaybeObject> views() const;
inline void set_views(Tagged<MaybeObject> value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
void AttachView(Tagged<JSArrayBufferView> view);
inline Tagged<Object> DetachKey(Isolate* isolate);
static void SetDetachKey(DirectHandle<JSArrayBuffer> array_buffer,
DirectHandle<Object> key, Isolate* isolate);
static constexpr Tagged<Smi> kNoView = Smi::zero();
static constexpr Tagged<Smi> kManyViews = Smi::FromInt(1);
// Initializes the fields of the ArrayBuffer. The provided backing_store can
// be nullptr. If it is not nullptr, then the function registers it with
// src/heap/array-buffer-tracker.h.
V8_EXPORT_PRIVATE void Setup(SharedFlag shared, ResizableFlag resizable,
std::shared_ptr<BackingStore> backing_store,
Isolate* isolate,
Tagged<MaybeObject> views = kNoView);
// Detach the backing store from this array buffer if it is detachable.
// This sets the internal pointer and length to 0 and unregisters the backing
// store from the array buffer tracker. If the array buffer is not detachable,
// this is a nop.
//
// Array buffers that wrap wasm memory objects are special in that they
// are normally not detachable, but can become detached as a side effect
// of growing the underlying memory object. The {force_for_wasm_memory} flag
// is used by the implementation of Wasm memory growth in order to bypass the
// non-detachable check.
V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT static Maybe<bool> Detach(
DirectHandle<JSArrayBuffer> buffer, bool force_for_wasm_memory = false,
DirectHandle<Object> key = {});
// Get a reference to backing store of this array buffer, if there is a
// backing store. Returns nullptr if there is no backing store (e.g. detached
// or a zero-length array buffer).
inline std::shared_ptr<BackingStore> GetBackingStore() const;
inline size_t GetByteLength() const;
static size_t GsabByteLength(Isolate* isolate, Address raw_array_buffer);
static Maybe<bool> GetResizableBackingStorePageConfiguration(
Isolate* isolate, size_t byte_length, size_t max_byte_length,
ShouldThrow should_throw, size_t* page_size, size_t* initial_pages,
size_t* max_pages);
static std::optional<MessageTemplate>
GetResizableBackingStorePageConfigurationImpl(
Isolate* isolate, size_t byte_length, size_t max_byte_length,
size_t* page_size, size_t* initial_pages, size_t* max_pages);
// Allocates an ArrayBufferExtension for this array buffer. This is assumed to
// be only called during setup as it always creates a new extension.
V8_EXPORT_PRIVATE ArrayBufferExtension* CreateExtension(
Isolate* isolate, std::shared_ptr<BackingStore> backing_store);
//
// Serializer/deserializer support.
//
// Backing stores are serialized/deserialized separately. During serialization
// the backing store reference is stored in the backing store field and upon
// deserialization it is converted back to actual external (off-heap) pointer
// value.
inline uint32_t GetBackingStoreRefForDeserialization() const;
inline void SetBackingStoreRefForSerialization(uint32_t ref);
// Dispatched behavior.
DECL_PRINTER(JSArrayBuffer)
DECL_VERIFIER(JSArrayBuffer)
class BodyDescriptor;
static uint32_t NotValidMask(TypedArrayAccessMode mode) {
switch (mode) {
case TypedArrayAccessMode::kRead:
return JSArrayBuffer::WasDetachedBit::kMask;
case TypedArrayAccessMode::kWrite:
return JSArrayBuffer::WasDetachedBit::kMask |
JSArrayBuffer::IsImmutableBit::kMask;
}
UNREACHABLE();
}
#if TAGGED_SIZE_8_BYTES
static const int kOptionalPaddingOffset;
static const int kOptionalPaddingOffsetEnd;
#endif
static const int kHeaderSize;
static const int kSizeWithEmbedderFields;
static constexpr bool kContainsEmbedderFields =
v8::ArrayBuffer::kEmbedderFieldCount > 0;
private:
inline Tagged<Cell> detach_key() const;
inline void set_detach_key(Tagged<Cell> value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline bool has_detach_key() const;
static void DetachInternal(DirectHandle<JSArrayBuffer> array_buffer,
bool force_for_wasm_memory, Isolate* isolate);
static bool TryDetachViews(DirectHandle<JSArrayBuffer> array_buffer,
Isolate* isolate);
#if V8_COMPRESS_POINTERS
// When pointer compression is enabled, the pointer to the extension is
// stored in the external pointer table and the object itself only contains a
// 32-bit external pointer handles. This simplifies alignment requirements
// and is also necessary for the sandbox.
inline ExternalPointerHandle* extension_handle_location() const;
#else
inline ArrayBufferExtension** extension_location() const;
#endif // V8_COMPRESS_POINTERS
public:
TaggedMember<MaybeObject> views_or_detach_key_;
UnalignedValueMember<uintptr_t> raw_byte_length_;
UnalignedValueMember<uintptr_t> raw_max_byte_length_;
UnalignedValueMember<Address> backing_store_;
ExternalPointerMember<kArrayBufferExtensionTag> extension_;
uint32_t bit_field_;
#if TAGGED_SIZE_8_BYTES
uint32_t optional_padding_;
#endif
} V8_OBJECT_END;
#if TAGGED_SIZE_8_BYTES
inline constexpr int JSArrayBuffer::kOptionalPaddingOffset =
offsetof(JSArrayBuffer, optional_padding_);
inline constexpr int JSArrayBuffer::kOptionalPaddingOffsetEnd =
kOptionalPaddingOffset + sizeof(uint32_t) - 1;
#endif
inline constexpr int JSArrayBuffer::kHeaderSize = sizeof(JSArrayBuffer);
inline constexpr int JSArrayBuffer::kSizeWithEmbedderFields =
JSArrayBuffer::kHeaderSize +
v8::ArrayBuffer::kEmbedderFieldCount * kEmbedderDataSlotSize;
// Each JSArrayBuffer (with a backing store) has a corresponding native-heap
// allocated ArrayBufferExtension for GC purposes and storing the backing store.
// When marking a JSArrayBuffer, the GC also marks the native
// extension-object. The GC periodically iterates all extensions concurrently
// and frees unmarked ones.
// https://docs.google.com/document/d/1-ZrLdlFX1nXT3z-FAgLbKal1gI8Auiaya_My-a0UJ28/edit
class ArrayBufferExtension final
#ifdef V8_COMPRESS_POINTERS
: public ExternalPointerTable::ManagedResource {
#else
: public Malloced {
#endif // V8_COMPRESS_POINTERS
public:
enum class Age : uint8_t { kYoung = 0, kOld = 1 };
// Packs `accounting_length` and `age` into a single integer for consistent
// accounting, allowing resize while concurrently sweeping.
struct AccountingState final {
size_t accounting_length() const {
return AccountingLengthField::decode(value);
}
Age age() const { return static_cast<Age>(AgeField::decode(value)); }
uint64_t value;
};
ArrayBufferExtension(std::shared_ptr<BackingStore> backing_store,
ArrayBufferExtension::Age age, SharedFlag is_shared,
ResizableFlag is_resizable_by_js)
: backing_store_(std::move(backing_store)),
accounting_state_(AccountingLengthField::encode(static_cast<size_t>(
backing_store_->PerIsolateAccountingLength())) |
AgeField::encode(static_cast<uint8_t>(age))),
is_shared_(is_shared),
is_resizable_by_js_(is_resizable_by_js) {
initialized_for_gc_.store(true, std::memory_order_release);
}
// Barrier used for publishing the object. This barrier must be used whenever
// the extension is accessed off the main thread.
//
// The constructor sets a value with release that is read with acquire in this
// varrier.
void InitializationBarrier() const {
std::ignore = initialized_for_gc_.load(std::memory_order_acquire);
}
void Mark() { marked_.store(true, std::memory_order_relaxed); }
void Unmark() { marked_.store(false, std::memory_order_relaxed); }
bool IsMarked() const { return marked_.load(std::memory_order_relaxed); }
void YoungMark() {
SBXCHECK_EQ(ArrayBufferExtension::Age::kYoung, age());
set_young_gc_state(GcState::Copied);
}
void YoungMarkPromoted() {
// When iterating promoted pages the extension object is already set as
// being promoted which happens before the page iteration. This may even run
// racefully between AB sweeping and page iteration.
set_young_gc_state(GcState::Promoted);
}
void YoungUnmark() {
DCHECK_EQ(ArrayBufferExtension::Age::kYoung, age());
set_young_gc_state(GcState::Dead);
}
bool IsYoungMarked() const {
DCHECK_EQ(ArrayBufferExtension::Age::kYoung, age());
return young_gc_state() != GcState::Dead;
}
bool IsYoungPromoted() const {
DCHECK_EQ(ArrayBufferExtension::Age::kYoung, age());
return young_gc_state() == GcState::Promoted;
}
std::shared_ptr<BackingStore> backing_store() { return backing_store_; }
void set_backing_store(std::shared_ptr<BackingStore> backing_store) {
backing_store_ = std::move(backing_store);
}
std::shared_ptr<BackingStore> RemoveBackingStore() {
return std::move(backing_store_);
}
size_t accounting_length() const {
return AccountingState{accounting_state_.load(std::memory_order_relaxed)}
.accounting_length();
}
// Applies `delta` to `accounting_length` and returns the AccountingState
// before the update.
AccountingState UpdateAccountingLength(int64_t delta) {
if (delta >= 0) {
return {accounting_state_.fetch_add(
AccountingLengthField::encode(static_cast<size_t>(delta)),
std::memory_order_relaxed)};
}
return {accounting_state_.fetch_sub(
AccountingLengthField::encode(static_cast<size_t>(-delta)),
std::memory_order_relaxed)};
}
// Clears `accounting_length` and returns the AccountingState before the
// update.
AccountingState ClearAccountingLength() {
return {accounting_state_.fetch_and(AgeField::kMask,
std::memory_order_relaxed)};
}
ArrayBufferExtension* next() const { return next_; }
void set_next(ArrayBufferExtension* extension) { next_ = extension; }
SharedFlag is_shared() const { return is_shared_; }
ResizableFlag is_resizable_by_js() const { return is_resizable_by_js_; }
void set_is_resizable_by_js(ResizableFlag value) {
is_resizable_by_js_ = value;
}
Age age() const {
return AccountingState{accounting_state_.load(std::memory_order_relaxed)}
.age();
}
// Updates `age` and returns the AccountingState before the update.
AccountingState SetOld() {
return {
accounting_state_.fetch_or(AgeField::kMask, std::memory_order_relaxed)};
}
AccountingState SetYoung() {
return {accounting_state_.fetch_and(~AgeField::kMask,
std::memory_order_relaxed)};
}
private:
enum class GcState : uint8_t { Dead = 0, Copied, Promoted };
using AgeField = base::BitField<uint8_t, 0, 1, uint64_t>;
using AccountingLengthField = AgeField::Next<size_t, 63>;
GcState young_gc_state() const {
return young_gc_state_.load(std::memory_order_relaxed);
}
void set_young_gc_state(GcState value) {
young_gc_state_.store(value, std::memory_order_relaxed);
}
std::shared_ptr<BackingStore> backing_store_;
ArrayBufferExtension* next_ = nullptr;
std::atomic<uint64_t> accounting_state_;
std::atomic<bool> initialized_for_gc_{false};
std::atomic<bool> marked_{false};
std::atomic<GcState> young_gc_state_{GcState::Dead};
// Trusted copies of the in-sandbox JSArrayBuffer flags. We verify that the
// in-sandbox flags match these trusted copies during critical operations.
const SharedFlag is_shared_;
ResizableFlag is_resizable_by_js_;
};
V8_OBJECT class JSArrayBufferView : public JSAPIObjectWithEmbedderSlots {
V8_IT_ABSTRACT;
public:
// [buffer]: the underlying ArrayBuffer.
inline Tagged<JSArrayBuffer> buffer() const;
inline void set_buffer(Tagged<JSArrayBuffer> value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
// [byte_offset]: offset of typed array in bytes.
inline size_t byte_offset() const;
inline void set_byte_offset(size_t value);
// [byte_length]: length of typed array in bytes.
// Only use for fixed-size arrays (`!IsVariableLength()`). Otherwise use
// `JSTypedArray::GetByteLength()`.
inline size_t byte_length() const;
inline void set_byte_length(size_t value);
// [bit_field]: boolean flags
inline uint32_t bit_field() const;
inline void set_bit_field(uint32_t value);
DECL_VERIFIER(JSArrayBufferView)
// Bit positions for [bit_field].
using IsLengthTrackingBit = base::BitField<bool, 0, 1, uint32_t>;
using IsBackedByRabBit = IsLengthTrackingBit::Next<bool, 1>;
enum Flag : uint32_t {
kNone = 0,
kIsLengthTracking = IsLengthTrackingBit::kMask,
kIsBackedByRab = IsBackedByRabBit::kMask,
};
using Flags = base::Flags<Flag>;
static constexpr int kFlagCount = 2;
inline bool WasDetached() const;
inline bool IsDetachedOrOutOfBounds() const;
DECL_BOOLEAN_ACCESSORS(is_length_tracking)
DECL_BOOLEAN_ACCESSORS(is_backed_by_rab)
inline bool IsVariableLength() const;
class BodyDescriptor;
static const int kHeaderSize;
public:
TaggedMember<JSArrayBuffer> buffer_;
uint32_t bit_field_;
#if TAGGED_SIZE_8_BYTES
uint32_t optional_padding_;
#endif
UnalignedValueMember<uintptr_t> raw_byte_offset_;
UnalignedValueMember<uintptr_t> raw_byte_length_;
} V8_OBJECT_END;
inline constexpr int JSArrayBufferView::kHeaderSize = sizeof(JSArrayBufferView);
static_assert(IsAligned(offsetof(JSArrayBufferView, raw_byte_offset_),
kUIntptrSize));
static_assert(IsAligned(offsetof(JSArrayBufferView, raw_byte_length_),
kUIntptrSize));
V8_OBJECT class JSTypedArray : public JSArrayBufferView {
V8_IT_OWN_TYPE;
public:
static constexpr size_t kMaxByteLength = JSArrayBuffer::kMaxByteLength;
static_assert(kMaxByteLength == v8::TypedArray::kMaxByteLength);
static constexpr std::pair<ExternalArrayType, size_t> TypeAndElementSizeFor(
ElementsKind);
// [length]: length in elements.
inline size_t length() const;
// [base_pointer]: the ByteArray containing the backing store, if it is
// on-heap, or Smi::zero() if it is off-heap.
inline Tagged<Object> base_pointer() const;
inline Tagged<Object> base_pointer(AcquireLoadTag) const;
// ES6 9.4.5.3
V8_WARN_UNUSED_RESULT static Maybe<bool> DefineOwnProperty(
Isolate* isolate, DirectHandle<JSTypedArray> o, DirectHandle<Object> key,
PropertyDescriptor* desc, Maybe<ShouldThrow> should_throw);
ExternalArrayType type() const;
V8_EXPORT_PRIVATE size_t element_size() const;
V8_EXPORT_PRIVATE Handle<JSArrayBuffer> GetBuffer(Isolate* isolate);
// The `DataPtr` is `base_ptr + external_pointer`, and `base_ptr` is nullptr
// for off-heap typed arrays.
static constexpr bool kOffHeapDataPtrEqualsExternalPointer = true;
// Use with care: returns raw pointer into heap.
inline void* DataPtr();
inline void SetOffHeapDataPtr(Isolate* isolate, void* base, Address offset);
// Whether the buffer's backing store is on-heap or off-heap.
inline bool is_on_heap() const;
inline bool is_on_heap(AcquireLoadTag tag) const;
// Only valid to call when IsVariableLength() is true.
size_t GetVariableByteLengthOrOutOfBounds(bool& out_of_bounds) const;
size_t GetVariableLengthOrOutOfBounds(bool& out_of_bounds) const;
inline size_t GetLengthOrOutOfBounds(bool& out_of_bounds) const;
inline size_t GetLength() const;
inline size_t GetByteLength() const;
inline bool IsOutOfBounds() const;
static inline void ForFixedTypedArray(ExternalArrayType array_type,
size_t* element_size,
ElementsKind* element_kind);
static size_t LengthTrackingGsabBackedTypedArrayLength(Isolate* isolate,
Address raw_array);
// Note: this is a pointer compression specific optimization.
// Normally, on-heap typed arrays contain HeapObject value in |base_pointer|
// field and an offset in |external_pointer|.
// When pointer compression is enabled we want to combine decompression with
// the offset addition. In order to do that we add an isolate root to the
// |external_pointer| value and therefore the data pointer computation can
// is a simple addition of a (potentially sign-extended) |base_pointer| loaded
// as Tagged_t value and an |external_pointer| value.
// For full-pointer mode the compensation value is zero.
static inline Address ExternalPointerCompensationForOnHeapArray(
PtrComprCageBase cage_base);
//
// Serializer/deserializer support.
//
// External backing stores are serialized/deserialized separately.
// During serialization the backing store reference is stored in the typed
// array object and upon deserialization it is converted back to actual
// external (off-heap) pointer value.
// The backing store reference is stored in the external_pointer field.
inline uint32_t GetExternalBackingStoreRefForDeserialization() const;
inline void SetExternalBackingStoreRefForSerialization(uint32_t ref);
// Subtracts external pointer compensation from the external pointer value.
inline void RemoveExternalPointerCompensationForSerialization(
Isolate* isolate);
// Adds external pointer compensation to the external pointer value.
inline void AddExternalPointerCompensationForDeserialization(
Isolate* isolate);
static inline MaybeDirectHandle<JSTypedArray> Validate(
Isolate* isolate, DirectHandle<Object> receiver, const char* method_name,
TypedArrayAccessMode access_mode = TypedArrayAccessMode::kRead);
// Dispatched behavior.
DECL_PRINTER(JSTypedArray)
DECL_VERIFIER(JSTypedArray)
class BodyDescriptor;
#ifdef V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP
static constexpr size_t kMaxSizeInHeap = V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP;
#else
static constexpr size_t kMaxSizeInHeap = 64;
#endif
static inline void MarkDetached(DirectHandle<JSTypedArray> array,
Isolate* isolate);
static const int kHeaderSize;
static const int kSizeWithEmbedderFields;
static constexpr bool kContainsEmbedderFields =
v8::ArrayBufferView::kEmbedderFieldCount > 0;
private:
template <typename IsolateT>
friend class Deserializer;
friend class Factory;
inline void set_length(size_t value);
inline Address external_pointer() const;
inline Address external_pointer(PtrComprCageBase cage_base) const;
inline void set_base_pointer(Tagged<Object> value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline void set_base_pointer(Tagged<Object> value, ReleaseStoreTag,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline void set_external_pointer(Isolate* isolate, Address value);
public:
UnalignedValueMember<uintptr_t> raw_length_;
UnalignedValueMember<Address> external_pointer_;
TaggedMember<Object> base_pointer_;
} V8_OBJECT_END;
inline constexpr int JSTypedArray::kHeaderSize = sizeof(JSTypedArray);
inline constexpr int JSTypedArray::kSizeWithEmbedderFields =
JSTypedArray::kHeaderSize +
v8::ArrayBufferView::kEmbedderFieldCount * kEmbedderDataSlotSize;
// TODO(v8:9287): Re-enable when GCMole stops mixing 32/64 bit configs.
// static_assert(IsAligned(JSTypedArray::kRawLengthOffset, kTaggedSize));
// static_assert(IsAligned(JSTypedArray::kExternalPointerOffset, kTaggedSize));
V8_OBJECT class JSDetachedTypedArray : public JSTypedArray {
public:
DECL_PRINTER(JSDetachedTypedArray)
DECL_VERIFIER(JSDetachedTypedArray)
} V8_OBJECT_END;
V8_OBJECT class JSDataViewOrRabGsabDataView : public JSArrayBufferView {
V8_IT_ABSTRACT;
public:
// [data_pointer]: pointer to the actual data.
inline void* data_pointer() const;
inline void* data_pointer(PtrComprCageBase cage_base) const;
inline void set_data_pointer(Isolate* isolate, void* value);
class BodyDescriptor;
static const int kHeaderSize;
static const int kSizeWithEmbedderFields;
static constexpr bool kContainsEmbedderFields =
v8::ArrayBufferView::kEmbedderFieldCount > 0;
public:
UnalignedValueMember<Address> data_pointer_;
} V8_OBJECT_END;
inline constexpr int JSDataViewOrRabGsabDataView::kHeaderSize =
sizeof(JSDataViewOrRabGsabDataView);
inline constexpr int JSDataViewOrRabGsabDataView::kSizeWithEmbedderFields =
JSDataViewOrRabGsabDataView::kHeaderSize +
v8::ArrayBufferView::kEmbedderFieldCount * kEmbedderDataSlotSize;
// TODO(v8:9287): Re-enable when GCMole stops mixing 32/64 bit configs.
// static_assert(IsAligned(JSDataViewOrRabGsabDataView::kDataPointerOffset,
// kTaggedSize));
V8_OBJECT class JSDataView : public JSDataViewOrRabGsabDataView {
public:
DECL_PRINTER(JSDataView)
DECL_VERIFIER(JSDataView)
} V8_OBJECT_END;
V8_OBJECT class JSRabGsabDataView : public JSDataViewOrRabGsabDataView {
public:
DECL_PRINTER(JSRabGsabDataView)
DECL_VERIFIER(JSRabGsabDataView)
inline size_t GetByteLength() const;
inline bool IsOutOfBounds() const;
} V8_OBJECT_END;
V8_OBJECT class TypedArrayConstructor : public JSFunctionWithPrototype {
V8_IT_ABSTRACT;
} V8_OBJECT_END;
V8_OBJECT class Uint8TypedArrayConstructor : public TypedArrayConstructor {
} V8_OBJECT_END;
V8_OBJECT class Int8TypedArrayConstructor : public TypedArrayConstructor {
} V8_OBJECT_END;
V8_OBJECT class Uint16TypedArrayConstructor : public TypedArrayConstructor {
} V8_OBJECT_END;
V8_OBJECT class Int16TypedArrayConstructor : public TypedArrayConstructor {
} V8_OBJECT_END;
V8_OBJECT class Uint32TypedArrayConstructor : public TypedArrayConstructor {
} V8_OBJECT_END;
V8_OBJECT class Int32TypedArrayConstructor : public TypedArrayConstructor {
} V8_OBJECT_END;
V8_OBJECT class Float16TypedArrayConstructor : public TypedArrayConstructor {
} V8_OBJECT_END;
V8_OBJECT class Float32TypedArrayConstructor : public TypedArrayConstructor {
} V8_OBJECT_END;
V8_OBJECT class Float64TypedArrayConstructor : public TypedArrayConstructor {
} V8_OBJECT_END;
V8_OBJECT class Uint8ClampedTypedArrayConstructor
: public TypedArrayConstructor {
} V8_OBJECT_END;
V8_OBJECT class Biguint64TypedArrayConstructor : public TypedArrayConstructor {
} V8_OBJECT_END;
V8_OBJECT class Bigint64TypedArrayConstructor : public TypedArrayConstructor {
} V8_OBJECT_END;
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_JS_ARRAY_BUFFER_H_