diff options
author | Ben Noordhuis <info@bnoordhuis.nl> | 2013-08-11 00:26:11 +0200 |
---|---|---|
committer | Ben Noordhuis <info@bnoordhuis.nl> | 2013-09-06 05:51:42 +0200 |
commit | 756b6222956b5d25b2e7db81f4e79033a3a4d20e (patch) | |
tree | eb03b6f0bf33c36e011858c4a31b10a6eaadfc19 /src/pipe_wrap.cc | |
parent | 81655a224a36948291e1f21f03273b5b604b7e6a (diff) | |
download | android-node-v8-756b6222956b5d25b2e7db81f4e79033a3a4d20e.tar.gz android-node-v8-756b6222956b5d25b2e7db81f4e79033a3a4d20e.tar.bz2 android-node-v8-756b6222956b5d25b2e7db81f4e79033a3a4d20e.zip |
src: add multi-context support
This commit makes it possible to use multiple V8 execution contexts
within a single event loop. Put another way, handle and request wrap
objects now "remember" the context they belong to and switch back to
that context when the time comes to call into JS land.
This could have been done in a quick and hacky way by calling
v8::Object::GetCreationContext() on the wrap object right before
making a callback but that leaves a fairly wide margin for bugs.
Instead, we make the context explicit through a new Environment class
that encapsulates everything (or almost everything) that belongs to
the context. Variables that used to be a static or a global are now
members of the aforementioned class. An additional benefit is that
this approach should make it relatively straightforward to add full
isolate support in due course.
There is no JavaScript API yet but that will be added in the near
future.
This work was graciously sponsored by GitHub, Inc.
Diffstat (limited to 'src/pipe_wrap.cc')
-rw-r--r-- | src/pipe_wrap.cc | 96 |
1 files changed, 55 insertions, 41 deletions
diff --git a/src/pipe_wrap.cc b/src/pipe_wrap.cc index 97375ab847..805e69b668 100644 --- a/src/pipe_wrap.cc +++ b/src/pipe_wrap.cc @@ -20,16 +20,22 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. #include "pipe_wrap.h" + +#include "env.h" +#include "env-inl.h" +#include "handle_wrap.h" #include "node.h" #include "node_buffer.h" -#include "handle_wrap.h" #include "node_wrap.h" #include "req_wrap.h" #include "stream_wrap.h" +#include "util-inl.h" +#include "util.h" namespace node { using v8::Boolean; +using v8::Context; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; @@ -38,17 +44,11 @@ using v8::HandleScope; using v8::Integer; using v8::Local; using v8::Object; -using v8::Persistent; using v8::PropertyAttribute; using v8::String; using v8::Undefined; using v8::Value; -static Persistent<Function> pipeConstructor; -static Cached<String> onconnection_sym; -static Cached<String> oncomplete_sym; - - // TODO(bnoordhuis) share with TCPWrap? typedef class ReqWrap<uv_connect_t> ConnectWrap; @@ -58,10 +58,14 @@ uv_pipe_t* PipeWrap::UVHandle() { } -Local<Object> PipeWrap::Instantiate() { - HandleScope scope(node_isolate); - assert(!pipeConstructor.IsEmpty()); - return scope.Close(NewInstance(pipeConstructor)); +Local<Object> PipeWrap::Instantiate(Environment* env) { + HandleScope handle_scope(env->isolate()); + assert(!env->pipe_constructor_template().IsEmpty()); + Local<Function> constructor = env->pipe_constructor_template()->GetFunction(); + assert(!constructor.IsEmpty()); + Local<Object> instance = constructor->NewInstance(); + assert(!instance.IsEmpty()); + return handle_scope.Close(instance); } @@ -72,14 +76,13 @@ PipeWrap* PipeWrap::Unwrap(Local<Object> obj) { } -void PipeWrap::Initialize(Handle<Object> target) { - StreamWrap::Initialize(target); - - HandleScope scope(node_isolate); +void PipeWrap::Initialize(Handle<Object> target, + Handle<Value> unused, + Handle<Context> context) { + Environment* env = Environment::GetCurrent(context); Local<FunctionTemplate> t = FunctionTemplate::New(New); t->SetClassName(FIXED_ONE_BYTE_STRING(node_isolate, "Pipe")); - t->InstanceTemplate()->SetInternalFieldCount(1); enum PropertyAttribute attributes = @@ -115,9 +118,8 @@ void PipeWrap::Initialize(Handle<Object> target) { NODE_SET_PROTOTYPE_METHOD(t, "setPendingInstances", SetPendingInstances); #endif - pipeConstructorTmpl.Reset(node_isolate, t); - pipeConstructor.Reset(node_isolate, t->GetFunction()); target->Set(FIXED_ONE_BYTE_STRING(node_isolate, "Pipe"), t->GetFunction()); + env->set_pipe_constructor_template(t); } @@ -126,16 +128,15 @@ void PipeWrap::New(const FunctionCallbackInfo<Value>& args) { // Therefore we assert that we are not trying to call this as a // normal function. assert(args.IsConstructCall()); - - HandleScope scope(node_isolate); - PipeWrap* wrap = new PipeWrap(args.This(), args[0]->IsTrue()); - assert(wrap); + Environment* env = Environment::GetCurrent(args.GetIsolate()); + HandleScope handle_scope(args.GetIsolate()); + new PipeWrap(env, args.This(), args[0]->IsTrue()); } -PipeWrap::PipeWrap(Handle<Object> object, bool ipc) - : StreamWrap(object, reinterpret_cast<uv_stream_t*>(&handle_)) { - int r = uv_pipe_init(uv_default_loop(), &handle_, ipc); +PipeWrap::PipeWrap(Environment* env, Handle<Object> object, bool ipc) + : StreamWrap(env, object, reinterpret_cast<uv_stream_t*>(&handle_)) { + int r = uv_pipe_init(env->event_loop(), &handle_, ipc); assert(r == 0); // How do we proxy this error up to javascript? // Suggestion: uv_pipe_init() returns void. UpdateWriteQueueSize(); @@ -184,11 +185,13 @@ void PipeWrap::Listen(const FunctionCallbackInfo<Value>& args) { // TODO(bnoordhuis) maybe share with TCPWrap? void PipeWrap::OnConnection(uv_stream_t* handle, int status) { - HandleScope scope(node_isolate); - PipeWrap* pipe_wrap = static_cast<PipeWrap*>(handle->data); assert(&pipe_wrap->handle_ == reinterpret_cast<uv_pipe_t*>(handle)); + Environment* env = pipe_wrap->env(); + Context::Scope context_scope(env->context()); + HandleScope handle_scope(env->isolate()); + // We should not be getting this callback if someone as already called // uv_close() on the handle. assert(pipe_wrap->persistent().IsEmpty() == false); @@ -199,12 +202,17 @@ void PipeWrap::OnConnection(uv_stream_t* handle, int status) { }; if (status != 0) { - MakeCallback(pipe_wrap->object(), "onconnection", ARRAY_SIZE(argv), argv); + MakeCallback(env, + pipe_wrap->object(), + env->onconnection_string(), + ARRAY_SIZE(argv), + argv); return; } // Instanciate the client javascript object and handle. - Local<Object> client_obj = NewInstance(pipeConstructor); + Local<Object> client_obj = + env->pipe_constructor_template()->GetFunction()->NewInstance(); // Unwrap the client javascript object. PipeWrap* wrap; @@ -215,18 +223,22 @@ void PipeWrap::OnConnection(uv_stream_t* handle, int status) { // Successful accept. Call the onconnection callback in JavaScript land. argv[1] = client_obj; - if (onconnection_sym.IsEmpty()) { - onconnection_sym = FIXED_ONE_BYTE_STRING(node_isolate, "onconnection"); - } - MakeCallback(pipe_wrap->object(), onconnection_sym, ARRAY_SIZE(argv), argv); + MakeCallback(env, + pipe_wrap->object(), + env->onconnection_string(), + ARRAY_SIZE(argv), + argv); } // TODO(bnoordhuis) Maybe share this with TCPWrap? void PipeWrap::AfterConnect(uv_connect_t* req, int status) { ConnectWrap* req_wrap = static_cast<ConnectWrap*>(req->data); PipeWrap* wrap = static_cast<PipeWrap*>(req->handle->data); + assert(req_wrap->env() == wrap->env()); + Environment* env = wrap->env(); - HandleScope scope(node_isolate); + Context::Scope context_scope(env->context()); + HandleScope handle_scope(env->isolate()); // The wrap and request objects should still be there. assert(req_wrap->persistent().IsEmpty() == false); @@ -250,10 +262,11 @@ void PipeWrap::AfterConnect(uv_connect_t* req, int status) { Boolean::New(writable) }; - if (oncomplete_sym.IsEmpty()) { - oncomplete_sym = FIXED_ONE_BYTE_STRING(node_isolate, "oncomplete"); - } - MakeCallback(req_wrap_obj, oncomplete_sym, ARRAY_SIZE(argv), argv); + MakeCallback(env, + req_wrap_obj, + env->oncomplete_string(), + ARRAY_SIZE(argv), + argv); delete req_wrap; } @@ -272,7 +285,8 @@ void PipeWrap::Open(const FunctionCallbackInfo<Value>& args) { void PipeWrap::Connect(const FunctionCallbackInfo<Value>& args) { - HandleScope scope(node_isolate); + Environment* env = Environment::GetCurrent(args.GetIsolate()); + HandleScope scope(args.GetIsolate()); PipeWrap* wrap; NODE_UNWRAP(args.This(), PipeWrap, wrap); @@ -283,7 +297,7 @@ void PipeWrap::Connect(const FunctionCallbackInfo<Value>& args) { Local<Object> req_wrap_obj = args[0].As<Object>(); String::AsciiValue name(args[1]); - ConnectWrap* req_wrap = new ConnectWrap(req_wrap_obj); + ConnectWrap* req_wrap = new ConnectWrap(env, req_wrap_obj); uv_pipe_connect(&req_wrap->req_, &wrap->handle_, *name, @@ -296,4 +310,4 @@ void PipeWrap::Connect(const FunctionCallbackInfo<Value>& args) { } // namespace node -NODE_MODULE(node_pipe_wrap, node::PipeWrap::Initialize) +NODE_MODULE_CONTEXT_AWARE(node_pipe_wrap, node::PipeWrap::Initialize) |