◐ Shell
clean mode source ↗

worker: add `SharedArrayBuffer` sharing · nodejs/node@d1f372f

1+

#include "sharedarraybuffer_metadata.h"

2+

#include "base_object.h"

3+

#include "base_object-inl.h"

4+

#include "node_errors.h"

5+6+

using v8::Context;

7+

using v8::Function;

8+

using v8::FunctionTemplate;

9+

using v8::Local;

10+

using v8::Maybe;

11+

using v8::MaybeLocal;

12+

using v8::Nothing;

13+

using v8::Object;

14+

using v8::SharedArrayBuffer;

15+

using v8::Value;

16+17+

namespace node {

18+

namespace worker {

19+20+

namespace {

21+22+

// Yield a JS constructor for SABLifetimePartner objects in the form of a

23+

// standard API object, that has a single field for containing the raw

24+

// SABLiftimePartner* pointer.

25+

Local<Function> GetSABLifetimePartnerConstructor(

26+

Environment* env, Local<Context> context) {

27+

Local<FunctionTemplate> templ;

28+

templ = env->sab_lifetimepartner_constructor_template();

29+

if (!templ.IsEmpty())

30+

return templ->GetFunction(context).ToLocalChecked();

31+32+

templ = BaseObject::MakeLazilyInitializedJSTemplate(env);

33+

templ->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(),

34+

"SABLifetimePartner"));

35+

env->set_sab_lifetimepartner_constructor_template(templ);

36+37+

return GetSABLifetimePartnerConstructor(env, context);

38+

}

39+40+

class SABLifetimePartner : public BaseObject {

41+

public:

42+

SABLifetimePartner(Environment* env,

43+

Local<Object> obj,

44+

SharedArrayBufferMetadataReference r)

45+

: BaseObject(env, obj),

46+

reference(r) {

47+

MakeWeak();

48+

}

49+50+

SharedArrayBufferMetadataReference reference;

51+

};

52+53+

} // anonymous namespace

54+55+

SharedArrayBufferMetadataReference

56+

SharedArrayBufferMetadata::ForSharedArrayBuffer(

57+

Environment* env,

58+

Local<Context> context,

59+

Local<SharedArrayBuffer> source) {

60+

Local<Value> lifetime_partner;

61+62+

if (!source->GetPrivate(context,

63+

env->sab_lifetimepartner_symbol())

64+

.ToLocal(&lifetime_partner)) {

65+

return nullptr;

66+

}

67+68+

if (lifetime_partner->IsObject() &&

69+

env->sab_lifetimepartner_constructor_template()

70+

->HasInstance(lifetime_partner)) {

71+

CHECK(source->IsExternal());

72+

SABLifetimePartner* partner =

73+

Unwrap<SABLifetimePartner>(lifetime_partner.As<Object>());

74+

CHECK_NE(partner, nullptr);

75+

return partner->reference;

76+

}

77+78+

if (source->IsExternal()) {

79+

// If this is an external SharedArrayBuffer but we do not see a lifetime

80+

// partner object, it was not us who externalized it. In that case, there

81+

// is no way to serialize it, because it's unclear how the memory

82+

// is actually owned.

83+

THROW_ERR_TRANSFERRING_EXTERNALIZED_SHAREDARRAYBUFFER(env);

84+

return nullptr;

85+

}

86+87+

SharedArrayBuffer::Contents contents = source->Externalize();

88+

SharedArrayBufferMetadataReference r(new SharedArrayBufferMetadata(

89+

contents.Data(), contents.ByteLength()));

90+

if (r->AssignToSharedArrayBuffer(env, context, source).IsNothing())

91+

return nullptr;

92+

return r;

93+

}

94+95+

Maybe<bool> SharedArrayBufferMetadata::AssignToSharedArrayBuffer(

96+

Environment* env, Local<Context> context,

97+

Local<SharedArrayBuffer> target) {

98+

CHECK(target->IsExternal());

99+

Local<Function> ctor = GetSABLifetimePartnerConstructor(env, context);

100+

Local<Object> obj;

101+

if (!ctor->NewInstance(context).ToLocal(&obj))

102+

return Nothing<bool>();

103+104+

new SABLifetimePartner(env, obj, shared_from_this());

105+

return target->SetPrivate(context,

106+

env->sab_lifetimepartner_symbol(),

107+

obj);

108+

}

109+110+

SharedArrayBufferMetadata::SharedArrayBufferMetadata(void* data, size_t size)

111+

: data(data), size(size) { }

112+113+

SharedArrayBufferMetadata::~SharedArrayBufferMetadata() {

114+

free(data);

115+

}

116+117+

MaybeLocal<SharedArrayBuffer> SharedArrayBufferMetadata::GetSharedArrayBuffer(

118+

Environment* env, Local<Context> context) {

119+

Local<SharedArrayBuffer> obj =

120+

SharedArrayBuffer::New(env->isolate(), data, size);

121+122+

if (AssignToSharedArrayBuffer(env, context, obj).IsNothing())

123+

return MaybeLocal<SharedArrayBuffer>();

124+125+

return obj;

126+

}

127+128+

} // namespace worker

129+

} // namespace node