[api] Remove deprecated [Shared]ArrayBuffer API
Bug: v8:9380 Change-Id: I47d23dda133c3838c7f0e8e5ccfdbe3b9520684f Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2720306 Reviewed-by: Andreas Haas <ahaas@chromium.org> Commit-Queue: Ulan Degenbaev <ulan@chromium.org> Cr-Commit-Position: refs/heads/master@{#73375}
This commit is contained in:
parent
5e08891f69
commit
578f6be77f
240
include/v8.h
240
include/v8.h
@ -5409,57 +5409,6 @@ class V8_EXPORT ArrayBuffer : public Object {
|
||||
static Allocator* NewDefaultAllocator();
|
||||
};
|
||||
|
||||
/**
|
||||
* The contents of an |ArrayBuffer|. Externalization of |ArrayBuffer|
|
||||
* returns an instance of this class, populated, with a pointer to data
|
||||
* and byte length.
|
||||
*
|
||||
* The Data pointer of ArrayBuffer::Contents must be freed using the provided
|
||||
* deleter, which will call ArrayBuffer::Allocator::Free if the buffer
|
||||
* was allocated with ArraryBuffer::Allocator::Allocate.
|
||||
*/
|
||||
class V8_EXPORT Contents { // NOLINT
|
||||
public:
|
||||
using DeleterCallback = void (*)(void* buffer, size_t length, void* info);
|
||||
|
||||
Contents()
|
||||
: data_(nullptr),
|
||||
byte_length_(0),
|
||||
allocation_base_(nullptr),
|
||||
allocation_length_(0),
|
||||
allocation_mode_(Allocator::AllocationMode::kNormal),
|
||||
deleter_(nullptr),
|
||||
deleter_data_(nullptr) {}
|
||||
|
||||
void* AllocationBase() const { return allocation_base_; }
|
||||
size_t AllocationLength() const { return allocation_length_; }
|
||||
Allocator::AllocationMode AllocationMode() const {
|
||||
return allocation_mode_;
|
||||
}
|
||||
|
||||
void* Data() const { return data_; }
|
||||
size_t ByteLength() const { return byte_length_; }
|
||||
DeleterCallback Deleter() const { return deleter_; }
|
||||
void* DeleterData() const { return deleter_data_; }
|
||||
|
||||
private:
|
||||
Contents(void* data, size_t byte_length, void* allocation_base,
|
||||
size_t allocation_length,
|
||||
Allocator::AllocationMode allocation_mode, DeleterCallback deleter,
|
||||
void* deleter_data);
|
||||
|
||||
void* data_;
|
||||
size_t byte_length_;
|
||||
void* allocation_base_;
|
||||
size_t allocation_length_;
|
||||
Allocator::AllocationMode allocation_mode_;
|
||||
DeleterCallback deleter_;
|
||||
void* deleter_data_;
|
||||
|
||||
friend class ArrayBuffer;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Data length in bytes.
|
||||
*/
|
||||
@ -5473,22 +5422,6 @@ class V8_EXPORT ArrayBuffer : public Object {
|
||||
*/
|
||||
static Local<ArrayBuffer> New(Isolate* isolate, size_t byte_length);
|
||||
|
||||
/**
|
||||
* Create a new ArrayBuffer over an existing memory block.
|
||||
* The created array buffer is by default immediately in externalized state.
|
||||
* In externalized state, the memory block will not be reclaimed when a
|
||||
* created ArrayBuffer is garbage-collected.
|
||||
* In internalized state, the memory block will be released using
|
||||
* |Allocator::Free| once all ArrayBuffers referencing it are collected by
|
||||
* the garbage collector.
|
||||
*/
|
||||
V8_DEPRECATED(
|
||||
"Use the version that takes a BackingStore. "
|
||||
"See http://crbug.com/v8/9908.")
|
||||
static Local<ArrayBuffer> New(
|
||||
Isolate* isolate, void* data, size_t byte_length,
|
||||
ArrayBufferCreationMode mode = ArrayBufferCreationMode::kExternalized);
|
||||
|
||||
/**
|
||||
* Create a new ArrayBuffer with an existing backing store.
|
||||
* The created array keeps a reference to the backing store until the array
|
||||
@ -5527,15 +5460,6 @@ class V8_EXPORT ArrayBuffer : public Object {
|
||||
void* data, size_t byte_length, v8::BackingStore::DeleterCallback deleter,
|
||||
void* deleter_data);
|
||||
|
||||
/**
|
||||
* Returns true if ArrayBuffer is externalized, that is, does not
|
||||
* own its memory block.
|
||||
*/
|
||||
V8_DEPRECATED(
|
||||
"With v8::BackingStore externalized ArrayBuffers are "
|
||||
"the same as ordinary ArrayBuffers. See http://crbug.com/v8/9908.")
|
||||
bool IsExternal() const;
|
||||
|
||||
/**
|
||||
* Returns true if this ArrayBuffer may be detached.
|
||||
*/
|
||||
@ -5549,47 +5473,11 @@ class V8_EXPORT ArrayBuffer : public Object {
|
||||
*/
|
||||
void Detach();
|
||||
|
||||
/**
|
||||
* Make this ArrayBuffer external. The pointer to underlying memory block
|
||||
* and byte length are returned as |Contents| structure. After ArrayBuffer
|
||||
* had been externalized, it does no longer own the memory block. The caller
|
||||
* should take steps to free memory when it is no longer needed.
|
||||
*
|
||||
* The Data pointer of ArrayBuffer::Contents must be freed using the provided
|
||||
* deleter, which will call ArrayBuffer::Allocator::Free if the buffer
|
||||
* was allocated with ArrayBuffer::Allocator::Allocate.
|
||||
*/
|
||||
V8_DEPRECATED("Use GetBackingStore or Detach. See http://crbug.com/v8/9908.")
|
||||
Contents Externalize();
|
||||
|
||||
/**
|
||||
* Marks this ArrayBuffer external given a witness that the embedder
|
||||
* has fetched the backing store using the new GetBackingStore() function.
|
||||
*
|
||||
* With the new lifetime management of backing stores there is no need for
|
||||
* externalizing, so this function exists only to make the transition easier.
|
||||
*/
|
||||
V8_DEPRECATED("This will be removed together with IsExternal.")
|
||||
void Externalize(const std::shared_ptr<BackingStore>& backing_store);
|
||||
|
||||
/**
|
||||
* Get a pointer to the ArrayBuffer's underlying memory block without
|
||||
* externalizing it. If the ArrayBuffer is not externalized, this pointer
|
||||
* will become invalid as soon as the ArrayBuffer gets garbage collected.
|
||||
*
|
||||
* The embedder should make sure to hold a strong reference to the
|
||||
* ArrayBuffer while accessing this pointer.
|
||||
*/
|
||||
V8_DEPRECATED("Use GetBackingStore. See http://crbug.com/v8/9908.")
|
||||
Contents GetContents();
|
||||
|
||||
/**
|
||||
* Get a shared pointer to the backing store of this array buffer. This
|
||||
* pointer coordinates the lifetime management of the internal storage
|
||||
* with any live ArrayBuffers on the heap, even across isolates. The embedder
|
||||
* should not attempt to manage lifetime of the storage through other means.
|
||||
*
|
||||
* This function replaces both Externalize() and GetContents().
|
||||
*/
|
||||
std::shared_ptr<BackingStore> GetBackingStore();
|
||||
|
||||
@ -5601,7 +5489,6 @@ class V8_EXPORT ArrayBuffer : public Object {
|
||||
private:
|
||||
ArrayBuffer();
|
||||
static void CheckCast(Value* obj);
|
||||
Contents GetContents(bool externalize);
|
||||
};
|
||||
|
||||
|
||||
@ -5894,57 +5781,6 @@ class V8_EXPORT DataView : public ArrayBufferView {
|
||||
*/
|
||||
class V8_EXPORT SharedArrayBuffer : public Object {
|
||||
public:
|
||||
/**
|
||||
* The contents of an |SharedArrayBuffer|. Externalization of
|
||||
* |SharedArrayBuffer| returns an instance of this class, populated, with a
|
||||
* pointer to data and byte length.
|
||||
*
|
||||
* The Data pointer of ArrayBuffer::Contents must be freed using the provided
|
||||
* deleter, which will call ArrayBuffer::Allocator::Free if the buffer
|
||||
* was allocated with ArraryBuffer::Allocator::Allocate.
|
||||
*/
|
||||
class V8_EXPORT Contents { // NOLINT
|
||||
public:
|
||||
using Allocator = v8::ArrayBuffer::Allocator;
|
||||
using DeleterCallback = void (*)(void* buffer, size_t length, void* info);
|
||||
|
||||
Contents()
|
||||
: data_(nullptr),
|
||||
byte_length_(0),
|
||||
allocation_base_(nullptr),
|
||||
allocation_length_(0),
|
||||
allocation_mode_(Allocator::AllocationMode::kNormal),
|
||||
deleter_(nullptr),
|
||||
deleter_data_(nullptr) {}
|
||||
|
||||
void* AllocationBase() const { return allocation_base_; }
|
||||
size_t AllocationLength() const { return allocation_length_; }
|
||||
Allocator::AllocationMode AllocationMode() const {
|
||||
return allocation_mode_;
|
||||
}
|
||||
|
||||
void* Data() const { return data_; }
|
||||
size_t ByteLength() const { return byte_length_; }
|
||||
DeleterCallback Deleter() const { return deleter_; }
|
||||
void* DeleterData() const { return deleter_data_; }
|
||||
|
||||
private:
|
||||
Contents(void* data, size_t byte_length, void* allocation_base,
|
||||
size_t allocation_length,
|
||||
Allocator::AllocationMode allocation_mode, DeleterCallback deleter,
|
||||
void* deleter_data);
|
||||
|
||||
void* data_;
|
||||
size_t byte_length_;
|
||||
void* allocation_base_;
|
||||
size_t allocation_length_;
|
||||
Allocator::AllocationMode allocation_mode_;
|
||||
DeleterCallback deleter_;
|
||||
void* deleter_data_;
|
||||
|
||||
friend class SharedArrayBuffer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Data length in bytes.
|
||||
*/
|
||||
@ -5958,19 +5794,6 @@ class V8_EXPORT SharedArrayBuffer : public Object {
|
||||
*/
|
||||
static Local<SharedArrayBuffer> New(Isolate* isolate, size_t byte_length);
|
||||
|
||||
/**
|
||||
* Create a new SharedArrayBuffer over an existing memory block. The created
|
||||
* array buffer is immediately in externalized state unless otherwise
|
||||
* specified. The memory block will not be reclaimed when a created
|
||||
* SharedArrayBuffer is garbage-collected.
|
||||
*/
|
||||
V8_DEPRECATED(
|
||||
"Use the version that takes a BackingStore. "
|
||||
"See http://crbug.com/v8/9908.")
|
||||
static Local<SharedArrayBuffer> New(
|
||||
Isolate* isolate, void* data, size_t byte_length,
|
||||
ArrayBufferCreationMode mode = ArrayBufferCreationMode::kExternalized);
|
||||
|
||||
/**
|
||||
* Create a new SharedArrayBuffer with an existing backing store.
|
||||
* The created array keeps a reference to the backing store until the array
|
||||
@ -6009,73 +5832,11 @@ class V8_EXPORT SharedArrayBuffer : public Object {
|
||||
void* data, size_t byte_length, v8::BackingStore::DeleterCallback deleter,
|
||||
void* deleter_data);
|
||||
|
||||
/**
|
||||
* Create a new SharedArrayBuffer over an existing memory block. Propagate
|
||||
* flags to indicate whether the underlying buffer can be grown.
|
||||
*/
|
||||
V8_DEPRECATED(
|
||||
"Use the version that takes a BackingStore. "
|
||||
"See http://crbug.com/v8/9908.")
|
||||
static Local<SharedArrayBuffer> New(
|
||||
Isolate* isolate, const SharedArrayBuffer::Contents&,
|
||||
ArrayBufferCreationMode mode = ArrayBufferCreationMode::kExternalized);
|
||||
|
||||
/**
|
||||
* Returns true if SharedArrayBuffer is externalized, that is, does not
|
||||
* own its memory block.
|
||||
*/
|
||||
V8_DEPRECATED(
|
||||
"With v8::BackingStore externalized SharedArrayBuffers are the same "
|
||||
"as ordinary SharedArrayBuffers. See http://crbug.com/v8/9908.")
|
||||
bool IsExternal() const;
|
||||
|
||||
/**
|
||||
* Make this SharedArrayBuffer external. The pointer to underlying memory
|
||||
* block and byte length are returned as |Contents| structure. After
|
||||
* SharedArrayBuffer had been externalized, it does no longer own the memory
|
||||
* block. The caller should take steps to free memory when it is no longer
|
||||
* needed.
|
||||
*
|
||||
* The memory block is guaranteed to be allocated with |Allocator::Allocate|
|
||||
* by the allocator specified in
|
||||
* v8::Isolate::CreateParams::array_buffer_allocator.
|
||||
*
|
||||
*/
|
||||
V8_DEPRECATED("Use GetBackingStore or Detach. See http://crbug.com/v8/9908.")
|
||||
Contents Externalize();
|
||||
|
||||
/**
|
||||
* Marks this SharedArrayBuffer external given a witness that the embedder
|
||||
* has fetched the backing store using the new GetBackingStore() function.
|
||||
*
|
||||
* With the new lifetime management of backing stores there is no need for
|
||||
* externalizing, so this function exists only to make the transition easier.
|
||||
*/
|
||||
V8_DEPRECATED("This will be removed together with IsExternal.")
|
||||
void Externalize(const std::shared_ptr<BackingStore>& backing_store);
|
||||
|
||||
/**
|
||||
* Get a pointer to the ArrayBuffer's underlying memory block without
|
||||
* externalizing it. If the ArrayBuffer is not externalized, this pointer
|
||||
* will become invalid as soon as the ArrayBuffer became garbage collected.
|
||||
*
|
||||
* The embedder should make sure to hold a strong reference to the
|
||||
* ArrayBuffer while accessing this pointer.
|
||||
*
|
||||
* The memory block is guaranteed to be allocated with |Allocator::Allocate|
|
||||
* by the allocator specified in
|
||||
* v8::Isolate::CreateParams::array_buffer_allocator.
|
||||
*/
|
||||
V8_DEPRECATED("Use GetBackingStore. See http://crbug.com/v8/9908.")
|
||||
Contents GetContents();
|
||||
|
||||
/**
|
||||
* Get a shared pointer to the backing store of this array buffer. This
|
||||
* pointer coordinates the lifetime management of the internal storage
|
||||
* with any live ArrayBuffers on the heap, even across isolates. The embedder
|
||||
* should not attempt to manage lifetime of the storage through other means.
|
||||
*
|
||||
* This function replaces both Externalize() and GetContents().
|
||||
*/
|
||||
std::shared_ptr<BackingStore> GetBackingStore();
|
||||
|
||||
@ -6086,7 +5847,6 @@ class V8_EXPORT SharedArrayBuffer : public Object {
|
||||
private:
|
||||
SharedArrayBuffer();
|
||||
static void CheckCast(Value* obj);
|
||||
Contents GetContents(bool externalize);
|
||||
};
|
||||
|
||||
|
||||
|
302
src/api/api.cc
302
src/api/api.cc
@ -7460,169 +7460,17 @@ v8::ArrayBuffer::Allocator* v8::ArrayBuffer::Allocator::NewDefaultAllocator() {
|
||||
return new ArrayBufferAllocator();
|
||||
}
|
||||
|
||||
bool v8::ArrayBuffer::IsExternal() const {
|
||||
return Utils::OpenHandle(this)->is_external();
|
||||
}
|
||||
|
||||
bool v8::ArrayBuffer::IsDetachable() const {
|
||||
return Utils::OpenHandle(this)->is_detachable();
|
||||
}
|
||||
|
||||
namespace {
|
||||
// The backing store deleter just deletes the indirection, which downrefs
|
||||
// the shared pointer. It will get collected normally.
|
||||
void BackingStoreDeleter(void* buffer, size_t length, void* info) {
|
||||
std::shared_ptr<i::BackingStore>* bs_indirection =
|
||||
reinterpret_cast<std::shared_ptr<i::BackingStore>*>(info);
|
||||
if (bs_indirection) {
|
||||
i::BackingStore* backing_store = bs_indirection->get();
|
||||
TRACE_BS("API:delete bs=%p mem=%p (length=%zu)\n", backing_store,
|
||||
backing_store->buffer_start(), backing_store->byte_length());
|
||||
USE(backing_store);
|
||||
}
|
||||
delete bs_indirection;
|
||||
}
|
||||
|
||||
void* MakeDeleterData(std::shared_ptr<i::BackingStore> backing_store) {
|
||||
if (!backing_store) return nullptr;
|
||||
TRACE_BS("API:extern bs=%p mem=%p (length=%zu)\n", backing_store.get(),
|
||||
backing_store->buffer_start(), backing_store->byte_length());
|
||||
return new std::shared_ptr<i::BackingStore>(backing_store);
|
||||
}
|
||||
|
||||
std::shared_ptr<i::BackingStore> LookupOrCreateBackingStore(
|
||||
i::Isolate* i_isolate, void* data, size_t byte_length, i::SharedFlag shared,
|
||||
ArrayBufferCreationMode mode) {
|
||||
// "internalized" means that the storage was allocated by the
|
||||
// ArrayBufferAllocator and thus should be freed upon destruction.
|
||||
bool free_on_destruct = mode == ArrayBufferCreationMode::kInternalized;
|
||||
|
||||
// Try to lookup a previously-registered backing store in the global
|
||||
// registry. If found, use that instead of wrapping an embedder allocation.
|
||||
std::shared_ptr<i::BackingStore> backing_store =
|
||||
i::GlobalBackingStoreRegistry::Lookup(data, byte_length);
|
||||
|
||||
if (backing_store) {
|
||||
// Check invariants for a previously-found backing store.
|
||||
|
||||
// 1. We cannot allow an embedder to first allocate a backing store that
|
||||
// should not be freed upon destruct, and then allocate an alias that should
|
||||
// destruct it. The other order is fine.
|
||||
bool changing_destruct_mode =
|
||||
free_on_destruct && !backing_store->free_on_destruct();
|
||||
Utils::ApiCheck(
|
||||
!changing_destruct_mode, "v8_[Shared]ArrayBuffer_New",
|
||||
"previous backing store found that should not be freed on destruct");
|
||||
|
||||
// 2. We cannot allow embedders to use the same backing store for both
|
||||
// SharedArrayBuffers and regular ArrayBuffers.
|
||||
bool changing_shared_flag =
|
||||
(shared == i::SharedFlag::kShared) != backing_store->is_shared();
|
||||
Utils::ApiCheck(
|
||||
!changing_shared_flag, "v8_[Shared]ArrayBuffer_New",
|
||||
"previous backing store found that does not match shared flag");
|
||||
} else {
|
||||
// No previous backing store found.
|
||||
backing_store = i::BackingStore::WrapAllocation(
|
||||
i_isolate, data, byte_length, shared, free_on_destruct);
|
||||
|
||||
// The embedder already has a direct pointer to the buffer start, so
|
||||
// globally register the backing store in case they come back with the
|
||||
// same buffer start and the backing store is marked as free_on_destruct.
|
||||
i::GlobalBackingStoreRegistry::Register(backing_store);
|
||||
}
|
||||
return backing_store;
|
||||
}
|
||||
|
||||
std::shared_ptr<i::BackingStore> ToInternal(
|
||||
std::shared_ptr<i::BackingStoreBase> backing_store) {
|
||||
return std::static_pointer_cast<i::BackingStore>(backing_store);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
v8::ArrayBuffer::Contents::Contents(void* data, size_t byte_length,
|
||||
void* allocation_base,
|
||||
size_t allocation_length,
|
||||
Allocator::AllocationMode allocation_mode,
|
||||
DeleterCallback deleter, void* deleter_data)
|
||||
: data_(data),
|
||||
byte_length_(byte_length),
|
||||
allocation_base_(allocation_base),
|
||||
allocation_length_(allocation_length),
|
||||
allocation_mode_(allocation_mode),
|
||||
deleter_(deleter),
|
||||
deleter_data_(deleter_data) {
|
||||
DCHECK_LE(allocation_base_, data_);
|
||||
DCHECK_LE(byte_length_, allocation_length_);
|
||||
}
|
||||
|
||||
v8::ArrayBuffer::Contents v8::ArrayBuffer::Externalize() {
|
||||
return GetContents(true);
|
||||
}
|
||||
|
||||
void v8::ArrayBuffer::Externalize(
|
||||
const std::shared_ptr<BackingStore>& backing_store) {
|
||||
i::Handle<i::JSArrayBuffer> self = Utils::OpenHandle(this);
|
||||
Utils::ApiCheck(!self->is_external(), "v8_ArrayBuffer_Externalize",
|
||||
"ArrayBuffer already externalized");
|
||||
self->set_is_external(true);
|
||||
DCHECK_EQ(self->backing_store(), backing_store->Data());
|
||||
}
|
||||
|
||||
v8::ArrayBuffer::Contents v8::ArrayBuffer::GetContents() {
|
||||
return GetContents(false);
|
||||
}
|
||||
|
||||
v8::ArrayBuffer::Contents v8::ArrayBuffer::GetContents(bool externalize) {
|
||||
// TODO(titzer): reduce duplication between shared/unshared GetContents()
|
||||
using BufferType = v8::ArrayBuffer;
|
||||
|
||||
i::Handle<i::JSArrayBuffer> self = Utils::OpenHandle(this);
|
||||
|
||||
std::shared_ptr<i::BackingStore> backing_store = self->GetBackingStore();
|
||||
|
||||
void* deleter_data = nullptr;
|
||||
if (externalize) {
|
||||
Utils::ApiCheck(!self->is_external(), "v8_ArrayBuffer_Externalize",
|
||||
"ArrayBuffer already externalized");
|
||||
self->set_is_external(true);
|
||||
// When externalizing, upref the shared pointer to the backing store
|
||||
// and store that as the deleter data. When the embedder calls the deleter
|
||||
// callback, we will delete the additional (on-heap) shared_ptr.
|
||||
deleter_data = MakeDeleterData(backing_store);
|
||||
}
|
||||
|
||||
if (!backing_store) {
|
||||
// If the array buffer has zero length or was detached, return empty
|
||||
// contents.
|
||||
DCHECK_EQ(0, self->byte_length());
|
||||
BufferType::Contents contents(
|
||||
nullptr, 0, nullptr, 0,
|
||||
v8::ArrayBuffer::Allocator::AllocationMode::kNormal,
|
||||
BackingStoreDeleter, deleter_data);
|
||||
return contents;
|
||||
}
|
||||
|
||||
// Backing stores that given to the embedder might be passed back through
|
||||
// the API using only the start of the buffer. We need to find such
|
||||
// backing stores using global registration until the API is changed.
|
||||
i::GlobalBackingStoreRegistry::Register(backing_store);
|
||||
|
||||
auto allocation_mode =
|
||||
backing_store->is_wasm_memory()
|
||||
? v8::ArrayBuffer::Allocator::AllocationMode::kReservation
|
||||
: v8::ArrayBuffer::Allocator::AllocationMode::kNormal;
|
||||
|
||||
BufferType::Contents contents(backing_store->buffer_start(), // --
|
||||
backing_store->byte_length(), // --
|
||||
backing_store->buffer_start(), // --
|
||||
backing_store->byte_length(), // --
|
||||
allocation_mode, // --
|
||||
BackingStoreDeleter, // --
|
||||
deleter_data);
|
||||
return contents;
|
||||
}
|
||||
|
||||
void v8::ArrayBuffer::Detach() {
|
||||
i::Handle<i::JSArrayBuffer> obj = Utils::OpenHandle(this);
|
||||
i::Isolate* isolate = obj->GetIsolate();
|
||||
@ -7656,27 +7504,6 @@ Local<ArrayBuffer> v8::ArrayBuffer::New(Isolate* isolate, size_t byte_length) {
|
||||
return Utils::ToLocal(array_buffer);
|
||||
}
|
||||
|
||||
Local<ArrayBuffer> v8::ArrayBuffer::New(Isolate* isolate, void* data,
|
||||
size_t byte_length,
|
||||
ArrayBufferCreationMode mode) {
|
||||
// Embedders must guarantee that the external backing store is valid.
|
||||
CHECK_IMPLIES(byte_length != 0, data != nullptr);
|
||||
CHECK_LE(byte_length, i::JSArrayBuffer::kMaxByteLength);
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
LOG_API(i_isolate, ArrayBuffer, New);
|
||||
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate);
|
||||
|
||||
std::shared_ptr<i::BackingStore> backing_store = LookupOrCreateBackingStore(
|
||||
i_isolate, data, byte_length, i::SharedFlag::kNotShared, mode);
|
||||
|
||||
i::Handle<i::JSArrayBuffer> obj =
|
||||
i_isolate->factory()->NewJSArrayBuffer(std::move(backing_store));
|
||||
if (mode == ArrayBufferCreationMode::kExternalized) {
|
||||
obj->set_is_external(true);
|
||||
}
|
||||
return Utils::ToLocal(obj);
|
||||
}
|
||||
|
||||
Local<ArrayBuffer> v8::ArrayBuffer::New(
|
||||
Isolate* isolate, std::shared_ptr<BackingStore> backing_store) {
|
||||
CHECK_IMPLIES(backing_store->ByteLength() != 0,
|
||||
@ -7850,119 +7677,6 @@ Local<DataView> DataView::New(Local<SharedArrayBuffer> shared_array_buffer,
|
||||
return Utils::ToLocal(obj);
|
||||
}
|
||||
|
||||
namespace {
|
||||
i::Handle<i::JSArrayBuffer> SetupSharedArrayBuffer(
|
||||
Isolate* isolate, void* data, size_t byte_length,
|
||||
ArrayBufferCreationMode mode) {
|
||||
CHECK(i::FLAG_harmony_sharedarraybuffer);
|
||||
// Embedders must guarantee that the external backing store is valid.
|
||||
CHECK(byte_length == 0 || data != nullptr);
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
LOG_API(i_isolate, SharedArrayBuffer, New);
|
||||
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate);
|
||||
|
||||
std::shared_ptr<i::BackingStore> backing_store = LookupOrCreateBackingStore(
|
||||
i_isolate, data, byte_length, i::SharedFlag::kShared, mode);
|
||||
|
||||
i::Handle<i::JSArrayBuffer> obj =
|
||||
i_isolate->factory()->NewJSSharedArrayBuffer(std::move(backing_store));
|
||||
|
||||
if (mode == ArrayBufferCreationMode::kExternalized) {
|
||||
obj->set_is_external(true);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool v8::SharedArrayBuffer::IsExternal() const {
|
||||
return Utils::OpenHandle(this)->is_external();
|
||||
}
|
||||
|
||||
v8::SharedArrayBuffer::Contents::Contents(
|
||||
void* data, size_t byte_length, void* allocation_base,
|
||||
size_t allocation_length, Allocator::AllocationMode allocation_mode,
|
||||
DeleterCallback deleter, void* deleter_data)
|
||||
: data_(data),
|
||||
byte_length_(byte_length),
|
||||
allocation_base_(allocation_base),
|
||||
allocation_length_(allocation_length),
|
||||
allocation_mode_(allocation_mode),
|
||||
deleter_(deleter),
|
||||
deleter_data_(deleter_data) {
|
||||
DCHECK_LE(allocation_base_, data_);
|
||||
DCHECK_LE(byte_length_, allocation_length_);
|
||||
}
|
||||
|
||||
v8::SharedArrayBuffer::Contents v8::SharedArrayBuffer::Externalize() {
|
||||
return GetContents(true);
|
||||
}
|
||||
|
||||
void v8::SharedArrayBuffer::Externalize(
|
||||
const std::shared_ptr<BackingStore>& backing_store) {
|
||||
i::Handle<i::JSArrayBuffer> self = Utils::OpenHandle(this);
|
||||
Utils::ApiCheck(!self->is_external(), "v8_SharedArrayBuffer_Externalize",
|
||||
"SharedArrayBuffer already externalized");
|
||||
self->set_is_external(true);
|
||||
|
||||
DCHECK_EQ(self->backing_store(), backing_store->Data());
|
||||
}
|
||||
|
||||
v8::SharedArrayBuffer::Contents v8::SharedArrayBuffer::GetContents() {
|
||||
return GetContents(false);
|
||||
}
|
||||
|
||||
v8::SharedArrayBuffer::Contents v8::SharedArrayBuffer::GetContents(
|
||||
bool externalize) {
|
||||
// TODO(titzer): reduce duplication between shared/unshared GetContents()
|
||||
using BufferType = v8::SharedArrayBuffer;
|
||||
|
||||
i::Handle<i::JSArrayBuffer> self = Utils::OpenHandle(this);
|
||||
|
||||
std::shared_ptr<i::BackingStore> backing_store = self->GetBackingStore();
|
||||
|
||||
void* deleter_data = nullptr;
|
||||
if (externalize) {
|
||||
Utils::ApiCheck(!self->is_external(), "v8_SharedArrayBuffer_Externalize",
|
||||
"SharedArrayBuffer already externalized");
|
||||
self->set_is_external(true);
|
||||
// When externalizing, upref the shared pointer to the backing store
|
||||
// and store that as the deleter data. When the embedder calls the deleter
|
||||
// callback, we will delete the additional (on-heap) shared_ptr.
|
||||
deleter_data = MakeDeleterData(backing_store);
|
||||
}
|
||||
|
||||
if (!backing_store) {
|
||||
// If the array buffer has zero length or was detached, return empty
|
||||
// contents.
|
||||
DCHECK_EQ(0, self->byte_length());
|
||||
BufferType::Contents contents(
|
||||
nullptr, 0, nullptr, 0,
|
||||
v8::ArrayBuffer::Allocator::AllocationMode::kNormal,
|
||||
BackingStoreDeleter, deleter_data);
|
||||
return contents;
|
||||
}
|
||||
|
||||
// Backing stores that given to the embedder might be passed back through
|
||||
// the API using only the start of the buffer. We need to find such
|
||||
// backing stores using global registration until the API is changed.
|
||||
i::GlobalBackingStoreRegistry::Register(backing_store);
|
||||
|
||||
auto allocation_mode =
|
||||
backing_store->is_wasm_memory()
|
||||
? v8::ArrayBuffer::Allocator::AllocationMode::kReservation
|
||||
: v8::ArrayBuffer::Allocator::AllocationMode::kNormal;
|
||||
|
||||
BufferType::Contents contents(backing_store->buffer_start(), // --
|
||||
backing_store->byte_length(), // --
|
||||
backing_store->buffer_start(), // --
|
||||
backing_store->byte_length(), // --
|
||||
allocation_mode, // --
|
||||
BackingStoreDeleter, // --
|
||||
deleter_data);
|
||||
return contents;
|
||||
}
|
||||
|
||||
size_t v8::SharedArrayBuffer::ByteLength() const {
|
||||
i::Handle<i::JSArrayBuffer> obj = Utils::OpenHandle(this);
|
||||
return obj->byte_length();
|
||||
@ -7990,14 +7704,6 @@ Local<SharedArrayBuffer> v8::SharedArrayBuffer::New(Isolate* isolate,
|
||||
return Utils::ToLocalShared(obj);
|
||||
}
|
||||
|
||||
Local<SharedArrayBuffer> v8::SharedArrayBuffer::New(
|
||||
Isolate* isolate, void* data, size_t byte_length,
|
||||
ArrayBufferCreationMode mode) {
|
||||
i::Handle<i::JSArrayBuffer> buffer =
|
||||
SetupSharedArrayBuffer(isolate, data, byte_length, mode);
|
||||
return Utils::ToLocalShared(buffer);
|
||||
}
|
||||
|
||||
Local<SharedArrayBuffer> v8::SharedArrayBuffer::New(
|
||||
Isolate* isolate, std::shared_ptr<BackingStore> backing_store) {
|
||||
CHECK(i::FLAG_harmony_sharedarraybuffer);
|
||||
@ -8015,14 +7721,6 @@ Local<SharedArrayBuffer> v8::SharedArrayBuffer::New(
|
||||
return Utils::ToLocalShared(obj);
|
||||
}
|
||||
|
||||
Local<SharedArrayBuffer> v8::SharedArrayBuffer::New(
|
||||
Isolate* isolate, const SharedArrayBuffer::Contents& contents,
|
||||
ArrayBufferCreationMode mode) {
|
||||
i::Handle<i::JSArrayBuffer> buffer = SetupSharedArrayBuffer(
|
||||
isolate, contents.Data(), contents.ByteLength(), mode);
|
||||
return Utils::ToLocalShared(buffer);
|
||||
}
|
||||
|
||||
std::unique_ptr<v8::BackingStore> v8::SharedArrayBuffer::NewBackingStore(
|
||||
Isolate* isolate, size_t byte_length) {
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
|
@ -47,31 +47,11 @@ Local<TypedArray> CreateAndCheck(Local<v8::ArrayBuffer> ab, int byteOffset,
|
||||
|
||||
std::shared_ptr<v8::BackingStore> Externalize(Local<v8::ArrayBuffer> ab) {
|
||||
std::shared_ptr<v8::BackingStore> backing_store = ab->GetBackingStore();
|
||||
// Keep the tests until the deprecated functions are removed.
|
||||
#if __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated"
|
||||
#endif
|
||||
ab->Externalize(backing_store);
|
||||
CHECK(ab->IsExternal());
|
||||
#if __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
return backing_store;
|
||||
}
|
||||
|
||||
std::shared_ptr<v8::BackingStore> Externalize(Local<v8::SharedArrayBuffer> ab) {
|
||||
std::shared_ptr<v8::BackingStore> backing_store = ab->GetBackingStore();
|
||||
// Keep the tests until the deprecated functions are removed.
|
||||
#if __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated"
|
||||
#endif
|
||||
ab->Externalize(backing_store);
|
||||
CHECK(ab->IsExternal());
|
||||
#if __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
return backing_store;
|
||||
}
|
||||
|
||||
@ -150,46 +130,6 @@ THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
|
||||
CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
|
||||
}
|
||||
|
||||
THREADED_TEST(ArrayBuffer_External) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
i::ScopedVector<uint8_t> my_data(100);
|
||||
memset(my_data.begin(), 0, 100);
|
||||
// Keep the tests until the deprecated functions are removed.
|
||||
#if __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated"
|
||||
#endif
|
||||
Local<v8::ArrayBuffer> ab3 =
|
||||
v8::ArrayBuffer::New(isolate, my_data.begin(), 100);
|
||||
CheckInternalFieldsAreZero(ab3);
|
||||
CHECK_EQ(100, ab3->ByteLength());
|
||||
CHECK(ab3->IsExternal());
|
||||
#if __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
CHECK(env->Global()->Set(env.local(), v8_str("ab3"), ab3).FromJust());
|
||||
|
||||
v8::Local<v8::Value> result = CompileRun("ab3.byteLength");
|
||||
CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
|
||||
|
||||
result = CompileRun(
|
||||
"var u8_b = new Uint8Array(ab3);"
|
||||
"u8_b[0] = 0xBB;"
|
||||
"u8_b[1] = 0xCC;"
|
||||
"u8_b.length");
|
||||
CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
|
||||
CHECK_EQ(0xBB, my_data[0]);
|
||||
CHECK_EQ(0xCC, my_data[1]);
|
||||
my_data[0] = 0xCC;
|
||||
my_data[1] = 0x11;
|
||||
result = CompileRun("u8_b[0] + u8_b[1]");
|
||||
CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
|
||||
}
|
||||
|
||||
THREADED_TEST(ArrayBuffer_DisableDetach) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
@ -293,37 +233,6 @@ THREADED_TEST(ArrayBuffer_DetachingScript) {
|
||||
CheckDataViewIsDetached(dv);
|
||||
}
|
||||
|
||||
// TODO(v8:9380) the Contents data structure should be deprecated.
|
||||
THREADED_TEST(ArrayBuffer_AllocationInformation) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
const size_t ab_size = 1024;
|
||||
Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, ab_size);
|
||||
#if __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated"
|
||||
#endif
|
||||
v8::ArrayBuffer::Contents contents(ab->GetContents());
|
||||
#if __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated"
|
||||
#endif
|
||||
|
||||
// Array buffers should have normal allocation mode.
|
||||
CHECK_EQ(contents.AllocationMode(),
|
||||
v8::ArrayBuffer::Allocator::AllocationMode::kNormal);
|
||||
// The allocation must contain the buffer (normally they will be equal, but
|
||||
// this is not required by the contract).
|
||||
CHECK_NOT_NULL(contents.AllocationBase());
|
||||
const uintptr_t alloc =
|
||||
reinterpret_cast<uintptr_t>(contents.AllocationBase());
|
||||
const uintptr_t data = reinterpret_cast<uintptr_t>(contents.Data());
|
||||
CHECK_LE(alloc, data);
|
||||
CHECK_LE(data + contents.ByteLength(), alloc + contents.AllocationLength());
|
||||
}
|
||||
|
||||
THREADED_TEST(ArrayBuffer_ExternalizeEmpty) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
@ -342,7 +251,6 @@ THREADED_TEST(ArrayBuffer_ExternalizeEmpty) {
|
||||
// marked as is_external or not.
|
||||
USE(u8a->Buffer());
|
||||
|
||||
CHECK(ab->IsExternal());
|
||||
CHECK_EQ(2, backing_store->ByteLength());
|
||||
}
|
||||
|
||||
@ -381,35 +289,6 @@ THREADED_TEST(SharedArrayBuffer_ApiInternalToExternal) {
|
||||
CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
|
||||
}
|
||||
|
||||
THREADED_TEST(ArrayBuffer_ExternalReused) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
i::ScopedVector<uint8_t> data(100);
|
||||
Local<v8::ArrayBuffer> ab1 = v8::ArrayBuffer::New(isolate, data.begin(), 100);
|
||||
std::shared_ptr<v8::BackingStore> bs1 = ab1->GetBackingStore();
|
||||
ab1->Detach();
|
||||
Local<v8::ArrayBuffer> ab2 = v8::ArrayBuffer::New(isolate, data.begin(), 100);
|
||||
std::shared_ptr<v8::BackingStore> bs2 = ab2->GetBackingStore();
|
||||
CHECK_EQ(bs1->Data(), bs2->Data());
|
||||
}
|
||||
|
||||
THREADED_TEST(SharedArrayBuffer_ExternalReused) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
i::ScopedVector<uint8_t> data(100);
|
||||
Local<v8::SharedArrayBuffer> ab1 =
|
||||
v8::SharedArrayBuffer::New(isolate, data.begin(), 100);
|
||||
std::shared_ptr<v8::BackingStore> bs1 = ab1->GetBackingStore();
|
||||
Local<v8::SharedArrayBuffer> ab2 =
|
||||
v8::SharedArrayBuffer::New(isolate, data.begin(), 100);
|
||||
std::shared_ptr<v8::BackingStore> bs2 = ab2->GetBackingStore();
|
||||
CHECK_EQ(bs1->Data(), bs2->Data());
|
||||
}
|
||||
|
||||
THREADED_TEST(SharedArrayBuffer_JSInternalToExternal) {
|
||||
i::FLAG_harmony_sharedarraybuffer = true;
|
||||
LocalContext env;
|
||||
@ -451,64 +330,6 @@ THREADED_TEST(SharedArrayBuffer_JSInternalToExternal) {
|
||||
CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
|
||||
}
|
||||
|
||||
THREADED_TEST(SharedArrayBuffer_External) {
|
||||
i::FLAG_harmony_sharedarraybuffer = true;
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
i::ScopedVector<uint8_t> my_data(100);
|
||||
memset(my_data.begin(), 0, 100);
|
||||
Local<v8::SharedArrayBuffer> ab3 =
|
||||
v8::SharedArrayBuffer::New(isolate, my_data.begin(), 100);
|
||||
CheckInternalFieldsAreZero(ab3);
|
||||
CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
|
||||
CHECK(ab3->IsExternal());
|
||||
|
||||
CHECK(env->Global()->Set(env.local(), v8_str("ab3"), ab3).FromJust());
|
||||
|
||||
v8::Local<v8::Value> result = CompileRun("ab3.byteLength");
|
||||
CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
|
||||
|
||||
result = CompileRun(
|
||||
"var u8_b = new Uint8Array(ab3);"
|
||||
"u8_b[0] = 0xBB;"
|
||||
"u8_b[1] = 0xCC;"
|
||||
"u8_b.length");
|
||||
CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
|
||||
CHECK_EQ(0xBB, my_data[0]);
|
||||
CHECK_EQ(0xCC, my_data[1]);
|
||||
my_data[0] = 0xCC;
|
||||
my_data[1] = 0x11;
|
||||
result = CompileRun("u8_b[0] + u8_b[1]");
|
||||
CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
|
||||
}
|
||||
|
||||
// TODO(v8:9380) the Contents data structure should be deprecated.
|
||||
THREADED_TEST(SharedArrayBuffer_AllocationInformation) {
|
||||
i::FLAG_harmony_sharedarraybuffer = true;
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
const size_t ab_size = 1024;
|
||||
Local<v8::SharedArrayBuffer> ab =
|
||||
v8::SharedArrayBuffer::New(isolate, ab_size);
|
||||
v8::SharedArrayBuffer::Contents contents(ab->GetContents());
|
||||
|
||||
// Array buffers should have normal allocation mode.
|
||||
CHECK_EQ(contents.AllocationMode(),
|
||||
v8::ArrayBuffer::Allocator::AllocationMode::kNormal);
|
||||
// The allocation must contain the buffer (normally they will be equal, but
|
||||
// this is not required by the contract).
|
||||
CHECK_NOT_NULL(contents.AllocationBase());
|
||||
const uintptr_t alloc =
|
||||
reinterpret_cast<uintptr_t>(contents.AllocationBase());
|
||||
const uintptr_t data = reinterpret_cast<uintptr_t>(contents.Data());
|
||||
CHECK_LE(alloc, data);
|
||||
CHECK_LE(data + contents.ByteLength(), alloc + contents.AllocationLength());
|
||||
}
|
||||
|
||||
THREADED_TEST(SkipArrayBufferBackingStoreDuringGC) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
@ -516,9 +337,12 @@ THREADED_TEST(SkipArrayBufferBackingStoreDuringGC) {
|
||||
|
||||
// Make sure the pointer looks like a heap object
|
||||
uint8_t* store_ptr = reinterpret_cast<uint8_t*>(i::kHeapObjectTag);
|
||||
auto backing_store = v8::ArrayBuffer::NewBackingStore(
|
||||
store_ptr, 8, [](void*, size_t, void*) {}, nullptr);
|
||||
|
||||
// Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store
|
||||
Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8);
|
||||
Local<v8::ArrayBuffer> ab =
|
||||
v8::ArrayBuffer::New(isolate, std::move(backing_store));
|
||||
|
||||
// Should not crash
|
||||
CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
|
||||
@ -539,12 +363,15 @@ THREADED_TEST(SkipArrayBufferDuringScavenge) {
|
||||
Local<v8::Object> tmp = v8::Object::New(isolate);
|
||||
uint8_t* store_ptr =
|
||||
reinterpret_cast<uint8_t*>(*reinterpret_cast<uintptr_t*>(*tmp));
|
||||
auto backing_store = v8::ArrayBuffer::NewBackingStore(
|
||||
store_ptr, 8, [](void*, size_t, void*) {}, nullptr);
|
||||
|
||||
// Make `store_ptr` point to from space
|
||||
CcTest::CollectGarbage(i::NEW_SPACE);
|
||||
|
||||
// Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store
|
||||
Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8);
|
||||
Local<v8::ArrayBuffer> ab =
|
||||
v8::ArrayBuffer::New(isolate, std::move(backing_store));
|
||||
|
||||
// Should not crash,
|
||||
// i.e. backing store pointer should not be treated as a heap object pointer
|
||||
|
@ -71,30 +71,6 @@ TEST(CopyContentsView) {
|
||||
TestArrayBufferViewContents(&env, true);
|
||||
}
|
||||
|
||||
|
||||
TEST(AllocateNotExternal) {
|
||||
LocalContext env;
|
||||
v8::HandleScope scope(env->GetIsolate());
|
||||
void* memory = reinterpret_cast<Isolate*>(env->GetIsolate())
|
||||
->array_buffer_allocator()
|
||||
->Allocate(1024);
|
||||
|
||||
// Keep the test until the functions are removed.
|
||||
#if __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated"
|
||||
#endif
|
||||
v8::Local<v8::ArrayBuffer> buffer =
|
||||
v8::ArrayBuffer::New(env->GetIsolate(), memory, 1024,
|
||||
v8::ArrayBufferCreationMode::kInternalized);
|
||||
CHECK(!buffer->IsExternal());
|
||||
#if __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
CHECK_EQ(memory, buffer->GetBackingStore()->Data());
|
||||
}
|
||||
|
||||
void TestSpeciesProtector(char* code,
|
||||
bool invalidates_species_protector = true) {
|
||||
v8::Isolate::CreateParams create_params;
|
||||
|
Loading…
Reference in New Issue
Block a user