GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/sharedarraybuffer_metadata.cc Lines: 57 63 90.5 %
Date: 2019-10-06 22:30:00 Branches: 20 30 66.7 %

Line Branch Exec Source
1
#include "sharedarraybuffer_metadata.h"
2
3
#include "base_object-inl.h"
4
#include "memory_tracker-inl.h"
5
#include "node_errors.h"
6
#include "node_worker.h"
7
#include "util-inl.h"
8
9
#include <utility>
10
11
using v8::Context;
12
using v8::Function;
13
using v8::FunctionTemplate;
14
using v8::Local;
15
using v8::Maybe;
16
using v8::MaybeLocal;
17
using v8::Nothing;
18
using v8::Object;
19
using v8::SharedArrayBuffer;
20
using v8::Value;
21
22
namespace node {
23
namespace worker {
24
25
namespace {
26
27
// Yield a JS constructor for SABLifetimePartner objects in the form of a
28
// standard API object, that has a single field for containing the raw
29
// SABLifetimePartner* pointer.
30
633
Local<Function> GetSABLifetimePartnerConstructor(
31
    Environment* env, Local<Context> context) {
32
  Local<FunctionTemplate> templ;
33
633
  templ = env->sab_lifetimepartner_constructor_template();
34
633
  if (!templ.IsEmpty())
35
658
    return templ->GetFunction(context).ToLocalChecked();
36
37
304
  templ = BaseObject::MakeLazilyInitializedJSTemplate(env);
38
  templ->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(),
39
608
                                            "SABLifetimePartner"));
40
304
  env->set_sab_lifetimepartner_constructor_template(templ);
41
42
304
  return GetSABLifetimePartnerConstructor(env, context);
43
}
44
45
class SABLifetimePartner : public BaseObject {
46
 public:
47
329
  SABLifetimePartner(Environment* env,
48
                     Local<Object> obj,
49
                     SharedArrayBufferMetadataReference r)
50
    : BaseObject(env, obj),
51
329
      reference(std::move(r)) {
52
329
    MakeWeak();
53
329
    env->AddCleanupHook(CleanupHook, static_cast<void*>(this));
54
329
  }
55
56
963
  ~SABLifetimePartner() {
57
321
    env()->RemoveCleanupHook(CleanupHook, static_cast<void*>(this));
58
642
  }
59
60
310
  static void CleanupHook(void* data) {
61
    // There is another cleanup hook attached to this object because it is a
62
    // BaseObject. Cleanup hooks are triggered in reverse order of addition,
63
    // so if this object is destroyed through GC, the destructor removes all
64
    // hooks associated with this object, meaning that this cleanup hook
65
    // only runs at the end of the Environment’s lifetime.
66
    // In that case, V8 still knows about the SharedArrayBuffer and tries to
67
    // free it when the last Isolate with access to it is disposed; for that,
68
    // the ArrayBuffer::Allocator needs to be kept alive longer than this
69
    // object and longer than the Environment instance.
70
    //
71
    // This is a workaround for https://github.com/nodejs/node-v8/issues/115
72
    // (introduced in V8 7.9) and we should be able to remove it once V8
73
    // ArrayBuffer::Allocator refactoring/removal is complete.
74
310
    SABLifetimePartner* self = static_cast<SABLifetimePartner*>(data);
75
    self->env()->AddArrayBufferAllocatorToKeepAliveUntilIsolateDispose(
76
310
        self->reference->allocator());
77
311
  }
78
79
4
  SET_NO_MEMORY_INFO()
80
4
  SET_MEMORY_INFO_NAME(SABLifetimePartner)
81
4
  SET_SELF_SIZE(SABLifetimePartner)
82
83
  SharedArrayBufferMetadataReference reference;
84
};
85
86
}  // anonymous namespace
87
88
SharedArrayBufferMetadataReference
89
232
SharedArrayBufferMetadata::ForSharedArrayBuffer(
90
    Environment* env,
91
    Local<Context> context,
92
    Local<SharedArrayBuffer> source) {
93
  Local<Value> lifetime_partner;
94
95
696
  if (!source->GetPrivate(context,
96
232
                          env->sab_lifetimepartner_symbol())
97
696
                              .ToLocal(&lifetime_partner)) {
98
    return nullptr;
99
  }
100
101

1052
  if (lifetime_partner->IsObject() &&
102
      env->sab_lifetimepartner_constructor_template()
103
604
         ->HasInstance(lifetime_partner)) {
104
124
    CHECK(source->IsExternal());
105
    SABLifetimePartner* partner =
106
124
        Unwrap<SABLifetimePartner>(lifetime_partner.As<Object>());
107
124
    CHECK_NOT_NULL(partner);
108
124
    return partner->reference;
109
  }
110
111
108
  if (source->IsExternal()) {
112
    // If this is an external SharedArrayBuffer but we do not see a lifetime
113
    // partner object, it was not us who externalized it. In that case, there
114
    // is no way to serialize it, because it's unclear how the memory
115
    // is actually owned.
116
    THROW_ERR_TRANSFERRING_EXTERNALIZED_SHAREDARRAYBUFFER(env);
117
    return nullptr;
118
  }
119
120
  // If the SharedArrayBuffer is coming from a Worker, we need to make sure
121
  // that the corresponding ArrayBuffer::Allocator lives at least as long as
122
  // the SharedArrayBuffer itself.
123
108
  worker::Worker* w = env->worker_context();
124
  std::shared_ptr<v8::ArrayBuffer::Allocator> allocator =
125
108
      w != nullptr ? w->array_buffer_allocator() : nullptr;
126
127
108
  SharedArrayBuffer::Contents contents = source->Externalize();
128
  SharedArrayBufferMetadataReference r(
129
216
      new SharedArrayBufferMetadata(contents, allocator));
130
216
  if (r->AssignToSharedArrayBuffer(env, context, source).IsNothing())
131
    return nullptr;
132
216
  return r;
133
}
134
135
329
Maybe<bool> SharedArrayBufferMetadata::AssignToSharedArrayBuffer(
136
    Environment* env, Local<Context> context,
137
    Local<SharedArrayBuffer> target) {
138
329
  CHECK(target->IsExternal());
139
329
  Local<Function> ctor = GetSABLifetimePartnerConstructor(env, context);
140
  Local<Object> obj;
141
658
  if (!ctor->NewInstance(context).ToLocal(&obj))
142
    return Nothing<bool>();
143
144
329
  new SABLifetimePartner(env, obj, shared_from_this());
145
329
  return target->SetPrivate(context,
146
                            env->sab_lifetimepartner_symbol(),
147
658
                            obj);
148
}
149
150
108
SharedArrayBufferMetadata::SharedArrayBufferMetadata(
151
    const SharedArrayBuffer::Contents& contents,
152
    std::shared_ptr<v8::ArrayBuffer::Allocator> allocator)
153
108
  : contents_(contents), allocator_(allocator) { }
154
155
200
SharedArrayBufferMetadata::~SharedArrayBufferMetadata() {
156
100
  contents_.Deleter()(contents_.Data(),
157
                      contents_.ByteLength(),
158
100
                      contents_.DeleterData());
159
100
}
160
161
221
MaybeLocal<SharedArrayBuffer> SharedArrayBufferMetadata::GetSharedArrayBuffer(
162
    Environment* env, Local<Context> context) {
163
  Local<SharedArrayBuffer> obj =
164
      SharedArrayBuffer::New(env->isolate(),
165
                             contents_.Data(),
166
221
                             contents_.ByteLength());
167
168
442
  if (AssignToSharedArrayBuffer(env, context, obj).IsNothing())
169
    return MaybeLocal<SharedArrayBuffer>();
170
171
221
  return obj;
172
}
173
174
}  // namespace worker
175
}  // namespace node