1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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
|