diff options
author | Anna Henningsen <anna@addaleax.net> | 2018-05-13 19:39:32 +0200 |
---|---|---|
committer | Anna Henningsen <anna@addaleax.net> | 2018-06-06 19:43:46 +0200 |
commit | b0404047c1e4f7652aaf6ecf911d5850d5acf570 (patch) | |
tree | f8e09cfda61b24d4c548e6d9ab560bfaa5d3a03a /src/sharedarraybuffer_metadata.cc | |
parent | 749a13b76c351d515ed489844ece575b8918d2ed (diff) | |
download | node-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.cc | 129 |
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 |