Skip to content

Commit 8a94957

Browse files
committed
contextify: cleanup weak ref for sandbox
Simplify how node_contextify was keeping a weak reference to the sandbox object in order to prepare for new style phantom weakness V8 API. It is simpler (and more robust) for the context to hold a reference to the sandbox in an embedder data field. Doing otherwise meant that the sandbox could become weak while the context was still alive. This wasn't a problem because we would make the reference strong at that point. Since the sandbox must live at least as long as the context, it would be better for the context to hold onto the sandbox. PR-URL: #5392 Reviewed-By: Reviewed-By: bnoordhuis - Ben Noordhuis <[email protected]>
1 parent 266c409 commit 8a94957

File tree

1 file changed

+28
-52
lines changed

1 file changed

+28
-52
lines changed

src/node_contextify.cc

Lines changed: 28 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -50,40 +50,29 @@ using v8::WeakCallbackData;
5050

5151
class ContextifyContext {
5252
protected:
53-
enum Kind {
54-
kSandbox,
55-
kContext
56-
};
53+
// V8 reserves the first field in context objects for the debugger. We use the
54+
// second field to hold a reference to the sandbox object.
55+
enum { kSandboxObjectIndex = 1 };
5756

5857
Environment* const env_;
59-
Persistent<Object> sandbox_;
6058
Persistent<Context> context_;
61-
int references_;
6259

6360
public:
64-
explicit ContextifyContext(Environment* env, Local<Object> sandbox)
65-
: env_(env),
66-
sandbox_(env->isolate(), sandbox),
67-
// Wait for sandbox_ and context_ to die
68-
references_(0) {
69-
context_.Reset(env->isolate(), CreateV8Context(env));
70-
71-
sandbox_.SetWeak(this, WeakCallback<Object, kSandbox>);
72-
sandbox_.MarkIndependent();
73-
references_++;
61+
explicit ContextifyContext(Environment* env, Local<Object> sandbox_obj)
62+
: env_(env) {
63+
Local<Context> v8_context = CreateV8Context(env, sandbox_obj);
64+
context_.Reset(env->isolate(), v8_context);
7465

7566
// Allocation failure or maximum call stack size reached
7667
if (context_.IsEmpty())
7768
return;
78-
context_.SetWeak(this, WeakCallback<Context, kContext>);
69+
context_.SetWeak(this, WeakCallback<Context>);
7970
context_.MarkIndependent();
80-
references_++;
8171
}
8272

8373

8474
~ContextifyContext() {
8575
context_.Reset();
86-
sandbox_.Reset();
8776
}
8877

8978

@@ -101,6 +90,11 @@ class ContextifyContext {
10190
return context()->Global();
10291
}
10392

93+
94+
inline Local<Object> sandbox() const {
95+
return Local<Object>::Cast(context()->GetEmbedderData(kSandboxObjectIndex));
96+
}
97+
10498
// XXX(isaacs): This function only exists because of a shortcoming of
10599
// the V8 SetNamedPropertyHandler function.
106100
//
@@ -128,15 +122,14 @@ class ContextifyContext {
128122
Local<Context> context = PersistentToLocal(env()->isolate(), context_);
129123
Local<Object> global =
130124
context->Global()->GetPrototype()->ToObject(env()->isolate());
131-
Local<Object> sandbox = PersistentToLocal(env()->isolate(), sandbox_);
132125

133126
Local<Function> clone_property_method;
134127

135128
Local<Array> names = global->GetOwnPropertyNames();
136129
int length = names->Length();
137130
for (int i = 0; i < length; i++) {
138131
Local<String> key = names->Get(i)->ToString(env()->isolate());
139-
bool has = sandbox->HasOwnProperty(context, key).FromJust();
132+
bool has = sandbox()->HasOwnProperty(context, key).FromJust();
140133
if (!has) {
141134
// Could also do this like so:
142135
//
@@ -168,7 +161,7 @@ class ContextifyContext {
168161
clone_property_method = Local<Function>::Cast(script->Run());
169162
CHECK(clone_property_method->IsFunction());
170163
}
171-
Local<Value> args[] = { global, key, sandbox };
164+
Local<Value> args[] = { global, key, sandbox() };
172165
clone_property_method->Call(global, ARRAY_SIZE(args), args);
173166
}
174167
}
@@ -193,14 +186,13 @@ class ContextifyContext {
193186
}
194187

195188

196-
Local<Context> CreateV8Context(Environment* env) {
189+
Local<Context> CreateV8Context(Environment* env, Local<Object> sandbox_obj) {
197190
EscapableHandleScope scope(env->isolate());
198191
Local<FunctionTemplate> function_template =
199192
FunctionTemplate::New(env->isolate());
200193
function_template->SetHiddenPrototype(true);
201194

202-
Local<Object> sandbox = PersistentToLocal(env->isolate(), sandbox_);
203-
function_template->SetClassName(sandbox->GetConstructorName());
195+
function_template->SetClassName(sandbox_obj->GetConstructorName());
204196

205197
Local<ObjectTemplate> object_template =
206198
function_template->InstanceTemplate();
@@ -217,6 +209,7 @@ class ContextifyContext {
217209

218210
CHECK(!ctx.IsEmpty());
219211
ctx->SetSecurityToken(env->context()->GetSecurityToken());
212+
ctx->SetEmbedderData(kSandboxObjectIndex, sandbox_obj);
220213

221214
env->AssignToContext(ctx);
222215

@@ -312,16 +305,11 @@ class ContextifyContext {
312305
}
313306

314307

315-
template <class T, Kind kind>
308+
template <class T>
316309
static void WeakCallback(const WeakCallbackData<T, ContextifyContext>& data) {
317310
ContextifyContext* context = data.GetParameter();
318-
if (kind == kSandbox)
319-
context->sandbox_.ClearWeak();
320-
else
321-
context->context_.ClearWeak();
322-
323-
if (--context->references_ == 0)
324-
delete context;
311+
context->context_.ClearWeak();
312+
delete context;
325313
}
326314

327315

@@ -343,26 +331,23 @@ class ContextifyContext {
343331
static void GlobalPropertyGetterCallback(
344332
Local<Name> property,
345333
const PropertyCallbackInfo<Value>& args) {
346-
Isolate* isolate = args.GetIsolate();
347-
348334
ContextifyContext* ctx =
349335
Unwrap<ContextifyContext>(args.Data().As<Object>());
350336

351337
// Stil initializing
352338
if (ctx->context_.IsEmpty())
353339
return;
354340

355-
Local<Object> sandbox = PersistentToLocal(isolate, ctx->sandbox_);
356341
MaybeLocal<Value> maybe_rv =
357-
sandbox->GetRealNamedProperty(ctx->context(), property);
342+
ctx->sandbox()->GetRealNamedProperty(ctx->context(), property);
358343
if (maybe_rv.IsEmpty()) {
359344
maybe_rv =
360345
ctx->global_proxy()->GetRealNamedProperty(ctx->context(), property);
361346
}
362347

363348
Local<Value> rv;
364349
if (maybe_rv.ToLocal(&rv)) {
365-
if (rv == ctx->sandbox_)
350+
if (rv == ctx->sandbox())
366351
rv = ctx->global_proxy();
367352

368353
args.GetReturnValue().Set(rv);
@@ -374,34 +359,30 @@ class ContextifyContext {
374359
Local<Name> property,
375360
Local<Value> value,
376361
const PropertyCallbackInfo<Value>& args) {
377-
Isolate* isolate = args.GetIsolate();
378-
379362
ContextifyContext* ctx =
380363
Unwrap<ContextifyContext>(args.Data().As<Object>());
381364

382365
// Stil initializing
383366
if (ctx->context_.IsEmpty())
384367
return;
385368

386-
PersistentToLocal(isolate, ctx->sandbox_)->Set(property, value);
369+
ctx->sandbox()->Set(property, value);
387370
}
388371

389372

390373
static void GlobalPropertyQueryCallback(
391374
Local<Name> property,
392375
const PropertyCallbackInfo<Integer>& args) {
393-
Isolate* isolate = args.GetIsolate();
394-
395376
ContextifyContext* ctx =
396377
Unwrap<ContextifyContext>(args.Data().As<Object>());
397378

398379
// Stil initializing
399380
if (ctx->context_.IsEmpty())
400381
return;
401382

402-
Local<Object> sandbox = PersistentToLocal(isolate, ctx->sandbox_);
403383
Maybe<PropertyAttribute> maybe_prop_attr =
404-
sandbox->GetRealNamedPropertyAttributes(ctx->context(), property);
384+
ctx->sandbox()->GetRealNamedPropertyAttributes(ctx->context(),
385+
property);
405386

406387
if (maybe_prop_attr.IsNothing()) {
407388
maybe_prop_attr =
@@ -419,18 +400,14 @@ class ContextifyContext {
419400
static void GlobalPropertyDeleterCallback(
420401
Local<Name> property,
421402
const PropertyCallbackInfo<Boolean>& args) {
422-
Isolate* isolate = args.GetIsolate();
423-
424403
ContextifyContext* ctx =
425404
Unwrap<ContextifyContext>(args.Data().As<Object>());
426405

427406
// Stil initializing
428407
if (ctx->context_.IsEmpty())
429408
return;
430409

431-
Local<Object> sandbox = PersistentToLocal(isolate, ctx->sandbox_);
432-
433-
Maybe<bool> success = sandbox->Delete(ctx->context(), property);
410+
Maybe<bool> success = ctx->sandbox()->Delete(ctx->context(), property);
434411

435412
if (success.IsJust())
436413
args.GetReturnValue().Set(success.FromJust());
@@ -446,8 +423,7 @@ class ContextifyContext {
446423
if (ctx->context_.IsEmpty())
447424
return;
448425

449-
Local<Object> sandbox = PersistentToLocal(args.GetIsolate(), ctx->sandbox_);
450-
args.GetReturnValue().Set(sandbox->GetPropertyNames());
426+
args.GetReturnValue().Set(ctx->sandbox()->GetPropertyNames());
451427
}
452428
};
453429

0 commit comments

Comments
 (0)