Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/deps
diff options
context:
space:
mode:
authorMichaël Zasso <targos@protonmail.com>2021-03-08 10:59:36 +0300
committerMichaël Zasso <targos@protonmail.com>2021-06-14 09:13:27 +0300
commit864fe9910bf0a09dfe5b9e1d0072718d17920338 (patch)
tree30e0fe365eb067a2611f7973fa2493fb4553b3f0 /deps
parent6111671d456f8287090b635da6df8cf72784011f (diff)
deps: make V8 9.1 abi-compatible with 9.0
Revert "[api] Avoid handles for const API functions" This reverts commit aee471b2ff5b1a9e622426454885b748d226535b. Revert "[api] Remove deprecated [Shared]ArrayBuffer API" This reverts commit 578f6be77fc5d8af975005c2baf918e7225abb62. Revert "[Jobs]: Cleanup in v8 platform." This reverts commit baf2b088dd9f585aa597459f30d71431171666e2. Revert "Skip global registration of [Shared]ArrayBuffer backing stores" This reverts commit fcdf35e6d70d51699ece063e25dc705e80673308. PR-URL: https://github.com/nodejs/node/pull/38991 Reviewed-By: Anna Henningsen <anna@addaleax.net>
Diffstat (limited to 'deps')
-rw-r--r--deps/v8/include/v8-platform.h18
-rw-r--r--deps/v8/include/v8.h276
-rw-r--r--deps/v8/src/api/api.cc529
-rw-r--r--deps/v8/src/objects/backing-store.cc37
-rw-r--r--deps/v8/src/objects/backing-store.h11
-rw-r--r--deps/v8/src/objects/string-inl.h78
-rw-r--r--deps/v8/src/objects/string.cc11
-rw-r--r--deps/v8/src/objects/string.h92
-rw-r--r--deps/v8/src/wasm/module-compiler.cc2
-rw-r--r--deps/v8/test/cctest/test-api-array-buffer.cc189
-rw-r--r--deps/v8/test/cctest/test-typedarrays.cc24
11 files changed, 1029 insertions, 238 deletions
diff --git a/deps/v8/include/v8-platform.h b/deps/v8/include/v8-platform.h
index fc9a357feb6..4c94d7fd392 100644
--- a/deps/v8/include/v8-platform.h
+++ b/deps/v8/include/v8-platform.h
@@ -181,8 +181,9 @@ class JobDelegate {
/**
* Returns true if the current task is called from the thread currently
* running JobHandle::Join().
+ * TODO(etiennep): Make pure virtual once custom embedders implement it.
*/
- virtual bool IsJoiningThread() const = 0;
+ virtual bool IsJoiningThread() const { return false; }
};
/**
@@ -219,14 +220,19 @@ class JobHandle {
* Forces all existing workers to yield ASAP but doesn’t wait for them.
* Warning, this is dangerous if the Job's callback is bound to or has access
* to state which may be deleted after this call.
+ * TODO(etiennep): Cleanup once implemented by all embedders.
*/
- virtual void CancelAndDetach() = 0;
+ virtual void CancelAndDetach() { Cancel(); }
/**
* Returns true if there's any work pending or any worker running.
*/
virtual bool IsActive() = 0;
+ // TODO(etiennep): Clean up once all overrides are removed.
+ V8_DEPRECATED("Use !IsActive() instead.")
+ virtual bool IsCompleted() { return !IsActive(); }
+
/**
* Returns true if associated with a Job and other methods may be called.
* Returns false after Join() or Cancel() was called. This may return true
@@ -234,6 +240,10 @@ class JobHandle {
*/
virtual bool IsValid() = 0;
+ // TODO(etiennep): Clean up once all overrides are removed.
+ V8_DEPRECATED("Use IsValid() instead.")
+ virtual bool IsRunning() { return IsValid(); }
+
/**
* Returns true if job priority can be changed.
*/
@@ -262,6 +272,10 @@ class JobTask {
* it must not call back any JobHandle methods.
*/
virtual size_t GetMaxConcurrency(size_t worker_count) const = 0;
+
+ // TODO(1114823): Clean up once all overrides are removed.
+ V8_DEPRECATED("Use the version that takes |worker_count|.")
+ virtual size_t GetMaxConcurrency() const { return 0; }
};
/**
diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h
index ba87e57a1e2..840dd2c2258 100644
--- a/deps/v8/include/v8.h
+++ b/deps/v8/include/v8.h
@@ -1495,7 +1495,7 @@ class V8_EXPORT UnboundScript {
*/
Local<Script> BindToCurrentContext();
- int GetId() const;
+ int GetId();
Local<Value> GetScriptName();
/**
@@ -1705,7 +1705,7 @@ class V8_EXPORT Module : public Data {
*
* The module must be a SourceTextModule and must not have a kErrored status.
*/
- int ScriptId() const;
+ int ScriptId();
/**
* Returns whether this module or any of its requested modules is async,
@@ -3547,12 +3547,12 @@ class V8_EXPORT String : public Name {
/**
* Returns true if this string can be made external.
*/
- bool CanMakeExternal() const;
+ bool CanMakeExternal();
/**
* Returns true if the strings values are equal. Same as JS ==/===.
*/
- bool StringEquals(Local<String> str) const;
+ bool StringEquals(Local<String> str);
/**
* Converts an object to a UTF-8-encoded character array. Useful if
@@ -4162,7 +4162,7 @@ class V8_EXPORT Object : public Value {
Maybe<bool> SetIntegrityLevel(Local<Context> context, IntegrityLevel level);
/** Gets the number of internal fields for this Object. */
- int InternalFieldCount() const;
+ int InternalFieldCount();
/** Same as above, but works for PersistentBase. */
V8_INLINE static int InternalFieldCount(
@@ -4272,10 +4272,10 @@ class V8_EXPORT Object : public Value {
Local<Context> context, Local<Name> key);
/** Tests for a named lookup interceptor.*/
- bool HasNamedLookupInterceptor() const;
+ bool HasNamedLookupInterceptor();
/** Tests for an index lookup interceptor.*/
- bool HasIndexedLookupInterceptor() const;
+ bool HasIndexedLookupInterceptor();
/**
* Returns the identity hash for this object. The current implementation
@@ -4315,12 +4315,12 @@ class V8_EXPORT Object : public Value {
* ObjectTemplate::SetCallAsFunctionHandler method.
* When an Object is callable this method returns true.
*/
- bool IsCallable() const;
+ bool IsCallable();
/**
* True if this object is a constructor.
*/
- bool IsConstructor() const;
+ bool IsConstructor();
/**
* True if this object can carry information relevant to the embedder in its
@@ -4329,14 +4329,14 @@ class V8_EXPORT Object : public Value {
* V8 automatically adds internal fields at compile time, such as e.g.
* v8::ArrayBuffer.
*/
- bool IsApiWrapper() const;
+ bool IsApiWrapper();
/**
* True if this object was created from an object template which was marked
* as undetectable. See v8::ObjectTemplate::MarkAsUndetectable for more
* information.
*/
- bool IsUndetectable() const;
+ bool IsUndetectable();
/**
* Call an Object as a function if a callback is set by the
@@ -4395,7 +4395,7 @@ class V8_EXPORT Object : public Value {
*
* See also: v8::ObjectTemplate::SetCodeLike
*/
- bool IsCodeLike(Isolate* isolate) const;
+ bool IsCodeLike(Isolate* isolate);
private:
Object();
@@ -4893,7 +4893,7 @@ class V8_EXPORT Promise : public Object {
* Returns true if the promise has at least one derived promise, and
* therefore resolve/reject handlers (including default handler).
*/
- bool HasHandler() const;
+ bool HasHandler();
/**
* Returns the content of the [[PromiseResult]] field. The Promise must not
@@ -5001,7 +5001,7 @@ class V8_EXPORT Proxy : public Object {
public:
Local<Value> GetTarget();
Local<Value> GetHandler();
- bool IsRevoked() const;
+ bool IsRevoked();
void Revoke();
/**
@@ -5417,6 +5417,57 @@ class V8_EXPORT ArrayBuffer : public Object {
};
/**
+ * 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.
*/
size_t ByteLength() const;
@@ -5430,6 +5481,22 @@ 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
* is garbage collected. Note that the IsExternal bit does not affect this
@@ -5468,6 +5535,15 @@ class V8_EXPORT ArrayBuffer : public Object {
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.
*/
bool IsDetachable() const;
@@ -5481,10 +5557,46 @@ 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();
@@ -5496,6 +5608,7 @@ class V8_EXPORT ArrayBuffer : public Object {
private:
ArrayBuffer();
static void CheckCast(Value* obj);
+ Contents GetContents(bool externalize);
};
@@ -5789,6 +5902,57 @@ 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.
*/
size_t ByteLength() const;
@@ -5802,6 +5966,19 @@ 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
* is garbage collected. Note that the IsExternal bit does not affect this
@@ -5840,10 +6017,72 @@ class V8_EXPORT SharedArrayBuffer : public Object {
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();
@@ -5854,6 +6093,7 @@ class V8_EXPORT SharedArrayBuffer : public Object {
private:
SharedArrayBuffer();
static void CheckCast(Value* obj);
+ Contents GetContents(bool externalize);
};
@@ -6953,7 +7193,7 @@ class V8_EXPORT ObjectTemplate : public Template {
* Gets the number of internal fields for objects generated from
* this template.
*/
- int InternalFieldCount() const;
+ int InternalFieldCount();
/**
* Sets the number of internal fields for objects generated from
@@ -6964,7 +7204,7 @@ class V8_EXPORT ObjectTemplate : public Template {
/**
* Returns true if the object will be an immutable prototype exotic object.
*/
- bool IsImmutableProto() const;
+ bool IsImmutableProto();
/**
* Makes the ObjectTemplate for an immutable prototype exotic object, with an
@@ -6982,7 +7222,7 @@ class V8_EXPORT ObjectTemplate : public Template {
* Reference: https://github.com/tc39/proposal-dynamic-code-brand-checks
*/
void SetCodeLike();
- bool IsCodeLike() const;
+ bool IsCodeLike();
V8_INLINE static ObjectTemplate* Cast(Data* data);
@@ -10547,7 +10787,7 @@ class V8_EXPORT Context : public Data {
* Returns true if code generation from strings is allowed for the context.
* For more details see AllowCodeGenerationFromStrings(bool) documentation.
*/
- bool IsCodeGenerationFromStringsAllowed() const;
+ bool IsCodeGenerationFromStringsAllowed();
/**
* Sets the error description for the exception that is thrown when
diff --git a/deps/v8/src/api/api.cc b/deps/v8/src/api/api.cc
index b0849860421..01833cafc61 100644
--- a/deps/v8/src/api/api.cc
+++ b/deps/v8/src/api/api.cc
@@ -937,9 +937,11 @@ bool Data::IsModule() const { return Utils::OpenHandle(this)->IsModule(); }
bool Data::IsValue() const {
i::DisallowGarbageCollection no_gc;
- i::Object self = *Utils::OpenHandle(this);
- if (self.IsSmi()) return true;
- i::HeapObject heap_object = i::HeapObject::cast(self);
+ i::Handle<i::Object> self = Utils::OpenHandle(this);
+ if (self->IsSmi()) {
+ return true;
+ }
+ i::HeapObject heap_object = i::HeapObject::cast(*self);
DCHECK(!heap_object.IsTheHole());
if (heap_object.IsSymbol()) {
return !i::Symbol::cast(heap_object).is_private();
@@ -1764,7 +1766,7 @@ void ObjectTemplate::SetCallAsFunctionHandler(FunctionCallback callback,
i::FunctionTemplateInfo::SetInstanceCallHandler(isolate, cons, obj);
}
-int ObjectTemplate::InternalFieldCount() const {
+int ObjectTemplate::InternalFieldCount() {
return Utils::OpenHandle(this)->embedder_field_count();
}
@@ -1785,7 +1787,7 @@ void ObjectTemplate::SetInternalFieldCount(int value) {
Utils::OpenHandle(this)->set_embedder_field_count(value);
}
-bool ObjectTemplate::IsImmutableProto() const {
+bool ObjectTemplate::IsImmutableProto() {
return Utils::OpenHandle(this)->immutable_proto();
}
@@ -1796,7 +1798,7 @@ void ObjectTemplate::SetImmutableProto() {
self->set_immutable_proto(true);
}
-bool ObjectTemplate::IsCodeLike() const {
+bool ObjectTemplate::IsCodeLike() {
return Utils::OpenHandle(this)->code_like();
}
@@ -1851,11 +1853,15 @@ Local<Script> UnboundScript::BindToCurrentContext() {
return ToApiHandle<Script>(function);
}
-int UnboundScript::GetId() const {
- auto function_info = i::SharedFunctionInfo::cast(*Utils::OpenHandle(this));
- i::Isolate* isolate = function_info.GetIsolate();
+int UnboundScript::GetId() {
+ auto function_info =
+ i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(this));
+ i::Isolate* isolate = function_info->GetIsolate();
LOG_API(isolate, UnboundScript, GetId);
- return i::Script::cast(function_info.script()).id();
+ i::HandleScope scope(isolate);
+ i::Handle<i::Script> script(i::Script::cast(function_info->script()),
+ isolate);
+ return script->id();
}
int UnboundScript::GetLineNumber(int code_pos) {
@@ -2066,10 +2072,13 @@ Local<Value> Module::GetException() const {
}
int Module::GetModuleRequestsLength() const {
- i::Module self = *Utils::OpenHandle(this);
- if (self.IsSyntheticModule()) return 0;
- ASSERT_NO_SCRIPT_NO_EXCEPTION(self.GetIsolate());
- return i::SourceTextModule::cast(self).info().module_requests().length();
+ i::Handle<i::Module> self = Utils::OpenHandle(this);
+ if (self->IsSyntheticModule()) return 0;
+ ASSERT_NO_SCRIPT_NO_EXCEPTION(self->GetIsolate());
+ return i::Handle<i::SourceTextModule>::cast(self)
+ ->info()
+ .module_requests()
+ .length();
}
Local<String> Module::GetModuleRequest(int i) const {
@@ -2170,22 +2179,22 @@ Local<UnboundModuleScript> Module::GetUnboundModuleScript() {
isolate));
}
-int Module::ScriptId() const {
- i::Module self = *Utils::OpenHandle(this);
- Utils::ApiCheck(self.IsSourceTextModule(), "v8::Module::ScriptId",
+int Module::ScriptId() {
+ i::Handle<i::Module> self = Utils::OpenHandle(this);
+ Utils::ApiCheck(self->IsSourceTextModule(), "v8::Module::ScriptId",
"v8::Module::ScriptId must be used on an SourceTextModule");
- ASSERT_NO_SCRIPT_NO_EXCEPTION(self.GetIsolate());
- return i::SourceTextModule::cast(self).GetScript().id();
+ ASSERT_NO_SCRIPT_NO_EXCEPTION(self->GetIsolate());
+ return i::Handle<i::SourceTextModule>::cast(self)->GetScript().id();
}
bool Module::IsGraphAsync() const {
Utils::ApiCheck(
GetStatus() >= kInstantiated, "v8::Module::IsGraphAsync",
"v8::Module::IsGraphAsync must be used on an instantiated module");
- i::Module self = *Utils::OpenHandle(this);
- auto isolate = self.GetIsolate();
+ i::Handle<i::Module> self = Utils::OpenHandle(this);
+ auto isolate = self->GetIsolate();
ASSERT_NO_SCRIPT_NO_EXCEPTION(isolate);
- return self.IsGraphAsync(isolate);
+ return self->IsGraphAsync(isolate);
}
bool Module::IsSourceTextModule() const {
@@ -3323,15 +3332,15 @@ bool Value::FullIsNull() const {
}
bool Value::IsTrue() const {
- i::Object object = *Utils::OpenHandle(this);
- if (object.IsSmi()) return false;
- return object.IsTrue();
+ i::Handle<i::Object> object = Utils::OpenHandle(this);
+ if (object->IsSmi()) return false;
+ return object->IsTrue();
}
bool Value::IsFalse() const {
- i::Object object = *Utils::OpenHandle(this);
- if (object.IsSmi()) return false;
- return object.IsFalse();
+ i::Handle<i::Object> object = Utils::OpenHandle(this);
+ if (object->IsSmi()) return false;
+ return object->IsFalse();
}
bool Value::IsFunction() const { return Utils::OpenHandle(this)->IsCallable(); }
@@ -3351,9 +3360,8 @@ bool Value::IsSymbol() const {
bool Value::IsArray() const { return Utils::OpenHandle(this)->IsJSArray(); }
bool Value::IsArrayBuffer() const {
- i::Object obj = *Utils::OpenHandle(this);
- if (!obj.IsJSArrayBuffer()) return false;
- return !i::JSArrayBuffer::cast(obj).is_shared();
+ i::Handle<i::Object> obj = Utils::OpenHandle(this);
+ return obj->IsJSArrayBuffer() && !i::JSArrayBuffer::cast(*obj).is_shared();
}
bool Value::IsArrayBufferView() const {
@@ -3380,9 +3388,8 @@ bool Value::IsDataView() const {
}
bool Value::IsSharedArrayBuffer() const {
- i::Object obj = *Utils::OpenHandle(this);
- if (!obj.IsJSArrayBuffer()) return false;
- return i::JSArrayBuffer::cast(obj).is_shared();
+ i::Handle<i::Object> obj = Utils::OpenHandle(this);
+ return obj->IsJSArrayBuffer() && i::JSArrayBuffer::cast(*obj).is_shared();
}
bool Value::IsObject() const { return Utils::OpenHandle(this)->IsJSReceiver(); }
@@ -3423,23 +3430,23 @@ VALUE_IS_SPECIFIC_TYPE(WeakSet, JSWeakSet)
bool Value::IsBoolean() const { return Utils::OpenHandle(this)->IsBoolean(); }
bool Value::IsExternal() const {
- i::Object obj = *Utils::OpenHandle(this);
- if (!obj.IsHeapObject()) return false;
- i::HeapObject heap_obj = i::HeapObject::cast(obj);
+ i::Handle<i::Object> obj = Utils::OpenHandle(this);
+ if (!obj->IsHeapObject()) return false;
+ i::Handle<i::HeapObject> heap_obj = i::Handle<i::HeapObject>::cast(obj);
// Check the instance type is JS_OBJECT (instance type of Externals) before
// attempting to get the Isolate since that guarantees the object is writable
// and GetIsolate will work.
- if (heap_obj.map().instance_type() != i::JS_OBJECT_TYPE) return false;
- i::Isolate* isolate = i::JSObject::cast(heap_obj).GetIsolate();
+ if (heap_obj->map().instance_type() != i::JS_OBJECT_TYPE) return false;
+ i::Isolate* isolate = i::JSObject::cast(*heap_obj).GetIsolate();
ASSERT_NO_SCRIPT_NO_EXCEPTION(isolate);
- return heap_obj.IsExternal(isolate);
+ return heap_obj->IsExternal(isolate);
}
bool Value::IsInt32() const {
- i::Object obj = *Utils::OpenHandle(this);
- if (obj.IsSmi()) return true;
- if (obj.IsNumber()) {
- return i::IsInt32Double(obj.Number());
+ i::Handle<i::Object> obj = Utils::OpenHandle(this);
+ if (obj->IsSmi()) return true;
+ if (obj->IsNumber()) {
+ return i::IsInt32Double(obj->Number());
}
return false;
}
@@ -3465,18 +3472,18 @@ bool Value::IsRegExp() const {
}
bool Value::IsAsyncFunction() const {
- i::Object obj = *Utils::OpenHandle(this);
- if (!obj.IsJSFunction()) return false;
- i::JSFunction func = i::JSFunction::cast(obj);
- return i::IsAsyncFunction(func.shared().kind());
+ i::Handle<i::Object> obj = Utils::OpenHandle(this);
+ if (!obj->IsJSFunction()) return false;
+ i::Handle<i::JSFunction> func = i::Handle<i::JSFunction>::cast(obj);
+ return i::IsAsyncFunction(func->shared().kind());
}
bool Value::IsGeneratorFunction() const {
- i::Object obj = *Utils::OpenHandle(this);
- if (!obj.IsJSFunction()) return false;
- i::JSFunction func = i::JSFunction::cast(obj);
- ASSERT_NO_SCRIPT_NO_EXCEPTION(func.GetIsolate());
- return i::IsGeneratorFunction(func.shared().kind());
+ i::Handle<i::Object> obj = Utils::OpenHandle(this);
+ if (!obj->IsJSFunction()) return false;
+ i::Handle<i::JSFunction> func = i::Handle<i::JSFunction>::cast(obj);
+ ASSERT_NO_SCRIPT_NO_EXCEPTION(func->GetIsolate());
+ return i::IsGeneratorFunction(func->shared().kind());
}
bool Value::IsGeneratorObject() const {
@@ -3797,6 +3804,7 @@ std::shared_ptr<v8::BackingStore> v8::ArrayBuffer::GetBackingStore() {
backing_store =
i::BackingStore::EmptyBackingStore(i::SharedFlag::kNotShared);
}
+ i::GlobalBackingStoreRegistry::Register(backing_store);
std::shared_ptr<i::BackingStoreBase> bs_base = backing_store;
return std::static_pointer_cast<v8::BackingStore>(bs_base);
}
@@ -3807,6 +3815,7 @@ std::shared_ptr<v8::BackingStore> v8::SharedArrayBuffer::GetBackingStore() {
if (!backing_store) {
backing_store = i::BackingStore::EmptyBackingStore(i::SharedFlag::kShared);
}
+ i::GlobalBackingStoreRegistry::Register(backing_store);
std::shared_ptr<i::BackingStoreBase> bs_base = backing_store;
return std::static_pointer_cast<v8::BackingStore>(bs_base);
}
@@ -4678,16 +4687,16 @@ Maybe<bool> v8::Object::HasRealNamedCallbackProperty(Local<Context> context,
return result;
}
-bool v8::Object::HasNamedLookupInterceptor() const {
- auto self = *Utils::OpenHandle(this);
- if (self.IsJSObject()) return false;
- return i::JSObject::cast(self).HasNamedInterceptor();
+bool v8::Object::HasNamedLookupInterceptor() {
+ auto self = Utils::OpenHandle(this);
+ return self->IsJSObject() &&
+ i::Handle<i::JSObject>::cast(self)->HasNamedInterceptor();
}
-bool v8::Object::HasIndexedLookupInterceptor() const {
- auto self = *Utils::OpenHandle(this);
- if (self.IsJSObject()) return false;
- return i::JSObject::cast(self).HasIndexedInterceptor();
+bool v8::Object::HasIndexedLookupInterceptor() {
+ auto self = Utils::OpenHandle(this);
+ return self->IsJSObject() &&
+ i::Handle<i::JSObject>::cast(self)->HasIndexedInterceptor();
}
MaybeLocal<Value> v8::Object::GetRealNamedPropertyInPrototypeChain(
@@ -4822,22 +4831,22 @@ int v8::Object::GetIdentityHash() {
return self->GetOrCreateIdentityHash(isolate).value();
}
-bool v8::Object::IsCallable() const {
+bool v8::Object::IsCallable() {
auto self = Utils::OpenHandle(this);
return self->IsCallable();
}
-bool v8::Object::IsConstructor() const {
+bool v8::Object::IsConstructor() {
auto self = Utils::OpenHandle(this);
return self->IsConstructor();
}
-bool v8::Object::IsApiWrapper() const {
+bool v8::Object::IsApiWrapper() {
auto self = i::Handle<i::JSObject>::cast(Utils::OpenHandle(this));
return self->IsApiWrapper();
}
-bool v8::Object::IsUndetectable() const {
+bool v8::Object::IsUndetectable() {
auto self = i::Handle<i::JSObject>::cast(Utils::OpenHandle(this));
return self->IsUndetectable();
}
@@ -5078,11 +5087,17 @@ int Function::GetScriptColumnNumber() const {
}
int Function::ScriptId() const {
- i::JSReceiver self = *Utils::OpenHandle(this);
- if (!self.IsJSFunction()) return v8::UnboundScript::kNoScriptId;
- auto func = i::JSFunction::cast(self);
- if (!func.shared().script().IsScript()) return v8::UnboundScript::kNoScriptId;
- return i::Script::cast(func.shared().script()).id();
+ auto self = Utils::OpenHandle(this);
+ if (!self->IsJSFunction()) {
+ return v8::UnboundScript::kNoScriptId;
+ }
+ auto func = i::Handle<i::JSFunction>::cast(self);
+ if (!func->shared().script().IsScript()) {
+ return v8::UnboundScript::kNoScriptId;
+ }
+ i::Handle<i::Script> script(i::Script::cast(func->shared().script()),
+ func->GetIsolate());
+ return script->id();
}
Local<v8::Value> Function::GetBoundFunction() const {
@@ -5616,36 +5631,36 @@ bool Boolean::Value() const {
}
int64_t Integer::Value() const {
- i::Object obj = *Utils::OpenHandle(this);
- if (obj.IsSmi()) {
- return i::Smi::ToInt(obj);
+ i::Handle<i::Object> obj = Utils::OpenHandle(this);
+ if (obj->IsSmi()) {
+ return i::Smi::ToInt(*obj);
} else {
- return static_cast<int64_t>(obj.Number());
+ return static_cast<int64_t>(obj->Number());
}
}
int32_t Int32::Value() const {
- i::Object obj = *Utils::OpenHandle(this);
- if (obj.IsSmi()) {
- return i::Smi::ToInt(obj);
+ i::Handle<i::Object> obj = Utils::OpenHandle(this);
+ if (obj->IsSmi()) {
+ return i::Smi::ToInt(*obj);
} else {
- return static_cast<int32_t>(obj.Number());
+ return static_cast<int32_t>(obj->Number());
}
}
uint32_t Uint32::Value() const {
- i::Object obj = *Utils::OpenHandle(this);
- if (obj.IsSmi()) {
- return i::Smi::ToInt(obj);
+ i::Handle<i::Object> obj = Utils::OpenHandle(this);
+ if (obj->IsSmi()) {
+ return i::Smi::ToInt(*obj);
} else {
- return static_cast<uint32_t>(obj.Number());
+ return static_cast<uint32_t>(obj->Number());
}
}
-int v8::Object::InternalFieldCount() const {
- i::JSReceiver self = *Utils::OpenHandle(this);
- if (!self.IsJSObject()) return 0;
- return i::JSObject::cast(self).GetEmbedderFieldCount();
+int v8::Object::InternalFieldCount() {
+ i::Handle<i::JSReceiver> self = Utils::OpenHandle(this);
+ if (!self->IsJSObject()) return 0;
+ return i::Handle<i::JSObject>::cast(self)->GetEmbedderFieldCount();
}
static bool InternalFieldOK(i::Handle<i::JSReceiver> obj, int index,
@@ -6178,9 +6193,9 @@ void Context::AllowCodeGenerationFromStrings(bool allow) {
: i::ReadOnlyRoots(isolate).false_value());
}
-bool Context::IsCodeGenerationFromStringsAllowed() const {
- i::Context context = *Utils::OpenHandle(this);
- return !context.allow_code_gen_from_strings().IsFalse(context.GetIsolate());
+bool Context::IsCodeGenerationFromStringsAllowed() {
+ i::Handle<i::Context> context = Utils::OpenHandle(this);
+ return !context->allow_code_gen_from_strings().IsFalse(context->GetIsolate());
}
void Context::SetErrorMessageForCodeGenerationFromStrings(Local<String> error) {
@@ -6624,7 +6639,8 @@ bool v8::String::MakeExternal(
return result;
}
-bool v8::String::CanMakeExternal() const {
+bool v8::String::CanMakeExternal() {
+ i::DisallowGarbageCollection no_gc;
i::String obj = *Utils::OpenHandle(this);
if (obj.IsThinString()) {
@@ -6639,7 +6655,7 @@ bool v8::String::CanMakeExternal() const {
return !i::Heap::InYoungGeneration(obj);
}
-bool v8::String::StringEquals(Local<String> that) const {
+bool v8::String::StringEquals(Local<String> that) {
auto self = Utils::OpenHandle(this);
auto other = Utils::OpenHandle(*that);
return self->Equals(*other);
@@ -6810,11 +6826,12 @@ Local<v8::Value> v8::BooleanObject::New(Isolate* isolate, bool value) {
}
bool v8::BooleanObject::ValueOf() const {
- i::Object obj = *Utils::OpenHandle(this);
- i::JSPrimitiveWrapper js_primitive_wrapper = i::JSPrimitiveWrapper::cast(obj);
- i::Isolate* isolate = js_primitive_wrapper.GetIsolate();
+ i::Handle<i::Object> obj = Utils::OpenHandle(this);
+ i::Handle<i::JSPrimitiveWrapper> js_primitive_wrapper =
+ i::Handle<i::JSPrimitiveWrapper>::cast(obj);
+ i::Isolate* isolate = js_primitive_wrapper->GetIsolate();
LOG_API(isolate, BooleanObject, BooleanValue);
- return js_primitive_wrapper.value().IsTrue(isolate);
+ return js_primitive_wrapper->value().IsTrue(isolate);
}
Local<v8::Value> v8::StringObject::New(Isolate* v8_isolate,
@@ -7341,13 +7358,16 @@ MaybeLocal<Promise> Promise::Then(Local<Context> context,
RETURN_ESCAPED(Local<Promise>::Cast(Utils::ToLocal(result)));
}
-bool Promise::HasHandler() const {
- i::JSReceiver promise = *Utils::OpenHandle(this);
- i::Isolate* isolate = promise.GetIsolate();
+bool Promise::HasHandler() {
+ i::Handle<i::JSReceiver> promise = Utils::OpenHandle(this);
+ i::Isolate* isolate = promise->GetIsolate();
LOG_API(isolate, Promise, HasRejectHandler);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
- if (!promise.IsJSPromise()) return false;
- return i::JSPromise::cast(promise).has_handler();
+ if (promise->IsJSPromise()) {
+ i::Handle<i::JSPromise> js_promise = i::Handle<i::JSPromise>::cast(promise);
+ return js_promise->has_handler();
+ }
+ return false;
}
Local<Value> Promise::Result() {
@@ -7386,7 +7406,7 @@ Local<Value> Proxy::GetHandler() {
return Utils::ToLocal(handler);
}
-bool Proxy::IsRevoked() const {
+bool Proxy::IsRevoked() {
i::Handle<i::JSProxy> self = Utils::OpenHandle(this);
return self->IsRevoked();
}
@@ -7513,17 +7533,169 @@ 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();
@@ -7557,6 +7729,27 @@ 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,
@@ -7730,6 +7923,119 @@ 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();
@@ -7758,6 +8064,14 @@ Local<SharedArrayBuffer> v8::SharedArrayBuffer::New(Isolate* isolate,
}
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);
CHECK_IMPLIES(backing_store->ByteLength() != 0,
@@ -7774,6 +8088,14 @@ 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);
@@ -9070,7 +9392,7 @@ void v8::Isolate::LocaleConfigurationChangeNotification() {
#endif // V8_INTL_SUPPORT
}
-bool v8::Object::IsCodeLike(v8::Isolate* isolate) const {
+bool v8::Object::IsCodeLike(v8::Isolate* isolate) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
LOG_API(i_isolate, Object, IsCodeLike);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate);
@@ -9121,21 +9443,18 @@ MicrotasksScope::~MicrotasksScope() {
#endif
}
-// static
void MicrotasksScope::PerformCheckpoint(Isolate* v8_isolate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
auto* microtask_queue = isolate->default_microtask_queue();
microtask_queue->PerformCheckpoint(v8_isolate);
}
-// static
int MicrotasksScope::GetCurrentDepth(Isolate* v8_isolate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
auto* microtask_queue = isolate->default_microtask_queue();
return microtask_queue->GetMicrotasksScopeDepth();
}
-// static
bool MicrotasksScope::IsRunningMicrotasks(Isolate* v8_isolate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
auto* microtask_queue = isolate->default_microtask_queue();
diff --git a/deps/v8/src/objects/backing-store.cc b/deps/v8/src/objects/backing-store.cc
index 08288ef62c0..7931fbf13dd 100644
--- a/deps/v8/src/objects/backing-store.cc
+++ b/deps/v8/src/objects/backing-store.cc
@@ -685,8 +685,17 @@ inline GlobalBackingStoreRegistryImpl* impl() {
void GlobalBackingStoreRegistry::Register(
std::shared_ptr<BackingStore> backing_store) {
if (!backing_store || !backing_store->buffer_start()) return;
- // Only wasm memory backing stores need to be registered globally.
- CHECK(backing_store->is_wasm_memory());
+
+ if (!backing_store->free_on_destruct()) {
+ // If the backing store buffer is managed by the embedder,
+ // then we don't have to guarantee that there is single unique
+ // BackingStore per buffer_start() because the destructor of
+ // of the BackingStore will be a no-op in that case.
+
+ // All Wasm memory has to be registered.
+ CHECK(!backing_store->is_wasm_memory());
+ return;
+ }
base::MutexGuard scope_lock(&impl()->mutex_);
if (backing_store->globally_registered_) return;
@@ -702,8 +711,6 @@ void GlobalBackingStoreRegistry::Register(
void GlobalBackingStoreRegistry::Unregister(BackingStore* backing_store) {
if (!backing_store->globally_registered_) return;
- CHECK(backing_store->is_wasm_memory());
-
DCHECK_NOT_NULL(backing_store->buffer_start());
base::MutexGuard scope_lock(&impl()->mutex_);
@@ -715,6 +722,26 @@ void GlobalBackingStoreRegistry::Unregister(BackingStore* backing_store) {
backing_store->globally_registered_ = false;
}
+std::shared_ptr<BackingStore> GlobalBackingStoreRegistry::Lookup(
+ void* buffer_start, size_t length) {
+ base::MutexGuard scope_lock(&impl()->mutex_);
+ TRACE_BS("BS:lookup mem=%p (%zu bytes)\n", buffer_start, length);
+ const auto& result = impl()->map_.find(buffer_start);
+ if (result == impl()->map_.end()) {
+ return std::shared_ptr<BackingStore>();
+ }
+ auto backing_store = result->second.lock();
+ CHECK_EQ(buffer_start, backing_store->buffer_start());
+ if (backing_store->is_wasm_memory()) {
+ // Grow calls to shared WebAssembly threads can be triggered from different
+ // workers, length equality cannot be guaranteed here.
+ CHECK_LE(length, backing_store->byte_length());
+ } else {
+ CHECK_EQ(length, backing_store->byte_length());
+ }
+ return backing_store;
+}
+
void GlobalBackingStoreRegistry::Purge(Isolate* isolate) {
// We need to keep a reference to all backing stores that are inspected
// in the purging loop below. Otherwise, we might get a deadlock
@@ -728,7 +755,7 @@ void GlobalBackingStoreRegistry::Purge(Isolate* isolate) {
auto backing_store = entry.second.lock();
prevent_destruction_under_lock.emplace_back(backing_store);
if (!backing_store) continue; // skip entries where weak ptr is null
- CHECK(backing_store->is_wasm_memory());
+ if (!backing_store->is_wasm_memory()) continue; // skip non-wasm memory
if (!backing_store->is_shared()) continue; // skip non-shared memory
SharedWasmMemoryData* shared_data =
backing_store->get_shared_wasm_memory_data();
diff --git a/deps/v8/src/objects/backing-store.h b/deps/v8/src/objects/backing-store.h
index eb879d5e8ad..4d20109676e 100644
--- a/deps/v8/src/objects/backing-store.h
+++ b/deps/v8/src/objects/backing-store.h
@@ -219,16 +219,21 @@ class V8_EXPORT_PRIVATE BackingStore : public BackingStoreBase {
#endif // V8_ENABLE_WEBASSEMBLY
};
-// A global, per-process mapping from buffer addresses to backing stores
-// of wasm memory objects.
+// A global, per-process mapping from buffer addresses to backing stores.
+// This is generally only used for dealing with an embedder that has not
+// migrated to the new API which should use proper pointers to manage
+// backing stores.
class GlobalBackingStoreRegistry {
public:
// Register a backing store in the global registry. A mapping from the
// {buffer_start} to the backing store object will be added. The backing
// store will automatically unregister itself upon destruction.
- // Only wasm memory backing stores are supported.
static void Register(std::shared_ptr<BackingStore> backing_store);
+ // Look up a backing store based on the {buffer_start} pointer.
+ static std::shared_ptr<BackingStore> Lookup(void* buffer_start,
+ size_t length);
+
private:
friend class BackingStore;
// Unregister a backing store in the global registry.
diff --git a/deps/v8/src/objects/string-inl.h b/deps/v8/src/objects/string-inl.h
index 912109b2e0a..5db17a0b6cd 100644
--- a/deps/v8/src/objects/string-inl.h
+++ b/deps/v8/src/objects/string-inl.h
@@ -134,51 +134,49 @@ StringShape::StringShape(InstanceType t) : type_(static_cast<uint32_t>(t)) {
DCHECK_EQ(type_ & kIsNotStringMask, kStringTag);
}
-bool StringShape::IsInternalized() const {
+bool StringShape::IsInternalized() {
DCHECK(valid());
STATIC_ASSERT(kNotInternalizedTag != 0);
return (type_ & (kIsNotStringMask | kIsNotInternalizedMask)) ==
(kStringTag | kInternalizedTag);
}
-bool StringShape::IsCons() const {
+bool StringShape::IsCons() {
return (type_ & kStringRepresentationMask) == kConsStringTag;
}
-bool StringShape::IsThin() const {
+bool StringShape::IsThin() {
return (type_ & kStringRepresentationMask) == kThinStringTag;
}
-bool StringShape::IsSliced() const {
+bool StringShape::IsSliced() {
return (type_ & kStringRepresentationMask) == kSlicedStringTag;
}
-bool StringShape::IsIndirect() const {
+bool StringShape::IsIndirect() {
return (type_ & kIsIndirectStringMask) == kIsIndirectStringTag;
}
-bool StringShape::IsExternal() const {
+bool StringShape::IsExternal() {
return (type_ & kStringRepresentationMask) == kExternalStringTag;
}
-bool StringShape::IsSequential() const {
+bool StringShape::IsSequential() {
return (type_ & kStringRepresentationMask) == kSeqStringTag;
}
-bool StringShape::IsUncachedExternal() const {
+bool StringShape::IsUncachedExternal() {
return (type_ & kUncachedExternalStringMask) == kUncachedExternalStringTag;
}
-StringRepresentationTag StringShape::representation_tag() const {
+StringRepresentationTag StringShape::representation_tag() {
uint32_t tag = (type_ & kStringRepresentationMask);
return static_cast<StringRepresentationTag>(tag);
}
-uint32_t StringShape::encoding_tag() const {
- return type_ & kStringEncodingMask;
-}
+uint32_t StringShape::encoding_tag() { return type_ & kStringEncodingMask; }
-uint32_t StringShape::full_representation_tag() const {
+uint32_t StringShape::full_representation_tag() {
return (type_ & (kStringRepresentationMask | kStringEncodingMask));
}
@@ -188,15 +186,15 @@ STATIC_ASSERT((kStringRepresentationMask | kStringEncodingMask) ==
STATIC_ASSERT(static_cast<uint32_t>(kStringEncodingMask) ==
Internals::kStringEncodingMask);
-bool StringShape::IsSequentialOneByte() const {
+bool StringShape::IsSequentialOneByte() {
return full_representation_tag() == (kSeqStringTag | kOneByteStringTag);
}
-bool StringShape::IsSequentialTwoByte() const {
+bool StringShape::IsSequentialTwoByte() {
return full_representation_tag() == (kSeqStringTag | kTwoByteStringTag);
}
-bool StringShape::IsExternalOneByte() const {
+bool StringShape::IsExternalOneByte() {
return full_representation_tag() == (kExternalStringTag | kOneByteStringTag);
}
@@ -205,7 +203,7 @@ STATIC_ASSERT((kExternalStringTag | kOneByteStringTag) ==
STATIC_ASSERT(v8::String::ONE_BYTE_ENCODING == kOneByteStringTag);
-bool StringShape::IsExternalTwoByte() const {
+bool StringShape::IsExternalTwoByte() {
return full_representation_tag() == (kExternalStringTag | kTwoByteStringTag);
}
@@ -301,7 +299,7 @@ bool String::IsOneByteRepresentationUnderneath(String string) {
}
}
-uc32 FlatStringReader::Get(int index) const {
+uc32 FlatStringReader::Get(int index) {
if (is_one_byte_) {
return Get<uint8_t>(index);
} else {
@@ -310,7 +308,7 @@ uc32 FlatStringReader::Get(int index) const {
}
template <typename Char>
-Char FlatStringReader::Get(int index) const {
+Char FlatStringReader::Get(int index) {
DCHECK_EQ(is_one_byte_, sizeof(Char) == 1);
DCHECK(0 <= index && index < length_);
if (sizeof(Char) == 1) {
@@ -436,7 +434,7 @@ class SeqSubStringKey final : public StringTableKey {
using SeqOneByteSubStringKey = SeqSubStringKey<SeqOneByteString>;
using SeqTwoByteSubStringKey = SeqSubStringKey<SeqTwoByteString>;
-bool String::Equals(String other) const {
+bool String::Equals(String other) {
if (other == *this) return true;
if (this->IsInternalizedString() && other.IsInternalizedString()) {
return false;
@@ -444,7 +442,6 @@ bool String::Equals(String other) const {
return SlowEquals(other);
}
-// static
bool String::Equals(Isolate* isolate, Handle<String> one, Handle<String> two) {
if (one.is_identical_to(two)) return true;
if (one->IsInternalizedString() && two->IsInternalizedString()) {
@@ -578,7 +575,7 @@ bool String::IsConsStringEqualToImpl(
bool String::IsOneByteEqualTo(Vector<const char> str) { return IsEqualTo(str); }
template <typename Char>
-const Char* String::GetChars(const DisallowGarbageCollection& no_gc) const {
+const Char* String::GetChars(const DisallowGarbageCollection& no_gc) {
DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*this));
return StringShape(*this).IsExternal()
? CharTraits<Char>::ExternalString::cast(*this).GetChars()
@@ -588,7 +585,7 @@ const Char* String::GetChars(const DisallowGarbageCollection& no_gc) const {
template <typename Char>
const Char* String::GetChars(
const DisallowGarbageCollection& no_gc,
- const SharedStringAccessGuardIfNeeded& access_guard) const {
+ const SharedStringAccessGuardIfNeeded& access_guard) {
return StringShape(*this).IsExternal()
? CharTraits<Char>::ExternalString::cast(*this).GetChars()
: CharTraits<Char>::String::cast(*this).GetChars(no_gc,
@@ -619,17 +616,17 @@ Handle<String> String::Flatten(LocalIsolate* isolate, Handle<String> string,
return string;
}
-uint16_t String::Get(int index, Isolate* isolate) const {
+uint16_t String::Get(int index, Isolate* isolate) {
DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*this));
return GetImpl(index);
}
-uint16_t String::Get(int index, LocalIsolate* local_isolate) const {
+uint16_t String::Get(int index, LocalIsolate* local_isolate) {
SharedStringAccessGuardIfNeeded scope(local_isolate);
return GetImpl(index);
}
-uint16_t String::GetImpl(int index) const {
+uint16_t String::GetImpl(int index) {
DCHECK(index >= 0 && index < length());
class StringGetDispatcher : public AllStatic {
@@ -658,12 +655,12 @@ void String::Set(int index, uint16_t value) {
: SeqTwoByteString::cast(*this).SeqTwoByteStringSet(index, value);
}
-bool String::IsFlat() const {
+bool String::IsFlat() {
if (!StringShape(*this).IsCons()) return true;
return ConsString::cast(*this).second().length() == 0;
}
-String String::GetUnderlying() const {
+String String::GetUnderlying() {
// Giving direct access to underlying string only makes sense if the
// wrapping string is already flattened.
DCHECK(this->IsFlat());
@@ -767,7 +764,7 @@ uint32_t String::ToValidIndex(Object number) {
return index;
}
-uint8_t SeqOneByteString::Get(int index) const {
+uint8_t SeqOneByteString::Get(int index) {
DCHECK(index >= 0 && index < length());
return ReadField<byte>(kHeaderSize + index * kCharSize);
}
@@ -777,12 +774,11 @@ void SeqOneByteString::SeqOneByteStringSet(int index, uint16_t value) {
WriteField<byte>(kHeaderSize + index * kCharSize, static_cast<byte>(value));
}
-Address SeqOneByteString::GetCharsAddress() const {
+Address SeqOneByteString::GetCharsAddress() {
return field_address(kHeaderSize);
}
-uint8_t* SeqOneByteString::GetChars(
- const DisallowGarbageCollection& no_gc) const {
+uint8_t* SeqOneByteString::GetChars(const DisallowGarbageCollection& no_gc) {
USE(no_gc);
DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*this));
return reinterpret_cast<uint8_t*>(GetCharsAddress());
@@ -790,17 +786,17 @@ uint8_t* SeqOneByteString::GetChars(
uint8_t* SeqOneByteString::GetChars(
const DisallowGarbageCollection& no_gc,
- const SharedStringAccessGuardIfNeeded& access_guard) const {
+ const SharedStringAccessGuardIfNeeded& access_guard) {
USE(no_gc);
USE(access_guard);
return reinterpret_cast<uint8_t*>(GetCharsAddress());
}
-Address SeqTwoByteString::GetCharsAddress() const {
+Address SeqTwoByteString::GetCharsAddress() {
return field_address(kHeaderSize);
}
-uc16* SeqTwoByteString::GetChars(const DisallowGarbageCollection& no_gc) const {
+uc16* SeqTwoByteString::GetChars(const DisallowGarbageCollection& no_gc) {
USE(no_gc);
DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*this));
return reinterpret_cast<uc16*>(GetCharsAddress());
@@ -808,13 +804,13 @@ uc16* SeqTwoByteString::GetChars(const DisallowGarbageCollection& no_gc) const {
uc16* SeqTwoByteString::GetChars(
const DisallowGarbageCollection& no_gc,
- const SharedStringAccessGuardIfNeeded& access_guard) const {
+ const SharedStringAccessGuardIfNeeded& access_guard) {
USE(no_gc);
USE(access_guard);
return reinterpret_cast<uc16*>(GetCharsAddress());
}
-uint16_t SeqTwoByteString::Get(int index) const {
+uint16_t SeqTwoByteString::Get(int index) {
DCHECK(index >= 0 && index < length());
return ReadField<uint16_t>(kHeaderSize + index * kShortSize);
}
@@ -941,7 +937,7 @@ void ExternalOneByteString::set_resource(
if (resource != nullptr) update_data_cache(isolate);
}
-const uint8_t* ExternalOneByteString::GetChars() const {
+const uint8_t* ExternalOneByteString::GetChars() {
DisallowGarbageCollection no_gc;
if (is_uncached()) {
if (resource()->IsCacheable()) {
@@ -963,7 +959,7 @@ const uint8_t* ExternalOneByteString::GetChars() const {
return reinterpret_cast<const uint8_t*>(resource()->data());
}
-uint8_t ExternalOneByteString::Get(int index) const {
+uint8_t ExternalOneByteString::Get(int index) {
DCHECK(index >= 0 && index < length());
return GetChars()[index];
}
@@ -1006,7 +1002,7 @@ void ExternalTwoByteString::set_resource(
if (resource != nullptr) update_data_cache(isolate);
}
-const uint16_t* ExternalTwoByteString::GetChars() const {
+const uint16_t* ExternalTwoByteString::GetChars() {
DisallowGarbageCollection no_gc;
if (is_uncached()) {
if (resource()->IsCacheable()) {
@@ -1028,7 +1024,7 @@ const uint16_t* ExternalTwoByteString::GetChars() const {
return resource()->data();
}
-uint16_t ExternalTwoByteString::Get(int index) const {
+uint16_t ExternalTwoByteString::Get(int index) {
DCHECK(index >= 0 && index < length());
return GetChars()[index];
}
diff --git a/deps/v8/src/objects/string.cc b/deps/v8/src/objects/string.cc
index ffa1be3aa34..2397f31f9d5 100644
--- a/deps/v8/src/objects/string.cc
+++ b/deps/v8/src/objects/string.cc
@@ -774,7 +774,7 @@ template Handle<FixedArray> String::CalculateLineEnds(LocalIsolate* isolate,
Handle<String> src,
bool include_ending_line);
-bool String::SlowEquals(String other) const {
+bool String::SlowEquals(String other) {
DisallowGarbageCollection no_gc;
// Fast check: negative check with lengths.
int len = length();
@@ -826,7 +826,6 @@ bool String::SlowEquals(String other) const {
return comparator.Equals(*this, other);
}
-// static
bool String::SlowEquals(Isolate* isolate, Handle<String> one,
Handle<String> two) {
// Fast check: negative check with lengths.
@@ -1442,7 +1441,7 @@ void SeqTwoByteString::clear_padding() {
SizeFor(length()) - data_size);
}
-uint16_t ConsString::Get(int index) const {
+uint16_t ConsString::Get(int index) {
DCHECK(index >= 0 && index < this->length());
// Check for a flattened cons string
@@ -1471,11 +1470,9 @@ uint16_t ConsString::Get(int index) const {
UNREACHABLE();
}
-uint16_t ThinString::Get(int index) const { return actual().Get(index); }
+uint16_t ThinString::Get(int index) { return actual().Get(index); }
-uint16_t SlicedString::Get(int index) const {
- return parent().Get(offset() + index);
-}
+uint16_t SlicedString::Get(int index) { return parent().Get(offset() + index); }
int ExternalString::ExternalPayloadSize() const {
int length_multiplier = IsTwoByteRepresentation() ? i::kShortSize : kCharSize;
diff --git a/deps/v8/src/objects/string.h b/deps/v8/src/objects/string.h
index b8d47b5551f..683dc34f12d 100644
--- a/deps/v8/src/objects/string.h
+++ b/deps/v8/src/objects/string.h
@@ -44,25 +44,25 @@ class StringShape {
inline explicit StringShape(const String s);
inline explicit StringShape(Map s);
inline explicit StringShape(InstanceType t);
- inline bool IsSequential() const;
- inline bool IsExternal() const;
- inline bool IsCons() const;
- inline bool IsSliced() const;
- inline bool IsThin() const;
- inline bool IsIndirect() const;
- inline bool IsUncachedExternal() const;
- inline bool IsExternalOneByte() const;
- inline bool IsExternalTwoByte() const;
- inline bool IsSequentialOneByte() const;
- inline bool IsSequentialTwoByte() const;
- inline bool IsInternalized() const;
- inline StringRepresentationTag representation_tag() const;
- inline uint32_t encoding_tag() const;
- inline uint32_t full_representation_tag() const;
+ inline bool IsSequential();
+ inline bool IsExternal();
+ inline bool IsCons();
+ inline bool IsSliced();
+ inline bool IsThin();
+ inline bool IsIndirect();
+ inline bool IsUncachedExternal();
+ inline bool IsExternalOneByte();
+ inline bool IsExternalTwoByte();
+ inline bool IsSequentialOneByte();
+ inline bool IsSequentialTwoByte();
+ inline bool IsInternalized();
+ inline StringRepresentationTag representation_tag();
+ inline uint32_t encoding_tag();
+ inline uint32_t full_representation_tag();
#ifdef DEBUG
- inline uint32_t type() const { return type_; }
+ inline uint32_t type() { return type_; }
inline void invalidate() { valid_ = false; }
- inline bool valid() const { return valid_; }
+ inline bool valid() { return valid_; }
#else
inline void invalidate() {}
#endif
@@ -181,13 +181,13 @@ class String : public TorqueGeneratedString<String, Name> {
// SharedStringAccessGuard is not needed (i.e. on the main thread or on
// read-only strings).
template <typename Char>
- inline const Char* GetChars(const DisallowGarbageCollection& no_gc) const;
+ inline const Char* GetChars(const DisallowGarbageCollection& no_gc);
// Get chars from sequential or external strings.
template <typename Char>
inline const Char* GetChars(
const DisallowGarbageCollection& no_gc,
- const SharedStringAccessGuardIfNeeded& access_guard) const;
+ const SharedStringAccessGuardIfNeeded& access_guard);
// Returns the address of the character at an offset into this string.
// Requires: this->IsFlat()
@@ -217,8 +217,8 @@ class String : public TorqueGeneratedString<String, Name> {
// to this method are not efficient unless the string is flat.
// If it is called from a background thread, the LocalIsolate version should
// be used.
- V8_INLINE uint16_t Get(int index, Isolate* isolate = nullptr) const;
- V8_INLINE uint16_t Get(int index, LocalIsolate* local_isolate) const;
+ V8_INLINE uint16_t Get(int index, Isolate* isolate = nullptr);
+ V8_INLINE uint16_t Get(int index, LocalIsolate* local_isolate);
// ES6 section 7.1.3.1 ToNumber Applied to the String Type
static Handle<Object> ToNumber(Isolate* isolate, Handle<String> subject);
@@ -253,7 +253,7 @@ class String : public TorqueGeneratedString<String, Name> {
// Returns the parent of a sliced string or first part of a flat cons string.
// Requires: StringShape(this).IsIndirect() && this->IsFlat()
- inline String GetUnderlying() const;
+ inline String GetUnderlying();
// String relational comparison, implemented according to ES6 section 7.2.11
// Abstract Relational Comparison (step 5): The comparison of Strings uses a
@@ -314,7 +314,7 @@ class String : public TorqueGeneratedString<String, Name> {
int start_index = 0);
// String equality operations.
- inline bool Equals(String other) const;
+ inline bool Equals(String other);
inline static bool Equals(Isolate* isolate, Handle<String> one,
Handle<String> two);
@@ -419,7 +419,7 @@ class String : public TorqueGeneratedString<String, Name> {
DECL_PRINTER(String)
DECL_VERIFIER(String)
- inline bool IsFlat() const;
+ inline bool IsFlat();
// Max char codes.
static const int32_t kMaxOneByteCharCode = unibrow::Latin1::kMaxChar;
@@ -541,7 +541,7 @@ class String : public TorqueGeneratedString<String, Name> {
friend class InternalizedStringKey;
// Implementation of the Get() public methods. Do not use directly.
- V8_INLINE uint16_t GetImpl(int index) const;
+ V8_INLINE uint16_t GetImpl(int index);
// Implementation of the IsEqualTo() public methods. Do not use directly.
template <EqualityType kEqType, typename Char>
@@ -561,7 +561,7 @@ class String : public TorqueGeneratedString<String, Name> {
// Slow case of String::Equals. This implementation works on any strings
// but it is most efficient on strings that are almost flat.
- V8_EXPORT_PRIVATE bool SlowEquals(String other) const;
+ V8_EXPORT_PRIVATE bool SlowEquals(String other);
V8_EXPORT_PRIVATE static bool SlowEquals(Isolate* isolate, Handle<String> one,
Handle<String> two);
@@ -633,21 +633,20 @@ class SeqOneByteString
using Char = uint8_t;
// Dispatched behavior.
- inline uint8_t Get(int index) const;
+ inline uint8_t Get(int index);
inline void SeqOneByteStringSet(int index, uint16_t value);
// Get the address of the characters in this string.
- inline Address GetCharsAddress() const;
+ inline Address GetCharsAddress();
// Get a pointer to the characters of the string. May only be called when a
// SharedStringAccessGuard is not needed (i.e. on the main thread or on
// read-only strings).
- inline uint8_t* GetChars(const DisallowGarbageCollection& no_gc) const;
+ inline uint8_t* GetChars(const DisallowGarbageCollection& no_gc);
// Get a pointer to the characters of the string.
- inline uint8_t* GetChars(
- const DisallowGarbageCollection& no_gc,
- const SharedStringAccessGuardIfNeeded& access_guard) const;
+ inline uint8_t* GetChars(const DisallowGarbageCollection& no_gc,
+ const SharedStringAccessGuardIfNeeded& access_guard);
// Clear uninitialized padding space. This ensures that the snapshot content
// is deterministic.
@@ -679,21 +678,20 @@ class SeqTwoByteString
using Char = uint16_t;
// Dispatched behavior.
- inline uint16_t Get(int index) const;
+ inline uint16_t Get(int index);
inline void SeqTwoByteStringSet(int index, uint16_t value);
// Get the address of the characters in this string.
- inline Address GetCharsAddress() const;
+ inline Address GetCharsAddress();
// Get a pointer to the characters of the string. May only be called when a
// SharedStringAccessGuard is not needed (i.e. on the main thread or on
// read-only strings).
- inline uc16* GetChars(const DisallowGarbageCollection& no_gc) const;
+ inline uc16* GetChars(const DisallowGarbageCollection& no_gc);
// Get a pointer to the characters of the string.
- inline uc16* GetChars(
- const DisallowGarbageCollection& no_gc,
- const SharedStringAccessGuardIfNeeded& access_guard) const;
+ inline uc16* GetChars(const DisallowGarbageCollection& no_gc,
+ const SharedStringAccessGuardIfNeeded& access_guard);
// Clear uninitialized padding space. This ensures that the snapshot content
// is deterministic.
@@ -736,7 +734,7 @@ class ConsString : public TorqueGeneratedConsString<ConsString, String> {
inline Object unchecked_second();
// Dispatched behavior.
- V8_EXPORT_PRIVATE uint16_t Get(int index) const;
+ V8_EXPORT_PRIVATE uint16_t Get(int index);
// Minimum length for a cons string.
static const int kMinLength = 13;
@@ -759,7 +757,7 @@ class ThinString : public TorqueGeneratedThinString<ThinString, String> {
public:
DECL_GETTER(unchecked_actual, HeapObject)
- V8_EXPORT_PRIVATE uint16_t Get(int index) const;
+ V8_EXPORT_PRIVATE uint16_t Get(int index);
DECL_VERIFIER(ThinString)
@@ -785,7 +783,7 @@ class SlicedString : public TorqueGeneratedSlicedString<SlicedString, String> {
inline void set_parent(String parent,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
// Dispatched behavior.
- V8_EXPORT_PRIVATE uint16_t Get(int index) const;
+ V8_EXPORT_PRIVATE uint16_t Get(int index);
// Minimum length for a sliced string.
static const int kMinLength = 13;
@@ -864,10 +862,10 @@ class ExternalOneByteString : public ExternalString {
// which the pointer cache has to be refreshed.
inline void update_data_cache(Isolate* isolate);
- inline const uint8_t* GetChars() const;
+ inline const uint8_t* GetChars();
// Dispatched behavior.
- inline uint8_t Get(int index) const;
+ inline uint8_t Get(int index);
DECL_CAST(ExternalOneByteString)
@@ -910,10 +908,10 @@ class ExternalTwoByteString : public ExternalString {
// which the pointer cache has to be refreshed.
inline void update_data_cache(Isolate* isolate);
- inline const uint16_t* GetChars() const;
+ inline const uint16_t* GetChars();
// Dispatched behavior.
- inline uint16_t Get(int index) const;
+ inline uint16_t Get(int index);
// For regexp code.
inline const uint16_t* ExternalTwoByteStringGetData(unsigned start);
@@ -943,9 +941,9 @@ class V8_EXPORT_PRIVATE FlatStringReader : public Relocatable {
public:
FlatStringReader(Isolate* isolate, Handle<String> str);
void PostGarbageCollection() override;
- inline uc32 Get(int index) const;
+ inline uc32 Get(int index);
template <typename Char>
- inline Char Get(int index) const;
+ inline Char Get(int index);
int length() { return length_; }
private:
diff --git a/deps/v8/src/wasm/module-compiler.cc b/deps/v8/src/wasm/module-compiler.cc
index 3b1d8750bac..d45c7385251 100644
--- a/deps/v8/src/wasm/module-compiler.cc
+++ b/deps/v8/src/wasm/module-compiler.cc
@@ -3342,8 +3342,6 @@ void CompilationStateImpl::WaitForCompilationEvent(
return done_->load(std::memory_order_relaxed);
}
- bool IsJoiningThread() const override { return true; }
-
void NotifyConcurrencyIncrease() override { UNIMPLEMENTED(); }
uint8_t GetTaskId() override { return kMainTaskId; }
diff --git a/deps/v8/test/cctest/test-api-array-buffer.cc b/deps/v8/test/cctest/test-api-array-buffer.cc
index 9875098d1fb..86044edcde4 100644
--- a/deps/v8/test/cctest/test-api-array-buffer.cc
+++ b/deps/v8/test/cctest/test-api-array-buffer.cc
@@ -47,11 +47,31 @@ 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;
}
@@ -130,6 +150,46 @@ 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();
@@ -233,6 +293,37 @@ 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();
@@ -251,6 +342,7 @@ THREADED_TEST(ArrayBuffer_ExternalizeEmpty) {
// marked as is_external or not.
USE(u8a->Buffer());
+ CHECK(ab->IsExternal());
CHECK_EQ(2, backing_store->ByteLength());
}
@@ -289,6 +381,35 @@ 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;
@@ -330,6 +451,64 @@ 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();
@@ -337,12 +516,9 @@ 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, std::move(backing_store));
+ Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8);
// Should not crash
CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
@@ -363,15 +539,12 @@ 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, std::move(backing_store));
+ Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8);
// Should not crash,
// i.e. backing store pointer should not be treated as a heap object pointer
diff --git a/deps/v8/test/cctest/test-typedarrays.cc b/deps/v8/test/cctest/test-typedarrays.cc
index 0134befedd2..867d0f90b95 100644
--- a/deps/v8/test/cctest/test-typedarrays.cc
+++ b/deps/v8/test/cctest/test-typedarrays.cc
@@ -71,6 +71,30 @@ 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;