Skip to content

Commit 9e6d817

Browse files
ofrobotsMyles Borins
authored and
Myles Borins
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: Ben Noordhuis <info@bnoordhuis.nl>
1 parent b6fc153 commit 9e6d817

File tree

1 file changed

+28
-52
lines changed

1 file changed

+28
-52
lines changed

src/node_contextify.cc

+28-52
Original file line numberDiff line numberDiff line change
@@ -48,40 +48,29 @@ using v8::WeakCallbackData;
4848

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

5655
Environment* const env_;
57-
Persistent<Object> sandbox_;
5856
Persistent<Context> context_;
59-
int references_;
6057

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

7364
// Allocation failure or maximum call stack size reached
7465
if (context_.IsEmpty())
7566
return;
76-
context_.SetWeak(this, WeakCallback<Context, kContext>);
67+
context_.SetWeak(this, WeakCallback<Context>);
7768
context_.MarkIndependent();
78-
references_++;
7969
}
8070

8171

8272
~ContextifyContext() {
8373
context_.Reset();
84-
sandbox_.Reset();
8574
}
8675

8776

@@ -99,6 +88,11 @@ class ContextifyContext {
9988
return context()->Global();
10089
}
10190

91+
92+
inline Local<Object> sandbox() const {
93+
return Local<Object>::Cast(context()->GetEmbedderData(kSandboxObjectIndex));
94+
}
95+
10296
// XXX(isaacs): This function only exists because of a shortcoming of
10397
// the V8 SetNamedPropertyHandler function.
10498
//
@@ -126,15 +120,14 @@ class ContextifyContext {
126120
Local<Context> context = PersistentToLocal(env()->isolate(), context_);
127121
Local<Object> global =
128122
context->Global()->GetPrototype()->ToObject(env()->isolate());
129-
Local<Object> sandbox = PersistentToLocal(env()->isolate(), sandbox_);
130123

131124
Local<Function> clone_property_method;
132125

133126
Local<Array> names = global->GetOwnPropertyNames();
134127
int length = names->Length();
135128
for (int i = 0; i < length; i++) {
136129
Local<String> key = names->Get(i)->ToString(env()->isolate());
137-
bool has = sandbox->HasOwnProperty(key);
130+
bool has = sandbox()->HasOwnProperty(context, key).FromJust();
138131
if (!has) {
139132
// Could also do this like so:
140133
//
@@ -167,7 +160,7 @@ class ContextifyContext {
167160
clone_property_method = Local<Function>::Cast(script->Run());
168161
CHECK(clone_property_method->IsFunction());
169162
}
170-
Local<Value> args[] = { global, key, sandbox };
163+
Local<Value> args[] = { global, key, sandbox() };
171164
clone_property_method->Call(global, ARRAY_SIZE(args), args);
172165
}
173166
}
@@ -191,14 +184,13 @@ class ContextifyContext {
191184
}
192185

193186

194-
Local<Context> CreateV8Context(Environment* env) {
187+
Local<Context> CreateV8Context(Environment* env, Local<Object> sandbox_obj) {
195188
EscapableHandleScope scope(env->isolate());
196189
Local<FunctionTemplate> function_template =
197190
FunctionTemplate::New(env->isolate());
198191
function_template->SetHiddenPrototype(true);
199192

200-
Local<Object> sandbox = PersistentToLocal(env->isolate(), sandbox_);
201-
function_template->SetClassName(sandbox->GetConstructorName());
193+
function_template->SetClassName(sandbox_obj->GetConstructorName());
202194

203195
Local<ObjectTemplate> object_template =
204196
function_template->InstanceTemplate();
@@ -215,6 +207,7 @@ class ContextifyContext {
215207

216208
CHECK(!ctx.IsEmpty());
217209
ctx->SetSecurityToken(env->context()->GetSecurityToken());
210+
ctx->SetEmbedderData(kSandboxObjectIndex, sandbox_obj);
218211

219212
env->AssignToContext(ctx);
220213

@@ -309,16 +302,11 @@ class ContextifyContext {
309302
}
310303

311304

312-
template <class T, Kind kind>
305+
template <class T>
313306
static void WeakCallback(const WeakCallbackData<T, ContextifyContext>& data) {
314307
ContextifyContext* context = data.GetParameter();
315-
if (kind == kSandbox)
316-
context->sandbox_.ClearWeak();
317-
else
318-
context->context_.ClearWeak();
319-
320-
if (--context->references_ == 0)
321-
delete context;
308+
context->context_.ClearWeak();
309+
delete context;
322310
}
323311

324312

@@ -340,26 +328,23 @@ class ContextifyContext {
340328
static void GlobalPropertyGetterCallback(
341329
Local<Name> property,
342330
const PropertyCallbackInfo<Value>& args) {
343-
Isolate* isolate = args.GetIsolate();
344-
345331
ContextifyContext* ctx =
346332
Unwrap<ContextifyContext>(args.Data().As<Object>());
347333

348334
// Stil initializing
349335
if (ctx->context_.IsEmpty())
350336
return;
351337

352-
Local<Object> sandbox = PersistentToLocal(isolate, ctx->sandbox_);
353338
MaybeLocal<Value> maybe_rv =
354-
sandbox->GetRealNamedProperty(ctx->context(), property);
339+
ctx->sandbox()->GetRealNamedProperty(ctx->context(), property);
355340
if (maybe_rv.IsEmpty()) {
356341
maybe_rv =
357342
ctx->global_proxy()->GetRealNamedProperty(ctx->context(), property);
358343
}
359344

360345
Local<Value> rv;
361346
if (maybe_rv.ToLocal(&rv)) {
362-
if (rv == ctx->sandbox_)
347+
if (rv == ctx->sandbox())
363348
rv = ctx->global_proxy();
364349

365350
args.GetReturnValue().Set(rv);
@@ -371,34 +356,30 @@ class ContextifyContext {
371356
Local<Name> property,
372357
Local<Value> value,
373358
const PropertyCallbackInfo<Value>& args) {
374-
Isolate* isolate = args.GetIsolate();
375-
376359
ContextifyContext* ctx =
377360
Unwrap<ContextifyContext>(args.Data().As<Object>());
378361

379362
// Stil initializing
380363
if (ctx->context_.IsEmpty())
381364
return;
382365

383-
PersistentToLocal(isolate, ctx->sandbox_)->Set(property, value);
366+
ctx->sandbox()->Set(property, value);
384367
}
385368

386369

387370
static void GlobalPropertyQueryCallback(
388371
Local<Name> property,
389372
const PropertyCallbackInfo<Integer>& args) {
390-
Isolate* isolate = args.GetIsolate();
391-
392373
ContextifyContext* ctx =
393374
Unwrap<ContextifyContext>(args.Data().As<Object>());
394375

395376
// Stil initializing
396377
if (ctx->context_.IsEmpty())
397378
return;
398379

399-
Local<Object> sandbox = PersistentToLocal(isolate, ctx->sandbox_);
400380
Maybe<PropertyAttribute> maybe_prop_attr =
401-
sandbox->GetRealNamedPropertyAttributes(ctx->context(), property);
381+
ctx->sandbox()->GetRealNamedPropertyAttributes(ctx->context(),
382+
property);
402383

403384
if (maybe_prop_attr.IsNothing()) {
404385
maybe_prop_attr =
@@ -416,18 +397,14 @@ class ContextifyContext {
416397
static void GlobalPropertyDeleterCallback(
417398
Local<Name> property,
418399
const PropertyCallbackInfo<Boolean>& args) {
419-
Isolate* isolate = args.GetIsolate();
420-
421400
ContextifyContext* ctx =
422401
Unwrap<ContextifyContext>(args.Data().As<Object>());
423402

424403
// Stil initializing
425404
if (ctx->context_.IsEmpty())
426405
return;
427406

428-
Local<Object> sandbox = PersistentToLocal(isolate, ctx->sandbox_);
429-
430-
Maybe<bool> success = sandbox->Delete(ctx->context(), property);
407+
Maybe<bool> success = ctx->sandbox()->Delete(ctx->context(), property);
431408

432409
if (success.IsJust())
433410
args.GetReturnValue().Set(success.FromJust());
@@ -443,8 +420,7 @@ class ContextifyContext {
443420
if (ctx->context_.IsEmpty())
444421
return;
445422

446-
Local<Object> sandbox = PersistentToLocal(args.GetIsolate(), ctx->sandbox_);
447-
args.GetReturnValue().Set(sandbox->GetPropertyNames());
423+
args.GetReturnValue().Set(ctx->sandbox()->GetPropertyNames());
448424
}
449425
};
450426

0 commit comments

Comments
 (0)