mirror of
https://github.com/zebrajr/node.git
synced 2026-01-15 12:15:26 +00:00
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>
This commit is contained in:
129
src/sharedarraybuffer_metadata.cc
Normal file
129
src/sharedarraybuffer_metadata.cc
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user