summaryrefslogtreecommitdiff
path: root/src/pipe_wrap.cc
diff options
context:
space:
mode:
authorBen Noordhuis <info@bnoordhuis.nl>2013-08-11 00:26:11 +0200
committerBen Noordhuis <info@bnoordhuis.nl>2013-09-06 05:51:42 +0200
commit756b6222956b5d25b2e7db81f4e79033a3a4d20e (patch)
treeeb03b6f0bf33c36e011858c4a31b10a6eaadfc19 /src/pipe_wrap.cc
parent81655a224a36948291e1f21f03273b5b604b7e6a (diff)
downloadandroid-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.cc96
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)