summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/env.cc15
-rw-r--r--src/env.h8
-rw-r--r--src/sharedarraybuffer_metadata.cc24
-rw-r--r--src/sharedarraybuffer_metadata.h3
-rw-r--r--test/parallel/test-worker-sharedarraybuffer-from-worker-thread.js1
5 files changed, 51 insertions, 0 deletions
diff --git a/src/env.cc b/src/env.cc
index 257bf78519..2400785ea8 100644
--- a/src/env.cc
+++ b/src/env.cc
@@ -1036,6 +1036,21 @@ char* Environment::Reallocate(char* data, size_t old_size, size_t size) {
return new_data;
}
+void Environment::AddArrayBufferAllocatorToKeepAliveUntilIsolateDispose(
+ std::shared_ptr<v8::ArrayBuffer::Allocator> allocator) {
+ if (keep_alive_allocators_ == nullptr) {
+ MultiIsolatePlatform* platform = isolate_data()->platform();
+ CHECK_NOT_NULL(platform);
+
+ keep_alive_allocators_ = new ArrayBufferAllocatorList();
+ platform->AddIsolateFinishedCallback(isolate(), [](void* data) {
+ delete static_cast<ArrayBufferAllocatorList*>(data);
+ }, static_cast<void*>(keep_alive_allocators_));
+ }
+
+ keep_alive_allocators_->insert(allocator);
+}
+
void AsyncRequest::Install(Environment* env, void* data, uv_async_cb target) {
CHECK_NULL(async_);
env_ = env;
diff --git a/src/env.h b/src/env.h
index 03d0a79a6d..534b888e2c 100644
--- a/src/env.h
+++ b/src/env.h
@@ -1251,6 +1251,10 @@ class Environment : public MemoryRetainer {
#endif // HAVE_INSPECTOR
+ // Only available if a MultiIsolatePlatform is in use.
+ void AddArrayBufferAllocatorToKeepAliveUntilIsolateDispose(
+ std::shared_ptr<v8::ArrayBuffer::Allocator>);
+
private:
template <typename Fn>
inline void CreateImmediate(Fn&& cb,
@@ -1425,6 +1429,10 @@ class Environment : public MemoryRetainer {
// Used by embedders to shutdown running Node instance.
AsyncRequest thread_stopper_;
+ typedef std::unordered_set<std::shared_ptr<v8::ArrayBuffer::Allocator>>
+ ArrayBufferAllocatorList;
+ ArrayBufferAllocatorList* keep_alive_allocators_ = nullptr;
+
template <typename T>
void ForEachBaseObject(T&& iterator);
diff --git a/src/sharedarraybuffer_metadata.cc b/src/sharedarraybuffer_metadata.cc
index b9d86d05ff..fc3bcdf3d3 100644
--- a/src/sharedarraybuffer_metadata.cc
+++ b/src/sharedarraybuffer_metadata.cc
@@ -50,6 +50,30 @@ class SABLifetimePartner : public BaseObject {
: BaseObject(env, obj),
reference(std::move(r)) {
MakeWeak();
+ env->AddCleanupHook(CleanupHook, static_cast<void*>(this));
+ }
+
+ ~SABLifetimePartner() {
+ env()->RemoveCleanupHook(CleanupHook, static_cast<void*>(this));
+ }
+
+ static void CleanupHook(void* data) {
+ // There is another cleanup hook attached to this object because it is a
+ // BaseObject. Cleanup hooks are triggered in reverse order of addition,
+ // so if this object is destroyed through GC, the destructor removes all
+ // hooks associated with this object, meaning that this cleanup hook
+ // only runs at the end of the Environment’s lifetime.
+ // In that case, V8 still knows about the SharedArrayBuffer and tries to
+ // free it when the last Isolate with access to it is disposed; for that,
+ // the ArrayBuffer::Allocator needs to be kept alive longer than this
+ // object and longer than the Environment instance.
+ //
+ // This is a workaround for https://github.com/nodejs/node-v8/issues/115
+ // (introduced in V8 7.9) and we should be able to remove it once V8
+ // ArrayBuffer::Allocator refactoring/removal is complete.
+ SABLifetimePartner* self = static_cast<SABLifetimePartner*>(data);
+ self->env()->AddArrayBufferAllocatorToKeepAliveUntilIsolateDispose(
+ self->reference->allocator());
}
SET_NO_MEMORY_INFO()
diff --git a/src/sharedarraybuffer_metadata.h b/src/sharedarraybuffer_metadata.h
index 8da603978a..4d89f08ee1 100644
--- a/src/sharedarraybuffer_metadata.h
+++ b/src/sharedarraybuffer_metadata.h
@@ -37,6 +37,9 @@ class SharedArrayBufferMetadata
// count is increased by 1.
v8::MaybeLocal<v8::SharedArrayBuffer> GetSharedArrayBuffer(
Environment* env, v8::Local<v8::Context> context);
+ std::shared_ptr<v8::ArrayBuffer::Allocator> allocator() const {
+ return allocator_;
+ }
SharedArrayBufferMetadata(SharedArrayBufferMetadata&& other) = delete;
SharedArrayBufferMetadata& operator=(
diff --git a/test/parallel/test-worker-sharedarraybuffer-from-worker-thread.js b/test/parallel/test-worker-sharedarraybuffer-from-worker-thread.js
index 60e8a5d52a..56dfe2ec41 100644
--- a/test/parallel/test-worker-sharedarraybuffer-from-worker-thread.js
+++ b/test/parallel/test-worker-sharedarraybuffer-from-worker-thread.js
@@ -1,3 +1,4 @@
+// Flags: --debug-arraybuffer-allocations
'use strict';
const common = require('../common');
const assert = require('assert');