diff --git a/src/node_contextify.cc b/src/node_contextify.cc index 6e04d5836ff894..eb013c645c533c 100644 --- a/src/node_contextify.cc +++ b/src/node_contextify.cc @@ -45,33 +45,53 @@ using v8::Uint8Array; using v8::UnboundScript; using v8::V8; using v8::Value; -using v8::WeakCallbackInfo; +using v8::WeakCallbackData; class ContextifyContext { protected: - // V8 reserves the first field in context objects for the debugger. We use the - // second field to hold a reference to the sandbox object. - enum { kSandboxObjectIndex = 1 }; + enum Kind { + kSandbox, + kContext, + kProxyGlobal + }; Environment* const env_; + Persistent sandbox_; Persistent context_; + Persistent proxy_global_; + int references_; public: - ContextifyContext(Environment* env, Local sandbox_obj) : env_(env) { - Local v8_context = CreateV8Context(env, sandbox_obj); - context_.Reset(env->isolate(), v8_context); + explicit ContextifyContext(Environment* env, Local sandbox) + : env_(env), + sandbox_(env->isolate(), sandbox), + // Wait for sandbox_, proxy_global_, and context_ to die + references_(0) { + context_.Reset(env->isolate(), CreateV8Context(env)); + + sandbox_.SetWeak(this, WeakCallback); + sandbox_.MarkIndependent(); + references_++; // Allocation failure or maximum call stack size reached if (context_.IsEmpty()) return; - context_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter); + context_.SetWeak(this, WeakCallback); context_.MarkIndependent(); + references_++; + + proxy_global_.Reset(env->isolate(), context()->Global()); + proxy_global_.SetWeak(this, WeakCallback); + proxy_global_.MarkIndependent(); + references_++; } ~ContextifyContext() { context_.Reset(); + proxy_global_.Reset(); + sandbox_.Reset(); } @@ -85,15 +105,6 @@ class ContextifyContext { } - inline Local global_proxy() const { - return context()->Global(); - } - - - inline Local sandbox() const { - return Local::Cast(context()->GetEmbedderData(kSandboxObjectIndex)); - } - // XXX(isaacs): This function only exists because of a shortcoming of // the V8 SetNamedPropertyHandler function. // @@ -121,7 +132,7 @@ class ContextifyContext { Local context = PersistentToLocal(env()->isolate(), context_); Local global = context->Global()->GetPrototype()->ToObject(env()->isolate()); - Local sandbox_obj = sandbox(); + Local sandbox = PersistentToLocal(env()->isolate(), sandbox_); Local clone_property_method; @@ -129,7 +140,7 @@ class ContextifyContext { int length = names->Length(); for (int i = 0; i < length; i++) { Local key = names->Get(i)->ToString(env()->isolate()); - bool has = sandbox_obj->HasOwnProperty(context, key).FromJust(); + bool has = sandbox->HasOwnProperty(context, key).FromJust(); if (!has) { // Could also do this like so: // @@ -161,7 +172,7 @@ class ContextifyContext { clone_property_method = Local::Cast(script->Run()); CHECK(clone_property_method->IsFunction()); } - Local args[] = { global, key, sandbox_obj }; + Local args[] = { global, key, sandbox }; clone_property_method->Call(global, ARRAY_SIZE(args), args); } } @@ -186,13 +197,14 @@ class ContextifyContext { } - Local CreateV8Context(Environment* env, Local sandbox_obj) { + Local CreateV8Context(Environment* env) { EscapableHandleScope scope(env->isolate()); Local function_template = FunctionTemplate::New(env->isolate()); function_template->SetHiddenPrototype(true); - function_template->SetClassName(sandbox_obj->GetConstructorName()); + Local sandbox = PersistentToLocal(env->isolate(), sandbox_); + function_template->SetClassName(sandbox->GetConstructorName()); Local object_template = function_template->InstanceTemplate(); @@ -209,7 +221,6 @@ class ContextifyContext { CHECK(!ctx.IsEmpty()); ctx->SetSecurityToken(env->context()->GetSecurityToken()); - ctx->SetEmbedderData(kSandboxObjectIndex, sandbox_obj); env->AssignToContext(ctx); @@ -305,9 +316,18 @@ class ContextifyContext { } - static void WeakCallback(const WeakCallbackInfo& data) { + template + static void WeakCallback(const WeakCallbackData& data) { ContextifyContext* context = data.GetParameter(); - delete context; + if (kind == kSandbox) + context->sandbox_.ClearWeak(); + else if (kind == kContext) + context->context_.ClearWeak(); + else + context->proxy_global_.ClearWeak(); + + if (--context->references_ == 0) + delete context; } @@ -329,6 +349,8 @@ class ContextifyContext { static void GlobalPropertyGetterCallback( Local property, const PropertyCallbackInfo& args) { + Isolate* isolate = args.GetIsolate(); + ContextifyContext* ctx = Unwrap(args.Data().As()); @@ -336,19 +358,19 @@ class ContextifyContext { if (ctx->context_.IsEmpty()) return; - Local context = ctx->context(); - Local sandbox = ctx->sandbox(); + Local sandbox = PersistentToLocal(isolate, ctx->sandbox_); MaybeLocal maybe_rv = - sandbox->GetRealNamedProperty(context, property); + sandbox->GetRealNamedProperty(ctx->context(), property); if (maybe_rv.IsEmpty()) { - maybe_rv = - ctx->global_proxy()->GetRealNamedProperty(context, property); + Local proxy_global = PersistentToLocal(isolate, + ctx->proxy_global_); + maybe_rv = proxy_global->GetRealNamedProperty(ctx->context(), property); } Local rv; if (maybe_rv.ToLocal(&rv)) { - if (rv == sandbox) - rv = ctx->global_proxy(); + if (rv == ctx->sandbox_) + rv = PersistentToLocal(isolate, ctx->proxy_global_); args.GetReturnValue().Set(rv); } @@ -359,6 +381,8 @@ class ContextifyContext { Local property, Local value, const PropertyCallbackInfo& args) { + Isolate* isolate = args.GetIsolate(); + ContextifyContext* ctx = Unwrap(args.Data().As()); @@ -366,13 +390,15 @@ class ContextifyContext { if (ctx->context_.IsEmpty()) return; - ctx->sandbox()->Set(property, value); + PersistentToLocal(isolate, ctx->sandbox_)->Set(property, value); } static void GlobalPropertyQueryCallback( Local property, const PropertyCallbackInfo& args) { + Isolate* isolate = args.GetIsolate(); + ContextifyContext* ctx = Unwrap(args.Data().As()); @@ -380,14 +406,17 @@ class ContextifyContext { if (ctx->context_.IsEmpty()) return; - Local context = ctx->context(); + Local sandbox = PersistentToLocal(isolate, ctx->sandbox_); Maybe maybe_prop_attr = - ctx->sandbox()->GetRealNamedPropertyAttributes(context, property); + sandbox->GetRealNamedPropertyAttributes(ctx->context(), property); if (maybe_prop_attr.IsNothing()) { + Local proxy_global = PersistentToLocal(isolate, + ctx->proxy_global_); + maybe_prop_attr = - ctx->global_proxy()->GetRealNamedPropertyAttributes(context, - property); + proxy_global->GetRealNamedPropertyAttributes(ctx->context(), + property); } if (maybe_prop_attr.IsJust()) { @@ -400,6 +429,8 @@ class ContextifyContext { static void GlobalPropertyDeleterCallback( Local property, const PropertyCallbackInfo& args) { + Isolate* isolate = args.GetIsolate(); + ContextifyContext* ctx = Unwrap(args.Data().As()); @@ -407,7 +438,9 @@ class ContextifyContext { if (ctx->context_.IsEmpty()) return; - Maybe success = ctx->sandbox()->Delete(ctx->context(), property); + Local sandbox = PersistentToLocal(isolate, ctx->sandbox_); + + Maybe success = sandbox->Delete(ctx->context(), property); if (success.IsJust()) args.GetReturnValue().Set(success.FromJust()); @@ -423,7 +456,8 @@ class ContextifyContext { if (ctx->context_.IsEmpty()) return; - args.GetReturnValue().Set(ctx->sandbox()->GetPropertyNames()); + Local sandbox = PersistentToLocal(args.GetIsolate(), ctx->sandbox_); + args.GetReturnValue().Set(sandbox->GetPropertyNames()); } };