summaryrefslogtreecommitdiff
path: root/src/sharedarraybuffer_metadata.cc
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2018-05-13 19:39:32 +0200
committerAnna Henningsen <anna@addaleax.net>2018-06-06 19:43:46 +0200
commitb0404047c1e4f7652aaf6ecf911d5850d5acf570 (patch)
treef8e09cfda61b24d4c548e6d9ab560bfaa5d3a03a /src/sharedarraybuffer_metadata.cc
parent749a13b76c351d515ed489844ece575b8918d2ed (diff)
downloadnode-new-b0404047c1e4f7652aaf6ecf911d5850d5acf570.tar.gz
worker: add `SharedArrayBuffer` sharing
Logic is added to the `MessagePort` mechanism that attaches hidden objects to those instances when they are transferred that track their lifetime and maintain a reference count, to make sure that memory is freed at the appropriate times. Thanks to Stephen Belanger for reviewing this change in its original PR. Refs: https://github.com/ayojs/ayo/pull/106 PR-URL: https://github.com/nodejs/node/pull/20876 Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Shingo Inoue <leko.noor@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com> Reviewed-By: John-David Dalton <john.david.dalton@gmail.com> Reviewed-By: Gus Caplan <me@gus.host>
Diffstat (limited to 'src/sharedarraybuffer_metadata.cc')
-rw-r--r--src/sharedarraybuffer_metadata.cc129
1 files changed, 129 insertions, 0 deletions
diff --git a/src/sharedarraybuffer_metadata.cc b/src/sharedarraybuffer_metadata.cc
new file mode 100644
index 0000000000..86476a9f12
--- /dev/null
+++ b/src/sharedarraybuffer_metadata.cc
@@ -0,0 +1,129 @@
+#include "sharedarraybuffer_metadata.h"
+#include "base_object.h"
+#include "base_object-inl.h"
+#include "node_errors.h"
+
+using v8::Context;
+using v8::Function;
+using v8::FunctionTemplate;
+using v8::Local;
+using v8::Maybe;
+using v8::MaybeLocal;
+using v8::Nothing;
+using v8::Object;
+using v8::SharedArrayBuffer;
+using v8::Value;
+
+namespace node {
+namespace worker {
+
+namespace {
+
+// Yield a JS constructor for SABLifetimePartner objects in the form of a
+// standard API object, that has a single field for containing the raw
+// SABLiftimePartner* pointer.
+Local<Function> GetSABLifetimePartnerConstructor(
+ Environment* env, Local<Context> context) {
+ Local<FunctionTemplate> templ;
+ templ = env->sab_lifetimepartner_constructor_template();
+ if (!templ.IsEmpty())
+ return templ->GetFunction(context).ToLocalChecked();
+
+ templ = BaseObject::MakeLazilyInitializedJSTemplate(env);
+ templ->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(),
+ "SABLifetimePartner"));
+ env->set_sab_lifetimepartner_constructor_template(templ);
+
+ return GetSABLifetimePartnerConstructor(env, context);
+}
+
+class SABLifetimePartner : public BaseObject {
+ public:
+ SABLifetimePartner(Environment* env,
+ Local<Object> obj,
+ SharedArrayBufferMetadataReference r)
+ : BaseObject(env, obj),
+ reference(r) {
+ MakeWeak();
+ }
+
+ SharedArrayBufferMetadataReference reference;
+};
+
+} // anonymous namespace
+
+SharedArrayBufferMetadataReference
+SharedArrayBufferMetadata::ForSharedArrayBuffer(
+ Environment* env,
+ Local<Context> context,
+ Local<SharedArrayBuffer> source) {
+ Local<Value> lifetime_partner;
+
+ if (!source->GetPrivate(context,
+ env->sab_lifetimepartner_symbol())
+ .ToLocal(&lifetime_partner)) {
+ return nullptr;
+ }
+
+ if (lifetime_partner->IsObject() &&
+ env->sab_lifetimepartner_constructor_template()
+ ->HasInstance(lifetime_partner)) {
+ CHECK(source->IsExternal());
+ SABLifetimePartner* partner =
+ Unwrap<SABLifetimePartner>(lifetime_partner.As<Object>());
+ CHECK_NE(partner, nullptr);
+ return partner->reference;
+ }
+
+ if (source->IsExternal()) {
+ // If this is an external SharedArrayBuffer but we do not see a lifetime
+ // partner object, it was not us who externalized it. In that case, there
+ // is no way to serialize it, because it's unclear how the memory
+ // is actually owned.
+ THROW_ERR_TRANSFERRING_EXTERNALIZED_SHAREDARRAYBUFFER(env);
+ return nullptr;
+ }
+
+ SharedArrayBuffer::Contents contents = source->Externalize();
+ SharedArrayBufferMetadataReference r(new SharedArrayBufferMetadata(
+ contents.Data(), contents.ByteLength()));
+ if (r->AssignToSharedArrayBuffer(env, context, source).IsNothing())
+ return nullptr;
+ return r;
+}
+
+Maybe<bool> SharedArrayBufferMetadata::AssignToSharedArrayBuffer(
+ Environment* env, Local<Context> context,
+ Local<SharedArrayBuffer> target) {
+ CHECK(target->IsExternal());
+ Local<Function> ctor = GetSABLifetimePartnerConstructor(env, context);
+ Local<Object> obj;
+ if (!ctor->NewInstance(context).ToLocal(&obj))
+ return Nothing<bool>();
+
+ new SABLifetimePartner(env, obj, shared_from_this());
+ return target->SetPrivate(context,
+ env->sab_lifetimepartner_symbol(),
+ obj);
+}
+
+SharedArrayBufferMetadata::SharedArrayBufferMetadata(void* data, size_t size)
+ : data(data), size(size) { }
+
+SharedArrayBufferMetadata::~SharedArrayBufferMetadata() {
+ free(data);
+}
+
+MaybeLocal<SharedArrayBuffer> SharedArrayBufferMetadata::GetSharedArrayBuffer(
+ Environment* env, Local<Context> context) {
+ Local<SharedArrayBuffer> obj =
+ SharedArrayBuffer::New(env->isolate(), data, size);
+
+ if (AssignToSharedArrayBuffer(env, context, obj).IsNothing())
+ return MaybeLocal<SharedArrayBuffer>();
+
+ return obj;
+}
+
+} // namespace worker
+} // namespace node