summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cares_wrap.cc236
-rw-r--r--src/env-inl.h289
-rw-r--r--src/env.h324
-rw-r--r--src/fs_event_wrap.cc60
-rw-r--r--src/handle_wrap.cc29
-rw-r--r--src/handle_wrap.h14
-rw-r--r--src/node.cc720
-rw-r--r--src/node.h32
-rw-r--r--src/node.js53
-rw-r--r--src/node_buffer.cc67
-rw-r--r--src/node_buffer.h18
-rw-r--r--src/node_contextify.cc127
-rw-r--r--src/node_crypto.cc277
-rw-r--r--src/node_crypto.h56
-rw-r--r--src/node_file.cc162
-rw-r--r--src/node_file.h5
-rw-r--r--src/node_http_parser.cc192
-rw-r--r--src/node_internals.h230
-rw-r--r--src/node_os.cc9
-rw-r--r--src/node_stat_watcher.cc49
-rw-r--r--src/node_stat_watcher.h9
-rw-r--r--src/node_version.h2
-rw-r--r--src/node_wrap.h45
-rw-r--r--src/node_zlib.cc111
-rw-r--r--src/pipe_wrap.cc96
-rw-r--r--src/pipe_wrap.h10
-rw-r--r--src/process_wrap.cc55
-rw-r--r--src/req_wrap.h40
-rw-r--r--src/signal_wrap.cc43
-rw-r--r--src/smalloc.cc43
-rw-r--r--src/stream_wrap.cc129
-rw-r--r--src/stream_wrap.h14
-rw-r--r--src/tcp_wrap.cc135
-rw-r--r--src/tcp_wrap.h10
-rw-r--r--src/timer_wrap.cc39
-rw-r--r--src/tls_wrap.cc166
-rw-r--r--src/tls_wrap.h13
-rw-r--r--src/tty_wrap.cc31
-rw-r--r--src/tty_wrap.h10
-rw-r--r--src/udp_wrap.cc82
-rw-r--r--src/udp_wrap.h14
-rw-r--r--src/util-inl.h83
-rw-r--r--src/util.h82
-rw-r--r--src/uv.cc8
44 files changed, 2515 insertions, 1704 deletions
diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc
index f09590e88e..00238788ad 100644
--- a/src/cares_wrap.cc
+++ b/src/cares_wrap.cc
@@ -21,6 +21,8 @@
#define CARES_STATICLIB
#include "ares.h"
+#include "env.h"
+#include "env-inl.h"
#include "node.h"
#include "req_wrap.h"
#include "tree.h"
@@ -45,6 +47,7 @@ namespace node {
namespace cares_wrap {
using v8::Array;
+using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::Handle;
@@ -57,22 +60,8 @@ using v8::Persistent;
using v8::String;
using v8::Value;
-
typedef class ReqWrap<uv_getaddrinfo_t> GetAddrInfoReqWrap;
-struct ares_task_t {
- uv_loop_t* loop;
- ares_socket_t sock;
- uv_poll_t poll_watcher;
- RB_ENTRY(ares_task_t) node;
-};
-
-
-static Cached<String> oncomplete_sym;
-static ares_channel ares_channel;
-static uv_timer_t ares_timer;
-static RB_HEAD(ares_task_list, ares_task_t) ares_tasks;
-
static int cmp_ares_tasks(const ares_task_t* a, const ares_task_t* b) {
if (a->sock < b->sock) return -1;
@@ -88,26 +77,28 @@ RB_GENERATE_STATIC(ares_task_list, ares_task_t, node, cmp_ares_tasks)
/* This is called once per second by loop->timer. It is used to constantly */
/* call back into c-ares for possibly processing timeouts. */
static void ares_timeout(uv_timer_t* handle, int status) {
- assert(!RB_EMPTY(&ares_tasks));
- ares_process_fd(ares_channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
+ Environment* env = Environment::from_cares_timer_handle(handle);
+ assert(!RB_EMPTY(env->cares_task_list()));
+ ares_process_fd(env->cares_channel(), ARES_SOCKET_BAD, ARES_SOCKET_BAD);
}
static void ares_poll_cb(uv_poll_t* watcher, int status, int events) {
ares_task_t* task = container_of(watcher, ares_task_t, poll_watcher);
+ Environment* env = task->env;
/* Reset the idle timer */
- uv_timer_again(&ares_timer);
+ uv_timer_again(env->cares_timer_handle());
if (status < 0) {
/* An error happened. Just pretend that the socket is both readable and */
/* writable. */
- ares_process_fd(ares_channel, task->sock, task->sock);
+ ares_process_fd(env->cares_channel(), task->sock, task->sock);
return;
}
/* Process DNS responses */
- ares_process_fd(ares_channel,
+ ares_process_fd(env->cares_channel(),
events & UV_READABLE ? task->sock : ARES_SOCKET_BAD,
events & UV_WRITABLE ? task->sock : ARES_SOCKET_BAD);
}
@@ -120,7 +111,7 @@ static void ares_poll_close_cb(uv_handle_t* watcher) {
/* Allocates and returns a new ares_task_t */
-static ares_task_t* ares_task_create(uv_loop_t* loop, ares_socket_t sock) {
+static ares_task_t* ares_task_create(Environment* env, ares_socket_t sock) {
ares_task_t* task = static_cast<ares_task_t*>(malloc(sizeof(*task)));
if (task == NULL) {
@@ -128,10 +119,10 @@ static ares_task_t* ares_task_create(uv_loop_t* loop, ares_socket_t sock) {
return NULL;
}
- task->loop = loop;
+ task->env = env;
task->sock = sock;
- if (uv_poll_init_socket(loop, &task->poll_watcher, sock) < 0) {
+ if (uv_poll_init_socket(env->event_loop(), &task->poll_watcher, sock) < 0) {
/* This should never happen. */
free(task);
return NULL;
@@ -146,24 +137,25 @@ static void ares_sockstate_cb(void* data,
ares_socket_t sock,
int read,
int write) {
- uv_loop_t* loop = static_cast<uv_loop_t*>(data);
+ Environment* env = static_cast<Environment*>(data);
ares_task_t* task;
ares_task_t lookup_task;
lookup_task.sock = sock;
- task = RB_FIND(ares_task_list, &ares_tasks, &lookup_task);
+ task = RB_FIND(ares_task_list, env->cares_task_list(), &lookup_task);
if (read || write) {
if (!task) {
/* New socket */
/* If this is the first socket then start the timer. */
- if (!uv_is_active(reinterpret_cast<uv_handle_t*>(&ares_timer))) {
- assert(RB_EMPTY(&ares_tasks));
- uv_timer_start(&ares_timer, ares_timeout, 1000, 1000);
+ uv_timer_t* timer_handle = env->cares_timer_handle();
+ if (!uv_is_active(reinterpret_cast<uv_handle_t*>(timer_handle))) {
+ assert(RB_EMPTY(env->cares_task_list()));
+ uv_timer_start(timer_handle, ares_timeout, 1000, 1000);
}
- task = ares_task_create(loop, sock);
+ task = ares_task_create(env, sock);
if (task == NULL) {
/* This should never happen unless we're out of memory or something */
/* is seriously wrong. The socket won't be polled, but the the query */
@@ -171,7 +163,7 @@ static void ares_sockstate_cb(void* data,
return;
}
- RB_INSERT(ares_task_list, &ares_tasks, task);
+ RB_INSERT(ares_task_list, env->cares_task_list(), task);
}
/* This should never fail. If it fails anyway, the query will eventually */
@@ -187,12 +179,12 @@ static void ares_sockstate_cb(void* data,
assert(task &&
"When an ares socket is closed we should have a handle for it");
- RB_REMOVE(ares_task_list, &ares_tasks, task);
+ RB_REMOVE(ares_task_list, env->cares_task_list(), task);
uv_close(reinterpret_cast<uv_handle_t*>(&task->poll_watcher),
ares_poll_close_cb);
- if (RB_EMPTY(&ares_tasks)) {
- uv_timer_stop(&ares_timer);
+ if (RB_EMPTY(env->cares_task_list())) {
+ uv_timer_stop(env->cares_timer_handle());
}
}
}
@@ -228,7 +220,7 @@ static Local<Array> HostentToNames(struct hostent* host) {
class QueryWrap {
public:
- explicit QueryWrap(Local<Object> req_wrap_obj) {
+ QueryWrap(Environment* env, Local<Object> req_wrap_obj) : env_(env) {
HandleScope scope(node_isolate);
persistent().Reset(node_isolate, req_wrap_obj);
}
@@ -289,24 +281,46 @@ class QueryWrap {
}
void CallOnComplete(Local<Value> answer) {
- HandleScope scope(node_isolate);
- Local<Value> argv[2] = { Integer::New(0, node_isolate), answer };
- MakeCallback(object(), oncomplete_sym, ARRAY_SIZE(argv), argv);
+ Context::Scope context_scope(env()->context());
+ HandleScope handle_scope(env()->isolate());
+ Local<Value> argv[] = {
+ Integer::New(0, env()->isolate()),
+ answer
+ };
+ MakeCallback(env(),
+ object(),
+ env()->oncomplete_string(),
+ ARRAY_SIZE(argv),
+ argv);
}
void CallOnComplete(Local<Value> answer, Local<Value> family) {
- HandleScope scope(node_isolate);
- Local<Value> argv[3] = { Integer::New(0, node_isolate), answer, family };
- MakeCallback(object(), oncomplete_sym, ARRAY_SIZE(argv), argv);
+ Context::Scope context_scope(env()->context());
+ HandleScope handle_scope(env()->isolate());
+ Local<Value> argv[] = {
+ Integer::New(0, env()->isolate()),
+ answer,
+ family
+ };
+ MakeCallback(env(),
+ object(),
+ env()->oncomplete_string(),
+ ARRAY_SIZE(argv),
+ argv);
}
void ParseError(int status) {
assert(status != ARES_SUCCESS);
- HandleScope scope(node_isolate);
+ Context::Scope context_scope(env()->context());
+ HandleScope handle_scope(env()->isolate());
Local<Value> argv[] = {
- Integer::New(status, node_isolate)
+ Integer::New(status, env()->isolate())
};
- MakeCallback(object(), oncomplete_sym, ARRAY_SIZE(argv), argv);
+ MakeCallback(env(),
+ object(),
+ env()->oncomplete_string(),
+ ARRAY_SIZE(argv),
+ argv);
}
// Subclasses should implement the appropriate Parse method.
@@ -318,18 +332,29 @@ class QueryWrap {
assert(0);
};
+ inline Environment* env() const {
+ return env_;
+ }
+
private:
Persistent<Object> object_;
+ Environment* const env_;
};
class QueryAWrap: public QueryWrap {
public:
- explicit QueryAWrap(Local<Object> req_wrap_obj) : QueryWrap(req_wrap_obj) {
+ QueryAWrap(Environment* env, Local<Object> req_wrap_obj)
+ : QueryWrap(env, req_wrap_obj) {
}
int Send(const char* name) {
- ares_query(ares_channel, name, ns_c_in, ns_t_a, Callback, GetQueryArg());
+ ares_query(env()->cares_channel(),
+ name,
+ ns_c_in,
+ ns_t_a,
+ Callback,
+ GetQueryArg());
return 0;
}
@@ -355,11 +380,12 @@ class QueryAWrap: public QueryWrap {
class QueryAaaaWrap: public QueryWrap {
public:
- explicit QueryAaaaWrap(Local<Object> req_wrap_obj) : QueryWrap(req_wrap_obj) {
+ QueryAaaaWrap(Environment* env, Local<Object> req_wrap_obj)
+ : QueryWrap(env, req_wrap_obj) {
}
int Send(const char* name) {
- ares_query(ares_channel,
+ ares_query(env()->cares_channel(),
name,
ns_c_in,
ns_t_aaaa,
@@ -390,12 +416,12 @@ class QueryAaaaWrap: public QueryWrap {
class QueryCnameWrap: public QueryWrap {
public:
- explicit QueryCnameWrap(Local<Object> req_wrap_obj)
- : QueryWrap(req_wrap_obj) {
+ QueryCnameWrap(Environment* env, Local<Object> req_wrap_obj)
+ : QueryWrap(env, req_wrap_obj) {
}
int Send(const char* name) {
- ares_query(ares_channel,
+ ares_query(env()->cares_channel(),
name,
ns_c_in,
ns_t_cname,
@@ -429,11 +455,17 @@ class QueryCnameWrap: public QueryWrap {
class QueryMxWrap: public QueryWrap {
public:
- explicit QueryMxWrap(Local<Object> req_wrap_obj) : QueryWrap(req_wrap_obj) {
+ QueryMxWrap(Environment* env, Local<Object> req_wrap_obj)
+ : QueryWrap(env, req_wrap_obj) {
}
int Send(const char* name) {
- ares_query(ares_channel, name, ns_c_in, ns_t_mx, Callback, GetQueryArg());
+ ares_query(env()->cares_channel(),
+ name,
+ ns_c_in,
+ ns_t_mx,
+ Callback,
+ GetQueryArg());
return 0;
}
@@ -473,11 +505,17 @@ class QueryMxWrap: public QueryWrap {
class QueryNsWrap: public QueryWrap {
public:
- explicit QueryNsWrap(Local<Object> req_wrap_obj) : QueryWrap(req_wrap_obj) {
+ QueryNsWrap(Environment* env, Local<Object> req_wrap_obj)
+ : QueryWrap(env, req_wrap_obj) {
}
int Send(const char* name) {
- ares_query(ares_channel, name, ns_c_in, ns_t_ns, Callback, GetQueryArg());
+ ares_query(env()->cares_channel(),
+ name,
+ ns_c_in,
+ ns_t_ns,
+ Callback,
+ GetQueryArg());
return 0;
}
@@ -501,11 +539,17 @@ class QueryNsWrap: public QueryWrap {
class QueryTxtWrap: public QueryWrap {
public:
- explicit QueryTxtWrap(Local<Object> req_wrap_obj) : QueryWrap(req_wrap_obj) {
+ QueryTxtWrap(Environment* env, Local<Object> req_wrap_obj)
+ : QueryWrap(env, req_wrap_obj) {
}
int Send(const char* name) {
- ares_query(ares_channel, name, ns_c_in, ns_t_txt, Callback, GetQueryArg());
+ ares_query(env()->cares_channel(),
+ name,
+ ns_c_in,
+ ns_t_txt,
+ Callback,
+ GetQueryArg());
return 0;
}
@@ -536,11 +580,12 @@ class QueryTxtWrap: public QueryWrap {
class QuerySrvWrap: public QueryWrap {
public:
- explicit QuerySrvWrap(Local<Object> req_wrap_obj) : QueryWrap(req_wrap_obj) {
+ explicit QuerySrvWrap(Environment* env, Local<Object> req_wrap_obj)
+ : QueryWrap(env, req_wrap_obj) {
}
int Send(const char* name) {
- ares_query(ares_channel,
+ ares_query(env()->cares_channel(),
name,
ns_c_in,
ns_t_srv,
@@ -592,12 +637,12 @@ class QuerySrvWrap: public QueryWrap {
class QueryNaptrWrap: public QueryWrap {
public:
- explicit QueryNaptrWrap(Local<Object> req_wrap_obj)
- : QueryWrap(req_wrap_obj) {
+ explicit QueryNaptrWrap(Environment* env, Local<Object> req_wrap_obj)
+ : QueryWrap(env, req_wrap_obj) {
}
int Send(const char* name) {
- ares_query(ares_channel,
+ ares_query(env()->cares_channel(),
name,
ns_c_in,
ns_t_naptr,
@@ -659,8 +704,8 @@ class QueryNaptrWrap: public QueryWrap {
class GetHostByAddrWrap: public QueryWrap {
public:
- explicit GetHostByAddrWrap(Local<Object> req_wrap_obj)
- : QueryWrap(req_wrap_obj) {
+ explicit GetHostByAddrWrap(Environment* env, Local<Object> req_wrap_obj)
+ : QueryWrap(env, req_wrap_obj) {
}
int Send(const char* name) {
@@ -677,7 +722,7 @@ class GetHostByAddrWrap: public QueryWrap {
return UV_EINVAL; // So errnoException() reports a proper error.
}
- ares_gethostbyaddr(ares_channel,
+ ares_gethostbyaddr(env()->cares_channel(),
address_buffer,
length,
family,
@@ -697,12 +742,16 @@ class GetHostByAddrWrap: public QueryWrap {
class GetHostByNameWrap: public QueryWrap {
public:
- explicit GetHostByNameWrap(Local<Object> req_wrap_obj)
- : QueryWrap(req_wrap_obj) {
+ explicit GetHostByNameWrap(Environment* env, Local<Object> req_wrap_obj)
+ : QueryWrap(env, req_wrap_obj) {
}
int Send(const char* name, int family) {
- ares_gethostbyname(ares_channel, name, family, Callback, GetQueryArg());
+ ares_gethostbyname(env()->cares_channel(),
+ name,
+ family,
+ Callback,
+ GetQueryArg());
return 0;
}
@@ -720,7 +769,8 @@ class GetHostByNameWrap: public QueryWrap {
template <class Wrap>
static void Query(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
assert(!args.IsConstructCall());
assert(args[0]->IsObject());
@@ -728,7 +778,7 @@ static void Query(const FunctionCallbackInfo<Value>& args) {
Local<Object> req_wrap_obj = args[0].As<Object>();
Local<String> string = args[1].As<String>();
- Wrap* wrap = new Wrap(req_wrap_obj);
+ Wrap* wrap = new Wrap(env, req_wrap_obj);
String::Utf8Value name(string);
int err = wrap->Send(*name);
@@ -739,9 +789,11 @@ static void Query(const FunctionCallbackInfo<Value>& args) {
void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, struct addrinfo* res) {
- HandleScope scope(node_isolate);
-
GetAddrInfoReqWrap* req_wrap = static_cast<GetAddrInfoReqWrap*>(req->data);
+ Environment* env = req_wrap->env();
+
+ Context::Scope context_scope(env->context());
+ HandleScope handle_scope(env->isolate());
Local<Value> argv[] = {
Integer::New(status, node_isolate),
@@ -828,7 +880,11 @@ void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, struct addrinfo* res) {
uv_freeaddrinfo(res);
// Make the callback into JavaScript
- MakeCallback(req_wrap->object(), oncomplete_sym, ARRAY_SIZE(argv), argv);
+ MakeCallback(env,
+ req_wrap->object(),
+ env->oncomplete_string(),
+ ARRAY_SIZE(argv),
+ argv);
delete req_wrap;
}
@@ -851,7 +907,8 @@ static void IsIP(const FunctionCallbackInfo<Value>& args) {
static void GetAddrInfo(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
assert(args[0]->IsObject());
assert(args[1]->IsString());
@@ -875,14 +932,14 @@ static void GetAddrInfo(const FunctionCallbackInfo<Value>& args) {
abort();
}
- GetAddrInfoReqWrap* req_wrap = new GetAddrInfoReqWrap(req_wrap_obj);
+ GetAddrInfoReqWrap* req_wrap = new GetAddrInfoReqWrap(env, req_wrap_obj);
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
- int err = uv_getaddrinfo(uv_default_loop(),
+ int err = uv_getaddrinfo(env->event_loop(),
&req_wrap->req_,
AfterGetAddrInfo,
*hostname,
@@ -896,13 +953,14 @@ static void GetAddrInfo(const FunctionCallbackInfo<Value>& args) {
static void GetServers(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
Local<Array> server_array = Array::New();
ares_addr_node* servers;
- int r = ares_get_servers(ares_channel, &servers);
+ int r = ares_get_servers(env->cares_channel(), &servers);
assert(r == ARES_SUCCESS);
ares_addr_node* cur = servers;
@@ -925,7 +983,8 @@ static void GetServers(const FunctionCallbackInfo<Value>& args) {
static void SetServers(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
assert(args[0]->IsArray());
@@ -934,7 +993,7 @@ static void SetServers(const FunctionCallbackInfo<Value>& args) {
uint32_t len = arr->Length();
if (len == 0) {
- int rv = ares_set_servers(ares_channel, NULL);
+ int rv = ares_set_servers(env->cares_channel(), NULL);
return args.GetReturnValue().Set(rv);
}
@@ -982,7 +1041,7 @@ static void SetServers(const FunctionCallbackInfo<Value>& args) {
}
if (err == 0)
- err = ares_set_servers(ares_channel, &servers[0]);
+ err = ares_set_servers(env->cares_channel(), &servers[0]);
else
err = ARES_EBADSTR;
@@ -999,28 +1058,29 @@ static void StrError(const FunctionCallbackInfo<Value>& args) {
}
-static void Initialize(Handle<Object> target) {
- HandleScope scope(node_isolate);
- int r;
+static void Initialize(Handle<Object> target,
+ Handle<Value> unused,
+ Handle<Context> context) {
+ Environment* env = Environment::GetCurrent(context);
- r = ares_library_init(ARES_LIB_INIT_ALL);
+ int r = ares_library_init(ARES_LIB_INIT_ALL);
assert(r == ARES_SUCCESS);
struct ares_options options;
memset(&options, 0, sizeof(options));
options.flags = ARES_FLAG_NOCHECKRESP;
options.sock_state_cb = ares_sockstate_cb;
- options.sock_state_cb_data = uv_default_loop();
+ options.sock_state_cb_data = env;
/* We do the call to ares_init_option for caller. */
- r = ares_init_options(&ares_channel,
+ r = ares_init_options(env->cares_channel_ptr(),
&options,
ARES_OPT_FLAGS | ARES_OPT_SOCK_STATE_CB);
assert(r == ARES_SUCCESS);
/* Initialize the timeout timer. The timer won't be started until the */
/* first socket is opened. */
- uv_timer_init(uv_default_loop(), &ares_timer);
+ uv_timer_init(env->event_loop(), env->cares_timer_handle());
NODE_SET_METHOD(target, "queryA", Query<QueryAWrap>);
NODE_SET_METHOD(target, "queryAaaa", Query<QueryAaaaWrap>);
@@ -1045,11 +1105,9 @@ static void Initialize(Handle<Object> target) {
Integer::New(AF_INET6, node_isolate));
target->Set(FIXED_ONE_BYTE_STRING(node_isolate, "AF_UNSPEC"),
Integer::New(AF_UNSPEC, node_isolate));
-
- oncomplete_sym = FIXED_ONE_BYTE_STRING(node_isolate, "oncomplete");
}
} // namespace cares_wrap
} // namespace node
-NODE_MODULE(node_cares_wrap, node::cares_wrap::Initialize)
+NODE_MODULE_CONTEXT_AWARE(node_cares_wrap, node::cares_wrap::Initialize)
diff --git a/src/env-inl.h b/src/env-inl.h
new file mode 100644
index 0000000000..a8fcc58603
--- /dev/null
+++ b/src/env-inl.h
@@ -0,0 +1,289 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+#ifndef SRC_ENV_INL_H_
+#define SRC_ENV_INL_H_
+
+#include "env.h"
+#include "util.h"
+#include "util-inl.h"
+#include "uv.h"
+#include "v8.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace node {
+
+inline Environment::IsolateData* Environment::IsolateData::GetOrCreate(
+ v8::Isolate* isolate) {
+ IsolateData* isolate_data = static_cast<IsolateData*>(isolate->GetData());
+ if (isolate_data == NULL) {
+ isolate_data = new IsolateData(isolate);
+ isolate->SetData(isolate_data);
+ }
+ isolate_data->ref_count_ += 1;
+ return isolate_data;
+}
+
+inline void Environment::IsolateData::Put() {
+ if (--ref_count_ == 0) {
+ isolate()->SetData(NULL);
+ delete this;
+ }
+}
+
+inline Environment::IsolateData::IsolateData(v8::Isolate* isolate)
+ : event_loop_(uv_default_loop())
+ , isolate_(isolate)
+#define V(PropertyName, StringValue) \
+ , PropertyName ## _index_( \
+ FIXED_ONE_BYTE_STRING(isolate, StringValue).Eternalize(isolate))
+ PER_ISOLATE_STRING_PROPERTIES(V)
+#undef V
+ , ref_count_(0) {
+}
+
+inline uv_loop_t* Environment::IsolateData::event_loop() const {
+ return event_loop_;
+}
+
+inline v8::Isolate* Environment::IsolateData::isolate() const {
+ return isolate_;
+}
+
+inline Environment::DomainFlag::DomainFlag() {
+ for (int i = 0; i < kFieldsCount; ++i) fields_[i] = 0;
+}
+
+inline uint32_t* Environment::DomainFlag::fields() {
+ return fields_;
+}
+
+inline int Environment::DomainFlag::fields_count() const {
+ return kFieldsCount;
+}
+
+inline uint32_t Environment::DomainFlag::count() const {
+ return fields_[kCount];
+}
+
+inline Environment::TickInfo::TickInfo() {
+ for (int i = 0; i < kFieldsCount; ++i) fields_[i] = 0;
+}
+
+inline uint32_t* Environment::TickInfo::fields() {
+ return fields_;
+}
+
+inline int Environment::TickInfo::fields_count() const {
+ return kFieldsCount;
+}
+
+inline uint32_t Environment::TickInfo::in_tick() const {
+ return fields_[kInTick];
+}
+
+inline uint32_t Environment::TickInfo::index() const {
+ return fields_[kIndex];
+}
+
+inline uint32_t Environment::TickInfo::last_threw() const {
+ return fields_[kLastThrew];
+}
+
+inline uint32_t Environment::TickInfo::length() const {
+ return fields_[kLength];
+}
+
+inline void Environment::TickInfo::set_index(uint32_t value) {
+ fields_[kIndex] = value;
+}
+
+inline void Environment::TickInfo::set_last_threw(uint32_t value) {
+ fields_[kLastThrew] = value;
+}
+
+inline Environment* Environment::New(v8::Local<v8::Context> context) {
+ Environment* env = new Environment(context);
+ context->SetAlignedPointerInEmbedderData(kContextEmbedderDataIndex, env);
+ return env;
+}
+
+inline Environment* Environment::GetCurrent(v8::Isolate* isolate) {
+ return GetCurrent(isolate->GetCurrentContext());
+}
+
+inline Environment* Environment::GetCurrent(v8::Local<v8::Context> context) {
+ return static_cast<Environment*>(
+ context->GetAlignedPointerFromEmbedderData(kContextEmbedderDataIndex));
+}
+
+inline Environment* Environment::GetCurrentChecked(v8::Isolate* isolate) {
+ if (isolate == NULL) {
+ return NULL;
+ } else {
+ return GetCurrentChecked(isolate->GetCurrentContext());
+ }
+}
+
+inline Environment* Environment::GetCurrentChecked(
+ v8::Local<v8::Context> context) {
+ if (context.IsEmpty()) {
+ return NULL;
+ } else {
+ return GetCurrent(context);
+ }
+}
+
+inline Environment::Environment(v8::Local<v8::Context> context)
+ : isolate_(context->GetIsolate())
+ , isolate_data_(IsolateData::GetOrCreate(context->GetIsolate()))
+ , using_smalloc_alloc_cb_(false)
+ , using_domains_(false)
+ , context_(context->GetIsolate(), context) {
+ // We'll be creating new objects so make sure we've entered the context.
+ v8::Context::Scope context_scope(context);
+ v8::HandleScope handle_scope(isolate());
+ set_binding_cache_object(v8::Object::New());
+ set_module_load_list_array(v8::Array::New());
+}
+
+inline Environment::~Environment() {
+ context()->SetAlignedPointerInEmbedderData(kContextEmbedderDataIndex, NULL);
+#define V(PropertyName, TypeName) PropertyName ## _.Dispose();
+ ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V)
+#undef V
+ isolate_data()->Put();
+}
+
+inline void Environment::Dispose() {
+ delete this;
+}
+
+inline v8::Isolate* Environment::isolate() const {
+ return isolate_;
+}
+
+inline bool Environment::in_domain() const {
+ // The const_cast is okay, it doesn't violate conceptual const-ness.
+ return using_domains() &&
+ const_cast<Environment*>(this)->domain_flag()->count() > 0;
+}
+
+inline Environment* Environment::from_immediate_check_handle(
+ uv_check_t* handle) {
+ return CONTAINER_OF(handle, Environment, immediate_check_handle_);
+}
+
+inline uv_check_t* Environment::immediate_check_handle() {
+ return &immediate_check_handle_;
+}
+
+inline uv_idle_t* Environment::immediate_idle_handle() {
+ return &immediate_idle_handle_;
+}
+
+inline uv_loop_t* Environment::event_loop() const {
+ return isolate_data()->event_loop();
+}
+
+inline Environment::DomainFlag* Environment::domain_flag() {
+ return &domain_flag_;
+}
+
+inline Environment::TickInfo* Environment::tick_info() {
+ return &tick_info_;
+}
+
+inline bool Environment::using_smalloc_alloc_cb() const {
+ return using_smalloc_alloc_cb_;
+}
+
+inline void Environment::set_using_smalloc_alloc_cb(bool value) {
+ using_smalloc_alloc_cb_ = value;
+}
+
+inline bool Environment::using_domains() const {
+ return using_domains_;
+}
+
+inline void Environment::set_using_domains(bool value) {
+ using_domains_ = value;
+}
+
+inline Environment* Environment::from_cares_timer_handle(uv_timer_t* handle) {
+ return CONTAINER_OF(handle, Environment, cares_timer_handle_);
+}
+
+inline uv_timer_t* Environment::cares_timer_handle() {
+ return &cares_timer_handle_;
+}
+
+inline ares_channel Environment::cares_channel() {
+ return cares_channel_;
+}
+
+// Only used in the call to ares_init_options().
+inline ares_channel* Environment::cares_channel_ptr() {
+ return &cares_channel_;
+}
+
+inline ares_task_list* Environment::cares_task_list() {
+ return &cares_task_list_;
+}
+
+inline Environment::IsolateData* Environment::isolate_data() const {
+ return isolate_data_;
+}
+
+#define V(PropertyName, StringValue) \
+ inline \
+ v8::Local<v8::String> Environment::IsolateData::PropertyName() const { \
+ return v8::Local<v8::String>::GetEternal(isolate(), \
+ PropertyName ## _index_); \
+ }
+ PER_ISOLATE_STRING_PROPERTIES(V)
+#undef V
+
+#define V(PropertyName, StringValue) \
+ inline v8::Local<v8::String> Environment::PropertyName() const { \
+ return isolate_data()->PropertyName(); \
+ }
+ PER_ISOLATE_STRING_PROPERTIES(V)
+#undef V
+
+#define V(PropertyName, TypeName) \
+ inline v8::Local<TypeName> Environment::PropertyName() const { \
+ return StrongPersistentToLocal(PropertyName ## _); \
+ } \
+ inline void Environment::set_ ## PropertyName(v8::Local<TypeName> value) { \
+ PropertyName ## _.Reset(isolate(), value); \
+ }
+ ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V)
+#undef V
+
+#undef ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES
+#undef PER_ISOLATE_STRING_PROPERTIES
+
+} // namespace node
+
+#endif // SRC_ENV_INL_H_
diff --git a/src/env.h b/src/env.h
new file mode 100644
index 0000000000..db8d660c30
--- /dev/null
+++ b/src/env.h
@@ -0,0 +1,324 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+#ifndef SRC_ENV_H_
+#define SRC_ENV_H_
+
+#include "ares.h"
+#include "tree.h"
+#include "util.h"
+#include "uv.h"
+#include "v8.h"
+
+#include <stdint.h>
+
+// Caveat emptor: we're going slightly crazy with macros here but the end
+// hopefully justifies the means. We have a lot of per-context properties
+// and adding and maintaining their getters and setters by hand would be
+// a nightmare so let's make the preprocessor generate them for us.
+//
+// Make sure that any macros defined here are undefined again at the bottom
+// of context-inl.h. The sole exception is NODE_CONTEXT_EMBEDDER_DATA_INDEX,
+// it may have been defined externally.
+namespace node {
+
+// Pick an index that's hopefully out of the way when we're embedded inside
+// another application. Performance-wise or memory-wise it doesn't matter:
+// Context::SetAlignedPointerInEmbedderData() is backed by a FixedArray,
+// worst case we pay a one-time penalty for resizing the array.
+#ifndef NODE_CONTEXT_EMBEDDER_DATA_INDEX
+#define NODE_CONTEXT_EMBEDDER_DATA_INDEX 32
+#endif
+
+// Strings are per-isolate primitives but Environment proxies them
+// for the sake of convenience.
+#define PER_ISOLATE_STRING_PROPERTIES(V) \
+ V(DELETE_string, "DELETE") \
+ V(GET_string, "GET") \
+ V(HEAD_string, "HEAD") \
+ V(POST_string, "POST") \
+ V(PUT_string, "PUT") \
+ V(address_string, "address") \
+ V(atime_string, "atime") \
+ V(birthtime_string, "birthtime") \
+ V(blksize_string, "blksize") \
+ V(blocks_string, "blocks") \
+ V(buffer_string, "buffer") \
+ V(bytes_string, "bytes") \
+ V(callback_string, "callback") \
+ V(change_string, "change") \
+ V(close_string, "close") \
+ V(code_string, "code") \
+ V(ctime_string, "ctime") \
+ V(dev_string, "dev") \
+ V(disposed_string, "_disposed") \
+ V(domain_string, "domain") \
+ V(enter_string, "enter") \
+ V(errno_string, "errno") \
+ V(exit_string, "exit") \
+ V(exponent_string, "exponent") \
+ V(exports_string, "exports") \
+ V(ext_key_usage_string, "ext_key_usage") \
+ V(family_string, "family") \
+ V(fatal_exception_string, "_fatalException") \
+ V(fingerprint_string, "fingerprint") \
+ V(gid_string, "gid") \
+ V(handle_string, "handle") \
+ V(headers_string, "headers") \
+ V(heap_total_string, "heapTotal") \
+ V(heap_used_string, "heapUsed") \
+ V(immediate_callback_string, "_immediateCallback") \
+ V(ino_string, "ino") \
+ V(ipv4_string, "IPv4") \
+ V(ipv6_string, "IPv6") \
+ V(issuer_string, "issuer") \
+ V(method_string, "method") \
+ V(mode_string, "mode") \
+ V(modulus_string, "modulus") \
+ V(mtime_string, "mtime") \
+ V(name_string, "name") \
+ V(nlink_string, "nlink") \
+ V(onchange_string, "onchange") \
+ V(onclienthello_string, "onclienthello") \
+ V(oncomplete_string, "oncomplete") \
+ V(onconnection_string, "onconnection") \
+ V(onerror_string, "onerror") \
+ V(onexit_string, "onexit") \
+ V(onhandshakedone_string, "onhandshakedone") \
+ V(onhandshakestart_string, "onhandshakestart") \
+ V(onmessage_string, "onmessage") \
+ V(onnewsession_string, "onnewsession") \
+ V(onread_string, "onread") \
+ V(onsignal_string, "onsignal") \
+ V(onstop_string, "onstop") \
+ V(path_string, "path") \
+ V(port_string, "port") \
+ V(rdev_string, "rdev") \
+ V(rename_string, "rename") \
+ V(rss_string, "rss") \
+ V(servername_string, "servername") \
+ V(session_id_string, "sessionId") \
+ V(should_keep_alive_string, "shouldKeepAlive") \
+ V(size_string, "size") \
+ V(smalloc_p_string, "_smalloc_p") \
+ V(sni_context_string, "sni_context") \
+ V(status_code_string, "statusCode") \
+ V(subject_string, "subject") \
+ V(subjectaltname_string, "subjectaltname") \
+ V(syscall_string, "syscall") \
+ V(tls_ticket_string, "tlsTicket") \
+ V(uid_string, "uid") \
+ V(upgrade_string, "upgrade") \
+ V(url_string, "url") \
+ V(valid_from_string, "valid_from") \
+ V(valid_to_string, "valid_to") \
+ V(version_major_string, "versionMajor") \
+ V(version_minor_string, "versionMinor") \
+ V(version_string, "version") \
+ V(write_queue_size_string, "writeQueueSize") \
+
+#define ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V) \
+ V(binding_cache_object, v8::Object) \
+ V(buffer_constructor_function, v8::Function) \
+ V(context, v8::Context) \
+ V(domain_array, v8::Array) \
+ V(module_load_list_array, v8::Array) \
+ V(pipe_constructor_template, v8::FunctionTemplate) \
+ V(process_object, v8::Object) \
+ V(script_context_constructor_template, v8::FunctionTemplate) \
+ V(script_data_constructor_function, v8::Function) \
+ V(secure_context_constructor_template, v8::FunctionTemplate) \
+ V(stats_constructor_function, v8::Function) \
+ V(tcp_constructor_template, v8::FunctionTemplate) \
+ V(tick_callback_function, v8::Function) \
+ V(tls_wrap_constructor_function, v8::Function) \
+ V(tty_constructor_template, v8::FunctionTemplate) \
+ V(udp_constructor_function, v8::Function) \
+
+class Environment;
+
+// TODO(bnoordhuis) Rename struct, the ares_ prefix implies it's part
+// of the c-ares API while the _t suffix implies it's a typedef.
+struct ares_task_t {
+ Environment* env;
+ ares_socket_t sock;
+ uv_poll_t poll_watcher;
+ RB_ENTRY(ares_task_t) node;
+};
+
+RB_HEAD(ares_task_list, ares_task_t);
+
+class Environment {
+ public:
+ class DomainFlag {
+ public:
+ inline uint32_t* fields();
+ inline int fields_count() const;
+ inline uint32_t count() const;
+
+ private:
+ friend class Environment; // So we can call the constructor.
+ inline DomainFlag();
+
+ enum Fields {
+ kCount,
+ kFieldsCount
+ };
+
+ uint32_t fields_[kFieldsCount];
+
+ DISALLOW_COPY_AND_ASSIGN(DomainFlag);
+ };
+
+ class TickInfo {
+ public:
+ inline uint32_t* fields();
+ inline int fields_count() const;
+ inline uint32_t in_tick() const;
+ inline uint32_t index() const;
+ inline uint32_t last_threw() const;
+ inline uint32_t length() const;
+ inline void set_index(uint32_t value);
+ inline void set_last_threw(uint32_t value);
+
+ private:
+ friend class Environment; // So we can call the constructor.
+ inline TickInfo();
+
+ enum Fields {
+ kInTick,
+ kIndex,
+ kLastThrew,
+ kLength,
+ kFieldsCount
+ };
+
+ uint32_t fields_[kFieldsCount];
+
+ DISALLOW_COPY_AND_ASSIGN(TickInfo);
+ };
+
+ static inline Environment* GetCurrent(v8::Isolate* isolate);
+ static inline Environment* GetCurrent(v8::Local<v8::Context> context);
+ static inline Environment* GetCurrentChecked(v8::Isolate* isolate);
+ static inline Environment* GetCurrentChecked(v8::Local<v8::Context> context);
+
+ // See CreateEnvironment() in src/node.cc.
+ static inline Environment* New(v8::Local<v8::Context> context);
+ inline void Dispose();
+
+ inline v8::Isolate* isolate() const;
+ inline uv_loop_t* event_loop() const;
+ inline bool in_domain() const;
+
+ static inline Environment* from_immediate_check_handle(uv_check_t* handle);
+ inline uv_check_t* immediate_check_handle();
+ inline uv_idle_t* immediate_idle_handle();
+ inline DomainFlag* domain_flag();
+ inline TickInfo* tick_info();
+
+ static inline Environment* from_cares_timer_handle(uv_timer_t* handle);
+ inline uv_timer_t* cares_timer_handle();
+ inline ares_channel cares_channel();
+ inline ares_channel* cares_channel_ptr();
+ inline ares_task_list* cares_task_list();
+
+ inline bool using_smalloc_alloc_cb() const;
+ inline void set_using_smalloc_alloc_cb(bool value);
+
+ inline bool using_domains() const;
+ inline void set_using_domains(bool value);
+
+ // Strings are shared across shared contexts. The getters simply proxy to
+ // the per-isolate primitive.
+#define V(PropertyName, StringValue) \
+ inline v8::Local<v8::String> PropertyName() const;
+ PER_ISOLATE_STRING_PROPERTIES(V)
+#undef V
+
+#define V(PropertyName, TypeName) \
+ inline v8::Local<TypeName> PropertyName() const; \
+ inline void set_ ## PropertyName(v8::Local<TypeName> value);
+ ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V)
+#undef V
+
+ private:
+ class IsolateData;
+ inline explicit Environment(v8::Local<v8::Context> context);
+ inline ~Environment();
+ inline IsolateData* isolate_data() const;
+
+ enum ContextEmbedderDataIndex {
+ kContextEmbedderDataIndex = NODE_CONTEXT_EMBEDDER_DATA_INDEX
+ };
+
+ v8::Isolate* const isolate_;
+ IsolateData* const isolate_data_;
+ uv_check_t immediate_check_handle_;
+ uv_idle_t immediate_idle_handle_;
+ DomainFlag domain_flag_;
+ TickInfo tick_info_;
+ uv_timer_t cares_timer_handle_;
+ ares_channel cares_channel_;
+ ares_task_list cares_task_list_;
+ bool using_smalloc_alloc_cb_;
+ bool using_domains_;
+
+#define V(PropertyName, TypeName) \
+ v8::Persistent<TypeName> PropertyName ## _;
+ ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V)
+#undef V
+
+ // Per-thread, reference-counted singleton.
+ class IsolateData {
+ public:
+ static inline IsolateData* GetOrCreate(v8::Isolate* isolate);
+ inline void Put();
+ inline uv_loop_t* event_loop() const;
+
+#define V(PropertyName, StringValue) \
+ inline v8::Local<v8::String> PropertyName() const;
+ PER_ISOLATE_STRING_PROPERTIES(V)
+#undef V
+
+ private:
+ inline explicit IsolateData(v8::Isolate* isolate);
+ inline v8::Isolate* isolate() const;
+
+ uv_loop_t* const event_loop_;
+ v8::Isolate* const isolate_;
+
+#define V(PropertyName, StringValue) \
+ const int PropertyName ## _index_;
+ PER_ISOLATE_STRING_PROPERTIES(V)
+#undef V
+
+ unsigned int ref_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(IsolateData);
+ };
+
+ DISALLOW_COPY_AND_ASSIGN(Environment);
+};
+
+} // namespace node
+
+#endif // SRC_ENV_H_
diff --git a/src/fs_event_wrap.cc b/src/fs_event_wrap.cc
index 8906f43ee3..719ee8c7eb 100644
--- a/src/fs_event_wrap.cc
+++ b/src/fs_event_wrap.cc
@@ -19,6 +19,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
+#include "env.h"
+#include "env-inl.h"
#include "node.h"
#include "handle_wrap.h"
@@ -26,6 +28,7 @@
namespace node {
+using v8::Context;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Handle;
@@ -36,19 +39,17 @@ using v8::Object;
using v8::String;
using v8::Value;
-static Cached<String> change_sym;
-static Cached<String> onchange_sym;
-static Cached<String> rename_sym;
-
class FSEventWrap: public HandleWrap {
public:
- static void Initialize(Handle<Object> target);
+ static void Initialize(Handle<Object> target,
+ Handle<Value> unused,
+ Handle<Context> context);
static void New(const FunctionCallbackInfo<Value>& args);
static void Start(const FunctionCallbackInfo<Value>& args);
static void Close(const FunctionCallbackInfo<Value>& args);
private:
- explicit FSEventWrap(Handle<Object> object);
+ FSEventWrap(Environment* env, Handle<Object> object);
virtual ~FSEventWrap();
static void OnEvent(uv_fs_event_t* handle, const char* filename, int events,
@@ -59,8 +60,8 @@ class FSEventWrap: public HandleWrap {
};
-FSEventWrap::FSEventWrap(Handle<Object> object)
- : HandleWrap(object, reinterpret_cast<uv_handle_t*>(&handle_)) {
+FSEventWrap::FSEventWrap(Environment* env, Handle<Object> object)
+ : HandleWrap(env, object, reinterpret_cast<uv_handle_t*>(&handle_)) {
initialized_ = false;
}
@@ -70,8 +71,11 @@ FSEventWrap::~FSEventWrap() {
}
-void FSEventWrap::Initialize(Handle<Object> target) {
- HandleScope scope(node_isolate);
+void FSEventWrap::Initialize(Handle<Object> target,
+ Handle<Value> unused,
+ Handle<Context> context) {
+ Environment* env = Environment::GetCurrent(context);
+ HandleScope handle_scope(env->isolate());
Local<FunctionTemplate> t = FunctionTemplate::New(New);
t->InstanceTemplate()->SetInternalFieldCount(1);
@@ -81,17 +85,13 @@ void FSEventWrap::Initialize(Handle<Object> target) {
NODE_SET_PROTOTYPE_METHOD(t, "close", Close);
target->Set(FIXED_ONE_BYTE_STRING(node_isolate, "FSEvent"), t->GetFunction());
-
- change_sym = FIXED_ONE_BYTE_STRING(node_isolate, "change");
- onchange_sym = FIXED_ONE_BYTE_STRING(node_isolate, "onchange");
- rename_sym = FIXED_ONE_BYTE_STRING(node_isolate, "rename");
}
void FSEventWrap::New(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
assert(args.IsConstructCall());
- new FSEventWrap(args.This());
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ new FSEventWrap(env, args.This());
}
@@ -107,7 +107,7 @@ void FSEventWrap::Start(const FunctionCallbackInfo<Value>& args) {
String::Utf8Value path(args[0]);
- int err = uv_fs_event_init(uv_default_loop(),
+ int err = uv_fs_event_init(wrap->env()->event_loop(),
&wrap->handle_,
*path,
OnEvent,
@@ -126,10 +126,11 @@ void FSEventWrap::Start(const FunctionCallbackInfo<Value>& args) {
void FSEventWrap::OnEvent(uv_fs_event_t* handle, const char* filename,
int events, int status) {
- HandleScope scope(node_isolate);
- Handle<String> eventStr;
-
FSEventWrap* wrap = static_cast<FSEventWrap*>(handle->data);
+ Environment* env = wrap->env();
+
+ Context::Scope context_scope(env->context());
+ HandleScope handle_scope(env->isolate());
assert(wrap->persistent().IsEmpty() == false);
@@ -144,20 +145,21 @@ void FSEventWrap::OnEvent(uv_fs_event_t* handle, const char* filename,
// For now, ignore the UV_CHANGE event if UV_RENAME is also set. Make the
// assumption that a rename implicitly means an attribute change. Not too
// unreasonable, right? Still, we should revisit this before v1.0.
+ Local<String> event_string;
if (status) {
- eventStr = String::Empty(node_isolate);
+ event_string = String::Empty(node_isolate);
} else if (events & UV_RENAME) {
- eventStr = rename_sym;
+ event_string = env->rename_string();
} else if (events & UV_CHANGE) {
- eventStr = change_sym;
+ event_string = env->change_string();
} else {
assert(0 && "bad fs events flag");
abort();
}
- Handle<Value> argv[3] = {
+ Local<Value> argv[] = {
Integer::New(status, node_isolate),
- eventStr,
+ event_string,
Null(node_isolate)
};
@@ -165,7 +167,11 @@ void FSEventWrap::OnEvent(uv_fs_event_t* handle, const char* filename,
argv[2] = OneByteString(node_isolate, filename);
}
- MakeCallback(wrap->object(), onchange_sym, ARRAY_SIZE(argv), argv);
+ MakeCallback(env,
+ wrap->object(),
+ env->onchange_string(),
+ ARRAY_SIZE(argv),
+ argv);
}
@@ -183,4 +189,4 @@ void FSEventWrap::Close(const FunctionCallbackInfo<Value>& args) {
} // namespace node
-NODE_MODULE(node_fs_event_wrap, node::FSEventWrap::Initialize)
+NODE_MODULE_CONTEXT_AWARE(node_fs_event_wrap, node::FSEventWrap::Initialize)
diff --git a/src/handle_wrap.cc b/src/handle_wrap.cc
index 858b55cdd4..05d4c4dddc 100644
--- a/src/handle_wrap.cc
+++ b/src/handle_wrap.cc
@@ -20,22 +20,23 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "handle_wrap.h"
+#include "env.h"
+#include "env-inl.h"
#include "node.h"
#include "queue.h"
namespace node {
+using v8::Context;
using v8::FunctionCallbackInfo;
using v8::Handle;
using v8::HandleScope;
using v8::Local;
using v8::Object;
-using v8::String;
using v8::Value;
// defined in node.cc
extern QUEUE handle_wrap_queue;
-static Cached<String> close_sym;
void HandleWrap::Ref(const FunctionCallbackInfo<Value>& args) {
@@ -73,27 +74,26 @@ void HandleWrap::Close(const FunctionCallbackInfo<Value>& args) {
// guard against uninitialized handle or double close
if (wrap == NULL || wrap->handle__ == NULL) return;
+ Environment* env = wrap->env();
assert(!wrap->persistent().IsEmpty());
uv_close(wrap->handle__, OnClose);
wrap->handle__ = NULL;
if (args[0]->IsFunction()) {
- if (close_sym.IsEmpty() == true) {
- close_sym = FIXED_ONE_BYTE_STRING(node_isolate, "close");
- }
- wrap->object()->Set(close_sym, args[0]);
+ wrap->object()->Set(env->close_string(), args[0]);
wrap->flags_ |= kCloseCallback;
}
}
-HandleWrap::HandleWrap(Handle<Object> object, uv_handle_t* h) {
- flags_ = 0;
- handle__ = h;
+HandleWrap::HandleWrap(Environment* env,
+ Handle<Object> object,
+ uv_handle_t* handle)
+ : env_(env)
+ , flags_(0)
+ , handle__(handle) {
handle__->data = this;
-
HandleScope scope(node_isolate);
- assert(persistent().IsEmpty());
persistent().Reset(node_isolate, object);
NODE_WRAP(object, this);
QUEUE_INSERT_TAIL(&handle_wrap_queue, &handle_wrap_queue_);
@@ -108,6 +108,7 @@ HandleWrap::~HandleWrap() {
void HandleWrap::OnClose(uv_handle_t* handle) {
HandleWrap* wrap = static_cast<HandleWrap*>(handle->data);
+ Environment* env = wrap->env();
// The wrap object should still be there.
assert(wrap->persistent().IsEmpty() == false);
@@ -115,12 +116,12 @@ void HandleWrap::OnClose(uv_handle_t* handle) {
// But the handle pointer should be gone.
assert(wrap->handle__ == NULL);
- HandleScope scope(node_isolate);
+ Context::Scope context_scope(env->context());
+ HandleScope handle_scope(env->isolate());
Local<Object> object = wrap->object();
if (wrap->flags_ & kCloseCallback) {
- assert(close_sym.IsEmpty() == false);
- MakeCallback(object, close_sym, 0, NULL);
+ MakeCallback(env, object, env->close_string());
}
object->SetAlignedPointerInInternalField(0, NULL);
diff --git a/src/handle_wrap.h b/src/handle_wrap.h
index b5918f5dfe..73a43c3a3f 100644
--- a/src/handle_wrap.h
+++ b/src/handle_wrap.h
@@ -22,6 +22,7 @@
#ifndef SRC_HANDLE_WRAP_H_
#define SRC_HANDLE_WRAP_H_
+#include "env.h"
#include "node.h"
#include "queue.h"
#include "uv.h"
@@ -58,11 +59,17 @@ class HandleWrap {
inline uv_handle_t* GetHandle() { return handle__; }
protected:
- explicit HandleWrap(v8::Handle<v8::Object> object, uv_handle_t* handle);
+ HandleWrap(Environment* env,
+ v8::Handle<v8::Object> object,
+ uv_handle_t* handle);
virtual ~HandleWrap();
+ inline Environment* env() const {
+ return env_;
+ }
+
inline v8::Local<v8::Object> object() {
- return PersistentToLocal(node_isolate, persistent());
+ return PersistentToLocal(env()->isolate(), persistent());
}
inline v8::Persistent<v8::Object>& persistent() {
@@ -74,10 +81,11 @@ class HandleWrap {
static void OnClose(uv_handle_t* handle);
v8::Persistent<v8::Object> object_;
QUEUE handle_wrap_queue_;
+ Environment* const env_;
+ unsigned int flags_;
// Using double underscore due to handle_ member in tcp_wrap. Probably
// tcp_wrap should rename it's member to 'handle'.
uv_handle_t* handle__;
- unsigned int flags_;
static const unsigned int kUnref = 1;
static const unsigned int kCloseCallback = 2;
diff --git a/src/node.cc b/src/node.cc
index c88b0effba..4670151a8a 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -44,6 +44,8 @@
#endif
#include "ares.h"
+#include "env.h"
+#include "env-inl.h"
#include "handle_wrap.h"
#include "req_wrap.h"
#include "string_bytes.h"
@@ -106,10 +108,7 @@ using v8::Message;
using v8::Number;
using v8::Object;
using v8::ObjectTemplate;
-using v8::Persistent;
using v8::PropertyCallbackInfo;
-using v8::ResourceConstraints;
-using v8::SetResourceConstraints;
using v8::String;
using v8::ThrowException;
using v8::TryCatch;
@@ -118,43 +117,10 @@ using v8::V8;
using v8::Value;
using v8::kExternalUnsignedIntArray;
+// FIXME(bnoordhuis) Make these per-context?
QUEUE handle_wrap_queue = { &handle_wrap_queue, &handle_wrap_queue };
QUEUE req_wrap_queue = { &req_wrap_queue, &req_wrap_queue };
-// declared in req_wrap.h
-Cached<String> process_symbol;
-Cached<String> domain_symbol;
-
-// declared in node_internals.h
-Persistent<Object> process_p;
-
-static Persistent<Function> process_tickCallback;
-static Persistent<Object> binding_cache;
-static Persistent<Array> module_load_list;
-static Persistent<Array> p_domain_box;
-
-static Cached<String> exports_symbol;
-
-static Cached<String> errno_symbol;
-static Cached<String> syscall_symbol;
-static Cached<String> errpath_symbol;
-static Cached<String> code_symbol;
-
-static Cached<String> rss_symbol;
-static Cached<String> heap_total_symbol;
-static Cached<String> heap_used_symbol;
-
-static Cached<String> fatal_exception_symbol;
-
-static Cached<String> enter_symbol;
-static Cached<String> exit_symbol;
-static Cached<String> disposed_symbol;
-
-// Essential for node_wrap.h
-Persistent<FunctionTemplate> pipeConstructorTmpl;
-Persistent<FunctionTemplate> tcpConstructorTmpl;
-Persistent<FunctionTemplate> ttyConstructorTmpl;
-
static bool print_eval = false;
static bool force_repl = false;
static bool trace_deprecation = false;
@@ -163,29 +129,10 @@ static const char* eval_string = NULL;
static bool use_debug_agent = false;
static bool debug_wait_connect = false;
static int debug_port = 5858;
-bool using_domains = false;
// used by C++ modules as well
bool no_deprecation = false;
-static uv_check_t check_immediate_watcher;
-static uv_idle_t idle_immediate_dummy;
-static bool need_immediate_cb;
-static Cached<String> immediate_callback_sym;
-
-// for quick ref to tickCallback values
-static struct {
- uint32_t length;
- uint32_t index;
- uint32_t in_tick;
- uint32_t last_threw;
-} tick_infobox;
-
-// easily communicate domain depth
-static struct {
- uint32_t count;
-} domain_flag;
-
// process-relative uptime base, initialized at start-up
static double prog_start_time;
@@ -227,24 +174,15 @@ void ArrayBufferAllocator::Free(void* data) {
static void CheckImmediate(uv_check_t* handle, int status) {
- assert(handle == &check_immediate_watcher);
- assert(status == 0);
-
- HandleScope scope(node_isolate);
-
- if (immediate_callback_sym.IsEmpty()) {
- immediate_callback_sym =
- FIXED_ONE_BYTE_STRING(node_isolate, "_immediateCallback");
- }
-
- MakeCallback(process_p, immediate_callback_sym, 0, NULL);
+ Environment* env = Environment::from_immediate_check_handle(handle);
+ Context::Scope context_scope(env->context());
+ MakeCallback(env, env->process_object(), env->immediate_callback_string());
}
-static void IdleImmediateDummy(uv_idle_t* handle, int status) {
- // Do nothing. Only for maintaining event loop
- assert(handle == &idle_immediate_dummy);
- assert(status == 0);
+static void IdleImmediateDummy(uv_idle_t*, int) {
+ // Do nothing. Only for maintaining event loop.
+ // TODO(bnoordhuis) Maybe make libuv accept NULL idle callbacks.
}
@@ -729,6 +667,8 @@ Local<Value> ErrnoException(int errorno,
const char *syscall,
const char *msg,
const char *path) {
+ Environment* env = Environment::GetCurrent(node_isolate);
+
Local<Value> e;
Local<String> estring = OneByteString(node_isolate, errno_string(errorno));
if (msg == NULL || msg[0] == '\0') {
@@ -740,13 +680,6 @@ Local<Value> ErrnoException(int errorno,
String::Concat(estring, FIXED_ONE_BYTE_STRING(node_isolate, ", "));
Local<String> cons2 = String::Concat(cons1, message);
- if (syscall_symbol.IsEmpty()) {
- syscall_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "syscall");
- errno_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "errno");
- errpath_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "path");
- code_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "code");
- }
-
if (path) {
Local<String> cons3 =
String::Concat(cons2, FIXED_ONE_BYTE_STRING(node_isolate, " '"));
@@ -760,11 +693,17 @@ Local<Value> ErrnoException(int errorno,
}
Local<Object> obj = e->ToObject();
+ obj->Set(env->errno_string(), Integer::New(errorno, node_isolate));
+ obj->Set(env->code_string(), estring);
+
+ if (path != NULL) {
+ obj->Set(env->path_string(), String::NewFromUtf8(node_isolate, path));
+ }
+
+ if (syscall != NULL) {
+ obj->Set(env->syscall_string(), OneByteString(node_isolate, syscall));
+ }
- obj->Set(errno_symbol, Integer::New(errorno, node_isolate));
- obj->Set(code_symbol, estring);
- if (path) obj->Set(errpath_symbol, String::NewFromUtf8(node_isolate, path));
- if (syscall) obj->Set(syscall_symbol, OneByteString(node_isolate, syscall));
return e;
}
@@ -774,12 +713,7 @@ Local<Value> UVException(int errorno,
const char *syscall,
const char *msg,
const char *path) {
- if (syscall_symbol.IsEmpty()) {
- syscall_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "syscall");
- errno_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "errno");
- errpath_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "path");
- code_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "code");
- }
+ Environment* env = Environment::GetCurrent(node_isolate);
if (!msg || !msg[0])
msg = uv_strerror(errorno);
@@ -820,12 +754,18 @@ Local<Value> UVException(int errorno,
}
Local<Object> obj = e->ToObject();
-
// TODO(piscisaureus) errno should probably go
- obj->Set(errno_symbol, Integer::New(errorno, node_isolate));
- obj->Set(code_symbol, estring);
- if (path) obj->Set(errpath_symbol, path_str);
- if (syscall) obj->Set(syscall_symbol, OneByteString(node_isolate, syscall));
+ obj->Set(env->errno_string(), Integer::New(errorno, node_isolate));
+ obj->Set(env->code_string(), estring);
+
+ if (path != NULL) {
+ obj->Set(env->path_string(), path_str);
+ }
+
+ if (syscall != NULL) {
+ obj->Set(env->syscall_string(), OneByteString(node_isolate, syscall));
+ }
+
return e;
}
@@ -859,19 +799,14 @@ Local<Value> WinapiErrnoException(int errorno,
const char* syscall,
const char* msg,
const char* path) {
+ Environment* env = Environment::GetCurrent(node_isolate);
+
Local<Value> e;
if (!msg || !msg[0]) {
msg = winapi_strerror(errorno);
}
Local<String> message = OneByteString(node_isolate, msg);
- if (syscall_symbol.IsEmpty()) {
- syscall_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "syscall");
- errno_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "errno");
- errpath_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "path");
- code_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "code");
- }
-
if (path) {
Local<String> cons1 =
String::Concat(message, FIXED_ONE_BYTE_STRING(node_isolate, " '"));
@@ -885,91 +820,92 @@ Local<Value> WinapiErrnoException(int errorno,
}
Local<Object> obj = e->ToObject();
+ obj->Set(env->errno_string(), Integer::New(errorno, node_isolate));
+
+ if (path != NULL) {
+ obj->Set(env->path_string(), String::NewFromUtf8(node_isolate, path));
+ }
+
+ if (syscall != NULL) {
+ obj->Set(env->syscall_string(), OneByteString(node_isolate, syscall));
+ }
- obj->Set(errno_symbol, Integer::New(errorno, node_isolate));
- if (path) obj->Set(errpath_symbol, String::NewFromUtf8(node_isolate, path));
- if (syscall) obj->Set(syscall_symbol, OneByteString(node_isolate, syscall));
return e;
}
#endif
void SetupDomainUse(const FunctionCallbackInfo<Value>& args) {
- if (using_domains) return;
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+
+ if (env->using_domains()) return;
+ env->set_using_domains(true);
+
HandleScope scope(node_isolate);
- using_domains = true;
- Local<Object> process = PersistentToLocal(node_isolate, process_p);
- Local<Value> tdc_v =
- process->Get(FIXED_ONE_BYTE_STRING(node_isolate, "_tickDomainCallback"));
- if (!tdc_v->IsFunction()) {
+ Local<Object> process_object = env->process_object();
+
+ Local<String> tick_callback_function_key =
+ FIXED_ONE_BYTE_STRING(node_isolate, "_tickDomainCallback");
+ Local<Function> tick_callback_function =
+ process_object->Get(tick_callback_function_key).As<Function>();
+
+ if (!tick_callback_function->IsFunction()) {
fprintf(stderr, "process._tickDomainCallback assigned to non-function\n");
abort();
}
- Local<Function> tdc = tdc_v.As<Function>();
- process->Set(FIXED_ONE_BYTE_STRING(node_isolate, "_tickCallback"), tdc);
- process_tickCallback.Reset(node_isolate, tdc);
+
+ process_object->Set(FIXED_ONE_BYTE_STRING(node_isolate, "_tickCallback"),
+ tick_callback_function);
+ env->set_tick_callback_function(tick_callback_function);
+
if (!args[0]->IsArray()) {
fprintf(stderr, "_setupDomainUse first argument must be an array\n");
abort();
}
- p_domain_box.Reset(node_isolate, args[0].As<Array>());
+ env->set_domain_array(args[0].As<Array>());
+
if (!args[1]->IsObject()) {
fprintf(stderr, "_setupDomainUse second argument must be an object\n");
abort();
}
- Local<Object> flag = args[1].As<Object>();
- flag->SetIndexedPropertiesToExternalArrayData(&domain_flag,
- kExternalUnsignedIntArray,
- 1);
-}
-
-bool InDomain() {
- return using_domains && domain_flag.count > 0;
+ Local<Object> domain_flag_obj = args[1].As<Object>();
+ Environment::DomainFlag* domain_flag = env->domain_flag();
+ domain_flag_obj->SetIndexedPropertiesToExternalArrayData(
+ domain_flag->fields(),
+ kExternalUnsignedIntArray,
+ domain_flag->fields_count());
}
-Handle<Value> GetDomain() {
- // no domain can exist if no domain module has been loaded
- if (!InDomain() || p_domain_box.IsEmpty())
- return Null(node_isolate);
-
- return PersistentToLocal(node_isolate, p_domain_box)->Get(0);
-}
-
+Handle<Value> MakeDomainCallback(Environment* env,
+ const Handle<Object> object,
+ const Handle<Function> callback,
+ int argc,
+ Handle<Value> argv[]) {
+ // If you hit this assertion, you forgot to enter the v8::Context first.
+ assert(env->context() == env->isolate()->GetCurrentContext());
-Handle<Value>
-MakeDomainCallback(const Handle<Object> object,
- const Handle<Function> callback,
- int argc,
- Handle<Value> argv[]) {
// TODO(trevnorris) Hook for long stack traces to be made here.
- // lazy load domain specific symbols
- if (enter_symbol.IsEmpty()) {
- enter_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "enter");
- exit_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "exit");
- disposed_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "_disposed");
- }
-
- Local<Value> domain_v = object->Get(domain_symbol);
+ Local<Value> domain_v = object->Get(env->domain_string());
Local<Object> domain;
- Local<Function> enter;
- Local<Function> exit;
TryCatch try_catch;
try_catch.SetVerbose(true);
bool has_domain = domain_v->IsObject();
if (has_domain) {
- domain = domain_v->ToObject();
- assert(!domain.IsEmpty());
- if (domain->Get(disposed_symbol)->IsTrue()) {
+ domain = domain_v.As<Object>();
+
+ if (domain->Get(env->disposed_string())->IsTrue()) {
// domain has been disposed of.
return Undefined(node_isolate);
}
- enter = Local<Function>::Cast(domain->Get(enter_symbol));
- assert(!enter.IsEmpty());
+
+ Local<Function> enter =
+ domain->Get(env->enter_string()).As<Function>();
+ assert(enter->IsFunction());
enter->Call(domain, 0, NULL);
if (try_catch.HasCaught()) {
@@ -984,8 +920,9 @@ MakeDomainCallback(const Handle<Object> object,
}
if (has_domain) {
- exit = Local<Function>::Cast(domain->Get(exit_symbol));
- assert(!exit.IsEmpty());
+ Local<Function> exit =
+ domain->Get(env->exit_string()).As<Function>();
+ assert(exit->IsFunction());
exit->Call(domain, 0, NULL);
if (try_catch.HasCaught()) {
@@ -993,24 +930,26 @@ MakeDomainCallback(const Handle<Object> object,
}
}
- if (tick_infobox.last_threw == 1) {
- tick_infobox.last_threw = 0;
+ Environment::TickInfo* tick_info = env->tick_info();
+
+ if (tick_info->last_threw() == 1) {
+ tick_info->set_last_threw(0);
return ret;
}
- if (tick_infobox.in_tick == 1) {
+ if (tick_info->in_tick() == 1) {
return ret;
}
- if (tick_infobox.length == 0) {
- tick_infobox.index = 0;
+ if (tick_info->length() == 0) {
+ tick_info->set_index(0);
return ret;
}
// process nextTicks after call
- Local<Object> process = PersistentToLocal(node_isolate, process_p);
- Local<Function> fn = PersistentToLocal(node_isolate, process_tickCallback);
- fn->Call(process, 0, NULL);
+ Local<Object> process_object = env->process_object();
+ Local<Function> tick_callback_function = env->tick_callback_function();
+ tick_callback_function->Call(process_object, 0, NULL);
if (try_catch.HasCaught()) {
return Undefined(node_isolate);
@@ -1020,27 +959,19 @@ MakeDomainCallback(const Handle<Object> object,
}
-Handle<Value>
-MakeCallback(const Handle<Object> object,
- const Handle<Function> callback,
- int argc,
- Handle<Value> argv[]) {
+Handle<Value> MakeCallback(Environment* env,
+ const Handle<Object> object,
+ const Handle<Function> callback,
+ int argc,
+ Handle<Value> argv[]) {
+ // If you hit this assertion, you forgot to enter the v8::Context first.
+ assert(env->context() == env->isolate()->GetCurrentContext());
+
// TODO(trevnorris) Hook for long stack traces to be made here.
- Local<Object> process = PersistentToLocal(node_isolate, process_p);
+ Local<Object> process_object = env->process_object();
- if (using_domains)
- return MakeDomainCallback(object, callback, argc, argv);
-
- // lazy load no domain next tick callbacks
- if (process_tickCallback.IsEmpty()) {
- Local<Value> cb_v =
- process->Get(FIXED_ONE_BYTE_STRING(node_isolate, "_tickCallback"));
- if (!cb_v->IsFunction()) {
- fprintf(stderr, "process._tickCallback assigned to non-function\n");
- abort();
- }
- process_tickCallback.Reset(node_isolate, cb_v.As<Function>());
- }
+ if (env->using_domains())
+ return MakeDomainCallback(env, object, callback, argc, argv);
TryCatch try_catch;
try_catch.SetVerbose(true);
@@ -1051,18 +982,33 @@ MakeCallback(const Handle<Object> object,
return Undefined(node_isolate);
}
- if (tick_infobox.in_tick == 1) {
+ Environment::TickInfo* tick_info = env->tick_info();
+
+ if (tick_info->in_tick() == 1) {
return ret;
}
- if (tick_infobox.length == 0) {
- tick_infobox.index = 0;
+ if (tick_info->length() == 0) {
+ tick_info->set_index(0);
return ret;
}
+ // lazy load no domain next tick callbacks
+ Local<Function> tick_callback_function = env->tick_callback_function();
+ if (tick_callback_function.IsEmpty()) {
+ Local<String> tick_callback_function_key =
+ FIXED_ONE_BYTE_STRING(node_isolate, "_tickCallback");
+ tick_callback_function =
+ process_object->Get(tick_callback_function_key).As<Function>();
+ if (!tick_callback_function->IsFunction()) {
+ fprintf(stderr, "process._tickCallback assigned to non-function\n");
+ abort();
+ }
+ env->set_tick_callback_function(tick_callback_function);
+ }
+
// process nextTicks after call
- Local<Function> fn = PersistentToLocal(node_isolate, process_tickCallback);
- fn->Call(process, 0, NULL);
+ tick_callback_function->Call(process_object, 0, NULL);
if (try_catch.HasCaught()) {
return Undefined(node_isolate);
@@ -1073,49 +1019,102 @@ MakeCallback(const Handle<Object> object,
// Internal only.
-Handle<Value>
-MakeCallback(const Handle<Object> object,
- uint32_t index,
- int argc,
- Handle<Value> argv[]) {
- HandleScope scope(node_isolate);
+Handle<Value> MakeCallback(Environment* env,
+ const Handle<Object> object,
+ uint32_t index,
+ int argc,
+ Handle<Value> argv[]) {
+ // If you hit this assertion, you forgot to enter the v8::Context first.
+ assert(env->context() == env->isolate()->GetCurrentContext());
Local<Function> callback = object->Get(index).As<Function>();
assert(callback->IsFunction());
- if (using_domains)
- return scope.Close(MakeDomainCallback(object, callback, argc, argv));
- return scope.Close(MakeCallback(object, callback, argc, argv));
+ if (env->using_domains()) {
+ return MakeDomainCallback(env, object, callback, argc, argv);
+ }
+
+ return MakeCallback(env, object, callback, argc, argv);
}
-Handle<Value>
-MakeCallback(const Handle<Object> object,
- const Handle<String> symbol,
- int argc,
- Handle<Value> argv[]) {
- HandleScope scope(node_isolate);
+Handle<Value> MakeCallback(Environment* env,
+ const Handle<Object> object,
+ const Handle<String> symbol,
+ int argc,
+ Handle<Value> argv[]) {
+ // If you hit this assertion, you forgot to enter the v8::Context first.
+ assert(env->context() == env->isolate()->GetCurrentContext());
Local<Function> callback = object->Get(symbol).As<Function>();
assert(callback->IsFunction());
- if (using_domains)
- return scope.Close(MakeDomainCallback(object, callback, argc, argv));
- return scope.Close(MakeCallback(object, callback, argc, argv));
-}
+ if (env->using_domains()) {
+ return MakeDomainCallback(env, object, callback, argc, argv);
+ }
+ return MakeCallback(env, object, callback, argc, argv);
+}
-Handle<Value>
-MakeCallback(const Handle<Object> object,
- const char* method,
- int argc,
- Handle<Value> argv[]) {
- HandleScope scope(node_isolate);
+Handle<Value> MakeCallback(Environment* env,
+ const Handle<Object> object,
+ const char* method,
+ int argc,
+ Handle<Value> argv[]) {
+ // If you hit this assertion, you forgot to enter the v8::Context first.
+ assert(env->context() == env->isolate()->GetCurrentContext());
Local<String> method_string = OneByteString(node_isolate, method);
- Handle<Value> ret = MakeCallback(object, method_string, argc, argv);
+ return MakeCallback(env, object, method_string, argc, argv);
+}
- return scope.Close(ret);
+
+Handle<Value> MakeCallback(const Handle<Object> object,
+ const char* method,
+ int argc,
+ Handle<Value> argv[]) {
+ Local<Context> context = object->CreationContext();
+ Environment* env = Environment::GetCurrent(context);
+ Context::Scope context_scope(context);
+ HandleScope handle_scope(env->isolate());
+ return handle_scope.Close(MakeCallback(env, object, method, argc, argv));
+}
+
+
+Handle<Value> MakeCallback(const Handle<Object> object,
+ const Handle<String> symbol,
+ int argc,
+ Handle<Value> argv[]) {
+ Local<Context> context = object->CreationContext();
+ Environment* env = Environment::GetCurrent(context);
+ Context::Scope context_scope(context);
+ HandleScope handle_scope(env->isolate());
+ return handle_scope.Close(MakeCallback(env, object, symbol, argc, argv));
+}
+
+
+Handle<Value> MakeCallback(const Handle<Object> object,
+ const Handle<Function> callback,
+ int argc,
+ Handle<Value> argv[]) {
+ Local<Context> context = object->CreationContext();
+ Environment* env = Environment::GetCurrent(context);
+ Context::Scope context_scope(context);
+ HandleScope handle_scope(env->isolate());
+ return handle_scope.Close(MakeCallback(env, object, callback, argc, argv));
+}
+
+
+Handle<Value> MakeDomainCallback(const Handle<Object> object,
+ const Handle<Function> callback,
+ int argc,
+ Handle<Value> argv[]) {
+ Local<Context> context = object->CreationContext();
+ Environment* env = Environment::GetCurrent(context);
+ Context::Scope context_scope(context);
+ HandleScope handle_scope(env->isolate());
+ return handle_scope.Close(
+ MakeDomainCallback(env, object, callback, argc, argv));
}
@@ -1730,34 +1729,28 @@ static void Uptime(const FunctionCallbackInfo<Value>& args) {
void MemoryUsage(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
size_t rss;
-
int err = uv_resident_set_memory(&rss);
if (err) {
return ThrowUVException(err, "uv_resident_set_memory");
}
- Local<Object> info = Object::New();
-
- if (rss_symbol.IsEmpty()) {
- rss_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "rss");
- heap_total_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "heapTotal");
- heap_used_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "heapUsed");
- }
-
- info->Set(rss_symbol, Number::New(rss));
-
// V8 memory usage
HeapStatistics v8_heap_stats;
node_isolate->GetHeapStatistics(&v8_heap_stats);
- info->Set(heap_total_symbol,
- Integer::NewFromUnsigned(v8_heap_stats.total_heap_size(),
- node_isolate));
- info->Set(heap_used_symbol,
- Integer::NewFromUnsigned(v8_heap_stats.used_heap_size(),
- node_isolate));
+
+ Local<Integer> heap_total =
+ Integer::NewFromUnsigned(v8_heap_stats.total_heap_size(), node_isolate);
+ Local<Integer> heap_used =
+ Integer::NewFromUnsigned(v8_heap_stats.used_heap_size(), node_isolate);
+
+ Local<Object> info = Object::New();
+ info->Set(env->rss_string(), Number::New(node_isolate, rss));
+ info->Set(env->heap_total_string(), heap_total);
+ info->Set(env->heap_used_string(), heap_used);
args.GetReturnValue().Set(info);
}
@@ -1811,8 +1804,13 @@ typedef void (UV_DYNAMIC* extInit)(Handle<Object> exports);
// DLOpen is process.dlopen(module, filename).
// Used to load 'module.node' dynamically shared objects.
+//
+// FIXME(bnoordhuis) Not multi-context ready. TBD how to resolve the conflict
+// when two contexts try to load the same shared object. Maybe have a shadow
+// cache that's a plain C list or hash table that's shared across contexts?
void DLOpen(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
char symbol[1024], *base, *pos;
uv_lib_t lib;
int r;
@@ -1824,13 +1822,11 @@ void DLOpen(const FunctionCallbackInfo<Value>& args) {
Local<Object> module = args[0]->ToObject(); // Cast
String::Utf8Value filename(args[1]); // Cast
- if (exports_symbol.IsEmpty()) {
- exports_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "exports");
- }
- Local<Object> exports = module->Get(exports_symbol)->ToObject();
+ Local<String> exports_string = env->exports_string();
+ Local<Object> exports = module->Get(exports_string)->ToObject();
if (uv_dlopen(*filename, &lib)) {
- Local<String> errmsg = OneByteString(node_isolate, uv_dlerror(&lib));
+ Local<String> errmsg = OneByteString(env->isolate(), uv_dlerror(&lib));
#ifdef _WIN32
// Windows needs to add the filename into the error message
errmsg = String::Concat(errmsg, args[1]->ToString());
@@ -1894,7 +1890,13 @@ void DLOpen(const FunctionCallbackInfo<Value>& args) {
}
// Execute the C++ module
- mod->register_func(exports, module);
+ if (mod->register_context_func != NULL) {
+ mod->register_context_func(exports, module, env->context());
+ } else if (mod->register_func != NULL) {
+ mod->register_func(exports, module);
+ } else {
+ return ThrowError("Module has no declared entry point.");
+ }
// Tell coverity that 'handle' should not be freed when we return.
// coverity[leaked_storage]
@@ -1925,30 +1927,27 @@ NO_RETURN void FatalError(const char* location, const char* message) {
void FatalException(Handle<Value> error, Handle<Message> message) {
HandleScope scope(node_isolate);
- if (fatal_exception_symbol.IsEmpty()) {
- fatal_exception_symbol =
- FIXED_ONE_BYTE_STRING(node_isolate, "_fatalException");
- }
+ Environment* env = Environment::GetCurrent(node_isolate);
+ Local<Object> process_object = env->process_object();
+ Local<String> fatal_exception_string = env->fatal_exception_string();
+ Local<Function> fatal_exception_function =
+ process_object->Get(fatal_exception_string).As<Function>();
- Local<Object> process = PersistentToLocal(node_isolate, process_p);
- Local<Value> fatal_v = process->Get(fatal_exception_symbol);
-
- if (!fatal_v->IsFunction()) {
+ if (!fatal_exception_function->IsFunction()) {
// failed before the process._fatalException function was added!
// this is probably pretty bad. Nothing to do but report and exit.
ReportException(error, message);
exit(6);
}
- Local<Function> fatal_f = Local<Function>::Cast(fatal_v);
-
TryCatch fatal_try_catch;
// Do not call FatalException when _fatalException handler throws
fatal_try_catch.SetVerbose(false);
// this will return true if the JS layer handled it, false otherwise
- Local<Value> caught = fatal_f->Call(process, 1, &error);
+ Local<Value> caught =
+ fatal_exception_function->Call(process_object, 1, &error);
if (fatal_try_catch.HasCaught()) {
// the fatal exception function threw, so we must exit
@@ -1979,13 +1978,13 @@ void OnMessage(Handle<Message> message, Handle<Value> error) {
static void Binding(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
Local<String> module = args[0]->ToString();
String::Utf8Value module_v(module);
- node_module_struct* modp;
- Local<Object> cache = PersistentToLocal(node_isolate, binding_cache);
+ Local<Object> cache = env->binding_cache_object();
Local<Object> exports;
if (cache->Has(module)) {
@@ -1998,15 +1997,18 @@ static void Binding(const FunctionCallbackInfo<Value>& args) {
char buf[1024];
snprintf(buf, sizeof(buf), "Binding %s", *module_v);
- Local<Array> modules = PersistentToLocal(node_isolate, module_load_list);
+ Local<Array> modules = env->module_load_list_array();
uint32_t l = modules->Length();
modules->Set(l, OneByteString(node_isolate, buf));
- if ((modp = get_builtin_module(*module_v)) != NULL) {
+ node_module_struct* mod = get_builtin_module(*module_v);
+ if (mod != NULL) {
exports = Object::New();
- // Internal bindings don't have a "module" object,
- // only exports.
- modp->register_func(exports, Undefined(node_isolate));
+ // Internal bindings don't have a "module" object, only exports.
+ assert(mod->register_func == NULL);
+ assert(mod->register_context_func != NULL);
+ Local<Value> unused = Undefined(env->isolate());
+ mod->register_context_func(exports, unused, env->context());
cache->Set(module, exports);
} else if (!strcmp(*module_v, "constants")) {
exports = Object::New();
@@ -2254,28 +2256,37 @@ static void DebugEnd(const FunctionCallbackInfo<Value>& args);
void NeedImmediateCallbackGetter(Local<String> property,
const PropertyCallbackInfo<Value>& info) {
- info.GetReturnValue().Set(need_immediate_cb);
+ Environment* env = Environment::GetCurrent(info.GetIsolate());
+ const uv_check_t* immediate_check_handle = env->immediate_check_handle();
+ bool active = uv_is_active(
+ reinterpret_cast<const uv_handle_t*>(immediate_check_handle));
+ info.GetReturnValue().Set(active);
}
-static void NeedImmediateCallbackSetter(Local<String> property,
- Local<Value> value,
- const PropertyCallbackInfo<void>&) {
- HandleScope scope(node_isolate);
+static void NeedImmediateCallbackSetter(
+ Local<String> property,
+ Local<Value> value,
+ const PropertyCallbackInfo<void>& info) {
+ Environment* env = Environment::GetCurrent(info.GetIsolate());
+ HandleScope handle_scope(info.GetIsolate());
- bool bool_value = value->BooleanValue();
+ uv_check_t* immediate_check_handle = env->immediate_check_handle();
+ bool active = uv_is_active(
+ reinterpret_cast<const uv_handle_t*>(immediate_check_handle));
- if (need_immediate_cb == bool_value) return;
+ if (active == value->BooleanValue())
+ return;
- need_immediate_cb = bool_value;
+ uv_idle_t* immediate_idle_handle = env->immediate_idle_handle();
- if (need_immediate_cb) {
- uv_check_start(&check_immediate_watcher, node::CheckImmediate);
- // idle handle is needed only to maintain event loop
- uv_idle_start(&idle_immediate_dummy, node::IdleImmediateDummy);
+ if (active) {
+ uv_check_stop(immediate_check_handle);
+ uv_idle_stop(immediate_idle_handle);
} else {
- uv_check_stop(&check_immediate_watcher);
- uv_idle_stop(&idle_immediate_dummy);
+ uv_check_start(immediate_check_handle, CheckImmediate);
+ // Idle handle is needed only to stop the event loop from blocking in poll.
+ uv_idle_start(immediate_idle_handle, IdleImmediateDummy);
}
}
@@ -2286,23 +2297,15 @@ static void NeedImmediateCallbackSetter(Local<String> property,
} while (0)
-Handle<Object> SetupProcessObject(int argc,
- const char* const* argv,
- int exec_argc,
- const char* const* exec_argv) {
+void SetupProcessObject(Environment* env,
+ int argc,
+ const char* const* argv,
+ int exec_argc,
+ const char* const* exec_argv) {
HandleScope scope(node_isolate);
-
int i, j;
- Local<FunctionTemplate> process_template = FunctionTemplate::New();
- process_template->SetClassName(
- FIXED_ONE_BYTE_STRING(node_isolate, "process"));
-
- Local<Object> process = process_template->GetFunction()->NewInstance();
- assert(process.IsEmpty() == false);
- assert(process->IsObject() == true);
-
- process_p.Reset(node_isolate, process);
+ Local<Object> process = env->process_object();
process->SetAccessor(FIXED_ONE_BYTE_STRING(node_isolate, "title"),
ProcessTitleGetter,
@@ -2314,9 +2317,9 @@ Handle<Object> SetupProcessObject(int argc,
FIXED_ONE_BYTE_STRING(node_isolate, NODE_VERSION));
// process.moduleLoadList
- Local<Array> modules = Array::New();
- module_load_list.Reset(node_isolate, modules);
- READONLY_PROPERTY(process, "moduleLoadList", modules);
+ READONLY_PROPERTY(process,
+ "moduleLoadList",
+ env->module_load_list_array());
// process.versions
Local<Object> versions = Object::New();
@@ -2367,8 +2370,6 @@ Handle<Object> SetupProcessObject(int argc,
OneByteString(node_isolate, &OPENSSL_VERSION_TEXT[i], j - i));
#endif
-
-
// process.arch
READONLY_PROPERTY(process, "arch", OneByteString(node_isolate, ARCH));
@@ -2392,15 +2393,15 @@ Handle<Object> SetupProcessObject(int argc,
process->Set(FIXED_ONE_BYTE_STRING(node_isolate, "execArgv"), exec_arguments);
// create process.env
- Local<ObjectTemplate> envTemplate = ObjectTemplate::New();
- envTemplate->SetNamedPropertyHandler(EnvGetter,
- EnvSetter,
- EnvQuery,
- EnvDeleter,
- EnvEnumerator,
- Object::New());
- Local<Object> env = envTemplate->NewInstance();
- process->Set(FIXED_ONE_BYTE_STRING(node_isolate, "env"), env);
+ Local<ObjectTemplate> process_env_template = ObjectTemplate::New();
+ process_env_template->SetNamedPropertyHandler(EnvGetter,
+ EnvSetter,
+ EnvQuery,
+ EnvDeleter,
+ EnvEnumerator,
+ Object::New());
+ Local<Object> process_env = process_env_template->NewInstance();
+ process->Set(FIXED_ONE_BYTE_STRING(node_isolate, "env"), process_env);
READONLY_PROPERTY(process, "pid", Integer::New(getpid(), node_isolate));
READONLY_PROPERTY(process, "features", GetFeatures());
@@ -2500,16 +2501,15 @@ Handle<Object> SetupProcessObject(int argc,
NODE_SET_METHOD(process, "_setupDomainUse", SetupDomainUse);
// values use to cross communicate with processNextTick
- Local<Object> info_box = Object::New();
- info_box->SetIndexedPropertiesToExternalArrayData(&tick_infobox,
- kExternalUnsignedIntArray,
- 4);
- process->Set(FIXED_ONE_BYTE_STRING(node_isolate, "_tickInfoBox"), info_box);
+ Local<Object> tick_info_obj = Object::New();
+ tick_info_obj->SetIndexedPropertiesToExternalArrayData(
+ env->tick_info()->fields(),
+ kExternalUnsignedIntArray,
+ env->tick_info()->fields_count());
+ process->Set(FIXED_ONE_BYTE_STRING(node_isolate, "_tickInfo"), tick_info_obj);
// pre-set _events object for faster emit checks
process->Set(FIXED_ONE_BYTE_STRING(node_isolate, "_events"), Object::New());
-
- return scope.Close(process);
}
@@ -2543,12 +2543,9 @@ static void RawDebug(const FunctionCallbackInfo<Value>& args) {
}
-void Load(Handle<Object> process_l) {
+void Load(Environment* env) {
HandleScope handle_scope(node_isolate);
- process_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "process");
- domain_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "domain");
-
// Compile, execute the src/node.js file. (Which was included as static C
// string in node_natives.h. 'natve_node' is the string containing that
// source code.)
@@ -2581,7 +2578,7 @@ void Load(Handle<Object> process_l) {
// Node's I/O bindings may want to replace 'f' with their own function.
// Add a reference to the global object
- Local<Object> global = v8::Context::GetCurrent()->Global();
+ Local<Object> global = env->context()->Global();
#if defined HAVE_DTRACE || defined HAVE_ETW || defined HAVE_SYSTEMTAP
InitDTrace(global);
@@ -2599,9 +2596,9 @@ void Load(Handle<Object> process_l) {
// thrown during process startup.
try_catch.SetVerbose(true);
- NODE_SET_METHOD(process_l, "_rawDebug", RawDebug);
+ NODE_SET_METHOD(env->process_object(), "_rawDebug", RawDebug);
- Local<Value> arg = process_l;
+ Local<Value> arg = env->process_object();
f->Call(global, 1, &arg);
}
@@ -2797,15 +2794,17 @@ static void DispatchMessagesDebugAgentCallback() {
// Called from the main thread
static void EmitDebugEnabledAsyncCallback(uv_async_t* handle, int status) {
- HandleScope handle_scope(node_isolate);
- Local<Object> obj = Object::New();
- obj->Set(FIXED_ONE_BYTE_STRING(node_isolate, "cmd"),
- FIXED_ONE_BYTE_STRING(node_isolate, "NODE_DEBUG_ENABLED"));
+ Environment* env = Environment::GetCurrent(node_isolate);
+ Context::Scope context_scope(env->context());
+ HandleScope handle_scope(env->isolate());
+ Local<Object> message = Object::New();
+ message->Set(FIXED_ONE_BYTE_STRING(node_isolate, "cmd"),
+ FIXED_ONE_BYTE_STRING(node_isolate, "NODE_DEBUG_ENABLED"));
Local<Value> args[] = {
FIXED_ONE_BYTE_STRING(node_isolate, "internalMessage"),
- obj
+ message
};
- MakeCallback(process_p, "emit", ARRAY_SIZE(args), args);
+ MakeCallback(env, env->process_object(), "emit", ARRAY_SIZE(args), args);
}
@@ -2837,10 +2836,9 @@ static void EnableDebug(bool wait_connect) {
debugger_running = true;
- // Do not emit NODE_DEBUG_ENABLED when debugger is enabled before starting
- // the main process (i.e. when called via `node --debug`)
- if (!process_p.IsEmpty())
+ if (Environment::GetCurrentChecked(node_isolate) != NULL) {
EmitDebugEnabled();
+ }
node_isolate->Exit();
}
@@ -3058,12 +3056,14 @@ void Init(int* argc,
uv_disable_stdio_inheritance();
// init async debug messages dispatching
+ // FIXME(bnoordhuis) Should be per-isolate or per-context, not global.
uv_async_init(uv_default_loop(),
&dispatch_debug_messages_async,
DispatchDebugMessagesAsyncCallback);
uv_unref(reinterpret_cast<uv_handle_t*>(&dispatch_debug_messages_async));
// init async NODE_DEBUG_ENABLED emitter
+ // FIXME(bnoordhuis) Should be per-isolate or per-context, not global.
uv_async_init(uv_default_loop(),
&emit_debug_enabled_async,
EmitDebugEnabledAsyncCallback);
@@ -3109,10 +3109,6 @@ void Init(int* argc,
RegisterSignalHandler(SIGTERM, SignalExit);
#endif // __POSIX__
- uv_check_init(uv_default_loop(), &check_immediate_watcher);
- uv_unref(reinterpret_cast<uv_handle_t*>(&check_immediate_watcher));
- uv_idle_init(uv_default_loop(), &idle_immediate_dummy);
-
V8::SetFatalErrorHandler(node::OnFatalError);
V8::AddMessageListener(OnMessage);
@@ -3123,6 +3119,7 @@ void Init(int* argc,
#ifdef _WIN32
RegisterDebugSignalHandler();
#else // Posix
+ // FIXME(bnoordhuis) Should be per-isolate or per-context, not global.
static uv_signal_t signal_watcher;
uv_signal_init(uv_default_loop(), &signal_watcher);
uv_signal_start(&signal_watcher, EnableDebugSignalHandler, SIGUSR1);
@@ -3141,7 +3138,8 @@ struct AtExitCallback {
static AtExitCallback* at_exit_functions_;
-void RunAtExit() {
+// TODO(bnoordhuis) Turn into per-context event.
+void RunAtExit(Environment* env) {
AtExitCallback* p = at_exit_functions_;
at_exit_functions_ = NULL;
@@ -3163,15 +3161,47 @@ void AtExit(void (*cb)(void* arg), void* arg) {
}
-void EmitExit(v8::Handle<v8::Object> process_l) {
+void EmitExit(Environment* env) {
// process.emit('exit')
- process_l->Set(FIXED_ONE_BYTE_STRING(node_isolate, "_exiting"),
- True(node_isolate));
+ Context::Scope context_scope(env->context());
+ HandleScope handle_scope(env->isolate());
+ Local<Object> process_object = env->process_object();
+ process_object->Set(FIXED_ONE_BYTE_STRING(node_isolate, "_exiting"),
+ True(node_isolate));
Local<Value> args[] = {
FIXED_ONE_BYTE_STRING(node_isolate, "exit"),
Integer::New(0, node_isolate)
};
- MakeCallback(process_l, "emit", ARRAY_SIZE(args), args);
+ MakeCallback(env, process_object, "emit", ARRAY_SIZE(args), args);
+}
+
+
+Environment* CreateEnvironment(Isolate* isolate,
+ int argc,
+ const char* const* argv,
+ int exec_argc,
+ const char* const* exec_argv) {
+ HandleScope handle_scope(isolate);
+
+ Local<Context> context = Context::New(isolate);
+ Context::Scope context_scope(context);
+ Environment* env = Environment::New(context);
+
+ uv_check_init(env->event_loop(), env->immediate_check_handle());
+ uv_unref(
+ reinterpret_cast<uv_handle_t*>(env->immediate_check_handle()));
+ uv_idle_init(env->event_loop(), env->immediate_idle_handle());
+
+ Local<FunctionTemplate> process_template = FunctionTemplate::New();
+ process_template->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "process"));
+
+ Local<Object> process_object = process_template->GetFunction()->NewInstance();
+ env->set_process_object(process_object);
+
+ SetupProcessObject(env, argc, argv, exec_argc, exec_argv);
+ Load(env);
+
+ return env;
}
@@ -3190,31 +3220,15 @@ int Start(int argc, char** argv) {
V8::Initialize();
{
Locker locker(node_isolate);
- HandleScope handle_scope(node_isolate);
-
- // Create the one and only Context.
- Local<Context> context = Context::New(node_isolate);
- Context::Scope context_scope(context);
-
- binding_cache.Reset(node_isolate, Object::New());
-
- // Use original argv, as we're just copying values out of it.
- Local<Object> process_l =
- SetupProcessObject(argc, argv, exec_argc, exec_argv);
-
- // Create all the objects, load modules, do everything.
- // so your next reading stop should be node::Load()!
- Load(process_l);
-
- // All our arguments are loaded. We've evaluated all of the scripts. We
- // might even have created TCP servers. Now we enter the main eventloop. If
- // there are no watchers on the loop (except for the ones that were
- // uv_unref'd) then this function exits. As long as there are active
- // watchers, it blocks.
- uv_run(uv_default_loop(), UV_RUN_DEFAULT);
-
- EmitExit(process_l);
- RunAtExit();
+ Environment* env =
+ CreateEnvironment(node_isolate, argc, argv, exec_argc, exec_argv);
+ Context::Scope context_scope(env->context());
+ HandleScope handle_scope(env->isolate());
+ uv_run(env->event_loop(), UV_RUN_DEFAULT);
+ EmitExit(env);
+ RunAtExit(env);
+ env->Dispose();
+ env = NULL;
}
#ifndef NDEBUG
diff --git a/src/node.h b/src/node.h
index 527ac25a35..00f60d3fb1 100644
--- a/src/node.h
+++ b/src/node.h
@@ -58,6 +58,7 @@
# define SIGKILL 9
#endif
+#include "v8.h" // NOLINT(build/include_order)
#include "node_version.h" // NODE_MODULE_VERSION
#include "node_object_wrap.h"
@@ -95,9 +96,6 @@ NODE_EXTERN v8::Handle<v8::Value> MakeCallback(
#include "node_internals.h"
#endif
-#include "uv.h"
-#include "v8.h"
-
#include <assert.h>
#ifndef NODE_STRINGIFY
@@ -185,9 +183,6 @@ NODE_EXTERN ssize_t DecodeWrite(char *buf,
v8::Handle<v8::Value>,
enum encoding encoding = BINARY);
-v8::Local<v8::Object> BuildStatsObject(const uv_stat_t* s);
-
-
#ifdef _WIN32
NODE_EXTERN v8::Local<v8::Value> WinapiErrnoException(int errorno,
const char *syscall = NULL, const char *msg = "",
@@ -197,14 +192,21 @@ NODE_EXTERN v8::Local<v8::Value> WinapiErrnoException(int errorno,
const char *signo_string(int errorno);
-NODE_EXTERN typedef void (* addon_register_func)(
- v8::Handle<v8::Object> exports, v8::Handle<v8::Value> module);
+NODE_EXTERN typedef void (*addon_register_func)(
+ v8::Handle<v8::Object> exports,
+ v8::Handle<v8::Value> module);
+
+NODE_EXTERN typedef void (*addon_context_register_func)(
+ v8::Handle<v8::Object> exports,
+ v8::Handle<v8::Value> module,
+ v8::Handle<v8::Context> context);
struct node_module_struct {
int version;
void *dso_handle;
const char *filename;
node::addon_register_func register_func;
+ node::addon_context_register_func register_context_func;
const char *modname;
};
@@ -226,7 +228,19 @@ node_module_struct* get_builtin_module(const char *name);
NODE_MODULE_EXPORT node::node_module_struct modname ## _module = \
{ \
NODE_STANDARD_MODULE_STUFF, \
- (node::addon_register_func)regfunc, \
+ (node::addon_register_func) (regfunc), \
+ NULL, \
+ NODE_STRINGIFY(modname) \
+ }; \
+ }
+
+#define NODE_MODULE_CONTEXT_AWARE(modname, regfunc) \
+ extern "C" { \
+ NODE_MODULE_EXPORT node::node_module_struct modname ## _module = \
+ { \
+ NODE_STANDARD_MODULE_STUFF, \
+ NULL, \
+ (regfunc), \
NODE_STRINGIFY(modname) \
}; \
}
diff --git a/src/node.js b/src/node.js
index 3c7ede82b8..9ba1b3b4a0 100644
--- a/src/node.js
+++ b/src/node.js
@@ -273,16 +273,15 @@
startup.processNextTick = function() {
var nextTickQueue = [];
- // this infoBox thing is used so that the C++ code in src/node.cc
- // can have easy access to our nextTick state, and avoid unnecessary
- // calls into process._tickCallback.
- // order is [length, index, inTick, lastThrew]
- // Never write code like this without very good reason!
- var infoBox = process._tickInfoBox;
- var length = 0;
- var index = 1;
- var inTick = 2;
- var lastThrew = 3;
+ // This tickInfo thing is used so that the C++ code in src/node.cc
+ // can have easy accesss to our nextTick state, and avoid unnecessary
+ var tickInfo = process._tickInfo;
+
+ // *Must* match Environment::TickInfo::Fields in src/env.h.
+ var kInTick = 0;
+ var kIndex = 1;
+ var kLastThrew = 2;
+ var kLength = 3;
process.nextTick = nextTick;
// needs to be accessible from cc land
@@ -290,17 +289,17 @@
process._tickDomainCallback = _tickDomainCallback;
function tickDone() {
- if (infoBox[length] !== 0) {
- if (infoBox[length] <= infoBox[index]) {
+ if (tickInfo[kLength] !== 0) {
+ if (tickInfo[kLength] <= tickInfo[kIndex]) {
nextTickQueue = [];
- infoBox[length] = 0;
+ tickInfo[kLength] = 0;
} else {
- nextTickQueue.splice(0, infoBox[index]);
- infoBox[length] = nextTickQueue.length;
+ nextTickQueue.splice(0, tickInfo[kIndex]);
+ tickInfo[kLength] = nextTickQueue.length;
}
}
- infoBox[inTick] = 0;
- infoBox[index] = 0;
+ tickInfo[kInTick] = 0;
+ tickInfo[kIndex] = 0;
}
// run callbacks that have no domain
@@ -308,10 +307,10 @@
function _tickCallback() {
var callback, threw;
- infoBox[inTick] = 1;
+ tickInfo[kInTick] = 1;
- while (infoBox[index] < infoBox[length]) {
- callback = nextTickQueue[infoBox[index]++].callback;
+ while (tickInfo[kIndex] < tickInfo[kLength]) {
+ callback = nextTickQueue[tickInfo[kIndex]++].callback;
threw = true;
try {
callback();
@@ -327,22 +326,22 @@
function _tickDomainCallback() {
var tock, callback, domain;
- infoBox[inTick] = 1;
+ tickInfo[kInTick] = 1;
- while (infoBox[index] < infoBox[length]) {
- tock = nextTickQueue[infoBox[index]++];
+ while (tickInfo[kIndex] < tickInfo[kLength]) {
+ tock = nextTickQueue[tickInfo[kIndex]++];
callback = tock.callback;
domain = tock.domain;
if (domain) {
if (domain._disposed) continue;
domain.enter();
}
- infoBox[lastThrew] = 1;
+ tickInfo[kLastThrew] = 1;
try {
callback();
- infoBox[lastThrew] = 0;
+ tickInfo[kLastThrew] = 0;
} finally {
- if (infoBox[lastThrew] === 1) tickDone();
+ if (tickInfo[kLastThrew] === 1) tickDone();
}
if (domain)
domain.exit();
@@ -360,7 +359,7 @@
callback: callback,
domain: process.domain || null
});
- infoBox[length]++;
+ tickInfo[kLength]++;
}
};
diff --git a/src/node_buffer.cc b/src/node_buffer.cc
index 519fddf4c1..2e7374971c 100644
--- a/src/node_buffer.cc
+++ b/src/node_buffer.cc
@@ -22,11 +22,13 @@
#include "node.h"
#include "node_buffer.h"
+
+#include "env.h"
+#include "env-inl.h"
#include "smalloc.h"
#include "string_bytes.h"
-
-#include "v8.h"
#include "v8-profiler.h"
+#include "v8.h"
#include <assert.h>
#include <string.h>
@@ -55,6 +57,7 @@
namespace node {
namespace Buffer {
+using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
@@ -63,13 +66,10 @@ using v8::HandleScope;
using v8::Local;
using v8::Number;
using v8::Object;
-using v8::Persistent;
using v8::String;
using v8::Uint32;
using v8::Value;
-static Persistent<Function> p_buffer_fn;
-
bool HasInstance(Handle<Value> val) {
return val->IsObject() && HasInstance(val.As<Object>());
@@ -124,12 +124,20 @@ Local<Object> New(Handle<String> string, enum encoding enc) {
Local<Object> New(size_t length) {
+ Environment* env = Environment::GetCurrent(node_isolate);
+ return Buffer::New(env, length);
+}
+
+
+// TODO(trevnorris): these have a flaw by needing to call the Buffer inst then
+// Alloc. continue to look for a better architecture.
+Local<Object> New(Environment* env, size_t length) {
HandleScope scope(node_isolate);
assert(length <= kMaxLength);
Local<Value> arg = Uint32::NewFromUnsigned(length, node_isolate);
- Local<Object> obj = NewInstance(p_buffer_fn, 1, &arg);
+ Local<Object> obj = env->buffer_constructor_function()->NewInstance(1, &arg);
// TODO(trevnorris): done like this to handle HasInstance since only checks
// if external array data has been set, but would like to use a better
@@ -148,16 +156,22 @@ Local<Object> New(size_t length) {
}
+Local<Object> New(const char* data, size_t length) {
+ Environment* env = Environment::GetCurrent(node_isolate);
+ return Buffer::New(env, data, length);
+}
+
+
// TODO(trevnorris): for backwards compatibility this is left to copy the data,
// but for consistency w/ the other should use data. And a copy version renamed
// to something else.
-Local<Object> New(const char* data, size_t length) {
+Local<Object> New(Environment* env, const char* data, size_t length) {
HandleScope scope(node_isolate);
assert(length <= kMaxLength);
Local<Value> arg = Uint32::NewFromUnsigned(length, node_isolate);
- Local<Object> obj = NewInstance(p_buffer_fn, 1, &arg);
+ Local<Object> obj = env->buffer_constructor_function()->NewInstance(1, &arg);
// TODO(trevnorris): done like this to handle HasInstance since only checks
// if external array data has been set, but would like to use a better
@@ -182,12 +196,22 @@ Local<Object> New(char* data,
size_t length,
smalloc::FreeCallback callback,
void* hint) {
+ Environment* env = Environment::GetCurrent(node_isolate);
+ return Buffer::New(env, data, length, callback, hint);
+}
+
+
+Local<Object> New(Environment* env,
+ char* data,
+ size_t length,
+ smalloc::FreeCallback callback,
+ void* hint) {
HandleScope scope(node_isolate);
assert(length <= kMaxLength);
Local<Value> arg = Uint32::NewFromUnsigned(length, node_isolate);
- Local<Object> obj = NewInstance(p_buffer_fn, 1, &arg);
+ Local<Object> obj = env->buffer_constructor_function()->NewInstance(1, &arg);
smalloc::Alloc(obj, data, length, callback, hint);
@@ -196,12 +220,18 @@ Local<Object> New(char* data,
Local<Object> Use(char* data, uint32_t length) {
+ Environment* env = Environment::GetCurrent(node_isolate);
+ return Buffer::Use(env, data, length);
+}
+
+
+Local<Object> Use(Environment* env, char* data, uint32_t length) {
HandleScope scope(node_isolate);
assert(length <= kMaxLength);
Local<Value> arg = Uint32::NewFromUnsigned(length, node_isolate);
- Local<Object> obj = NewInstance(p_buffer_fn, 1, &arg);
+ Local<Object> obj = env->buffer_constructor_function()->NewInstance(1, &arg);
smalloc::Alloc(obj, data, length);
@@ -534,12 +564,13 @@ void ByteLength(const FunctionCallbackInfo<Value> &args) {
// pass Buffer object to load prototype methods
void SetupBufferJS(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
assert(args[0]->IsFunction());
Local<Function> bv = args[0].As<Function>();
- p_buffer_fn.Reset(node_isolate, bv);
+ env->set_buffer_constructor_function(bv);
Local<Value> proto_v =
bv->Get(FIXED_ONE_BYTE_STRING(node_isolate, "prototype"));
@@ -588,10 +619,12 @@ void SetupBufferJS(const FunctionCallbackInfo<Value>& args) {
}
-void Initialize(Handle<Object> target) {
- HandleScope scope(node_isolate);
-
- target->Set(FIXED_ONE_BYTE_STRING(node_isolate, "setupBufferJS"),
+void Initialize(Handle<Object> target,
+ Handle<Value> unused,
+ Handle<Context> context) {
+ Environment* env = Environment::GetCurrent(context);
+ HandleScope handle_scope(env->isolate());
+ target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "setupBufferJS"),
FunctionTemplate::New(SetupBufferJS)->GetFunction());
}
@@ -599,4 +632,4 @@ void Initialize(Handle<Object> target) {
} // namespace Buffer
} // namespace node
-NODE_MODULE(node_buffer, node::Buffer::Initialize)
+NODE_MODULE_CONTEXT_AWARE(node_buffer, node::Buffer::Initialize)
diff --git a/src/node_buffer.h b/src/node_buffer.h
index ca9a135e9d..78e6e42f6c 100644
--- a/src/node_buffer.h
+++ b/src/node_buffer.h
@@ -26,6 +26,10 @@
#include "smalloc.h"
#include "v8.h"
+#if defined(NODE_WANT_INTERNALS)
+#include "env.h"
+#endif // defined(NODE_WANT_INTERNALS)
+
namespace node {
namespace Buffer {
@@ -56,6 +60,20 @@ NODE_EXTERN v8::Local<v8::Object> New(char* data,
// TODO(trevnorris): should be New() for consistency
NODE_EXTERN v8::Local<v8::Object> Use(char* data, uint32_t len);
+// Internal. Not for public consumption. We can't define these in
+// src/node_internals.h due to a circular dependency issue with
+// the smalloc.h and node_internals.h headers.
+#if defined(NODE_WANT_INTERNALS)
+v8::Local<v8::Object> New(Environment* env, size_t size);
+v8::Local<v8::Object> New(Environment* env, const char* data, size_t len);
+v8::Local<v8::Object> New(Environment* env,
+ char* data,
+ size_t length,
+ smalloc::FreeCallback callback,
+ void* hint);
+v8::Local<v8::Object> Use(Environment* env, char* data, uint32_t length);
+#endif // defined(NODE_WANT_INTERNALS)
+
} // namespace Buffer
} // namespace node
diff --git a/src/node_contextify.cc b/src/node_contextify.cc
index 331dbdb6e9..132fa911de 100644
--- a/src/node_contextify.cc
+++ b/src/node_contextify.cc
@@ -22,6 +22,8 @@
#include "node.h"
#include "node_internals.h"
#include "node_watchdog.h"
+#include "env.h"
+#include "env-inl.h"
namespace node {
@@ -33,6 +35,7 @@ using v8::External;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
+using v8::Handle;
using v8::HandleScope;
using v8::Integer;
using v8::Isolate;
@@ -51,18 +54,17 @@ using v8::Value;
class ContextifyContext {
private:
+ Environment* const env_;
Persistent<Object> sandbox_;
- Persistent<Object> proxy_global_;
Persistent<Context> context_;
- static Persistent<Function> data_wrapper_ctor;
+ Persistent<Object> proxy_global_;
public:
- explicit ContextifyContext(Local<Object> sandbox) :
- sandbox_(node_isolate, sandbox) {
- HandleScope scope(node_isolate);
- Local<Context> v8_context = CreateV8Context();
- context_.Reset(node_isolate, v8_context);
- proxy_global_.Reset(node_isolate, v8_context->Global());
+ explicit ContextifyContext(Environment* env, Local<Object> sandbox)
+ : env_(env)
+ , sandbox_(env->isolate(), sandbox)
+ , context_(env->isolate(), CreateV8Context(env))
+ , proxy_global_(env->isolate(), context()->Global()) {
sandbox_.MakeWeak(this, SandboxFreeCallback);
sandbox_.MarkIndependent();
}
@@ -75,21 +77,31 @@ class ContextifyContext {
}
+ inline Environment* env() const {
+ return env_;
+ }
+
+
+ inline Local<Context> context() const {
+ return PersistentToLocal(env()->isolate(), context_);
+ }
+
+
// This is an object that just keeps an internal pointer to this
// ContextifyContext. It's passed to the NamedPropertyHandler. If we
// pass the main JavaScript context object we're embedded in, then the
// NamedPropertyHandler will store a reference to it forever and keep it
// from getting gc'd.
- Local<Value> CreateDataWrapper() {
+ Local<Value> CreateDataWrapper(Environment* env) {
HandleScope scope(node_isolate);
- Local<Function> ctor = PersistentToLocal(node_isolate, data_wrapper_ctor);
- Local<Object> wrapper = ctor->NewInstance();
+ Local<Object> wrapper =
+ env->script_data_constructor_function()->NewInstance();
NODE_WRAP(wrapper, this);
return scope.Close(wrapper);
}
- Local<Context> CreateV8Context() {
+ Local<Context> CreateV8Context(Environment* env) {
HandleScope scope(node_isolate);
Local<FunctionTemplate> function_template = FunctionTemplate::New();
function_template->SetHiddenPrototype(true);
@@ -104,19 +116,17 @@ class ContextifyContext {
GlobalPropertyQueryCallback,
GlobalPropertyDeleterCallback,
GlobalPropertyEnumeratorCallback,
- CreateDataWrapper());
+ CreateDataWrapper(env));
object_template->SetAccessCheckCallbacks(GlobalPropertyNamedAccessCheck,
GlobalPropertyIndexedAccessCheck);
return scope.Close(Context::New(node_isolate, NULL, object_template));
}
- static void Init(Local<Object> target) {
- HandleScope scope(node_isolate);
-
+ static void Init(Environment* env, Local<Object> target) {
Local<FunctionTemplate> function_template = FunctionTemplate::New();
function_template->InstanceTemplate()->SetInternalFieldCount(1);
- data_wrapper_ctor.Reset(node_isolate, function_template->GetFunction());
+ env->set_script_data_constructor_function(function_template->GetFunction());
NODE_SET_METHOD(target, "makeContext", MakeContext);
NODE_SET_METHOD(target, "isContext", IsContext);
@@ -124,7 +134,8 @@ class ContextifyContext {
static void MakeContext(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
if (!args[0]->IsObject()) {
return ThrowTypeError("sandbox argument must be an object.");
@@ -137,7 +148,7 @@ class ContextifyContext {
// Don't allow contextifying a sandbox multiple times.
assert(sandbox->GetHiddenValue(hidden_name).IsEmpty());
- ContextifyContext* context = new ContextifyContext(sandbox);
+ ContextifyContext* context = new ContextifyContext(env, sandbox);
Local<External> hidden_context = External::New(context);
sandbox->SetHiddenValue(hidden_name, hidden_context);
}
@@ -179,18 +190,6 @@ class ContextifyContext {
return static_cast<ContextifyContext*>(context_external->Value());
}
- static Local<Context> V8ContextFromContextifiedSandbox(
- const Local<Object>& sandbox) {
- ContextifyContext* contextify_context =
- ContextFromContextifiedSandbox(sandbox);
- if (contextify_context == NULL) {
- ThrowTypeError("sandbox argument must have been converted to a context.");
- return Local<Context>();
- }
-
- return PersistentToLocal(node_isolate, contextify_context->context_);
- }
-
static bool GlobalPropertyNamedAccessCheck(Local<Object> host,
Local<Value> key,
@@ -300,24 +299,21 @@ class ContextifyScript : ObjectWrap {
Persistent<Script> script_;
public:
- static Persistent<FunctionTemplate> script_tmpl;
-
- static void Init(Local<Object> target) {
+ static void Init(Environment* env, Local<Object> target) {
HandleScope scope(node_isolate);
Local<String> class_name =
FIXED_ONE_BYTE_STRING(node_isolate, "ContextifyScript");
- script_tmpl.Reset(node_isolate, FunctionTemplate::New(New));
- Local<FunctionTemplate> lscript_tmpl =
- PersistentToLocal(node_isolate, script_tmpl);
- lscript_tmpl->InstanceTemplate()->SetInternalFieldCount(1);
- lscript_tmpl->SetClassName(class_name);
- NODE_SET_PROTOTYPE_METHOD(lscript_tmpl, "runInContext", RunInContext);
- NODE_SET_PROTOTYPE_METHOD(lscript_tmpl,
+ Local<FunctionTemplate> script_tmpl = FunctionTemplate::New(New);
+ script_tmpl->InstanceTemplate()->SetInternalFieldCount(1);
+ script_tmpl->SetClassName(class_name);
+ NODE_SET_PROTOTYPE_METHOD(script_tmpl, "runInContext", RunInContext);
+ NODE_SET_PROTOTYPE_METHOD(script_tmpl,
"runInThisContext",
RunInThisContext);
- target->Set(class_name, lscript_tmpl->GetFunction());
+ target->Set(class_name, script_tmpl->GetFunction());
+ env->set_script_context_constructor_template(script_tmpl);
}
@@ -357,15 +353,16 @@ class ContextifyScript : ObjectWrap {
}
- static bool InstanceOf(const Local<Value>& value) {
+ static bool InstanceOf(Environment* env, const Local<Value>& value) {
return !value.IsEmpty() &&
- PersistentToLocal(node_isolate, script_tmpl)->HasInstance(value);
+ env->script_context_constructor_template()->HasInstance(value);
}
// args: [options]
static void RunInThisContext(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
// Assemble arguments
TryCatch try_catch;
@@ -377,7 +374,7 @@ class ContextifyScript : ObjectWrap {
}
// Do the eval within this context
- EvalMachine(timeout, display_errors, args, try_catch);
+ EvalMachine(env, timeout, display_errors, args, try_catch);
}
// args: sandbox, [options]
@@ -398,16 +395,20 @@ class ContextifyScript : ObjectWrap {
}
// Get the context from the sandbox
- Local<Context> context =
- ContextifyContext::V8ContextFromContextifiedSandbox(sandbox);
- if (try_catch.HasCaught()) {
- try_catch.ReThrow();
- return;
+ ContextifyContext* contextify_context =
+ ContextifyContext::ContextFromContextifiedSandbox(sandbox);
+ if (contextify_context == NULL) {
+ return ThrowTypeError(
+ "sandbox argument must have been converted to a context.");
}
// Do the eval within the context
- Context::Scope context_scope(context);
- EvalMachine(timeout, display_errors, args, try_catch);
+ Context::Scope context_scope(contextify_context->context());
+ EvalMachine(contextify_context->env(),
+ timeout,
+ display_errors,
+ args,
+ try_catch);
}
static int64_t GetTimeoutArg(const FunctionCallbackInfo<Value>& args,
@@ -475,11 +476,12 @@ class ContextifyScript : ObjectWrap {
}
- static void EvalMachine(const int64_t timeout,
+ static void EvalMachine(Environment* env,
+ const int64_t timeout,
const bool display_errors,
const FunctionCallbackInfo<Value>& args,
TryCatch& try_catch) {
- if (!ContextifyScript::InstanceOf(args.This())) {
+ if (!ContextifyScript::InstanceOf(env, args.This())) {
return ThrowTypeError(
"Script methods can only be called on script instances.");
}
@@ -521,15 +523,14 @@ class ContextifyScript : ObjectWrap {
};
-Persistent<Function> ContextifyContext::data_wrapper_ctor;
-Persistent<FunctionTemplate> ContextifyScript::script_tmpl;
-
-void InitContextify(Local<Object> target) {
- HandleScope scope(node_isolate);
- ContextifyContext::Init(target);
- ContextifyScript::Init(target);
+void InitContextify(Handle<Object> target,
+ Handle<Value> unused,
+ Handle<Context> context) {
+ Environment* env = Environment::GetCurrent(context);
+ ContextifyContext::Init(env, target);
+ ContextifyScript::Init(env, target);
}
} // namespace node
-NODE_MODULE(node_contextify, node::InitContextify);
+NODE_MODULE_CONTEXT_AWARE(node_contextify, node::InitContextify);
diff --git a/src/node_crypto.cc b/src/node_crypto.cc
index ff90e91a46..9a3cfe9390 100644
--- a/src/node_crypto.cc
+++ b/src/node_crypto.cc
@@ -27,6 +27,8 @@
#include "node_root_certs.h"
#include "tls_wrap.h" // TLSCallbacks
+#include "env.h"
+#include "env-inl.h"
#include "string_bytes.h"
#include "v8.h"
@@ -70,6 +72,7 @@ namespace crypto {
using v8::Array;
using v8::Boolean;
+using v8::Context;
using v8::Exception;
using v8::False;
using v8::FunctionCallbackInfo;
@@ -95,27 +98,6 @@ struct ClearErrorOnReturn {
~ClearErrorOnReturn() { ERR_clear_error(); }
};
-static Cached<String> subject_symbol;
-static Cached<String> subjectaltname_symbol;
-static Cached<String> modulus_symbol;
-static Cached<String> exponent_symbol;
-static Cached<String> issuer_symbol;
-static Cached<String> valid_from_symbol;
-static Cached<String> valid_to_symbol;
-static Cached<String> fingerprint_symbol;
-static Cached<String> name_symbol;
-static Cached<String> version_symbol;
-static Cached<String> ext_key_usage_symbol;
-static Cached<String> onhandshakestart_sym;
-static Cached<String> onhandshakedone_sym;
-static Cached<String> onclienthello_sym;
-static Cached<String> onnewsession_sym;
-static Cached<String> sessionid_sym;
-static Cached<String> servername_sym;
-static Cached<String> tls_ticket_sym;
-
-static Persistent<FunctionTemplate> secure_context_constructor;
-
static uv_rwlock_t* locks;
X509_STORE* root_cert_store;
@@ -203,12 +185,8 @@ void ThrowCryptoTypeError(unsigned long err) {
}
-void SecureContext::Initialize(Handle<Object> target) {
- HandleScope scope(node_isolate);
-
+void SecureContext::Initialize(Environment* env, Handle<Object> target) {
Local<FunctionTemplate> t = FunctionTemplate::New(SecureContext::New);
- secure_context_constructor.Reset(node_isolate, t);
-
t->InstanceTemplate()->SetInternalFieldCount(1);
t->SetClassName(FIXED_ONE_BYTE_STRING(node_isolate, "SecureContext"));
@@ -231,12 +209,14 @@ void SecureContext::Initialize(Handle<Object> target) {
target->Set(FIXED_ONE_BYTE_STRING(node_isolate, "SecureContext"),
t->GetFunction());
+ env->set_secure_context_constructor_template(t);
}
void SecureContext::New(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
- SecureContext* sc = new SecureContext();
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
+ SecureContext* sc = new SecureContext(env);
sc->Wrap(args.This());
}
@@ -750,12 +730,12 @@ void SecureContext::LoadPKCS12(const FunctionCallbackInfo<Value>& args) {
void SecureContext::GetTicketKeys(const FunctionCallbackInfo<Value>& args) {
#if !defined(OPENSSL_NO_TLSEXT) && defined(SSL_CTX_get_tlsext_ticket_keys)
- HandleScope scope(node_isolate);
+ HandleScope handle_scope(args.GetIsolate());
SecureContext* wrap;
NODE_UNWRAP(args.This(), SecureContext, wrap);
- Local<Object> buff = Buffer::New(48);
+ Local<Object> buff = Buffer::New(wrap->env(), 48);
if (SSL_CTX_get_tlsext_ticket_keys(wrap->ctx_,
Buffer::Data(buff),
Buffer::Length(buff)) != 1) {
@@ -836,6 +816,7 @@ int SSLWrap<Base>::NewSessionCallback(SSL* s, SSL_SESSION* sess) {
HandleScope scope(node_isolate);
Base* w = static_cast<Base*>(SSL_get_app_data(s));
+ Environment* env = w->env();
if (!w->session_callbacks_)
return 0;
@@ -846,19 +827,19 @@ int SSLWrap<Base>::NewSessionCallback(SSL* s, SSL_SESSION* sess) {
return 0;
// Serialize session
- Local<Object> buff = Buffer::New(size);
+ Local<Object> buff = Buffer::New(env, size);
unsigned char* serialized = reinterpret_cast<unsigned char*>(
Buffer::Data(buff));
memset(serialized, 0, size);
i2d_SSL_SESSION(sess, &serialized);
- Local<Object> session = Buffer::New(reinterpret_cast<char*>(sess->session_id),
+ Local<Object> session = Buffer::New(env,
+ reinterpret_cast<char*>(sess->session_id),
sess->session_id_length);
Local<Value> argv[] = { session, buff };
- if (onnewsession_sym.IsEmpty())
- onnewsession_sym = FIXED_ONE_BYTE_STRING(node_isolate, "onnewsession");
- MakeCallback(w->handle(node_isolate),
- onnewsession_sym,
+ MakeCallback(env,
+ w->handle(node_isolate),
+ env->onnewsession_string(),
ARRAY_SIZE(argv),
argv);
@@ -872,34 +853,28 @@ void SSLWrap<Base>::OnClientHello(void* arg,
HandleScope scope(node_isolate);
Base* w = static_cast<Base*>(arg);
-
- if (onclienthello_sym.IsEmpty())
- onclienthello_sym = FIXED_ONE_BYTE_STRING(node_isolate, "onclienthello");
- if (sessionid_sym.IsEmpty())
- sessionid_sym = FIXED_ONE_BYTE_STRING(node_isolate, "sessionId");
- if (servername_sym.IsEmpty())
- servername_sym = FIXED_ONE_BYTE_STRING(node_isolate, "servername");
- if (tls_ticket_sym.IsEmpty())
- tls_ticket_sym = FIXED_ONE_BYTE_STRING(node_isolate, "tlsTicket");
+ Environment* env = w->env();
Local<Object> hello_obj = Object::New();
Local<Object> buff = Buffer::New(
+ env,
reinterpret_cast<const char*>(hello.session_id()),
- hello.session_size());
- hello_obj->Set(sessionid_sym, buff);
+ hello.session_size());
+ hello_obj->Set(env->session_id_string(), buff);
if (hello.servername() == NULL) {
- hello_obj->Set(servername_sym, String::Empty(node_isolate));
+ hello_obj->Set(env->servername_string(), String::Empty(node_isolate));
} else {
Local<String> servername = OneByteString(node_isolate,
hello.servername(),
hello.servername_size());
- hello_obj->Set(servername_sym, servername);
+ hello_obj->Set(env->servername_string(), servername);
}
- hello_obj->Set(tls_ticket_sym, Boolean::New(hello.has_ticket()));
+ hello_obj->Set(env->tls_ticket_string(), Boolean::New(hello.has_ticket()));
Local<Value> argv[] = { hello_obj };
- MakeCallback(w->handle(node_isolate),
- onclienthello_sym,
+ MakeCallback(env,
+ w->handle(node_isolate),
+ env->onclienthello_string(),
ARRAY_SIZE(argv),
argv);
}
@@ -912,6 +887,7 @@ void SSLWrap<Base>::GetPeerCertificate(
HandleScope scope(node_isolate);
Base* w = ObjectWrap::Unwrap<Base>(args.This());
+ Environment* env = w->env();
Local<Object> info = Object::New();
X509* peer_cert = SSL_get_peer_certificate(w->ssl_);
@@ -923,7 +899,7 @@ void SSLWrap<Base>::GetPeerCertificate(
0,
X509_NAME_FLAGS) > 0) {
BIO_get_mem_ptr(bio, &mem);
- info->Set(subject_symbol,
+ info->Set(env->subject_string(),
OneByteString(node_isolate, mem->data, mem->length));
}
(void) BIO_reset(bio);
@@ -931,7 +907,7 @@ void SSLWrap<Base>::GetPeerCertificate(
X509_NAME* issuer_name = X509_get_issuer_name(peer_cert);
if (X509_NAME_print_ex(bio, issuer_name, 0, X509_NAME_FLAGS) > 0) {
BIO_get_mem_ptr(bio, &mem);
- info->Set(issuer_symbol,
+ info->Set(env->issuer_string(),
OneByteString(node_isolate, mem->data, mem->length));
}
(void) BIO_reset(bio);
@@ -948,7 +924,7 @@ void SSLWrap<Base>::GetPeerCertificate(
assert(rv == 1);
BIO_get_mem_ptr(bio, &mem);
- info->Set(subjectaltname_symbol,
+ info->Set(env->subjectaltname_string(),
OneByteString(node_isolate, mem->data, mem->length));
(void) BIO_reset(bio);
@@ -962,13 +938,13 @@ void SSLWrap<Base>::GetPeerCertificate(
if (rsa != NULL) {
BN_print(bio, rsa->n);
BIO_get_mem_ptr(bio, &mem);
- info->Set(modulus_symbol,
+ info->Set(env->modulus_string(),
OneByteString(node_isolate, mem->data, mem->length));
(void) BIO_reset(bio);
BN_print(bio, rsa->e);
BIO_get_mem_ptr(bio, &mem);
- info->Set(exponent_symbol,
+ info->Set(env->exponent_string(),
OneByteString(node_isolate, mem->data, mem->length));
(void) BIO_reset(bio);
}
@@ -984,13 +960,13 @@ void SSLWrap<Base>::GetPeerCertificate(
ASN1_TIME_print(bio, X509_get_notBefore(peer_cert));
BIO_get_mem_ptr(bio, &mem);
- info->Set(valid_from_symbol,
+ info->Set(env->valid_from_string(),
OneByteString(node_isolate, mem->data, mem->length));
(void) BIO_reset(bio);
ASN1_TIME_print(bio, X509_get_notAfter(peer_cert));
BIO_get_mem_ptr(bio, &mem);
- info->Set(valid_to_symbol,
+ info->Set(env->valid_to_string(),
OneByteString(node_isolate, mem->data, mem->length));
BIO_free_all(bio);
@@ -1013,7 +989,8 @@ void SSLWrap<Base>::GetPeerCertificate(
fingerprint[0] = '\0';
}
- info->Set(fingerprint_symbol, OneByteString(node_isolate, fingerprint));
+ info->Set(env->fingerprint_string(),
+ OneByteString(node_isolate, fingerprint));
}
STACK_OF(ASN1_OBJECT)* eku = static_cast<STACK_OF(ASN1_OBJECT)*>(
@@ -1029,7 +1006,7 @@ void SSLWrap<Base>::GetPeerCertificate(
}
sk_ASN1_OBJECT_pop_free(eku, ASN1_OBJECT_free);
- info->Set(ext_key_usage_symbol, ext_key_usage);
+ info->Set(env->ext_key_usage_string(), ext_key_usage);
}
X509_free(peer_cert);
@@ -1103,6 +1080,7 @@ void SSLWrap<Base>::LoadSession(const FunctionCallbackInfo<Value>& args) {
HandleScope scope(node_isolate);
Base* w = ObjectWrap::Unwrap<Base>(args.This());
+ Environment* env = w->env();
if (args.Length() >= 1 && Buffer::HasInstance(args[0])) {
ssize_t slen = Buffer::Length(args[0]);
@@ -1118,12 +1096,10 @@ void SSLWrap<Base>::LoadSession(const FunctionCallbackInfo<Value>& args) {
Local<Object> info = Object::New();
#ifndef OPENSSL_NO_TLSEXT
- if (servername_sym.IsEmpty())
- servername_sym = FIXED_ONE_BYTE_STRING(node_isolate, "servername");
if (sess->tlsext_hostname == NULL) {
- info->Set(servername_sym, False(node_isolate));
+ info->Set(env->servername_string(), False(node_isolate));
} else {
- info->Set(servername_sym,
+ info->Set(env->servername_string(),
OneByteString(node_isolate, sess->tlsext_hostname));
}
#endif
@@ -1255,6 +1231,7 @@ void SSLWrap<Base>::GetCurrentCipher(const FunctionCallbackInfo<Value>& args) {
HandleScope scope(node_isolate);
Base* w = ObjectWrap::Unwrap<Base>(args.This());
+ Environment* env = w->env();
OPENSSL_CONST SSL_CIPHER* c = SSL_get_current_cipher(w->ssl_);
if (c == NULL)
@@ -1262,9 +1239,9 @@ void SSLWrap<Base>::GetCurrentCipher(const FunctionCallbackInfo<Value>& args) {
Local<Object> info = Object::New();
const char* cipher_name = SSL_CIPHER_get_name(c);
- info->Set(name_symbol, OneByteString(node_isolate, cipher_name));
+ info->Set(env->name_string(), OneByteString(node_isolate, cipher_name));
const char* cipher_version = SSL_CIPHER_get_version(c);
- info->Set(version_symbol, OneByteString(node_isolate, cipher_version));
+ info->Set(env->version_string(), OneByteString(node_isolate, cipher_version));
args.GetReturnValue().Set(info);
}
@@ -1539,9 +1516,7 @@ void Connection::SetShutdownFlags() {
}
-void Connection::Initialize(Handle<Object> target) {
- HandleScope scope(node_isolate);
-
+void Connection::Initialize(Environment* env, Handle<Object> target) {
Local<FunctionTemplate> t = FunctionTemplate::New(Connection::New);
t->InstanceTemplate()->SetInternalFieldCount(1);
t->SetClassName(FIXED_ONE_BYTE_STRING(node_isolate, "Connection"));
@@ -1629,6 +1604,7 @@ int Connection::SelectSNIContextCallback_(SSL *s, int *ad, void* arg) {
HandleScope scope(node_isolate);
Connection* conn = static_cast<Connection*>(SSL_get_app_data(s));
+ Environment* env = conn->env();
const char* servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
@@ -1640,11 +1616,15 @@ int Connection::SelectSNIContextCallback_(SSL *s, int *ad, void* arg) {
if (!conn->sniObject_.IsEmpty()) {
conn->sniContext_.Dispose();
+ Local<Object> sni_object =
+ PersistentToLocal(node_isolate, conn->sniObject_);
Local<Value> arg = PersistentToLocal(node_isolate, conn->servername_);
- Local<Value> ret = MakeCallback(conn->sniObject_, "onselect", 1, &arg);
+ Local<Value> ret = MakeCallback(env, sni_object, "onselect", 1, &arg);
// If ret is SecureContext
- if (HasInstance(secure_context_constructor, ret)) {
+ Local<FunctionTemplate> secure_context_constructor_template =
+ env->secure_context_constructor_template();
+ if (secure_context_constructor_template->HasInstance(ret)) {
conn->sniContext_.Reset(node_isolate, ret);
SecureContext* sc = ObjectWrap::Unwrap<SecureContext>(ret.As<Object>());
SSL_set_SSL_CTX(s, sc->ctx_);
@@ -1666,12 +1646,13 @@ void Connection::New(const FunctionCallbackInfo<Value>& args) {
}
SecureContext* sc = ObjectWrap::Unwrap<SecureContext>(args[0]->ToObject());
+ Environment* env = sc->env();
bool is_server = args[1]->BooleanValue();
- Connection* conn = new Connection(
- sc,
- is_server ? SSLWrap<Connection>::kServer : SSLWrap<Connection>::kClient);
+ SSLWrap<Connection>::Kind kind =
+ is_server ? SSLWrap<Connection>::kServer : SSLWrap<Connection>::kClient;
+ Connection* conn = new Connection(env, sc, kind);
conn->Wrap(args.This());
conn->ssl_ = SSL_new(sc->ctx_);
@@ -1746,26 +1727,27 @@ void Connection::New(const FunctionCallbackInfo<Value>& args) {
void Connection::SSLInfoCallback(const SSL *ssl_, int where, int ret) {
+ if (!(where & (SSL_CB_HANDSHAKE_START | SSL_CB_HANDSHAKE_DONE)))
+ return;
+
// Be compatible with older versions of OpenSSL. SSL_get_app_data() wants
// a non-const SSL* in OpenSSL <= 0.9.7e.
SSL* ssl = const_cast<SSL*>(ssl_);
+ Connection* conn = static_cast<Connection*>(SSL_get_app_data(ssl));
+ Environment* env = conn->env();
+ Context::Scope context_scope(env->context());
+ HandleScope handle_scope(env->isolate());
+
if (where & SSL_CB_HANDSHAKE_START) {
- HandleScope scope(node_isolate);
- Connection* conn = static_cast<Connection*>(SSL_get_app_data(ssl));
- if (onhandshakestart_sym.IsEmpty()) {
- onhandshakestart_sym =
- FIXED_ONE_BYTE_STRING(node_isolate, "onhandshakestart");
- }
- MakeCallback(conn->handle(node_isolate), onhandshakestart_sym, 0, NULL);
+ MakeCallback(env,
+ conn->handle(node_isolate),
+ env->onhandshakestart_string());
}
+
if (where & SSL_CB_HANDSHAKE_DONE) {
- HandleScope scope(node_isolate);
- Connection* conn = static_cast<Connection*>(SSL_get_app_data(ssl));
- if (onhandshakedone_sym.IsEmpty()) {
- onhandshakedone_sym =
- FIXED_ONE_BYTE_STRING(node_isolate, "onhandshakedone");
- }
- MakeCallback(conn->handle(node_isolate), onhandshakedone_sym, 0, NULL);
+ MakeCallback(env,
+ conn->handle(node_isolate),
+ env->onhandshakedone_string());
}
}
@@ -2060,9 +2042,7 @@ void Connection::SetSNICallback(const FunctionCallbackInfo<Value>& args) {
#endif
-void CipherBase::Initialize(Handle<Object> target) {
- HandleScope scope(node_isolate);
-
+void CipherBase::Initialize(Environment* env, Handle<Object> target) {
Local<FunctionTemplate> t = FunctionTemplate::New(New);
t->InstanceTemplate()->SetInternalFieldCount(1);
@@ -2215,7 +2195,8 @@ bool CipherBase::Update(const char* data,
void CipherBase::Update(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
CipherBase* cipher = ObjectWrap::Unwrap<CipherBase>(args.This());
@@ -2247,7 +2228,7 @@ void CipherBase::Update(const FunctionCallbackInfo<Value>& args) {
return ThrowCryptoTypeError(ERR_get_error());
}
- Local<Object> buf = Buffer::New(reinterpret_cast<char*>(out), out_len);
+ Local<Object> buf = Buffer::New(env, reinterpret_cast<char*>(out), out_len);
if (out) delete[] out;
args.GetReturnValue().Set(buf);
@@ -2280,7 +2261,8 @@ bool CipherBase::Final(unsigned char** out, int *out_len) {
void CipherBase::Final(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
CipherBase* cipher = ObjectWrap::Unwrap<CipherBase>(args.This());
@@ -2298,13 +2280,11 @@ void CipherBase::Final(const FunctionCallbackInfo<Value>& args) {
}
args.GetReturnValue().Set(
- Buffer::New(reinterpret_cast<char*>(out_value), out_len));
+ Buffer::New(env, reinterpret_cast<char*>(out_value), out_len));
}
-void Hmac::Initialize(v8::Handle<v8::Object> target) {
- HandleScope scope(node_isolate);
-
+void Hmac::Initialize(Environment* env, v8::Handle<v8::Object> target) {
Local<FunctionTemplate> t = FunctionTemplate::New(New);
t->InstanceTemplate()->SetInternalFieldCount(1);
@@ -2434,9 +2414,7 @@ void Hmac::HmacDigest(const FunctionCallbackInfo<Value>& args) {
}
-void Hash::Initialize(v8::Handle<v8::Object> target) {
- HandleScope scope(node_isolate);
-
+void Hash::Initialize(Environment* env, v8::Handle<v8::Object> target) {
Local<FunctionTemplate> t = FunctionTemplate::New(New);
t->InstanceTemplate()->SetInternalFieldCount(1);
@@ -2543,9 +2521,7 @@ void Hash::HashDigest(const FunctionCallbackInfo<Value>& args) {
}
-void Sign::Initialize(v8::Handle<v8::Object> target) {
- HandleScope scope(node_isolate);
-
+void Sign::Initialize(Environment* env, v8::Handle<v8::Object> target) {
Local<FunctionTemplate> t = FunctionTemplate::New(New);
t->InstanceTemplate()->SetInternalFieldCount(1);
@@ -2688,9 +2664,7 @@ void Sign::SignFinal(const FunctionCallbackInfo<Value>& args) {
}
-void Verify::Initialize(v8::Handle<v8::Object> target) {
- HandleScope scope(node_isolate);
-
+void Verify::Initialize(Environment* env, v8::Handle<v8::Object> target) {
Local<FunctionTemplate> t = FunctionTemplate::New(New);
t->InstanceTemplate()->SetInternalFieldCount(1);
@@ -2891,9 +2865,7 @@ void Verify::VerifyFinal(const FunctionCallbackInfo<Value>& args) {
}
-void DiffieHellman::Initialize(v8::Handle<v8::Object> target) {
- HandleScope scope(node_isolate);
-
+void DiffieHellman::Initialize(Environment* env, Handle<Object> target) {
Local<FunctionTemplate> t = FunctionTemplate::New(New);
t->InstanceTemplate()->SetInternalFieldCount(1);
@@ -3244,8 +3216,10 @@ bool DiffieHellman::VerifyContext() {
}
+// TODO(bnoordhuis) Turn into proper RAII class.
struct pbkdf2_req {
uv_work_t work_req;
+ Environment* env;
int err;
char* pass;
size_t passlen;
@@ -3299,7 +3273,9 @@ void EIO_PBKDF2After(pbkdf2_req* req, Local<Value> argv[2]) {
void EIO_PBKDF2After(uv_work_t* work_req, int status) {
assert(status == 0);
pbkdf2_req* req = container_of(work_req, pbkdf2_req, work_req);
- HandleScope scope(node_isolate);
+ Environment* env = req->env;
+ Context::Scope context_scope(env->context());
+ HandleScope handle_scope(env->isolate());
// Create a new Local that's associated with the current HandleScope.
// PersistentToLocal() returns a handle that gets zeroed when we call
// Dispose() so don't use that.
@@ -3307,12 +3283,13 @@ void EIO_PBKDF2After(uv_work_t* work_req, int status) {
req->obj.Dispose();
Local<Value> argv[2];
EIO_PBKDF2After(req, argv);
- MakeCallback(obj, "ondone", ARRAY_SIZE(argv), argv);
+ MakeCallback(env, obj, "ondone", ARRAY_SIZE(argv), argv);
}
void PBKDF2(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
const char* type_error = NULL;
char* pass = NULL;
@@ -3375,6 +3352,7 @@ void PBKDF2(const FunctionCallbackInfo<Value>& args) {
}
req = new pbkdf2_req;
+ req->env = env;
req->err = 0;
req->pass = pass;
req->passlen = passlen;
@@ -3387,9 +3365,11 @@ void PBKDF2(const FunctionCallbackInfo<Value>& args) {
if (args[4]->IsFunction()) {
Local<Object> obj = Object::New();
obj->Set(FIXED_ONE_BYTE_STRING(node_isolate, "ondone"), args[4]);
- obj->Set(FIXED_ONE_BYTE_STRING(node_isolate, "domain"), GetDomain());
+ if (env->in_domain()) {
+ obj->Set(env->domain_string(), env->domain_array()->Get(0));
+ }
req->obj.Reset(node_isolate, obj);
- uv_queue_work(uv_default_loop(),
+ uv_queue_work(env->event_loop(),
&req->work_req,
EIO_PBKDF2,
EIO_PBKDF2After);
@@ -3411,8 +3391,10 @@ void PBKDF2(const FunctionCallbackInfo<Value>& args) {
}
+// TODO(bnoordhuis) Turn into proper RAII class.
struct RandomBytesRequest {
~RandomBytesRequest();
+ Environment* env_;
Persistent<Object> obj_;
unsigned long error_; // openssl error code or zero
uv_work_t work_req_;
@@ -3474,17 +3456,21 @@ void RandomBytesAfter(uv_work_t* work_req, int status) {
RandomBytesRequest* req = container_of(work_req,
RandomBytesRequest,
work_req_);
- HandleScope scope(node_isolate);
+ Environment* env = req->env_;
+ Context::Scope context_scope(env->context());
+ HandleScope handle_scope(env->isolate());
Local<Value> argv[2];
RandomBytesCheck(req, argv);
- MakeCallback(req->obj_, "ondone", ARRAY_SIZE(argv), argv);
+ Local<Object> obj = PersistentToLocal(node_isolate, req->obj_);
+ MakeCallback(env, obj, "ondone", ARRAY_SIZE(argv), argv);
delete req;
}
template <bool pseudoRandom>
void RandomBytes(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
// maybe allow a buffer to write to? cuts down on object creation
// when generating random data in a loop
@@ -3498,6 +3484,7 @@ void RandomBytes(const FunctionCallbackInfo<Value>& args) {
}
RandomBytesRequest* req = new RandomBytesRequest();
+ req->env_ = env;
req->error_ = 0;
req->size_ = size;
req->data_ = static_cast<char*>(malloc(size));
@@ -3511,10 +3498,12 @@ void RandomBytes(const FunctionCallbackInfo<Value>& args) {
if (args[1]->IsFunction()) {
Local<Object> obj = Object::New();
obj->Set(FIXED_ONE_BYTE_STRING(node_isolate, "ondone"), args[1]);
- obj->Set(FIXED_ONE_BYTE_STRING(node_isolate, "domain"), GetDomain());
+ if (env->in_domain()) {
+ obj->Set(env->domain_string(), env->domain_array()->Get(0));
+ }
req->obj_.Reset(node_isolate, obj);
- uv_queue_work(uv_default_loop(),
+ uv_queue_work(env->event_loop(),
&req->work_req_,
RandomBytesWork<pseudoRandom>,
RandomBytesAfter);
@@ -3588,9 +3577,7 @@ void GetHashes(const FunctionCallbackInfo<Value>& args) {
}
-void InitCrypto(Handle<Object> target) {
- HandleScope scope(node_isolate);
-
+void InitCryptoOnce() {
SSL_library_init();
OpenSSL_add_all_algorithms();
OpenSSL_add_all_digests();
@@ -3601,7 +3588,7 @@ void InitCrypto(Handle<Object> target) {
CRYPTO_set_locking_callback(crypto_lock_cb);
CRYPTO_THREADID_set_callback(crypto_threadid_cb);
- // Turn off compression. Saves memory - do it in userland.
+ // Turn off compression. Saves memory and protects against BEAST attacks.
#if !defined(OPENSSL_NO_COMP)
#if OPENSSL_VERSION_NUMBER < 0x00908000L
STACK_OF(SSL_COMP)* comp_methods = SSL_COMP_get_compression_method();
@@ -3611,15 +3598,25 @@ void InitCrypto(Handle<Object> target) {
sk_SSL_COMP_zero(comp_methods);
assert(sk_SSL_COMP_num(comp_methods) == 0);
#endif
+}
+
- SecureContext::Initialize(target);
- Connection::Initialize(target);
- CipherBase::Initialize(target);
- DiffieHellman::Initialize(target);
- Hmac::Initialize(target);
- Hash::Initialize(target);
- Sign::Initialize(target);
- Verify::Initialize(target);
+// FIXME(bnoordhuis) Handle global init correctly.
+void InitCrypto(Handle<Object> target,
+ Handle<Value> unused,
+ Handle<Context> context) {
+ static uv_once_t init_once = UV_ONCE_INIT;
+ uv_once(&init_once, InitCryptoOnce);
+
+ Environment* env = Environment::GetCurrent(context);
+ SecureContext::Initialize(env, target);
+ Connection::Initialize(env, target);
+ CipherBase::Initialize(env, target);
+ DiffieHellman::Initialize(env, target);
+ Hmac::Initialize(env, target);
+ Hash::Initialize(env, target);
+ Sign::Initialize(env, target);
+ Verify::Initialize(env, target);
NODE_SET_METHOD(target, "PBKDF2", PBKDF2);
NODE_SET_METHOD(target, "randomBytes", RandomBytes<false>);
@@ -3627,21 +3624,9 @@ void InitCrypto(Handle<Object> target) {
NODE_SET_METHOD(target, "getSSLCiphers", GetSSLCiphers);
NODE_SET_METHOD(target, "getCiphers", GetCiphers);
NODE_SET_METHOD(target, "getHashes", GetHashes);
-
- subject_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "subject");
- issuer_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "issuer");
- valid_from_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "valid_from");
- valid_to_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "valid_to");
- subjectaltname_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "subjectaltname");
- modulus_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "modulus");
- exponent_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "exponent");
- fingerprint_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "fingerprint");
- name_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "name");
- version_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "version");
- ext_key_usage_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "ext_key_usage");
}
} // namespace crypto
} // namespace node
-NODE_MODULE(node_crypto, node::crypto::InitCrypto)
+NODE_MODULE_CONTEXT_AWARE(node_crypto, node::crypto::InitCrypto)
diff --git a/src/node_crypto.h b/src/node_crypto.h
index b1c2c7fb07..2ae8794031 100644
--- a/src/node_crypto.h
+++ b/src/node_crypto.h
@@ -31,6 +31,7 @@
#include "node_buffer.h"
#endif
+#include "env.h"
#include "v8.h"
#include <openssl/ssl.h>
@@ -58,10 +59,14 @@ class Connection;
class SecureContext : ObjectWrap {
public:
- static void Initialize(v8::Handle<v8::Object> target);
+ static void Initialize(Environment* env, v8::Handle<v8::Object> target);
+
+ inline Environment* env() const {
+ return env_;
+ }
- SSL_CTX* ctx_;
X509_STORE* ca_store_;
+ SSL_CTX* ctx_;
static const int kMaxSessionSize = 10 * 1024;
@@ -85,9 +90,11 @@ class SecureContext : ObjectWrap {
static void GetTicketKeys(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetTicketKeys(const v8::FunctionCallbackInfo<v8::Value>& args);
- SecureContext() : ObjectWrap() {
- ctx_ = NULL;
- ca_store_ = NULL;
+ explicit SecureContext(Environment* env)
+ : ObjectWrap()
+ , ca_store_(NULL)
+ , ctx_(NULL)
+ , env_(env) {
}
void FreeCTXMem() {
@@ -112,6 +119,7 @@ class SecureContext : ObjectWrap {
}
private:
+ Environment* const env_;
};
template <class Base>
@@ -122,9 +130,11 @@ class SSLWrap {
kServer
};
- SSLWrap(SecureContext* sc, Kind kind) : kind_(kind),
- next_sess_(NULL),
- session_callbacks_(false) {
+ SSLWrap(Environment* env, SecureContext* sc, Kind kind)
+ : env_(env)
+ , kind_(kind)
+ , next_sess_(NULL)
+ , session_callbacks_(false) {
ssl_ = SSL_new(sc->ctx_);
assert(ssl_ != NULL);
}
@@ -190,6 +200,11 @@ class SSLWrap {
void* arg);
#endif // OPENSSL_NPN_NEGOTIATED
+ inline Environment* env() const {
+ return env_;
+ }
+
+ Environment* const env_;
Kind kind_;
SSL_SESSION* next_sess_;
SSL* ssl_;
@@ -206,7 +221,7 @@ class SSLWrap {
class Connection : public SSLWrap<Connection>, public ObjectWrap {
public:
- static void Initialize(v8::Handle<v8::Object> target);
+ static void Initialize(Environment* env, v8::Handle<v8::Object> target);
#ifdef OPENSSL_NPN_NEGOTIATED
v8::Persistent<v8::Object> npnProtos_;
@@ -263,10 +278,13 @@ class Connection : public SSLWrap<Connection>, public ObjectWrap {
return conn;
}
- Connection(SecureContext* sc, SSLWrap<Connection>::Kind kind)
- : SSLWrap<Connection>(sc, kind),
- hello_offset_(0) {
- bio_read_ = bio_write_ = NULL;
+ Connection(Environment* env,
+ SecureContext* sc,
+ SSLWrap<Connection>::Kind kind)
+ : SSLWrap<Connection>(env, sc, kind)
+ , bio_read_(NULL)
+ , bio_write_(NULL)
+ , hello_offset_(0) {
hello_parser_.Start(SSLWrap<Connection>::OnClientHello,
OnClientHelloParseEnd,
this);
@@ -296,7 +314,7 @@ class Connection : public SSLWrap<Connection>, public ObjectWrap {
class CipherBase : public ObjectWrap {
public:
- static void Initialize(v8::Handle<v8::Object> target);
+ static void Initialize(Environment* env, v8::Handle<v8::Object> target);
protected:
enum CipherKind {
@@ -340,7 +358,7 @@ class CipherBase : public ObjectWrap {
class Hmac : public ObjectWrap {
public:
- static void Initialize(v8::Handle<v8::Object> target);
+ static void Initialize(Environment* env, v8::Handle<v8::Object> target);
protected:
void HmacInit(const char* hash_type, const char* key, int key_len);
@@ -368,7 +386,7 @@ class Hmac : public ObjectWrap {
class Hash : public ObjectWrap {
public:
- static void Initialize(v8::Handle<v8::Object> target);
+ static void Initialize(Environment* env, v8::Handle<v8::Object> target);
bool HashInit(const char* hash_type);
bool HashUpdate(const char* data, int len);
@@ -394,7 +412,7 @@ class Hash : public ObjectWrap {
class Sign : public ObjectWrap {
public:
- static void Initialize(v8::Handle<v8::Object> target);
+ static void Initialize(Environment* env, v8::Handle<v8::Object> target);
void SignInit(const char* sign_type);
bool SignUpdate(const char* data, int len);
@@ -425,7 +443,7 @@ class Sign : public ObjectWrap {
class Verify : public ObjectWrap {
public:
- static void Initialize(v8::Handle<v8::Object> target);
+ static void Initialize(Environment* env, v8::Handle<v8::Object> target);
void VerifyInit(const char* verify_type);
bool VerifyUpdate(const char* data, int len);
@@ -456,7 +474,7 @@ class Verify : public ObjectWrap {
class DiffieHellman : public ObjectWrap {
public:
- static void Initialize(v8::Handle<v8::Object> target);
+ static void Initialize(Environment* env, v8::Handle<v8::Object> target);
bool Init(int primeLength);
bool Init(const char* p, int p_len);
diff --git a/src/node_file.cc b/src/node_file.cc
index c29c0fda50..fa49dd4bcc 100644
--- a/src/node_file.cc
+++ b/src/node_file.cc
@@ -24,6 +24,9 @@
#include "node_buffer.h"
#include "node_internals.h"
#include "node_stat_watcher.h"
+
+#include "env.h"
+#include "env-inl.h"
#include "req_wrap.h"
#include "string_bytes.h"
@@ -42,6 +45,7 @@
namespace node {
using v8::Array;
+using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
@@ -51,7 +55,6 @@ using v8::Integer;
using v8::Local;
using v8::Number;
using v8::Object;
-using v8::Persistent;
using v8::String;
using v8::Value;
@@ -63,8 +66,9 @@ using v8::Value;
class FSReqWrap: public ReqWrap<uv_fs_t> {
public:
- explicit FSReqWrap(const char* syscall, char* data = NULL)
- : syscall_(syscall)
+ FSReqWrap(Environment* env, const char* syscall, char* data = NULL)
+ : ReqWrap<uv_fs_t>(env)
+ , syscall_(syscall)
, data_(data) {
}
@@ -82,9 +86,6 @@ class FSReqWrap: public ReqWrap<uv_fs_t> {
};
-static Cached<String> oncomplete_sym;
-
-
#define ASSERT_OFFSET(a) \
if (!(a)->IsUndefined() && !(a)->IsNull() && !IsInt64((a)->NumberValue())) { \
return ThrowTypeError("Not an integer"); \
@@ -102,12 +103,14 @@ static inline int IsInt64(double x) {
static void After(uv_fs_t *req) {
- HandleScope scope(node_isolate);
-
FSReqWrap* req_wrap = static_cast<FSReqWrap*>(req->data);
assert(&req_wrap->req_ == req);
req_wrap->ReleaseEarly(); // Free memory that's no longer used now.
+ Environment* env = req_wrap->env();
+ Context::Scope context_scope(env->context());
+ HandleScope handle_scope(env->isolate());
+
// there is always at least one argument. "error"
int argc = 1;
@@ -168,7 +171,8 @@ static void After(uv_fs_t *req) {
case UV_FS_STAT:
case UV_FS_LSTAT:
case UV_FS_FSTAT:
- argv[1] = BuildStatsObject(static_cast<const uv_stat_t*>(req->ptr));
+ argv[1] = BuildStatsObject(env,
+ static_cast<const uv_stat_t*>(req->ptr));
break;
case UV_FS_READLINK:
@@ -209,7 +213,7 @@ static void After(uv_fs_t *req) {
}
}
- MakeCallback(req_wrap->object(), oncomplete_sym, argc, argv);
+ MakeCallback(env, req_wrap->object(), env->oncomplete_string(), argc, argv);
uv_fs_req_cleanup(&req_wrap->req_);
delete req_wrap;
@@ -227,27 +231,31 @@ struct fs_req_wrap {
};
-#define ASYNC_CALL(func, callback, ...) \
- FSReqWrap* req_wrap = new FSReqWrap(#func); \
- int err = uv_fs_ ## func(uv_default_loop(), &req_wrap->req_, \
- __VA_ARGS__, After); \
- req_wrap->object()->Set(oncomplete_sym, callback); \
- req_wrap->Dispatched(); \
- if (err < 0) { \
- uv_fs_t* req = &req_wrap->req_; \
- req->result = err; \
- req->path = NULL; \
- After(req); \
- } \
+#define ASYNC_CALL(func, callback, ...) \
+ Environment* env = Environment::GetCurrent(args.GetIsolate()); \
+ FSReqWrap* req_wrap = new FSReqWrap(env, #func); \
+ int err = uv_fs_ ## func(env->event_loop(), \
+ &req_wrap->req_, \
+ __VA_ARGS__, \
+ After); \
+ req_wrap->object()->Set(env->oncomplete_string(), callback); \
+ req_wrap->Dispatched(); \
+ if (err < 0) { \
+ uv_fs_t* req = &req_wrap->req_; \
+ req->result = err; \
+ req->path = NULL; \
+ After(req); \
+ } \
args.GetReturnValue().Set(req_wrap->persistent());
-#define SYNC_CALL(func, path, ...) \
- fs_req_wrap req_wrap; \
- int err = uv_fs_ ## func(uv_default_loop(), \
- &req_wrap.req, \
- __VA_ARGS__, \
- NULL); \
- if (err < 0) return ThrowUVException(err, #func, NULL, path); \
+#define SYNC_CALL(func, path, ...) \
+ fs_req_wrap req_wrap; \
+ Environment* env = Environment::GetCurrent(args.GetIsolate()); \
+ int err = uv_fs_ ## func(env->event_loop(), \
+ &req_wrap.req, \
+ __VA_ARGS__, \
+ NULL); \
+ if (err < 0) return ThrowUVException(err, #func, NULL, path); \
#define SYNC_REQ req_wrap.req
@@ -271,47 +279,16 @@ static void Close(const FunctionCallbackInfo<Value>& args) {
}
-static Persistent<Function> stats_constructor;
-
-static Cached<String> dev_symbol;
-static Cached<String> ino_symbol;
-static Cached<String> mode_symbol;
-static Cached<String> nlink_symbol;
-static Cached<String> uid_symbol;
-static Cached<String> gid_symbol;
-static Cached<String> rdev_symbol;
-static Cached<String> size_symbol;
-static Cached<String> blksize_symbol;
-static Cached<String> blocks_symbol;
-static Cached<String> atime_symbol;
-static Cached<String> mtime_symbol;
-static Cached<String> ctime_symbol;
-static Cached<String> birthtime_symbol;
-
-Local<Object> BuildStatsObject(const uv_stat_t* s) {
- HandleScope scope(node_isolate);
+Local<Object> BuildStatsObject(Environment* env, const uv_stat_t* s) {
+ // If you hit this assertion, you forgot to enter the v8::Context first.
+ assert(env->context() == env->isolate()->GetCurrentContext());
- if (dev_symbol.IsEmpty()) {
- dev_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "dev");
- ino_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "ino");
- mode_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "mode");
- nlink_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "nlink");
- uid_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "uid");
- gid_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "gid");
- rdev_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "rdev");
- size_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "size");
- blksize_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "blksize");
- blocks_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "blocks");
- atime_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "atime");
- mtime_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "mtime");
- ctime_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "ctime");
- birthtime_symbol = FIXED_ONE_BYTE_STRING(node_isolate, "birthtime");
- }
+ HandleScope handle_scope(env->isolate());
- Local<Function> constructor =
- PersistentToLocal(node_isolate, stats_constructor);
- Local<Object> stats = constructor->NewInstance();
- if (stats.IsEmpty()) return Local<Object>();
+ Local<Object> stats = env->stats_constructor_function()->NewInstance();
+ if (stats.IsEmpty()) {
+ return Local<Object>();
+ }
// The code below is very nasty-looking but it prevents a segmentation fault
// when people run JS code like the snippet below. It's apparently more
@@ -328,7 +305,7 @@ Local<Object> BuildStatsObject(const uv_stat_t* s) {
{ \
Local<Value> val = Integer::New(s->st_##name, node_isolate); \
if (val.IsEmpty()) return Local<Object>(); \
- stats->Set(name##_symbol, val); \
+ stats->Set(env->name ## _string(), val); \
}
X(dev)
X(mode)
@@ -345,7 +322,7 @@ Local<Object> BuildStatsObject(const uv_stat_t* s) {
{ \
Local<Value> val = Number::New(static_cast<double>(s->st_##name)); \
if (val.IsEmpty()) return Local<Object>(); \
- stats->Set(name##_symbol, val); \
+ stats->Set(env->name ## _string(), val); \
}
X(ino)
X(size)
@@ -360,7 +337,7 @@ Local<Object> BuildStatsObject(const uv_stat_t* s) {
msecs += static_cast<double>(s->st_##rec.tv_nsec / 1000000); \
Local<Value> val = v8::Date::New(msecs); \
if (val.IsEmpty()) return Local<Object>(); \
- stats->Set(name##_symbol, val); \
+ stats->Set(env->name ## _string(), val); \
}
X(atime, atim)
X(mtime, mtim)
@@ -368,7 +345,7 @@ Local<Object> BuildStatsObject(const uv_stat_t* s) {
X(birthtime, birthtim)
#undef X
- return scope.Close(stats);
+ return handle_scope.Close(stats);
}
static void Stat(const FunctionCallbackInfo<Value>& args) {
@@ -384,7 +361,7 @@ static void Stat(const FunctionCallbackInfo<Value>& args) {
} else {
SYNC_CALL(stat, *path, *path)
args.GetReturnValue().Set(
- BuildStatsObject(static_cast<const uv_stat_t*>(SYNC_REQ.ptr)));
+ BuildStatsObject(env, static_cast<const uv_stat_t*>(SYNC_REQ.ptr)));
}
}
@@ -401,7 +378,7 @@ static void LStat(const FunctionCallbackInfo<Value>& args) {
} else {
SYNC_CALL(lstat, *path, *path)
args.GetReturnValue().Set(
- BuildStatsObject(static_cast<const uv_stat_t*>(SYNC_REQ.ptr)));
+ BuildStatsObject(env, static_cast<const uv_stat_t*>(SYNC_REQ.ptr)));
}
}
@@ -419,7 +396,7 @@ static void FStat(const FunctionCallbackInfo<Value>& args) {
} else {
SYNC_CALL(fstat, 0, fd)
args.GetReturnValue().Set(
- BuildStatsObject(static_cast<const uv_stat_t*>(SYNC_REQ.ptr)));
+ BuildStatsObject(env, static_cast<const uv_stat_t*>(SYNC_REQ.ptr)));
}
}
@@ -719,7 +696,8 @@ static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
// if null, write from the current position
// 3 enc encoding of string
static void WriteString(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
if (!args[0]->IsInt32())
return ThrowTypeError("First argument must be file descriptor");
@@ -753,15 +731,15 @@ static void WriteString(const FunctionCallbackInfo<Value>& args) {
return args.GetReturnValue().Set(SYNC_RESULT);
}
- FSReqWrap* req_wrap = new FSReqWrap("write", must_free ? buf : NULL);
- int err = uv_fs_write(uv_default_loop(),
+ FSReqWrap* req_wrap = new FSReqWrap(env, "write", must_free ? buf : NULL);
+ int err = uv_fs_write(env->event_loop(),
&req_wrap->req_,
fd,
buf,
len,
pos,
After);
- req_wrap->object()->Set(oncomplete_sym, cb);
+ req_wrap->object()->Set(env->oncomplete_string(), cb);
req_wrap->Dispatched();
if (err < 0) {
uv_fs_t* req = &req_wrap->req_;
@@ -972,8 +950,15 @@ static void FUTimes(const FunctionCallbackInfo<Value>& args) {
}
-void File::Initialize(Handle<Object> target) {
- HandleScope scope(node_isolate);
+void InitFs(Handle<Object> target,
+ Handle<Value> unused,
+ Handle<Context> context) {
+ Environment* env = Environment::GetCurrent(context);
+
+ // Initialize the stats object
+ Local<Function> constructor = FunctionTemplate::New()->GetFunction();
+ target->Set(FIXED_ONE_BYTE_STRING(node_isolate, "Stats"), constructor);
+ env->set_stats_constructor_function(constructor);
NODE_SET_METHOD(target, "close", Close);
NODE_SET_METHOD(target, "open", Open);
@@ -1005,23 +990,10 @@ void File::Initialize(Handle<Object> target) {
NODE_SET_METHOD(target, "utimes", UTimes);
NODE_SET_METHOD(target, "futimes", FUTimes);
-}
-
-void InitFs(Handle<Object> target) {
- HandleScope scope(node_isolate);
-
- // Initialize the stats object
- Local<Function> constructor = FunctionTemplate::New()->GetFunction();
- target->Set(FIXED_ONE_BYTE_STRING(node_isolate, "Stats"), constructor);
- stats_constructor.Reset(node_isolate, constructor);
-
- File::Initialize(target);
-
- oncomplete_sym = FIXED_ONE_BYTE_STRING(node_isolate, "oncomplete");
StatWatcher::Initialize(target);
}
} // end namespace node
-NODE_MODULE(node_fs, node::InitFs)
+NODE_MODULE_CONTEXT_AWARE(node_fs, node::InitFs)
diff --git a/src/node_file.h b/src/node_file.h
index 0a5d270101..dc5deedb0a 100644
--- a/src/node_file.h
+++ b/src/node_file.h
@@ -27,11 +27,6 @@
namespace node {
-class File {
- public:
- static void Initialize(v8::Handle<v8::Object> target);
-};
-
void InitFs(v8::Handle<v8::Object> target);
} // namespace node
diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc
index 80485ec05f..80046a9b7b 100644
--- a/src/node_http_parser.cc
+++ b/src/node_http_parser.cc
@@ -22,6 +22,9 @@
#include "node.h"
#include "node_buffer.h"
#include "node_http_parser.h"
+
+#include "env.h"
+#include "env-inl.h"
#include "v8.h"
#include <stdlib.h> // free()
@@ -48,6 +51,7 @@
namespace node {
using v8::Array;
+using v8::Context;
using v8::Exception;
using v8::Function;
using v8::FunctionCallbackInfo;
@@ -65,32 +69,6 @@ const uint32_t kOnHeadersComplete = 1;
const uint32_t kOnBody = 2;
const uint32_t kOnMessageComplete = 3;
-static Cached<String> method_sym;
-static Cached<String> status_code_sym;
-static Cached<String> http_version_sym;
-static Cached<String> version_major_sym;
-static Cached<String> version_minor_sym;
-static Cached<String> should_keep_alive_sym;
-static Cached<String> upgrade_sym;
-static Cached<String> headers_sym;
-static Cached<String> url_sym;
-
-static Cached<String> unknown_method_sym;
-
-#define X(num, name, string) static Cached<String> name##_sym;
-HTTP_METHOD_MAP(X)
-#undef X
-
-static struct http_parser_settings settings;
-
-
-// This is a hack to get the current_buffer to the callbacks with the least
-// amount of overhead. Nothing else will run while http_parser_execute()
-// runs, therefore this pointer can be set and used for the execution.
-static Local<Value>* current_buffer;
-static char* current_buffer_data;
-static size_t current_buffer_len;
-
#define HTTP_CB(name) \
static int name(http_parser* p_) { \
@@ -108,14 +86,30 @@ static size_t current_buffer_len;
int name##_(const char* at, size_t length)
-static inline Handle<String>
-method_to_str(unsigned short m) {
- switch (m) {
-#define X(num, name, string) case HTTP_##name: return name##_sym;
- HTTP_METHOD_MAP(X)
-#undef X
+// Call this function only when there is a valid HandleScope on the stack
+// somewhere.
+inline Local<String> MethodToString(Environment* env, uint32_t method) {
+ // XXX(bnoordhuis) Predicated on the observation that 99.9% of all HTTP
+ // requests are either GET, HEAD or POST. I threw in DELETE and PUT for
+ // good measure.
+ switch (method) {
+ case HTTP_DELETE: return env->DELETE_string();
+ case HTTP_GET: return env->GET_string();
+ case HTTP_HEAD: return env->HEAD_string();
+ case HTTP_POST: return env->POST_string();
+ case HTTP_PUT: return env->PUT_string();
}
- return unknown_method_sym;
+
+ switch (method) {
+#define V(num, name, string) \
+ case HTTP_ ## name: \
+ return FIXED_ONE_BYTE_STRING(node_isolate, #string);
+ HTTP_METHOD_MAP(V)
+#undef V
+ }
+
+ // Unreachable, http_parser parses only a restricted set of request methods.
+ return FIXED_ONE_BYTE_STRING(node_isolate, "UNKNOWN_METHOD");
}
@@ -193,7 +187,11 @@ struct StringPtr {
class Parser : public ObjectWrap {
public:
- explicit Parser(enum http_parser_type type) : ObjectWrap() {
+ Parser(Environment* env, enum http_parser_type type)
+ : ObjectWrap()
+ , env_(env)
+ , current_buffer_len_(0)
+ , current_buffer_data_(NULL) {
Init(type);
}
@@ -267,34 +265,35 @@ class Parser : public ObjectWrap {
Flush();
} else {
// Fast case, pass headers and URL to JS land.
- message_info->Set(headers_sym, CreateHeaders());
+ message_info->Set(env()->headers_string(), CreateHeaders());
if (parser_.type == HTTP_REQUEST)
- message_info->Set(url_sym, url_.ToString());
+ message_info->Set(env()->url_string(), url_.ToString());
}
num_fields_ = num_values_ = 0;
// METHOD
if (parser_.type == HTTP_REQUEST) {
- message_info->Set(method_sym, method_to_str(parser_.method));
+ message_info->Set(env()->method_string(),
+ MethodToString(env(), parser_.method));
}
// STATUS
if (parser_.type == HTTP_RESPONSE) {
- message_info->Set(status_code_sym,
+ message_info->Set(env()->status_code_string(),
Integer::New(parser_.status_code, node_isolate));
}
// VERSION
- message_info->Set(version_major_sym,
+ message_info->Set(env()->version_major_string(),
Integer::New(parser_.http_major, node_isolate));
- message_info->Set(version_minor_sym,
+ message_info->Set(env()->version_minor_string(),
Integer::New(parser_.http_minor, node_isolate));
- message_info->Set(should_keep_alive_sym,
+ message_info->Set(env()->should_keep_alive_string(),
http_should_keep_alive(&parser_) ? True(node_isolate)
: False(node_isolate));
- message_info->Set(upgrade_sym,
+ message_info->Set(env()->upgrade_string(),
parser_.upgrade ? True(node_isolate)
: False(node_isolate));
@@ -321,9 +320,9 @@ class Parser : public ObjectWrap {
return 0;
Local<Value> argv[3] = {
- *current_buffer,
- Integer::New(at - current_buffer_data, node_isolate),
- Integer::New(length, node_isolate)
+ current_buffer_,
+ Integer::NewFromUnsigned(at - current_buffer_data_, node_isolate),
+ Integer::NewFromUnsigned(length, node_isolate)
};
Local<Value> r = cb.As<Function>()->Call(obj, ARRAY_SIZE(argv), argv);
@@ -361,13 +360,14 @@ class Parser : public ObjectWrap {
static void New(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
http_parser_type type =
static_cast<http_parser_type>(args[0]->Int32Value());
assert(type == HTTP_REQUEST || type == HTTP_RESPONSE);
- Parser* parser = new Parser(type);
+ Parser* parser = new Parser(env, type);
parser->Wrap(args.This());
}
@@ -390,28 +390,21 @@ class Parser : public ObjectWrap {
HandleScope scope(node_isolate);
Parser* parser = ObjectWrap::Unwrap<Parser>(args.This());
+ assert(parser->current_buffer_.IsEmpty());
+ assert(parser->current_buffer_len_ == 0);
+ assert(parser->current_buffer_data_ == NULL);
+ assert(Buffer::HasInstance(args[0]) == true);
- assert(!current_buffer);
- assert(!current_buffer_data);
-
- if (current_buffer) {
- return ThrowTypeError("Already parsing a buffer");
- }
-
- Local<Value> buffer_v = args[0];
-
- if (!Buffer::HasInstance(buffer_v)) {
- return ThrowTypeError("Argument should be a buffer");
- }
-
- Local<Object> buffer_obj = buffer_v->ToObject();
- char *buffer_data = Buffer::Data(buffer_obj);
+ Local<Object> buffer_obj = args[0].As<Object>();
+ char* buffer_data = Buffer::Data(buffer_obj);
size_t buffer_len = Buffer::Length(buffer_obj);
- // Assign 'buffer_' while we parse. The callbacks will access that varible.
- current_buffer = &buffer_v;
- current_buffer_data = buffer_data;
- current_buffer_len = buffer_len;
+ // This is a hack to get the current_buffer to the callbacks with the least
+ // amount of overhead. Nothing else will run while http_parser_execute()
+ // runs, therefore this pointer can be set and used for the execution.
+ parser->current_buffer_ = buffer_obj;
+ parser->current_buffer_len_ = buffer_len;
+ parser->current_buffer_data_ = buffer_data;
parser->got_exception_ = false;
size_t nparsed =
@@ -420,9 +413,9 @@ class Parser : public ObjectWrap {
parser->Save();
// Unassign the 'buffer_' variable
- assert(current_buffer);
- current_buffer = NULL;
- current_buffer_data = NULL;
+ parser->current_buffer_.Clear();
+ parser->current_buffer_len_ = 0;
+ parser->current_buffer_data_ = NULL;
// If there was an exception in one of the callbacks
if (parser->got_exception_) return;
@@ -439,6 +432,7 @@ class Parser : public ObjectWrap {
obj->Set(FIXED_ONE_BYTE_STRING(node_isolate, "bytesParsed"), nparsed_obj);
obj->Set(FIXED_ONE_BYTE_STRING(node_isolate, "code"),
OneByteString(node_isolate, http_errno_name(err)));
+
args.GetReturnValue().Set(e);
} else {
args.GetReturnValue().Set(nparsed_obj);
@@ -451,7 +445,7 @@ class Parser : public ObjectWrap {
Parser* parser = ObjectWrap::Unwrap<Parser>(args.This());
- assert(!current_buffer);
+ assert(parser->current_buffer_.IsEmpty());
parser->got_exception_ = false;
int rv = http_parser_execute(&(parser->parser_), &settings, NULL, 0);
@@ -468,19 +462,23 @@ class Parser : public ObjectWrap {
Integer::New(0, node_isolate));
obj->Set(FIXED_ONE_BYTE_STRING(node_isolate, "code"),
OneByteString(node_isolate, http_errno_name(err)));
+
args.GetReturnValue().Set(e);
}
}
static void Reinitialize(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
http_parser_type type =
static_cast<http_parser_type>(args[0]->Int32Value());
assert(type == HTTP_REQUEST || type == HTTP_RESPONSE);
Parser* parser = ObjectWrap::Unwrap<Parser>(args.This());
+ // Should always be called from the same context.
+ assert(env == parser->env());
parser->Init(type);
}
@@ -536,6 +534,12 @@ class Parser : public ObjectWrap {
}
+ inline Environment* env() const {
+ return env_;
+ }
+
+
+ Environment* const env_;
http_parser parser_;
StringPtr fields_[32]; // header fields
StringPtr values_[32]; // header values
@@ -544,12 +548,27 @@ class Parser : public ObjectWrap {
int num_values_;
bool have_flushed_;
bool got_exception_;
+ Local<Object> current_buffer_;
+ size_t current_buffer_len_;
+ char* current_buffer_data_;
+ static const struct http_parser_settings settings;
};
-void InitHttpParser(Handle<Object> target) {
- HandleScope scope(node_isolate);
+const struct http_parser_settings Parser::settings = {
+ Parser::on_message_begin,
+ Parser::on_url,
+ Parser::on_header_field,
+ Parser::on_header_value,
+ Parser::on_headers_complete,
+ Parser::on_body,
+ Parser::on_message_complete
+};
+
+void InitHttpParser(Handle<Object> target,
+ Handle<Value> unused,
+ Handle<Context> context) {
Local<FunctionTemplate> t = FunctionTemplate::New(Parser::New);
t->InstanceTemplate()->SetInternalFieldCount(1);
t->SetClassName(FIXED_ONE_BYTE_STRING(node_isolate, "HTTPParser"));
@@ -573,33 +592,8 @@ void InitHttpParser(Handle<Object> target) {
target->Set(FIXED_ONE_BYTE_STRING(node_isolate, "HTTPParser"),
t->GetFunction());
-
-#define X(num, name, string) \
- name ## _sym = OneByteString(node_isolate, #string);
- HTTP_METHOD_MAP(X)
-#undef X
- unknown_method_sym = FIXED_ONE_BYTE_STRING(node_isolate, "UNKNOWN_METHOD");
-
- method_sym = FIXED_ONE_BYTE_STRING(node_isolate, "method");
- status_code_sym = FIXED_ONE_BYTE_STRING(node_isolate, "statusCode");
- http_version_sym = FIXED_ONE_BYTE_STRING(node_isolate, "httpVersion");
- version_major_sym = FIXED_ONE_BYTE_STRING(node_isolate, "versionMajor");
- version_minor_sym = FIXED_ONE_BYTE_STRING(node_isolate, "versionMinor");
- should_keep_alive_sym =
- FIXED_ONE_BYTE_STRING(node_isolate, "shouldKeepAlive");
- upgrade_sym = FIXED_ONE_BYTE_STRING(node_isolate, "upgrade");
- headers_sym = FIXED_ONE_BYTE_STRING(node_isolate, "headers");
- url_sym = FIXED_ONE_BYTE_STRING(node_isolate, "url");
-
- settings.on_message_begin = Parser::on_message_begin;
- settings.on_url = Parser::on_url;
- settings.on_header_field = Parser::on_header_field;
- settings.on_header_value = Parser::on_header_value;
- settings.on_headers_complete = Parser::on_headers_complete;
- settings.on_body = Parser::on_body;
- settings.on_message_complete = Parser::on_message_complete;
}
} // namespace node
-NODE_MODULE(node_http_parser, node::InitHttpParser)
+NODE_MODULE_CONTEXT_AWARE(node_http_parser, node::InitHttpParser)
diff --git a/src/node_internals.h b/src/node_internals.h
index ba110a51c8..141bd92ff0 100644
--- a/src/node_internals.h
+++ b/src/node_internals.h
@@ -22,15 +22,16 @@
#ifndef SRC_NODE_INTERNALS_H_
#define SRC_NODE_INTERNALS_H_
+#include "env.h"
+#include "util.h"
+#include "util-inl.h"
+#include "uv.h"
#include "v8.h"
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
-#define FIXED_ONE_BYTE_STRING(isolate, string) \
- (node::OneByteString((isolate), (string), sizeof(string) - 1))
-
struct sockaddr;
namespace node {
@@ -38,36 +39,6 @@ namespace node {
// Defined in node.cc
extern v8::Isolate* node_isolate;
-// Defined in node.cc at startup.
-extern v8::Persistent<v8::Object> process_p;
-
-template <typename TypeName>
-class CachedBase {
- public:
- CachedBase();
- operator v8::Handle<TypeName>() const;
- void operator=(v8::Handle<TypeName> that); // Can only assign once.
- bool IsEmpty() const;
- private:
- CachedBase(const CachedBase&);
- void operator=(const CachedBase&);
- v8::Persistent<TypeName> handle_;
-};
-
-template <typename TypeName>
-class Cached : public CachedBase<TypeName> {
- public:
- operator v8::Handle<v8::Value>() const;
- void operator=(v8::Handle<TypeName> that);
-};
-
-template <>
-class Cached<v8::Value> : public CachedBase<v8::Value> {
- public:
- operator v8::Handle<v8::Value>() const;
- void operator=(v8::Handle<v8::Value> that);
-};
-
// If persistent.IsWeak() == false, then do not call persistent.Dispose()
// while the returned Local<T> is still in scope, it will destroy the
// reference to the object.
@@ -76,55 +47,41 @@ inline v8::Local<TypeName> PersistentToLocal(
v8::Isolate* isolate,
const v8::Persistent<TypeName>& persistent);
-v8::Handle<v8::Value> MakeCallback(
- const v8::Handle<v8::Object> recv,
- uint32_t index,
- int argc,
- v8::Handle<v8::Value>* argv);
-
-template <typename TypeName>
-v8::Handle<v8::Value> MakeCallback(
- const v8::Persistent<v8::Object>& recv,
- const TypeName method,
- int argc,
- v8::Handle<v8::Value>* argv);
-
-template <typename TypeName>
-v8::Handle<v8::Value> MakeCallback(
- const v8::Persistent<v8::Object>& recv,
- const Cached<TypeName>& method,
- int argc,
- v8::Handle<v8::Value>* argv);
-
-inline bool HasInstance(
- const v8::Persistent<v8::FunctionTemplate>& function_template,
- v8::Handle<v8::Value> value);
-
-inline v8::Local<v8::Object> NewInstance(
- const v8::Persistent<v8::Function>& ctor,
- int argc = 0,
- v8::Handle<v8::Value>* argv = NULL);
-
-// Convenience wrapper around v8::String::NewFromOneByte().
-inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
- const char* data,
- int length = -1);
-
-// For the people that compile with -funsigned-char.
-inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
- const signed char* data,
- int length = -1);
-
-inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
- const unsigned char* data,
- int length = -1);
+// Call with valid HandleScope and while inside Context scope.
+v8::Handle<v8::Value> MakeCallback(Environment* env,
+ const v8::Handle<v8::Object> object,
+ const char* method,
+ int argc = 0,
+ v8::Handle<v8::Value>* argv = NULL);
+
+// Call with valid HandleScope and while inside Context scope.
+v8::Handle<v8::Value> MakeCallback(Environment* env,
+ const v8::Handle<v8::Object> object,
+ uint32_t index,
+ int argc = 0,
+ v8::Handle<v8::Value>* argv = NULL);
+
+// Call with valid HandleScope and while inside Context scope.
+v8::Handle<v8::Value> MakeCallback(Environment* env,
+ const v8::Handle<v8::Object> object,
+ const v8::Handle<v8::String> symbol,
+ int argc = 0,
+ v8::Handle<v8::Value>* argv = NULL);
+
+// Call with valid HandleScope and while inside Context scope.
+v8::Handle<v8::Value> MakeCallback(Environment* env,
+ const v8::Handle<v8::Object> object,
+ const v8::Handle<v8::Function> callback,
+ int argc = 0,
+ v8::Handle<v8::Value>* argv = NULL);
// Convert a struct sockaddr to a { address: '1.2.3.4', port: 1234 } JS object.
// Sets address and port properties on the info object and returns it.
// If |info| is omitted, a new object is returned.
v8::Local<v8::Object> AddressToJS(
+ Environment* env,
const sockaddr* addr,
- v8::Handle<v8::Object> info = v8::Handle<v8::Object>());
+ v8::Local<v8::Object> info = v8::Handle<v8::Object>());
#ifdef _WIN32
// emulate snprintf() on windows, _snprintf() doesn't zero-terminate the buffer
@@ -213,6 +170,8 @@ inline static void ThrowUVException(int errorno,
NO_RETURN void FatalError(const char* location, const char* message);
+v8::Local<v8::Object> BuildStatsObject(Environment* env, const uv_stat_t* s);
+
#define NODE_WRAP(Object, Pointer) \
do { \
assert(!Object.IsEmpty()); \
@@ -286,125 +245,6 @@ inline MUST_USE_RESULT bool ParseArrayIndex(v8::Handle<v8::Value> arg,
return true;
}
-template <class TypeName>
-inline v8::Local<TypeName> PersistentToLocal(
- v8::Isolate* isolate,
- const v8::Persistent<TypeName>& persistent) {
- if (persistent.IsWeak()) {
- return v8::Local<TypeName>::New(isolate, persistent);
- } else {
- return *reinterpret_cast<v8::Local<TypeName>*>(
- const_cast<v8::Persistent<TypeName>*>(&persistent));
- }
-}
-
-template <typename TypeName>
-CachedBase<TypeName>::CachedBase() {
-}
-
-template <typename TypeName>
-CachedBase<TypeName>::operator v8::Handle<TypeName>() const {
- return PersistentToLocal(node_isolate, handle_);
-}
-
-template <typename TypeName>
-void CachedBase<TypeName>::operator=(v8::Handle<TypeName> that) {
- assert(handle_.IsEmpty() == true); // Can only assign once.
- handle_.Reset(node_isolate, that);
-}
-
-template <typename TypeName>
-bool CachedBase<TypeName>::IsEmpty() const {
- return handle_.IsEmpty();
-}
-
-template <typename TypeName>
-Cached<TypeName>::operator v8::Handle<v8::Value>() const {
- return CachedBase<TypeName>::operator v8::Handle<TypeName>();
-}
-
-template <typename TypeName>
-void Cached<TypeName>::operator=(v8::Handle<TypeName> that) {
- CachedBase<TypeName>::operator=(that);
-}
-
-inline Cached<v8::Value>::operator v8::Handle<v8::Value>() const {
- return CachedBase<v8::Value>::operator v8::Handle<v8::Value>();
-}
-
-inline void Cached<v8::Value>::operator=(v8::Handle<v8::Value> that) {
- CachedBase<v8::Value>::operator=(that);
-}
-
-template <typename TypeName>
-v8::Handle<v8::Value> MakeCallback(
- const v8::Persistent<v8::Object>& recv,
- const TypeName method,
- int argc,
- v8::Handle<v8::Value>* argv) {
- v8::Local<v8::Object> recv_obj = PersistentToLocal(node_isolate, recv);
- return MakeCallback(recv_obj, method, argc, argv);
-}
-
-template <typename TypeName>
-v8::Handle<v8::Value> MakeCallback(
- const v8::Persistent<v8::Object>& recv,
- const Cached<TypeName>& method,
- int argc,
- v8::Handle<v8::Value>* argv) {
- const v8::Handle<TypeName> handle = method;
- return MakeCallback(recv, handle, argc, argv);
-}
-
-inline bool HasInstance(
- const v8::Persistent<v8::FunctionTemplate>& function_template,
- v8::Handle<v8::Value> value) {
- if (function_template.IsEmpty()) return false;
- v8::Local<v8::FunctionTemplate> function_template_handle =
- PersistentToLocal(node_isolate, function_template);
- return function_template_handle->HasInstance(value);
-}
-
-inline v8::Local<v8::Object> NewInstance(
- const v8::Persistent<v8::Function>& ctor,
- int argc,
- v8::Handle<v8::Value>* argv) {
- v8::Local<v8::Function> constructor_handle =
- PersistentToLocal(node_isolate, ctor);
- return constructor_handle->NewInstance(argc, argv);
-}
-
-inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
- const char* data,
- int length) {
- return v8::String::NewFromOneByte(isolate,
- reinterpret_cast<const uint8_t*>(data),
- v8::String::kNormalString,
- length);
-}
-
-inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
- const signed char* data,
- int length) {
- return v8::String::NewFromOneByte(isolate,
- reinterpret_cast<const uint8_t*>(data),
- v8::String::kNormalString,
- length);
-}
-
-inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
- const unsigned char* data,
- int length) {
- return v8::String::NewFromOneByte(isolate,
- reinterpret_cast<const uint8_t*>(data),
- v8::String::kNormalString,
- length);
-}
-
-bool InDomain();
-
-v8::Handle<v8::Value> GetDomain();
-
} // namespace node
#endif // SRC_NODE_INTERNALS_H_
diff --git a/src/node_os.cc b/src/node_os.cc
index 36506fc6ed..e3d9971e3e 100644
--- a/src/node_os.cc
+++ b/src/node_os.cc
@@ -46,6 +46,7 @@ namespace node {
namespace os {
using v8::Array;
+using v8::Context;
using v8::FunctionCallbackInfo;
using v8::Handle;
using v8::HandleScope;
@@ -275,9 +276,9 @@ static void GetInterfaceAddresses(const FunctionCallbackInfo<Value>& args) {
}
-void Initialize(Handle<Object> target) {
- HandleScope scope(node_isolate);
-
+void Initialize(Handle<Object> target,
+ Handle<Value> unused,
+ Handle<Context> context) {
NODE_SET_METHOD(target, "getEndianness", GetEndianness);
NODE_SET_METHOD(target, "getHostname", GetHostname);
NODE_SET_METHOD(target, "getLoadAvg", GetLoadAvg);
@@ -293,4 +294,4 @@ void Initialize(Handle<Object> target) {
} // namespace os
} // namespace node
-NODE_MODULE(node_os, node::os::Initialize)
+NODE_MODULE_CONTEXT_AWARE(node_os, node::os::Initialize)
diff --git a/src/node_stat_watcher.cc b/src/node_stat_watcher.cc
index fb3cf4f8aa..1cd13c0847 100644
--- a/src/node_stat_watcher.cc
+++ b/src/node_stat_watcher.cc
@@ -20,6 +20,8 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "node_stat_watcher.h"
+#include "env.h"
+#include "env-inl.h"
#include <assert.h>
#include <string.h>
@@ -27,6 +29,7 @@
namespace node {
+using v8::Context;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Handle;
@@ -37,9 +40,6 @@ using v8::Object;
using v8::String;
using v8::Value;
-static Cached<String> onchange_sym;
-static Cached<String> onstop_sym;
-
void StatWatcher::Initialize(Handle<Object> target) {
HandleScope scope(node_isolate);
@@ -61,9 +61,11 @@ static void Delete(uv_handle_t* handle) {
}
-StatWatcher::StatWatcher() : ObjectWrap(),
- watcher_(new uv_fs_poll_t) {
- uv_fs_poll_init(uv_default_loop(), watcher_);
+StatWatcher::StatWatcher(Environment* env)
+ : ObjectWrap()
+ , watcher_(new uv_fs_poll_t)
+ , env_(env) {
+ uv_fs_poll_init(env->event_loop(), watcher_);
watcher_->data = static_cast<void*>(this);
}
@@ -80,16 +82,17 @@ void StatWatcher::Callback(uv_fs_poll_t* handle,
const uv_stat_t* curr) {
StatWatcher* wrap = static_cast<StatWatcher*>(handle->data);
assert(wrap->watcher_ == handle);
- HandleScope scope(node_isolate);
- Local<Value> argv[3];
- argv[0] = BuildStatsObject(curr);
- argv[1] = BuildStatsObject(prev);
- argv[2] = Integer::New(status, node_isolate);
- if (onchange_sym.IsEmpty()) {
- onchange_sym = FIXED_ONE_BYTE_STRING(node_isolate, "onchange");
- }
- MakeCallback(wrap->handle(node_isolate),
- onchange_sym,
+ Environment* env = wrap->env();
+ Context::Scope context_scope(env->context());
+ HandleScope handle_scope(env->isolate());
+ Local<Value> argv[] = {
+ BuildStatsObject(env, curr),
+ BuildStatsObject(env, prev),
+ Integer::New(status, node_isolate)
+ };
+ MakeCallback(env,
+ wrap->handle(node_isolate),
+ env->onchange_string(),
ARRAY_SIZE(argv),
argv);
}
@@ -97,8 +100,9 @@ void StatWatcher::Callback(uv_fs_poll_t* handle,
void StatWatcher::New(const FunctionCallbackInfo<Value>& args) {
assert(args.IsConstructCall());
- HandleScope scope(node_isolate);
- StatWatcher* s = new StatWatcher();
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
+ StatWatcher* s = new StatWatcher(env);
s->Wrap(args.This());
}
@@ -119,12 +123,11 @@ void StatWatcher::Start(const FunctionCallbackInfo<Value>& args) {
void StatWatcher::Stop(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
StatWatcher* wrap = ObjectWrap::Unwrap<StatWatcher>(args.This());
- if (onstop_sym.IsEmpty()) {
- onstop_sym = FIXED_ONE_BYTE_STRING(node_isolate, "onstop");
- }
- MakeCallback(wrap->handle(node_isolate), onstop_sym, 0, NULL);
+ Environment* env = wrap->env();
+ Context::Scope context_scope(env->context());
+ HandleScope handle_scope(env->isolate());
+ MakeCallback(env, wrap->handle(node_isolate), env->onstop_string());
wrap->Stop();
}
diff --git a/src/node_stat_watcher.h b/src/node_stat_watcher.h
index 082608f76a..fd38c8b42f 100644
--- a/src/node_stat_watcher.h
+++ b/src/node_stat_watcher.h
@@ -22,17 +22,21 @@
#ifndef SRC_NODE_STAT_WATCHER_H_
#define SRC_NODE_STAT_WATCHER_H_
-#include "node.h"
+#include "node_object_wrap.h"
+
+#include "env.h"
#include "uv.h"
+#include "v8.h"
namespace node {
class StatWatcher : ObjectWrap {
public:
static void Initialize(v8::Handle<v8::Object> target);
+ inline Environment* env() const { return env_; }
protected:
- StatWatcher();
+ explicit StatWatcher(Environment* env);
virtual ~StatWatcher();
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
@@ -47,6 +51,7 @@ class StatWatcher : ObjectWrap {
void Stop();
uv_fs_poll_t* watcher_;
+ Environment* const env_;
};
} // namespace node
diff --git a/src/node_version.h b/src/node_version.h
index e02b932523..a355cfac53 100644
--- a/src/node_version.h
+++ b/src/node_version.h
@@ -64,6 +64,6 @@
* an API is broken in the C++ side, including in v8 or
* other dependencies.
*/
-#define NODE_MODULE_VERSION 0x000C /* v0.12 */
+#define NODE_MODULE_VERSION 13 /* v0.12 */
#endif /* SRC_NODE_VERSION_H_ */
diff --git a/src/node_wrap.h b/src/node_wrap.h
index 8839a7a50b..0f56f6ddf7 100644
--- a/src/node_wrap.h
+++ b/src/node_wrap.h
@@ -22,38 +22,39 @@
#ifndef SRC_NODE_WRAP_H_
#define SRC_NODE_WRAP_H_
-#include "v8.h"
-#include "uv.h"
-
+#include "env.h"
+#include "env-inl.h"
#include "pipe_wrap.h"
-#include "tty_wrap.h"
#include "tcp_wrap.h"
+#include "tty_wrap.h"
#include "udp_wrap.h"
+#include "uv.h"
+#include "v8.h"
namespace node {
-extern v8::Persistent<v8::FunctionTemplate> pipeConstructorTmpl;
-extern v8::Persistent<v8::FunctionTemplate> ttyConstructorTmpl;
-extern v8::Persistent<v8::FunctionTemplate> tcpConstructorTmpl;
-
-#define WITH_GENERIC_STREAM(obj, BODY) \
- do { \
- if (HasInstance(tcpConstructorTmpl, obj)) { \
- TCPWrap* const wrap = TCPWrap::Unwrap(obj); \
- BODY \
- } else if (HasInstance(ttyConstructorTmpl, obj)) { \
- TTYWrap* const wrap = TTYWrap::Unwrap(obj); \
- BODY \
- } else if (HasInstance(pipeConstructorTmpl, obj)) { \
- PipeWrap* const wrap = PipeWrap::Unwrap(obj); \
- BODY \
- } \
+#define WITH_GENERIC_STREAM(env, obj, BODY) \
+ do { \
+ if (env->tcp_constructor_template().IsEmpty() == false && \
+ env->tcp_constructor_template()->HasInstance(obj)) { \
+ TCPWrap* const wrap = TCPWrap::Unwrap(obj); \
+ BODY \
+ } else if (env->tty_constructor_template().IsEmpty() == false && \
+ env->tty_constructor_template()->HasInstance(obj)) { \
+ TTYWrap* const wrap = TTYWrap::Unwrap(obj); \
+ BODY \
+ } else if (env->pipe_constructor_template().IsEmpty() == false && \
+ env->pipe_constructor_template()->HasInstance(obj)) { \
+ PipeWrap* const wrap = PipeWrap::Unwrap(obj); \
+ BODY \
+ } \
} while (0)
-inline uv_stream_t* HandleToStream(v8::Local<v8::Object> obj) {
+inline uv_stream_t* HandleToStream(Environment* env,
+ v8::Local<v8::Object> obj) {
v8::HandleScope scope(node_isolate);
- WITH_GENERIC_STREAM(obj, {
+ WITH_GENERIC_STREAM(env, obj, {
return reinterpret_cast<uv_stream_t*>(wrap->UVHandle());
});
diff --git a/src/node_zlib.cc b/src/node_zlib.cc
index 91bfb0dd3d..ebc9d2b916 100644
--- a/src/node_zlib.cc
+++ b/src/node_zlib.cc
@@ -21,6 +21,9 @@
#include "node.h"
#include "node_buffer.h"
+
+#include "env.h"
+#include "env-inl.h"
#include "v8.h"
#include "zlib.h"
@@ -31,6 +34,7 @@
namespace node {
+using v8::Context;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Handle;
@@ -42,9 +46,6 @@ using v8::Object;
using v8::String;
using v8::Value;
-static Cached<String> callback_sym;
-static Cached<String> onerror_sym;
-
enum node_zlib_mode {
NONE,
DEFLATE,
@@ -66,19 +67,21 @@ void InitZlib(v8::Handle<v8::Object> target);
class ZCtx : public ObjectWrap {
public:
- explicit ZCtx(node_zlib_mode mode) : ObjectWrap(),
- init_done_(false),
- level_(0),
- windowBits_(0),
- memLevel_(0),
- strategy_(0),
- err_(0),
- dictionary_(NULL),
- dictionary_len_(0),
- flush_(0),
- chunk_size_(0),
- write_in_progress_(false),
- mode_(mode) {
+ ZCtx(Environment* env, node_zlib_mode mode)
+ : ObjectWrap()
+ , chunk_size_(0)
+ , dictionary_(NULL)
+ , dictionary_len_(0)
+ , env_(env)
+ , err_(0)
+ , flush_(0)
+ , init_done_(false)
+ , level_(0)
+ , memLevel_(0)
+ , mode_(mode)
+ , strategy_(0)
+ , windowBits_(0)
+ , write_in_progress_(false) {
}
@@ -87,6 +90,10 @@ class ZCtx : public ObjectWrap {
}
+ inline Environment* env() const {
+ return env_;
+ }
+
void Close() {
assert(!write_in_progress_ && "write in progress");
assert(init_done_ && "close before init");
@@ -182,7 +189,7 @@ class ZCtx : public ObjectWrap {
// set this so that later on, I can easily tell how much was written.
ctx->chunk_size_ = out_len;
- uv_queue_work(uv_default_loop(),
+ uv_queue_work(ctx->env()->event_loop(),
work_req,
ZCtx::Process,
ZCtx::After);
@@ -245,8 +252,11 @@ class ZCtx : public ObjectWrap {
static void After(uv_work_t* work_req, int status) {
assert(status == 0);
- HandleScope scope(node_isolate);
- ZCtx *ctx = container_of(work_req, ZCtx, work_req_);
+ ZCtx* ctx = container_of(work_req, ZCtx, work_req_);
+ Environment* env = ctx->env();
+
+ Context::Scope context_scope(env->context());
+ HandleScope handle_scope(env->isolate());
// Acceptable error states depend on the type of zlib stream.
switch (ctx->err_) {
@@ -275,29 +285,29 @@ class ZCtx : public ObjectWrap {
// call the write() cb
Local<Object> handle = ctx->handle(node_isolate);
- assert(handle->Get(callback_sym)->IsFunction() && "Invalid callback");
Local<Value> args[2] = { avail_in, avail_out };
- MakeCallback(handle, callback_sym, ARRAY_SIZE(args), args);
+ MakeCallback(env, handle, env->callback_string(), ARRAY_SIZE(args), args);
ctx->Unref();
}
- static void Error(ZCtx *ctx, const char *msg_) {
- const char *msg;
+ static void Error(ZCtx* ctx, const char* message) {
+ Environment* env = ctx->env();
+
+ // If you hit this assertion, you forgot to enter the v8::Context first.
+ assert(env->context() == env->isolate()->GetCurrentContext());
+
if (ctx->strm_.msg != NULL) {
- msg = ctx->strm_.msg;
- } else {
- msg = msg_;
+ message = ctx->strm_.msg;
}
Local<Object> handle = ctx->handle(node_isolate);
- assert(handle->Get(onerror_sym)->IsFunction() && "Invalid error handler");
HandleScope scope(node_isolate);
Local<Value> args[2] = {
- OneByteString(node_isolate, msg),
+ OneByteString(node_isolate, message),
Number::New(ctx->err_)
};
- MakeCallback(handle, onerror_sym, ARRAY_SIZE(args), args);
+ MakeCallback(env, handle, env->onerror_string(), ARRAY_SIZE(args), args);
// no hope of rescue.
ctx->write_in_progress_ = false;
@@ -305,7 +315,9 @@ class ZCtx : public ObjectWrap {
}
static void New(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
+
if (args.Length() < 1 || !args[0]->IsInt32()) {
return ThrowTypeError("Bad argument");
}
@@ -315,7 +327,7 @@ class ZCtx : public ObjectWrap {
return ThrowTypeError("Bad argument");
}
- ZCtx *ctx = new ZCtx(mode);
+ ZCtx* ctx = new ZCtx(env, mode);
ctx->Wrap(args.This());
}
@@ -506,33 +518,27 @@ class ZCtx : public ObjectWrap {
static const int kDeflateContextSize = 16384; // approximate
static const int kInflateContextSize = 10240; // approximate
+ int chunk_size_;
+ Bytef* dictionary_;
+ size_t dictionary_len_;
+ Environment* const env_;
+ int err_;
+ int flush_;
bool init_done_;
-
- z_stream strm_;
int level_;
- int windowBits_;
int memLevel_;
+ node_zlib_mode mode_;
int strategy_;
-
- int err_;
-
- Bytef* dictionary_;
- size_t dictionary_len_;
-
- int flush_;
-
- int chunk_size_;
-
- bool write_in_progress_;
-
+ z_stream strm_;
+ int windowBits_;
uv_work_t work_req_;
- node_zlib_mode mode_;
+ bool write_in_progress_;
};
-void InitZlib(Handle<Object> target) {
- HandleScope scope(node_isolate);
-
+void InitZlib(Handle<Object> target,
+ Handle<Value> unused,
+ Handle<Context> context) {
Local<FunctionTemplate> z = FunctionTemplate::New(ZCtx::New);
z->InstanceTemplate()->SetInternalFieldCount(1);
@@ -546,9 +552,6 @@ void InitZlib(Handle<Object> target) {
z->SetClassName(FIXED_ONE_BYTE_STRING(node_isolate, "Zlib"));
target->Set(FIXED_ONE_BYTE_STRING(node_isolate, "Zlib"), z->GetFunction());
- callback_sym = FIXED_ONE_BYTE_STRING(node_isolate, "callback");
- onerror_sym = FIXED_ONE_BYTE_STRING(node_isolate, "onerror");
-
// valid flush values.
NODE_DEFINE_CONSTANT(target, Z_NO_FLUSH);
NODE_DEFINE_CONSTANT(target, Z_PARTIAL_FLUSH);
@@ -593,4 +596,4 @@ void InitZlib(Handle<Object> target) {
} // namespace node
-NODE_MODULE(node_zlib, node::InitZlib)
+NODE_MODULE_CONTEXT_AWARE(node_zlib, node::InitZlib)
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)
diff --git a/src/pipe_wrap.h b/src/pipe_wrap.h
index 944835774d..89330fc724 100644
--- a/src/pipe_wrap.h
+++ b/src/pipe_wrap.h
@@ -21,6 +21,8 @@
#ifndef SRC_PIPE_WRAP_H_
#define SRC_PIPE_WRAP_H_
+
+#include "env.h"
#include "stream_wrap.h"
namespace node {
@@ -29,12 +31,14 @@ class PipeWrap : public StreamWrap {
public:
uv_pipe_t* UVHandle();
- static v8::Local<v8::Object> Instantiate();
+ static v8::Local<v8::Object> Instantiate(Environment* env);
static PipeWrap* Unwrap(v8::Local<v8::Object> obj);
- static void Initialize(v8::Handle<v8::Object> target);
+ static void Initialize(v8::Handle<v8::Object> target,
+ v8::Handle<v8::Value> unused,
+ v8::Handle<v8::Context> context);
private:
- PipeWrap(v8::Handle<v8::Object> object, bool ipc);
+ PipeWrap(Environment* env, v8::Handle<v8::Object> object, bool ipc);
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Bind(const v8::FunctionCallbackInfo<v8::Value>& args);
diff --git a/src/process_wrap.cc b/src/process_wrap.cc
index 1784a163da..bff4e0ba86 100644
--- a/src/process_wrap.cc
+++ b/src/process_wrap.cc
@@ -19,7 +19,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
-#include "node.h"
+#include "env.h"
+#include "env-inl.h"
#include "handle_wrap.h"
#include "node_wrap.h"
@@ -29,6 +30,7 @@
namespace node {
using v8::Array;
+using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
@@ -41,13 +43,11 @@ using v8::Object;
using v8::String;
using v8::Value;
-static Cached<String> onexit_sym;
-
class ProcessWrap : public HandleWrap {
public:
- static void Initialize(Handle<Object> target) {
- HandleScope scope(node_isolate);
-
+ static void Initialize(Handle<Object> target,
+ Handle<Value> unused,
+ Handle<Context> context) {
Local<FunctionTemplate> constructor = FunctionTemplate::New(New);
constructor->InstanceTemplate()->SetInternalFieldCount(1);
constructor->SetClassName(FIXED_ONE_BYTE_STRING(node_isolate, "Process"));
@@ -70,22 +70,25 @@ class ProcessWrap : public HandleWrap {
// Therefore we assert that we are not trying to call this as a
// normal function.
assert(args.IsConstructCall());
- HandleScope scope(node_isolate);
- new ProcessWrap(args.This());
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
+ new ProcessWrap(env, args.This());
}
- explicit ProcessWrap(Handle<Object> object)
- : HandleWrap(object, reinterpret_cast<uv_handle_t*>(&process_)) {
+ ProcessWrap(Environment* env, Handle<Object> object)
+ : HandleWrap(env, object, reinterpret_cast<uv_handle_t*>(&process_)) {
}
~ProcessWrap() {
}
- static void ParseStdioOptions(Local<Object> js_options,
+ static void ParseStdioOptions(Environment* env,
+ Local<Object> js_options,
uv_process_options_t* options) {
Local<String> stdio_key =
FIXED_ONE_BYTE_STRING(node_isolate, "stdio");
Local<Array> stdios = js_options->Get(stdio_key).As<Array>();
+
uint32_t len = stdios->Length();
options->stdio = new uv_stdio_container_t[len];
options->stdio_count = len;
@@ -110,7 +113,7 @@ class ProcessWrap : public HandleWrap {
Local<String> handle_key =
FIXED_ONE_BYTE_STRING(node_isolate, "handle");
Local<Object> handle = stdio->Get(handle_key).As<Object>();
- uv_stream_t* stream = HandleToStream(handle);
+ uv_stream_t* stream = HandleToStream(env, handle);
assert(stream != NULL);
options->stdio[i].flags = UV_INHERIT_STREAM;
@@ -118,7 +121,6 @@ class ProcessWrap : public HandleWrap {
} else {
Local<String> fd_key = FIXED_ONE_BYTE_STRING(node_isolate, "fd");
int fd = static_cast<int>(stdio->Get(fd_key)->IntegerValue());
-
options->stdio[i].flags = UV_INHERIT_FD;
options->stdio[i].data.fd = fd;
}
@@ -126,7 +128,8 @@ class ProcessWrap : public HandleWrap {
}
static void Spawn(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
ProcessWrap* wrap;
NODE_UNWRAP(args.This(), ProcessWrap, wrap);
@@ -216,7 +219,7 @@ class ProcessWrap : public HandleWrap {
}
// options.stdio
- ParseStdioOptions(js_options, &options);
+ ParseStdioOptions(env, js_options, &options);
// options.windows_verbatim_arguments
Local<String> windows_verbatim_arguments_key =
@@ -232,7 +235,7 @@ class ProcessWrap : public HandleWrap {
options.flags |= UV_PROCESS_DETACHED;
}
- int err = uv_spawn(uv_default_loop(), &wrap->process_, &options);
+ int err = uv_spawn(env->event_loop(), &wrap->process_, &options);
if (err == 0) {
assert(wrap->process_.data == wrap);
@@ -268,22 +271,24 @@ class ProcessWrap : public HandleWrap {
static void OnExit(uv_process_t* handle,
int64_t exit_status,
int term_signal) {
- HandleScope scope(node_isolate);
-
ProcessWrap* wrap = static_cast<ProcessWrap*>(handle->data);
- assert(wrap);
+ assert(wrap != NULL);
assert(&wrap->process_ == handle);
+ Environment* env = wrap->env();
+ Context::Scope context_scope(env->context());
+ HandleScope handle_scope(env->isolate());
+
Local<Value> argv[] = {
Number::New(node_isolate, static_cast<double>(exit_status)),
OneByteString(node_isolate, signo_string(term_signal))
};
- if (onexit_sym.IsEmpty()) {
- onexit_sym = FIXED_ONE_BYTE_STRING(node_isolate, "onexit");
- }
-
- MakeCallback(wrap->object(), onexit_sym, ARRAY_SIZE(argv), argv);
+ MakeCallback(env,
+ wrap->object(),
+ env->onexit_string(),
+ ARRAY_SIZE(argv),
+ argv);
}
uv_process_t process_;
@@ -292,4 +297,4 @@ class ProcessWrap : public HandleWrap {
} // namespace node
-NODE_MODULE(node_process_wrap, node::ProcessWrap::Initialize)
+NODE_MODULE_CONTEXT_AWARE(node_process_wrap, node::ProcessWrap::Initialize)
diff --git a/src/req_wrap.h b/src/req_wrap.h
index 44749a3004..8a701e5158 100644
--- a/src/req_wrap.h
+++ b/src/req_wrap.h
@@ -22,29 +22,31 @@
#ifndef SRC_REQ_WRAP_H_
#define SRC_REQ_WRAP_H_
-#include "node.h"
-#include "node_internals.h"
+#include "env.h"
+#include "env-inl.h"
#include "queue.h"
+#include "util.h"
namespace node {
// defined in node.cc
-extern Cached<v8::String> process_symbol;
-extern Cached<v8::String> domain_symbol;
extern QUEUE req_wrap_queue;
template <typename T>
class ReqWrap {
public:
- ReqWrap(v8::Handle<v8::Object> object = v8::Handle<v8::Object>()) {
- v8::HandleScope scope(node_isolate);
- if (object.IsEmpty()) object = v8::Object::New();
- persistent().Reset(node_isolate, object);
-
- if (InDomain()) {
- v8::Local<v8::Value> domain = GetDomain();
- if (domain->IsObject())
- object->Set(domain_symbol, domain);
+ ReqWrap(Environment* env,
+ v8::Handle<v8::Object> object = v8::Handle<v8::Object>())
+ : env_(env) {
+ v8::HandleScope handle_scope(env->isolate());
+
+ if (object.IsEmpty()) {
+ object = v8::Object::New();
+ }
+ persistent().Reset(env->isolate(), object);
+
+ if (env->in_domain()) {
+ object->Set(env->domain_string(), env->domain_array()->Get(0));
}
QUEUE_INSERT_TAIL(&req_wrap_queue, &req_wrap_queue_);
@@ -64,17 +66,25 @@ class ReqWrap {
req_.data = this;
}
+ inline Environment* env() const {
+ return env_;
+ }
+
inline v8::Local<v8::Object> object() {
- return PersistentToLocal(node_isolate, persistent());
+ return PersistentToLocal(env()->isolate(), persistent());
}
inline v8::Persistent<v8::Object>& persistent() {
return object_;
}
- v8::Persistent<v8::Object> object_;
+ // TODO(bnoordhuis) Make these private.
QUEUE req_wrap_queue_;
T req_; // *must* be last, GetActiveRequests() in node.cc depends on it
+
+ private:
+ v8::Persistent<v8::Object> object_;
+ Environment* const env_;
};
diff --git a/src/signal_wrap.cc b/src/signal_wrap.cc
index b9f6d49ff1..a0d62e84a9 100644
--- a/src/signal_wrap.cc
+++ b/src/signal_wrap.cc
@@ -19,12 +19,14 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
-#include "node.h"
+#include "env.h"
+#include "env-inl.h"
#include "handle_wrap.h"
-
+#include "v8.h"
namespace node {
+using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
@@ -33,17 +35,13 @@ using v8::HandleScope;
using v8::Integer;
using v8::Local;
using v8::Object;
-using v8::String;
using v8::Value;
-static Cached<String> onsignal_sym;
-
-
class SignalWrap : public HandleWrap {
public:
- static void Initialize(Handle<Object> target) {
- HandleScope scope(node_isolate);
-
+ static void Initialize(Handle<Object> target,
+ Handle<Value> unused,
+ Handle<Context> context) {
Local<FunctionTemplate> constructor = FunctionTemplate::New(New);
constructor->InstanceTemplate()->SetInternalFieldCount(1);
constructor->SetClassName(FIXED_ONE_BYTE_STRING(node_isolate, "Signal"));
@@ -54,8 +52,6 @@ class SignalWrap : public HandleWrap {
NODE_SET_PROTOTYPE_METHOD(constructor, "start", Start);
NODE_SET_PROTOTYPE_METHOD(constructor, "stop", Stop);
- onsignal_sym = FIXED_ONE_BYTE_STRING(node_isolate, "onsignal");
-
target->Set(FIXED_ONE_BYTE_STRING(node_isolate, "Signal"),
constructor->GetFunction());
}
@@ -66,14 +62,14 @@ class SignalWrap : public HandleWrap {
// Therefore we assert that we are not trying to call this as a
// normal function.
assert(args.IsConstructCall());
-
- HandleScope scope(node_isolate);
- new SignalWrap(args.This());
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
+ new SignalWrap(env, args.This());
}
- explicit SignalWrap(Handle<Object> object)
- : HandleWrap(object, reinterpret_cast<uv_handle_t*>(&handle_)) {
- int r = uv_signal_init(uv_default_loop(), &handle_);
+ SignalWrap(Environment* env, Handle<Object> object)
+ : HandleWrap(env, object, reinterpret_cast<uv_handle_t*>(&handle_)) {
+ int r = uv_signal_init(env->event_loop(), &handle_);
assert(r == 0);
}
@@ -100,13 +96,12 @@ class SignalWrap : public HandleWrap {
}
static void OnSignal(uv_signal_t* handle, int signum) {
- HandleScope scope(node_isolate);
-
SignalWrap* wrap = container_of(handle, SignalWrap, handle_);
- assert(wrap);
-
- Local<Value> argv[1] = { Integer::New(signum, node_isolate) };
- MakeCallback(wrap->object(), onsignal_sym, ARRAY_SIZE(argv), argv);
+ Environment* env = wrap->env();
+ Context::Scope context_scope(env->context());
+ HandleScope handle_scope(env->isolate());
+ Local<Value> arg = Integer::New(signum, env->isolate());
+ MakeCallback(env, wrap->object(), env->onsignal_string(), 1, &arg);
}
uv_signal_t handle_;
@@ -116,4 +111,4 @@ class SignalWrap : public HandleWrap {
} // namespace node
-NODE_MODULE(node_signal_wrap, node::SignalWrap::Initialize)
+NODE_MODULE_CONTEXT_AWARE(node_signal_wrap, node::SignalWrap::Initialize)
diff --git a/src/smalloc.cc b/src/smalloc.cc
index 07eecb9427..62a57fada9 100644
--- a/src/smalloc.cc
+++ b/src/smalloc.cc
@@ -20,11 +20,12 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "smalloc.h"
-#include "node.h"
-#include "node_internals.h"
-#include "v8.h"
+#include "env.h"
+#include "env-inl.h"
+#include "node_internals.h"
#include "v8-profiler.h"
+#include "v8.h"
#include <string.h>
#include <assert.h>
@@ -34,6 +35,7 @@
namespace node {
namespace smalloc {
+using v8::Context;
using v8::External;
using v8::ExternalArrayType;
using v8::FunctionCallbackInfo;
@@ -45,7 +47,6 @@ using v8::Local;
using v8::Object;
using v8::Persistent;
using v8::RetainedObjectInfo;
-using v8::String;
using v8::Uint32;
using v8::Value;
using v8::kExternalUnsignedByteArray;
@@ -64,9 +65,6 @@ void TargetFreeCallback(Isolate* isolate,
Persistent<Object>* target,
CallbackInfo* arg);
-Cached<String> smalloc_sym;
-static bool using_alloc_cb;
-
// return size of external array type, or 0 if unrecognized
size_t ExternalArraySize(enum ExternalArrayType type) {
@@ -299,10 +297,11 @@ void AllocDispose(const FunctionCallbackInfo<Value>& args) {
void AllocDispose(Handle<Object> obj) {
- HandleScope handle_scope(node_isolate);
+ Environment* env = Environment::GetCurrent(node_isolate);
+ HandleScope handle_scope(env->isolate());
- if (using_alloc_cb) {
- Local<Value> ext_v = obj->GetHiddenValue(smalloc_sym);
+ if (env->using_smalloc_alloc_cb()) {
+ Local<Value> ext_v = obj->GetHiddenValue(env->smalloc_p_string());
if (ext_v->IsExternal()) {
Local<External> ext = ext_v.As<External>();
CallbackInfo* cb_info = static_cast<CallbackInfo*>(ext->Value());
@@ -361,16 +360,14 @@ void Alloc(Handle<Object> obj,
enum ExternalArrayType type) {
assert(!obj->HasIndexedPropertiesInExternalArrayData());
- if (smalloc_sym.IsEmpty()) {
- smalloc_sym = FIXED_ONE_BYTE_STRING(node_isolate, "_smalloc_p");
- using_alloc_cb = true;
- }
+ Environment* env = Environment::GetCurrent(node_isolate);
+ env->set_using_smalloc_alloc_cb(true);
CallbackInfo* cb_info = new CallbackInfo;
cb_info->cb = fn;
cb_info->hint = hint;
cb_info->p_obj.Reset(node_isolate, obj);
- obj->SetHiddenValue(smalloc_sym, External::New(cb_info));
+ obj->SetHiddenValue(env->smalloc_p_string(), External::New(cb_info));
node_isolate->AdjustAmountOfExternalAllocatedMemory(length +
sizeof(*cb_info));
@@ -462,7 +459,11 @@ RetainedObjectInfo* WrapperInfo(uint16_t class_id, Handle<Value> wrapper) {
}
-void Initialize(Handle<Object> exports) {
+void Initialize(Handle<Object> exports,
+ Handle<Value> unused,
+ Handle<Context> context) {
+ Environment* env = Environment::GetCurrent(context);
+
NODE_SET_METHOD(exports, "copyOnto", CopyOnto);
NODE_SET_METHOD(exports, "sliceOnto", SliceOnto);
@@ -470,13 +471,9 @@ void Initialize(Handle<Object> exports) {
NODE_SET_METHOD(exports, "dispose", AllocDispose);
exports->Set(FIXED_ONE_BYTE_STRING(node_isolate, "kMaxLength"),
- Uint32::NewFromUnsigned(kMaxLength, node_isolate));
-
- // for performance, begin checking if allocation object may contain
- // callbacks if at least one has been set.
- using_alloc_cb = false;
+ Uint32::NewFromUnsigned(kMaxLength, env->isolate()));
- HeapProfiler* heap_profiler = node_isolate->GetHeapProfiler();
+ HeapProfiler* heap_profiler = env->isolate()->GetHeapProfiler();
heap_profiler->SetWrapperClassInfoProvider(ALLOC_ID, WrapperInfo);
}
@@ -484,4 +481,4 @@ void Initialize(Handle<Object> exports) {
} // namespace smalloc
} // namespace node
-NODE_MODULE(node_smalloc, node::smalloc::Initialize)
+NODE_MODULE_CONTEXT_AWARE(node_smalloc, node::smalloc::Initialize)
diff --git a/src/stream_wrap.cc b/src/stream_wrap.cc
index 6a5ff168d4..49a2f90f46 100644
--- a/src/stream_wrap.cc
+++ b/src/stream_wrap.cc
@@ -20,10 +20,11 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "stream_wrap.h"
-#include "node.h"
+#include "env-inl.h"
+#include "env.h"
+#include "handle_wrap.h"
#include "node_buffer.h"
#include "node_counters.h"
-#include "handle_wrap.h"
#include "pipe_wrap.h"
#include "req_wrap.h"
#include "tcp_wrap.h"
@@ -36,6 +37,7 @@
namespace node {
using v8::Array;
+using v8::Context;
using v8::FunctionCallbackInfo;
using v8::Handle;
using v8::HandleScope;
@@ -49,31 +51,13 @@ using v8::Undefined;
using v8::Value;
-static Cached<String> bytes_sym;
-static Cached<String> write_queue_size_sym;
-static Cached<String> onread_sym;
-static Cached<String> oncomplete_sym;
-static Cached<String> handle_sym;
-static bool initialized;
-
-
-void StreamWrap::Initialize(Handle<Object> target) {
- if (initialized) return;
- initialized = true;
-
- HandleScope scope(node_isolate);
- bytes_sym = FIXED_ONE_BYTE_STRING(node_isolate, "bytes");
- write_queue_size_sym = FIXED_ONE_BYTE_STRING(node_isolate, "writeQueueSize");
- onread_sym = FIXED_ONE_BYTE_STRING(node_isolate, "onread");
- oncomplete_sym = FIXED_ONE_BYTE_STRING(node_isolate, "oncomplete");
-}
-
-
-StreamWrap::StreamWrap(Handle<Object> object, uv_stream_t* stream)
- : HandleWrap(object, reinterpret_cast<uv_handle_t*>(stream)),
- stream_(stream),
- default_callbacks_(this),
- callbacks_(&default_callbacks_) {
+StreamWrap::StreamWrap(Environment* env,
+ Local<Object> object,
+ uv_stream_t* stream)
+ : HandleWrap(env, object, reinterpret_cast<uv_handle_t*>(stream))
+ , stream_(stream)
+ , default_callbacks_(this)
+ , callbacks_(&default_callbacks_) {
}
@@ -95,7 +79,7 @@ void StreamWrap::UpdateWriteQueueSize() {
HandleScope scope(node_isolate);
Local<Integer> write_queue_size =
Integer::NewFromUnsigned(stream()->write_queue_size, node_isolate);
- object()->Set(write_queue_size_sym, write_queue_size);
+ object()->Set(env()->write_queue_size_string(), write_queue_size);
}
@@ -137,12 +121,12 @@ void StreamWrap::OnAlloc(uv_handle_t* handle,
template <class WrapType, class UVType>
-static Local<Object> AcceptHandle(uv_stream_t* pipe) {
+static Local<Object> AcceptHandle(Environment* env, uv_stream_t* pipe) {
HandleScope scope(node_isolate);
Local<Object> wrap_obj;
UVType* handle;
- wrap_obj = WrapType::Instantiate();
+ wrap_obj = WrapType::Instantiate(env);
if (wrap_obj.IsEmpty())
return Local<Object>();
@@ -208,7 +192,8 @@ size_t StreamWrap::WriteBuffer(Handle<Value> val, uv_buf_t* buf) {
void StreamWrap::WriteBuffer(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
StreamWrap* wrap;
NODE_UNWRAP(args.This(), StreamWrap, wrap);
@@ -221,7 +206,8 @@ void StreamWrap::WriteBuffer(const FunctionCallbackInfo<Value>& args) {
size_t length = Buffer::Length(buf_obj);
char* storage = new char[sizeof(WriteWrap)];
- WriteWrap* req_wrap = new(storage) WriteWrap(req_wrap_obj, wrap);
+ WriteWrap* req_wrap =
+ new(storage) WriteWrap(env, req_wrap_obj, wrap);
uv_buf_t buf;
WriteBuffer(buf_obj, &buf);
@@ -232,7 +218,8 @@ void StreamWrap::WriteBuffer(const FunctionCallbackInfo<Value>& args) {
NULL,
StreamWrap::AfterWrite);
req_wrap->Dispatched();
- req_wrap_obj->Set(bytes_sym, Integer::NewFromUnsigned(length, node_isolate));
+ req_wrap_obj->Set(env->bytes_string(),
+ Integer::NewFromUnsigned(length, node_isolate));
if (err) {
req_wrap->~WriteWrap();
@@ -245,7 +232,8 @@ void StreamWrap::WriteBuffer(const FunctionCallbackInfo<Value>& args) {
template <enum encoding encoding>
void StreamWrap::WriteStringImpl(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
int err;
StreamWrap* wrap;
@@ -272,7 +260,8 @@ void StreamWrap::WriteStringImpl(const FunctionCallbackInfo<Value>& args) {
}
char* storage = new char[sizeof(WriteWrap) + storage_size + 15];
- WriteWrap* req_wrap = new(storage) WriteWrap(req_wrap_obj, wrap);
+ WriteWrap* req_wrap =
+ new(storage) WriteWrap(env, req_wrap_obj, wrap);
char* data = reinterpret_cast<char*>(ROUND_UP(
reinterpret_cast<uintptr_t>(storage) + sizeof(WriteWrap), 16));
@@ -301,14 +290,10 @@ void StreamWrap::WriteStringImpl(const FunctionCallbackInfo<Value>& args) {
HandleWrap* wrap;
NODE_UNWRAP(send_handle_obj, HandleWrap, wrap);
send_handle = wrap->GetHandle();
-
// Reference StreamWrap instance to prevent it from being garbage
// collected before `AfterWrite` is called.
- if (handle_sym.IsEmpty()) {
- handle_sym = FIXED_ONE_BYTE_STRING(node_isolate, "handle");
- }
assert(!req_wrap->persistent().IsEmpty());
- req_wrap->object()->Set(handle_sym, send_handle_obj);
+ req_wrap->object()->Set(env->handle_string(), send_handle_obj);
}
err = wrap->callbacks()->DoWrite(
@@ -320,7 +305,8 @@ void StreamWrap::WriteStringImpl(const FunctionCallbackInfo<Value>& args) {
}
req_wrap->Dispatched();
- req_wrap->object()->Set(bytes_sym, Number::New(node_isolate, data_size));
+ req_wrap->object()->Set(env->bytes_string(),
+ Number::New(node_isolate, data_size));
if (err) {
req_wrap->~WriteWrap();
@@ -332,7 +318,8 @@ void StreamWrap::WriteStringImpl(const FunctionCallbackInfo<Value>& args) {
void StreamWrap::Writev(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope;
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
StreamWrap* wrap;
NODE_UNWRAP(args.This(), StreamWrap, wrap);
@@ -378,7 +365,8 @@ void StreamWrap::Writev(const FunctionCallbackInfo<Value>& args) {
storage_size += sizeof(WriteWrap);
char* storage = new char[storage_size];
- WriteWrap* req_wrap = new(storage) WriteWrap(req_wrap_obj, wrap);
+ WriteWrap* req_wrap =
+ new(storage) WriteWrap(env, req_wrap_obj, wrap);
uint32_t bytes = 0;
size_t offset = sizeof(WriteWrap);
@@ -419,7 +407,8 @@ void StreamWrap::Writev(const FunctionCallbackInfo<Value>& args) {
delete[] bufs;
req_wrap->Dispatched();
- req_wrap->object()->Set(bytes_sym, Number::New(node_isolate, bytes));
+ req_wrap->object()->Set(env->bytes_string(),
+ Number::New(node_isolate, bytes));
if (err) {
req_wrap->~WriteWrap();
@@ -448,8 +437,10 @@ void StreamWrap::WriteUcs2String(const FunctionCallbackInfo<Value>& args) {
void StreamWrap::AfterWrite(uv_write_t* req, int status) {
WriteWrap* req_wrap = container_of(req, WriteWrap, req_);
StreamWrap* wrap = req_wrap->wrap();
+ 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);
@@ -457,11 +448,8 @@ void StreamWrap::AfterWrite(uv_write_t* req, int status) {
// Unref handle property
Local<Object> req_wrap_obj = req_wrap->object();
- if (!handle_sym.IsEmpty()) {
- req_wrap_obj->Delete(handle_sym);
- }
-
- wrap->callbacks()->AfterWrite(req_wrap);
+ req_wrap_obj->Delete(env->handle_string());
+ wrap->callbacks_->AfterWrite(req_wrap);
Local<Value> argv[] = {
Integer::New(status, node_isolate),
@@ -469,7 +457,11 @@ void StreamWrap::AfterWrite(uv_write_t* req, int status) {
req_wrap_obj
};
- MakeCallback(req_wrap_obj, oncomplete_sym, ARRAY_SIZE(argv), argv);
+ MakeCallback(env,
+ req_wrap_obj,
+ env->oncomplete_string(),
+ ARRAY_SIZE(argv),
+ argv);
req_wrap->~WriteWrap();
delete[] reinterpret_cast<char*>(req_wrap);
@@ -477,7 +469,8 @@ void StreamWrap::AfterWrite(uv_write_t* req, int status) {
void StreamWrap::Shutdown(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
StreamWrap* wrap;
NODE_UNWRAP(args.This(), StreamWrap, wrap);
@@ -485,7 +478,7 @@ void StreamWrap::Shutdown(const FunctionCallbackInfo<Value>& args) {
assert(args[0]->IsObject());
Local<Object> req_wrap_obj = args[0].As<Object>();
- ShutdownWrap* req_wrap = new ShutdownWrap(req_wrap_obj);
+ ShutdownWrap* req_wrap = new ShutdownWrap(env, req_wrap_obj);
int err = wrap->callbacks()->DoShutdown(req_wrap, AfterShutdown);
req_wrap->Dispatched();
if (err) delete req_wrap;
@@ -496,12 +489,14 @@ void StreamWrap::Shutdown(const FunctionCallbackInfo<Value>& args) {
void StreamWrap::AfterShutdown(uv_shutdown_t* req, int status) {
ShutdownWrap* req_wrap = static_cast<ShutdownWrap*>(req->data);
StreamWrap* wrap = static_cast<StreamWrap*>(req->handle->data);
+ Environment* env = wrap->env();
// The wrap and request objects should still be there.
assert(req_wrap->persistent().IsEmpty() == false);
assert(wrap->persistent().IsEmpty() == false);
- HandleScope scope(node_isolate);
+ Context::Scope context_scope(env->context());
+ HandleScope handle_scope(env->isolate());
Local<Object> req_wrap_obj = req_wrap->object();
Local<Value> argv[3] = {
@@ -510,7 +505,11 @@ void StreamWrap::AfterShutdown(uv_shutdown_t* req, int status) {
req_wrap_obj
};
- 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;
}
@@ -568,7 +567,9 @@ void StreamWrapCallbacks::DoRead(uv_stream_t* handle,
ssize_t nread,
const uv_buf_t* buf,
uv_handle_type pending) {
- HandleScope scope(node_isolate);
+ Environment* env = wrap()->env();
+ Context::Scope context_scope(env->context());
+ HandleScope handle_scope(env->isolate());
Local<Value> argv[] = {
Integer::New(nread, node_isolate),
@@ -579,7 +580,7 @@ void StreamWrapCallbacks::DoRead(uv_stream_t* handle,
if (nread < 0) {
if (buf->base != NULL)
free(buf->base);
- MakeCallback(Self(), onread_sym, ARRAY_SIZE(argv), argv);
+ MakeCallback(env, Self(), env->onread_string(), ARRAY_SIZE(argv), argv);
return;
}
@@ -591,15 +592,15 @@ void StreamWrapCallbacks::DoRead(uv_stream_t* handle,
char* base = static_cast<char*>(realloc(buf->base, nread));
assert(static_cast<size_t>(nread) <= buf->len);
- argv[1] = Buffer::Use(base, nread);
+ argv[1] = Buffer::Use(env, base, nread);
Local<Object> pending_obj;
if (pending == UV_TCP) {
- pending_obj = AcceptHandle<TCPWrap, uv_tcp_t>(handle);
+ pending_obj = AcceptHandle<TCPWrap, uv_tcp_t>(env, handle);
} else if (pending == UV_NAMED_PIPE) {
- pending_obj = AcceptHandle<PipeWrap, uv_pipe_t>(handle);
+ pending_obj = AcceptHandle<PipeWrap, uv_pipe_t>(env, handle);
} else if (pending == UV_UDP) {
- pending_obj = AcceptHandle<UDPWrap, uv_udp_t>(handle);
+ pending_obj = AcceptHandle<UDPWrap, uv_udp_t>(env, handle);
} else {
assert(pending == UV_UNKNOWN_HANDLE);
}
@@ -608,7 +609,11 @@ void StreamWrapCallbacks::DoRead(uv_stream_t* handle,
argv[2] = pending_obj;
}
- MakeCallback(wrap()->object(), onread_sym, ARRAY_SIZE(argv), argv);
+ MakeCallback(env,
+ wrap()->object(),
+ env->onread_string(),
+ ARRAY_SIZE(argv),
+ argv);
}
diff --git a/src/stream_wrap.h b/src/stream_wrap.h
index 6731fdbf75..26fb5d5ef6 100644
--- a/src/stream_wrap.h
+++ b/src/stream_wrap.h
@@ -22,11 +22,11 @@
#ifndef SRC_STREAM_WRAP_H_
#define SRC_STREAM_WRAP_H_
-#include "v8.h"
-#include "node.h"
+#include "env.h"
#include "handle_wrap.h"
#include "req_wrap.h"
#include "string_bytes.h"
+#include "v8.h"
namespace node {
@@ -37,8 +37,8 @@ typedef class ReqWrap<uv_shutdown_t> ShutdownWrap;
class WriteWrap: public ReqWrap<uv_write_t> {
public:
- WriteWrap(v8::Local<v8::Object> obj, StreamWrap* wrap)
- : ReqWrap<uv_write_t>(obj)
+ WriteWrap(Environment* env, v8::Local<v8::Object> obj, StreamWrap* wrap)
+ : ReqWrap<uv_write_t>(env, obj)
, wrap_(wrap) {
}
@@ -108,8 +108,6 @@ class StreamWrap : public HandleWrap {
delete old;
}
- static void Initialize(v8::Handle<v8::Object> target);
-
static void GetFD(v8::Local<v8::String>,
const v8::PropertyCallbackInfo<v8::Value>&);
@@ -148,7 +146,9 @@ class StreamWrap : public HandleWrap {
protected:
static size_t WriteBuffer(v8::Handle<v8::Value> val, uv_buf_t* buf);
- StreamWrap(v8::Handle<v8::Object> object, uv_stream_t* stream);
+ StreamWrap(Environment* env,
+ v8::Local<v8::Object> object,
+ uv_stream_t* stream);
~StreamWrap() {
if (callbacks_ != &default_callbacks_) {
diff --git a/src/tcp_wrap.cc b/src/tcp_wrap.cc
index e007056296..305ee1db2b 100644
--- a/src/tcp_wrap.cc
+++ b/src/tcp_wrap.cc
@@ -20,10 +20,12 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "tcp_wrap.h"
-#include "node.h"
+
+#include "env.h"
+#include "env-inl.h"
+#include "handle_wrap.h"
#include "node_buffer.h"
#include "node_wrap.h"
-#include "handle_wrap.h"
#include "req_wrap.h"
#include "stream_wrap.h"
@@ -32,6 +34,7 @@
namespace node {
+using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
@@ -40,40 +43,32 @@ 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> tcpConstructor;
-static Cached<String> oncomplete_sym;
-static Cached<String> onconnection_sym;
-
-
typedef class ReqWrap<uv_connect_t> ConnectWrap;
-Local<Object> TCPWrap::Instantiate() {
- // If this assert fire then process.binding('tcp_wrap') hasn't been
- // called yet.
- assert(tcpConstructor.IsEmpty() == false);
-
- HandleScope scope(node_isolate);
- Local<Object> obj = NewInstance(tcpConstructor);
-
- return scope.Close(obj);
+Local<Object> TCPWrap::Instantiate(Environment* env) {
+ HandleScope handle_scope(env->isolate());
+ assert(env->tcp_constructor_template().IsEmpty() == false);
+ Local<Function> constructor = env->tcp_constructor_template()->GetFunction();
+ assert(constructor.IsEmpty() == false);
+ Local<Object> instance = constructor->NewInstance();
+ assert(instance.IsEmpty() == false);
+ return handle_scope.Close(instance);
}
-void TCPWrap::Initialize(Handle<Object> target) {
- StreamWrap::Initialize(target);
-
- HandleScope scope(node_isolate);
+void TCPWrap::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, "TCP"));
-
t->InstanceTemplate()->SetInternalFieldCount(1);
enum PropertyAttribute attributes =
@@ -119,12 +114,8 @@ void TCPWrap::Initialize(Handle<Object> target) {
SetSimultaneousAccepts);
#endif
- onconnection_sym = FIXED_ONE_BYTE_STRING(node_isolate, "onconnection");
- oncomplete_sym = FIXED_ONE_BYTE_STRING(node_isolate, "oncomplete");
-
- tcpConstructorTmpl.Reset(node_isolate, t);
- tcpConstructor.Reset(node_isolate, t->GetFunction());
target->Set(FIXED_ONE_BYTE_STRING(node_isolate, "TCP"), t->GetFunction());
+ env->set_tcp_constructor_template(t);
}
@@ -145,15 +136,16 @@ void TCPWrap::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);
- TCPWrap* wrap = new TCPWrap(args.This());
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
+ TCPWrap* wrap = new TCPWrap(env, args.This());
assert(wrap);
}
-TCPWrap::TCPWrap(Handle<Object> object)
- : StreamWrap(object, reinterpret_cast<uv_stream_t*>(&handle_)) {
- int r = uv_tcp_init(uv_default_loop(), &handle_);
+TCPWrap::TCPWrap(Environment* env, Handle<Object> object)
+ : StreamWrap(env, object, reinterpret_cast<uv_stream_t*>(&handle_)) {
+ int r = uv_tcp_init(env->event_loop(), &handle_);
assert(r == 0); // How do we proxy this error up to javascript?
// Suggestion: uv_tcp_init() returns void.
UpdateWriteQueueSize();
@@ -166,7 +158,8 @@ TCPWrap::~TCPWrap() {
void TCPWrap::GetSockName(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
struct sockaddr_storage address;
TCPWrap* wrap;
@@ -181,7 +174,7 @@ void TCPWrap::GetSockName(const FunctionCallbackInfo<Value>& args) {
&addrlen);
if (err == 0) {
const sockaddr* addr = reinterpret_cast<const sockaddr*>(&address);
- AddressToJS(addr, out);
+ AddressToJS(env, addr, out);
}
args.GetReturnValue().Set(err);
@@ -189,7 +182,8 @@ void TCPWrap::GetSockName(const FunctionCallbackInfo<Value>& args) {
void TCPWrap::GetPeerName(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
struct sockaddr_storage address;
TCPWrap* wrap;
@@ -204,7 +198,7 @@ void TCPWrap::GetPeerName(const FunctionCallbackInfo<Value>& args) {
&addrlen);
if (err == 0) {
const sockaddr* addr = reinterpret_cast<const sockaddr*>(&address);
- AddressToJS(addr, out);
+ AddressToJS(env, addr, out);
}
args.GetReturnValue().Set(err);
@@ -311,10 +305,12 @@ void TCPWrap::Listen(const FunctionCallbackInfo<Value>& args) {
void TCPWrap::OnConnection(uv_stream_t* handle, int status) {
- HandleScope scope(node_isolate);
-
TCPWrap* tcp_wrap = static_cast<TCPWrap*>(handle->data);
assert(&tcp_wrap->handle_ == reinterpret_cast<uv_tcp_t*>(handle));
+ Environment* env = tcp_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.
@@ -327,7 +323,7 @@ void TCPWrap::OnConnection(uv_stream_t* handle, int status) {
if (status == 0) {
// Instantiate the client javascript object and handle.
- Local<Object> client_obj = Instantiate();
+ Local<Object> client_obj = Instantiate(env);
// Unwrap the client javascript object.
TCPWrap* wrap;
@@ -340,15 +336,22 @@ void TCPWrap::OnConnection(uv_stream_t* handle, int status) {
argv[1] = client_obj;
}
- MakeCallback(tcp_wrap->object(), onconnection_sym, ARRAY_SIZE(argv), argv);
+ MakeCallback(env,
+ tcp_wrap->object(),
+ env->onconnection_string(),
+ ARRAY_SIZE(argv),
+ argv);
}
void TCPWrap::AfterConnect(uv_connect_t* req, int status) {
ConnectWrap* req_wrap = static_cast<ConnectWrap*>(req->data);
TCPWrap* wrap = static_cast<TCPWrap*>(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);
@@ -362,14 +365,19 @@ void TCPWrap::AfterConnect(uv_connect_t* req, int status) {
v8::True(node_isolate),
v8::True(node_isolate)
};
- 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;
}
void TCPWrap::Connect(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
TCPWrap* wrap;
NODE_UNWRAP(args.This(), TCPWrap, wrap);
@@ -386,7 +394,7 @@ void TCPWrap::Connect(const FunctionCallbackInfo<Value>& args) {
int err = uv_ip4_addr(*ip_address, port, &addr);
if (err == 0) {
- ConnectWrap* req_wrap = new ConnectWrap(req_wrap_obj);
+ ConnectWrap* req_wrap = new ConnectWrap(env, req_wrap_obj);
err = uv_tcp_connect(&req_wrap->req_,
&wrap->handle_,
reinterpret_cast<const sockaddr*>(&addr),
@@ -400,7 +408,8 @@ void TCPWrap::Connect(const FunctionCallbackInfo<Value>& args) {
void TCPWrap::Connect6(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
TCPWrap* wrap;
NODE_UNWRAP(args.This(), TCPWrap, wrap);
@@ -417,7 +426,7 @@ void TCPWrap::Connect6(const FunctionCallbackInfo<Value>& args) {
int err = uv_ip6_addr(*ip_address, port, &addr);
if (err == 0) {
- ConnectWrap* req_wrap = new ConnectWrap(req_wrap_obj);
+ ConnectWrap* req_wrap = new ConnectWrap(env, req_wrap_obj);
err = uv_tcp_connect(&req_wrap->req_,
&wrap->handle_,
reinterpret_cast<const sockaddr*>(&addr),
@@ -431,27 +440,15 @@ void TCPWrap::Connect6(const FunctionCallbackInfo<Value>& args) {
// also used by udp_wrap.cc
-Local<Object> AddressToJS(const sockaddr* addr, Handle<Object> info) {
- static Cached<String> address_sym;
- static Cached<String> family_sym;
- static Cached<String> port_sym;
- static Cached<String> ipv4_sym;
- static Cached<String> ipv6_sym;
-
+Local<Object> AddressToJS(Environment* env,
+ const sockaddr* addr,
+ Local<Object> info) {
HandleScope scope(node_isolate);
char ip[INET6_ADDRSTRLEN];
const sockaddr_in *a4;
const sockaddr_in6 *a6;
int port;
- if (address_sym.IsEmpty()) {
- address_sym = FIXED_ONE_BYTE_STRING(node_isolate, "address");
- family_sym = FIXED_ONE_BYTE_STRING(node_isolate, "family");
- port_sym = FIXED_ONE_BYTE_STRING(node_isolate, "port");
- ipv4_sym = FIXED_ONE_BYTE_STRING(node_isolate, "IPv4");
- ipv6_sym = FIXED_ONE_BYTE_STRING(node_isolate, "IPv6");
- }
-
if (info.IsEmpty()) info = Object::New();
switch (addr->sa_family) {
@@ -459,22 +456,22 @@ Local<Object> AddressToJS(const sockaddr* addr, Handle<Object> info) {
a6 = reinterpret_cast<const sockaddr_in6*>(addr);
uv_inet_ntop(AF_INET6, &a6->sin6_addr, ip, sizeof ip);
port = ntohs(a6->sin6_port);
- info->Set(address_sym, OneByteString(node_isolate, ip));
- info->Set(family_sym, ipv6_sym);
- info->Set(port_sym, Integer::New(port, node_isolate));
+ info->Set(env->address_string(), OneByteString(node_isolate, ip));
+ info->Set(env->family_string(), env->ipv6_string());
+ info->Set(env->port_string(), Integer::New(port, node_isolate));
break;
case AF_INET:
a4 = reinterpret_cast<const sockaddr_in*>(addr);
uv_inet_ntop(AF_INET, &a4->sin_addr, ip, sizeof ip);
port = ntohs(a4->sin_port);
- info->Set(address_sym, OneByteString(node_isolate, ip));
- info->Set(family_sym, ipv4_sym);
- info->Set(port_sym, Integer::New(port, node_isolate));
+ info->Set(env->address_string(), OneByteString(node_isolate, ip));
+ info->Set(env->family_string(), env->ipv4_string());
+ info->Set(env->port_string(), Integer::New(port, node_isolate));
break;
default:
- info->Set(address_sym, String::Empty(node_isolate));
+ info->Set(env->address_string(), String::Empty(node_isolate));
}
return scope.Close(info);
@@ -483,4 +480,4 @@ Local<Object> AddressToJS(const sockaddr* addr, Handle<Object> info) {
} // namespace node
-NODE_MODULE(node_tcp_wrap, node::TCPWrap::Initialize)
+NODE_MODULE_CONTEXT_AWARE(node_tcp_wrap, node::TCPWrap::Initialize)
diff --git a/src/tcp_wrap.h b/src/tcp_wrap.h
index 374458b78d..b1fa4c7f8f 100644
--- a/src/tcp_wrap.h
+++ b/src/tcp_wrap.h
@@ -21,20 +21,24 @@
#ifndef SRC_TCP_WRAP_H_
#define SRC_TCP_WRAP_H_
+
+#include "env.h"
#include "stream_wrap.h"
namespace node {
class TCPWrap : public StreamWrap {
public:
- static v8::Local<v8::Object> Instantiate();
+ static v8::Local<v8::Object> Instantiate(Environment* env);
static TCPWrap* Unwrap(v8::Local<v8::Object> obj);
- static void Initialize(v8::Handle<v8::Object> target);
+ static void Initialize(v8::Handle<v8::Object> target,
+ v8::Handle<v8::Value> unused,
+ v8::Handle<v8::Context> context);
uv_tcp_t* UVHandle();
private:
- explicit TCPWrap(v8::Handle<v8::Object> object);
+ TCPWrap(Environment* env, v8::Handle<v8::Object> object);
~TCPWrap();
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
diff --git a/src/timer_wrap.cc b/src/timer_wrap.cc
index c9782d8713..76b95540f2 100644
--- a/src/timer_wrap.cc
+++ b/src/timer_wrap.cc
@@ -19,13 +19,15 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
-#include "node.h"
+#include "env.h"
+#include "env-inl.h"
#include "handle_wrap.h"
#include <stdint.h>
namespace node {
+using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
@@ -40,9 +42,9 @@ const uint32_t kOnTimeout = 0;
class TimerWrap : public HandleWrap {
public:
- static void Initialize(Handle<Object> target) {
- HandleScope scope(node_isolate);
-
+ static void Initialize(Handle<Object> target,
+ Handle<Value> unused,
+ Handle<Context> context) {
Local<FunctionTemplate> constructor = FunctionTemplate::New(New);
constructor->InstanceTemplate()->SetInternalFieldCount(1);
constructor->SetClassName(FIXED_ONE_BYTE_STRING(node_isolate, "Timer"));
@@ -71,13 +73,14 @@ class TimerWrap : public HandleWrap {
// Therefore we assert that we are not trying to call this as a
// normal function.
assert(args.IsConstructCall());
- HandleScope scope(node_isolate);
- new TimerWrap(args.This());
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
+ new TimerWrap(env, args.This());
}
- explicit TimerWrap(Handle<Object> object)
- : HandleWrap(object, reinterpret_cast<uv_handle_t*>(&handle_)) {
- int r = uv_timer_init(uv_default_loop(), &handle_);
+ TimerWrap(Environment* env, Handle<Object> object)
+ : HandleWrap(env, object, reinterpret_cast<uv_handle_t*>(&handle_)) {
+ int r = uv_timer_init(env->event_loop(), &handle_);
assert(r == 0);
}
@@ -133,19 +136,19 @@ class TimerWrap : public HandleWrap {
}
static void OnTimeout(uv_timer_t* handle, int status) {
- HandleScope scope(node_isolate);
-
TimerWrap* wrap = static_cast<TimerWrap*>(handle->data);
- assert(wrap);
-
+ Environment* env = wrap->env();
+ Context::Scope context_scope(env->context());
+ HandleScope handle_scope(env->isolate());
Local<Value> argv[1] = { Integer::New(status, node_isolate) };
- MakeCallback(wrap->object(), kOnTimeout, ARRAY_SIZE(argv), argv);
+ MakeCallback(env, wrap->object(), kOnTimeout, ARRAY_SIZE(argv), argv);
}
static void Now(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
- uv_update_time(uv_default_loop());
- double now = static_cast<double>(uv_now(uv_default_loop()));
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
+ uv_update_time(env->event_loop());
+ double now = static_cast<double>(uv_now(env->event_loop()));
args.GetReturnValue().Set(now);
}
@@ -155,4 +158,4 @@ class TimerWrap : public HandleWrap {
} // namespace node
-NODE_MODULE(node_timer_wrap, node::TimerWrap::Initialize)
+NODE_MODULE_CONTEXT_AWARE(node_timer_wrap, node::TimerWrap::Initialize)
diff --git a/src/tls_wrap.cc b/src/tls_wrap.cc
index cff2cded8c..e6afda6c0c 100644
--- a/src/tls_wrap.cc
+++ b/src/tls_wrap.cc
@@ -34,6 +34,7 @@ namespace node {
using crypto::SSLWrap;
using crypto::SecureContext;
using v8::Boolean;
+using v8::Context;
using v8::Exception;
using v8::Function;
using v8::FunctionCallbackInfo;
@@ -44,40 +45,20 @@ using v8::Integer;
using v8::Local;
using v8::Null;
using v8::Object;
-using v8::Persistent;
using v8::String;
using v8::Value;
-static Cached<String> onread_sym;
-static Cached<String> onerror_sym;
-static Cached<String> onhandshakestart_sym;
-static Cached<String> onhandshakedone_sym;
-static Cached<String> onclienthello_sym;
-static Cached<String> subject_sym;
-static Cached<String> subjectaltname_sym;
-static Cached<String> modulus_sym;
-static Cached<String> exponent_sym;
-static Cached<String> issuer_sym;
-static Cached<String> valid_from_sym;
-static Cached<String> valid_to_sym;
-static Cached<String> fingerprint_sym;
-static Cached<String> name_sym;
-static Cached<String> version_sym;
-static Cached<String> ext_key_usage_sym;
-static Cached<String> sni_context_sym;
-
-static Persistent<Function> tlsWrap;
-
static const int X509_NAME_FLAGS = ASN1_STRFLGS_ESC_CTRL
| ASN1_STRFLGS_ESC_MSB
| XN_FLAG_SEP_MULTILINE
| XN_FLAG_FN_SN;
-TLSCallbacks::TLSCallbacks(Kind kind,
+TLSCallbacks::TLSCallbacks(Environment* env,
+ Kind kind,
Handle<Object> sc,
StreamWrapCallbacks* old)
- : SSLWrap<TLSCallbacks>(ObjectWrap::Unwrap<SecureContext>(sc), kind),
+ : SSLWrap<TLSCallbacks>(env, ObjectWrap::Unwrap<SecureContext>(sc), kind),
StreamWrapCallbacks(old),
enc_in_(NULL),
enc_out_(NULL),
@@ -92,7 +73,7 @@ TLSCallbacks::TLSCallbacks(Kind kind,
sc_ = ObjectWrap::Unwrap<SecureContext>(sc);
sc_handle_.Reset(node_isolate, sc);
- Local<Object> object = NewInstance(tlsWrap);
+ Local<Object> object = env->tls_wrap_constructor_function()->NewInstance();
NODE_WRAP(object, this);
persistent().Reset(node_isolate, object);
@@ -197,7 +178,8 @@ void TLSCallbacks::InitSSL() {
void TLSCallbacks::Wrap(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
if (args.Length() < 1 || !args[0]->IsObject())
return ThrowTypeError("First argument should be a StreamWrap instance");
@@ -212,8 +194,8 @@ void TLSCallbacks::Wrap(const FunctionCallbackInfo<Value>& args) {
SSLWrap<TLSCallbacks>::kClient;
TLSCallbacks* callbacks = NULL;
- WITH_GENERIC_STREAM(stream, {
- callbacks = new TLSCallbacks(kind, sc, wrap->callbacks());
+ WITH_GENERIC_STREAM(env, stream, {
+ callbacks = new TLSCallbacks(env, kind, sc, wrap->callbacks());
wrap->OverrideCallbacks(callbacks);
});
@@ -243,23 +225,32 @@ void TLSCallbacks::Start(const FunctionCallbackInfo<Value>& args) {
void TLSCallbacks::SSLInfoCallback(const SSL* ssl_, int where, int ret) {
+ if (!(where & (SSL_CB_HANDSHAKE_START | SSL_CB_HANDSHAKE_DONE)))
+ return;
+
// Be compatible with older versions of OpenSSL. SSL_get_app_data() wants
// a non-const SSL* in OpenSSL <= 0.9.7e.
SSL* ssl = const_cast<SSL*>(ssl_);
+ TLSCallbacks* c = static_cast<TLSCallbacks*>(SSL_get_app_data(ssl));
+ Environment* env = c->env();
+ // There should be a Context::Scope a few stack frames down.
+ assert(env->context() == env->isolate()->GetCurrentContext());
+ HandleScope handle_scope(env->isolate());
+ Local<Object> object = c->object(env->isolate());
+
if (where & SSL_CB_HANDSHAKE_START) {
- HandleScope scope(node_isolate);
- TLSCallbacks* c = static_cast<TLSCallbacks*>(SSL_get_app_data(ssl));
- Local<Object> object = c->object(node_isolate);
- if (object->Has(onhandshakestart_sym))
- MakeCallback(object, onhandshakestart_sym, 0, NULL);
+ Local<Value> callback = object->Get(env->onhandshakestart_string());
+ if (callback->IsFunction()) {
+ MakeCallback(env, object, callback.As<Function>());
+ }
}
+
if (where & SSL_CB_HANDSHAKE_DONE) {
- HandleScope scope(node_isolate);
- TLSCallbacks* c = static_cast<TLSCallbacks*>(SSL_get_app_data(ssl));
c->established_ = true;
- Local<Object> object = c->object(node_isolate);
- if (object->Has(onhandshakedone_sym))
- MakeCallback(object, onhandshakedone_sym, 0, NULL);
+ Local<Value> callback = object->Get(env->onhandshakedone_string());
+ if (callback->IsFunction()) {
+ MakeCallback(env, object, callback.As<Function>());
+ }
}
}
@@ -306,9 +297,8 @@ void TLSCallbacks::EncOut() {
void TLSCallbacks::EncOutCb(uv_write_t* req, int status) {
- HandleScope scope(node_isolate);
-
TLSCallbacks* callbacks = static_cast<TLSCallbacks*>(req->data);
+ Environment* env = callbacks->env();
// Handle error
if (status) {
@@ -317,10 +307,16 @@ void TLSCallbacks::EncOutCb(uv_write_t* req, int status) {
return;
// Notify about error
+ Context::Scope context_scope(env->context());
+ HandleScope handle_scope(env->isolate());
Local<Value> arg = String::Concat(
FIXED_ONE_BYTE_STRING(node_isolate, "write cb error, status: "),
Integer::New(status, node_isolate)->ToString());
- MakeCallback(callbacks->object(node_isolate), onerror_sym, 1, &arg);
+ MakeCallback(env,
+ callbacks->object(node_isolate),
+ env->onerror_string(),
+ 1,
+ &arg);
callbacks->InvokeQueued(status);
return;
}
@@ -334,7 +330,7 @@ void TLSCallbacks::EncOutCb(uv_write_t* req, int status) {
}
-Handle<Value> TLSCallbacks::GetSSLError(int status, int* err) {
+Local<Value> TLSCallbacks::GetSSLError(int status, int* err) {
HandleScope scope(node_isolate);
*err = SSL_get_error(ssl_, status);
@@ -365,7 +361,7 @@ Handle<Value> TLSCallbacks::GetSSLError(int status, int* err) {
return scope.Close(exception);
}
}
- return Handle<Value>();
+ return Local<Value>();
}
@@ -374,7 +370,8 @@ void TLSCallbacks::ClearOut() {
if (!hello_parser_.IsEnded())
return;
- HandleScope scope(node_isolate);
+ Context::Scope context_scope(env()->context());
+ HandleScope handle_scope(env()->isolate());
assert(ssl_ != NULL);
@@ -385,9 +382,13 @@ void TLSCallbacks::ClearOut() {
if (read > 0) {
Local<Value> argv[] = {
Integer::New(read, node_isolate),
- Buffer::New(out, read)
+ Buffer::New(env(), out, read)
};
- MakeCallback(Self(), onread_sym, ARRAY_SIZE(argv), argv);
+ MakeCallback(env(),
+ Self(),
+ env()->onread_string(),
+ ARRAY_SIZE(argv),
+ argv);
}
} while (read > 0);
@@ -395,8 +396,13 @@ void TLSCallbacks::ClearOut() {
int err;
Handle<Value> argv = GetSSLError(read, &err);
- if (!argv.IsEmpty())
- MakeCallback(object(node_isolate), onerror_sym, 1, &argv);
+ if (!argv.IsEmpty()) {
+ MakeCallback(env(),
+ object(node_isolate),
+ env()->onerror_string(),
+ 1,
+ &argv);
+ }
}
}
@@ -406,8 +412,6 @@ bool TLSCallbacks::ClearIn() {
if (!hello_parser_.IsEnded())
return false;
- HandleScope scope(node_isolate);
-
int written = 0;
while (clear_in_->Length() > 0) {
size_t avail = 0;
@@ -425,11 +429,19 @@ bool TLSCallbacks::ClearIn() {
return true;
}
+ Context::Scope context_scope(env()->context());
+ HandleScope handle_scope(env()->isolate());
+
// Error or partial write
int err;
Handle<Value> argv = GetSSLError(written, &err);
- if (!argv.IsEmpty())
- MakeCallback(object(node_isolate), onerror_sym, 1, &argv);
+ if (!argv.IsEmpty()) {
+ MakeCallback(env(),
+ object(node_isolate),
+ env()->onerror_string(),
+ 1,
+ &argv);
+ }
return false;
}
@@ -440,8 +452,6 @@ int TLSCallbacks::DoWrite(WriteWrap* w,
size_t count,
uv_stream_t* send_handle,
uv_write_cb cb) {
- HandleScope scope(node_isolate);
-
assert(send_handle == NULL);
// Queue callback to execute it on next tick
@@ -489,9 +499,15 @@ int TLSCallbacks::DoWrite(WriteWrap* w,
if (i != count) {
int err;
+ Context::Scope context_scope(env()->context());
+ HandleScope handle_scope(env()->isolate());
Handle<Value> argv = GetSSLError(written, &err);
if (!argv.IsEmpty()) {
- MakeCallback(object(node_isolate), onerror_sym, 1, &argv);
+ MakeCallback(env(),
+ object(node_isolate),
+ env()->onerror_string(),
+ 1,
+ &argv);
return -1;
}
@@ -527,8 +543,10 @@ void TLSCallbacks::DoRead(uv_stream_t* handle,
if (nread < 0) {
// Error should be emitted only after all data was read
ClearOut();
+ Context::Scope context_scope(env()->context());
+ HandleScope handle_scope(env()->isolate());
Local<Value> arg = Integer::New(nread, node_isolate);
- MakeCallback(Self(), onread_sym, 1, &arg);
+ MakeCallback(env(), Self(), env()->onread_string(), 1, &arg);
return;
}
@@ -664,18 +682,16 @@ int TLSCallbacks::SelectSNIContextCallback(SSL* s, int* ad, void* arg) {
HandleScope scope(node_isolate);
TLSCallbacks* p = static_cast<TLSCallbacks*>(arg);
+ Environment* env = p->env();
const char* servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
if (servername != NULL) {
// Call the SNI callback and use its return value as context
Local<Object> object = p->object(node_isolate);
- Local<Value> ctx;
- if (object->Has(sni_context_sym)) {
- ctx = object->Get(sni_context_sym);
- }
+ Local<Value> ctx = object->Get(env->sni_context_string());
- if (ctx.IsEmpty() || ctx->IsUndefined())
+ if (!ctx->IsObject())
return SSL_TLSEXT_ERR_NOACK;
p->sni_context_.Dispose();
@@ -690,8 +706,10 @@ int TLSCallbacks::SelectSNIContextCallback(SSL* s, int* ad, void* arg) {
#endif // SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
-void TLSCallbacks::Initialize(Handle<Object> target) {
- HandleScope scope(node_isolate);
+void TLSCallbacks::Initialize(Handle<Object> target,
+ Handle<Value> unused,
+ Handle<Context> context) {
+ Environment* env = Environment::GetCurrent(context);
NODE_SET_METHOD(target, "wrap", TLSCallbacks::Wrap);
@@ -715,29 +733,9 @@ void TLSCallbacks::Initialize(Handle<Object> target) {
NODE_SET_PROTOTYPE_METHOD(t, "setServername", SetServername);
#endif // SSL_CRT_SET_TLSEXT_SERVERNAME_CB
- tlsWrap.Reset(node_isolate, t->GetFunction());
-
- onread_sym = FIXED_ONE_BYTE_STRING(node_isolate, "onread");
- onerror_sym = FIXED_ONE_BYTE_STRING(node_isolate, "onerror");
- onhandshakestart_sym =
- FIXED_ONE_BYTE_STRING(node_isolate, "onhandshakestart");
- onhandshakedone_sym = FIXED_ONE_BYTE_STRING(node_isolate, "onhandshakedone");
- onclienthello_sym = FIXED_ONE_BYTE_STRING(node_isolate, "onclienthello");
-
- subject_sym = FIXED_ONE_BYTE_STRING(node_isolate, "subject");
- issuer_sym = FIXED_ONE_BYTE_STRING(node_isolate, "issuer");
- valid_from_sym = FIXED_ONE_BYTE_STRING(node_isolate, "valid_from");
- valid_to_sym = FIXED_ONE_BYTE_STRING(node_isolate, "valid_to");
- subjectaltname_sym = FIXED_ONE_BYTE_STRING(node_isolate, "subjectaltname");
- modulus_sym = FIXED_ONE_BYTE_STRING(node_isolate, "modulus");
- exponent_sym = FIXED_ONE_BYTE_STRING(node_isolate, "exponent");
- fingerprint_sym = FIXED_ONE_BYTE_STRING(node_isolate, "fingerprint");
- name_sym = FIXED_ONE_BYTE_STRING(node_isolate, "name");
- version_sym = FIXED_ONE_BYTE_STRING(node_isolate, "version");
- ext_key_usage_sym = FIXED_ONE_BYTE_STRING(node_isolate, "ext_key_usage");
- sni_context_sym = FIXED_ONE_BYTE_STRING(node_isolate, "sni_context");
+ env->set_tls_wrap_constructor_function(t->GetFunction());
}
} // namespace node
-NODE_MODULE(node_tls_wrap, node::TLSCallbacks::Initialize)
+NODE_MODULE_CONTEXT_AWARE(node_tls_wrap, node::TLSCallbacks::Initialize)
diff --git a/src/tls_wrap.h b/src/tls_wrap.h
index 83f54c3b92..d8f3997923 100644
--- a/src/tls_wrap.h
+++ b/src/tls_wrap.h
@@ -24,6 +24,8 @@
#include "node.h"
#include "node_crypto.h" // SSLWrap
+
+#include "env.h"
#include "queue.h"
#include "stream_wrap.h"
#include "v8.h"
@@ -42,7 +44,9 @@ namespace crypto {
class TLSCallbacks : public crypto::SSLWrap<TLSCallbacks>,
public StreamWrapCallbacks {
public:
- static void Initialize(v8::Handle<v8::Object> target);
+ static void Initialize(v8::Handle<v8::Object> target,
+ v8::Handle<v8::Value> unused,
+ v8::Handle<v8::Context> context);
int DoWrite(WriteWrap* w,
uv_buf_t* bufs,
@@ -82,7 +86,10 @@ class TLSCallbacks : public crypto::SSLWrap<TLSCallbacks>,
QUEUE member_;
};
- TLSCallbacks(Kind kind, v8::Handle<v8::Object> sc, StreamWrapCallbacks* old);
+ TLSCallbacks(Environment* env,
+ Kind kind,
+ v8::Handle<v8::Object> sc,
+ StreamWrapCallbacks* old);
~TLSCallbacks();
static void SSLInfoCallback(const SSL* ssl_, int where, int ret);
@@ -99,7 +106,7 @@ class TLSCallbacks : public crypto::SSLWrap<TLSCallbacks>,
EncOut();
}
- v8::Handle<v8::Value> GetSSLError(int status, int* err);
+ v8::Local<v8::Value> GetSSLError(int status, int* err);
static void OnClientHelloParseEnd(void* arg);
static void Wrap(const v8::FunctionCallbackInfo<v8::Value>& args);
diff --git a/src/tty_wrap.cc b/src/tty_wrap.cc
index 0b675e1bb8..aad19a7e60 100644
--- a/src/tty_wrap.cc
+++ b/src/tty_wrap.cc
@@ -20,9 +20,11 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "tty_wrap.h"
-#include "node.h"
-#include "node_buffer.h"
+
+#include "env.h"
+#include "env-inl.h"
#include "handle_wrap.h"
+#include "node_buffer.h"
#include "node_wrap.h"
#include "req_wrap.h"
#include "stream_wrap.h"
@@ -30,6 +32,7 @@
namespace node {
using v8::Array;
+using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
@@ -43,14 +46,13 @@ using v8::String;
using v8::Value;
-void TTYWrap::Initialize(Handle<Object> target) {
- StreamWrap::Initialize(target);
-
- HandleScope scope(node_isolate);
+void TTYWrap::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, "TTY"));
-
t->InstanceTemplate()->SetInternalFieldCount(1);
enum PropertyAttribute attributes =
@@ -81,8 +83,8 @@ void TTYWrap::Initialize(Handle<Object> target) {
NODE_SET_METHOD(target, "isTTY", IsTTY);
NODE_SET_METHOD(target, "guessHandleType", GuessHandleType);
- ttyConstructorTmpl.Reset(node_isolate, t);
target->Set(FIXED_ONE_BYTE_STRING(node_isolate, "TTY"), t->GetFunction());
+ env->set_tty_constructor_template(t);
}
@@ -162,7 +164,8 @@ void TTYWrap::SetRawMode(const FunctionCallbackInfo<Value>& args) {
void TTYWrap::New(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
// This constructor should not be exposed to public javascript.
// Therefore we assert that we are not trying to call this as a
@@ -172,16 +175,16 @@ void TTYWrap::New(const FunctionCallbackInfo<Value>& args) {
int fd = args[0]->Int32Value();
assert(fd >= 0);
- TTYWrap* wrap = new TTYWrap(args.This(), fd, args[1]->IsTrue());
+ TTYWrap* wrap = new TTYWrap(env, args.This(), fd, args[1]->IsTrue());
wrap->UpdateWriteQueueSize();
}
-TTYWrap::TTYWrap(Handle<Object> object, int fd, bool readable)
- : StreamWrap(object, reinterpret_cast<uv_stream_t*>(&handle_)) {
- uv_tty_init(uv_default_loop(), &handle_, fd, readable);
+TTYWrap::TTYWrap(Environment* env, Handle<Object> object, int fd, bool readable)
+ : StreamWrap(env, object, reinterpret_cast<uv_stream_t*>(&handle_)) {
+ uv_tty_init(env->event_loop(), &handle_, fd, readable);
}
} // namespace node
-NODE_MODULE(node_tty_wrap, node::TTYWrap::Initialize)
+NODE_MODULE_CONTEXT_AWARE(node_tty_wrap, node::TTYWrap::Initialize)
diff --git a/src/tty_wrap.h b/src/tty_wrap.h
index 0475073fdc..4c69b4c88a 100644
--- a/src/tty_wrap.h
+++ b/src/tty_wrap.h
@@ -22,6 +22,7 @@
#ifndef SRC_TTY_WRAP_H_
#define SRC_TTY_WRAP_H_
+#include "env.h"
#include "handle_wrap.h"
#include "stream_wrap.h"
@@ -29,13 +30,18 @@ namespace node {
class TTYWrap : public StreamWrap {
public:
- static void Initialize(v8::Handle<v8::Object> target);
+ static void Initialize(v8::Handle<v8::Object> target,
+ v8::Handle<v8::Value> unused,
+ v8::Handle<v8::Context> context);
static TTYWrap* Unwrap(v8::Local<v8::Object> obj);
uv_tty_t* UVHandle();
private:
- TTYWrap(v8::Handle<v8::Object> object, int fd, bool readable);
+ TTYWrap(Environment* env,
+ v8::Handle<v8::Object> object,
+ int fd,
+ bool readable);
static void GuessHandleType(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsTTY(const v8::FunctionCallbackInfo<v8::Value>& args);
diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc
index 1e5d32269b..fd679ab4d8 100644
--- a/src/udp_wrap.cc
+++ b/src/udp_wrap.cc
@@ -20,7 +20,8 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "udp_wrap.h"
-#include "node.h"
+#include "env.h"
+#include "env-inl.h"
#include "node_buffer.h"
#include "handle_wrap.h"
#include "req_wrap.h"
@@ -30,6 +31,7 @@
namespace node {
+using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
@@ -38,7 +40,6 @@ using v8::HandleScope;
using v8::Integer;
using v8::Local;
using v8::Object;
-using v8::Persistent;
using v8::PropertyAttribute;
using v8::PropertyCallbackInfo;
using v8::String;
@@ -49,20 +50,17 @@ using v8::Value;
class SendWrap : public ReqWrap<uv_udp_send_t> {
public:
- SendWrap(Local<Object> req_wrap_obj, bool have_callback);
+ SendWrap(Environment* env, Local<Object> req_wrap_obj, bool have_callback);
inline bool have_callback() const;
private:
const bool have_callback_;
};
-static Persistent<Function> constructor;
-static Cached<String> oncomplete_sym;
-static Cached<String> onmessage_sym;
-
-
-SendWrap::SendWrap(Local<Object> req_wrap_obj, bool have_callback)
- : ReqWrap<uv_udp_send_t>(req_wrap_obj)
+SendWrap::SendWrap(Environment* env,
+ Local<Object> req_wrap_obj,
+ bool have_callback)
+ : ReqWrap<uv_udp_send_t>(env, req_wrap_obj)
, have_callback_(have_callback) {
}
@@ -72,9 +70,9 @@ inline bool SendWrap::have_callback() const {
}
-UDPWrap::UDPWrap(Handle<Object> object)
- : HandleWrap(object, reinterpret_cast<uv_handle_t*>(&handle_)) {
- int r = uv_udp_init(uv_default_loop(), &handle_);
+UDPWrap::UDPWrap(Environment* env, Handle<Object> object)
+ : HandleWrap(env, object, reinterpret_cast<uv_handle_t*>(&handle_)) {
+ int r = uv_udp_init(env->event_loop(), &handle_);
assert(r == 0); // can't fail anyway
}
@@ -83,11 +81,10 @@ UDPWrap::~UDPWrap() {
}
-void UDPWrap::Initialize(Handle<Object> target) {
- HandleScope scope(node_isolate);
-
- oncomplete_sym = FIXED_ONE_BYTE_STRING(node_isolate, "oncomplete");
- onmessage_sym = FIXED_ONE_BYTE_STRING(node_isolate, "onmessage");
+void UDPWrap::Initialize(Handle<Object> target,
+ Handle<Value> unused,
+ Handle<Context> context) {
+ Environment* env = Environment::GetCurrent(context);
Local<FunctionTemplate> t = FunctionTemplate::New(New);
t->InstanceTemplate()->SetInternalFieldCount(1);
@@ -120,15 +117,16 @@ void UDPWrap::Initialize(Handle<Object> target) {
NODE_SET_PROTOTYPE_METHOD(t, "ref", HandleWrap::Ref);
NODE_SET_PROTOTYPE_METHOD(t, "unref", HandleWrap::Unref);
- constructor.Reset(node_isolate, t->GetFunction());
target->Set(FIXED_ONE_BYTE_STRING(node_isolate, "UDP"), t->GetFunction());
+ env->set_udp_constructor_function(t->GetFunction());
}
void UDPWrap::New(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
assert(args.IsConstructCall());
- new UDPWrap(args.This());
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
+ new UDPWrap(env, args.This());
}
@@ -244,7 +242,8 @@ void UDPWrap::DropMembership(const FunctionCallbackInfo<Value>& args) {
void UDPWrap::DoSend(const FunctionCallbackInfo<Value>& args, int family) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
UDPWrap* wrap;
NODE_UNWRAP(args.This(), UDPWrap, wrap);
@@ -269,7 +268,7 @@ void UDPWrap::DoSend(const FunctionCallbackInfo<Value>& args, int family) {
assert(offset < Buffer::Length(buffer_obj));
assert(length <= Buffer::Length(buffer_obj) - offset);
- SendWrap* req_wrap = new SendWrap(req_wrap_obj, have_callback);
+ SendWrap* req_wrap = new SendWrap(env, req_wrap_obj, have_callback);
uv_buf_t buf = uv_buf_init(Buffer::Data(buffer_obj) + offset,
length);
@@ -337,7 +336,9 @@ void UDPWrap::RecvStop(const FunctionCallbackInfo<Value>& args) {
void UDPWrap::GetSockName(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
+
struct sockaddr_storage address;
UDPWrap* wrap;
NODE_UNWRAP(args.This(), UDPWrap, wrap);
@@ -352,7 +353,7 @@ void UDPWrap::GetSockName(const FunctionCallbackInfo<Value>& args) {
if (err == 0) {
const sockaddr* addr = reinterpret_cast<const sockaddr*>(&address);
- AddressToJS(addr, obj);
+ AddressToJS(env, addr, obj);
}
args.GetReturnValue().Set(err);
@@ -363,10 +364,12 @@ void UDPWrap::GetSockName(const FunctionCallbackInfo<Value>& args) {
void UDPWrap::OnSend(uv_udp_send_t* req, int status) {
SendWrap* req_wrap = static_cast<SendWrap*>(req->data);
if (req_wrap->have_callback()) {
- HandleScope scope(node_isolate);
+ Environment* env = req_wrap->env();
+ Context::Scope context_scope(env->context());
+ HandleScope handle_scope(env->isolate());
Local<Object> req_wrap_obj = req_wrap->object();
Local<Value> arg = Integer::New(status, node_isolate);
- MakeCallback(req_wrap_obj, oncomplete_sym, 1, &arg);
+ MakeCallback(env, req_wrap_obj, env->oncomplete_string(), 1, &arg);
}
delete req_wrap;
}
@@ -397,8 +400,11 @@ void UDPWrap::OnRecv(uv_udp_t* handle,
}
UDPWrap* wrap = static_cast<UDPWrap*>(handle->data);
+ Environment* env = wrap->env();
+
+ Context::Scope context_scope(env->context());
+ HandleScope handle_scope(env->isolate());
- HandleScope scope(node_isolate);
Local<Object> wrap_obj = wrap->object();
Local<Value> argv[] = {
Integer::New(nread, node_isolate),
@@ -410,14 +416,18 @@ void UDPWrap::OnRecv(uv_udp_t* handle,
if (nread < 0) {
if (buf->base != NULL)
free(buf->base);
- MakeCallback(wrap_obj, onmessage_sym, ARRAY_SIZE(argv), argv);
+ MakeCallback(env,
+ wrap_obj,
+ env->onmessage_string(),
+ ARRAY_SIZE(argv),
+ argv);
return;
}
char* base = static_cast<char*>(realloc(buf->base, nread));
- argv[2] = Buffer::Use(base, nread);
- argv[3] = AddressToJS(addr);
- MakeCallback(wrap_obj, onmessage_sym, ARRAY_SIZE(argv), argv);
+ argv[2] = Buffer::Use(env, base, nread);
+ argv[3] = AddressToJS(env, addr);
+ MakeCallback(env, wrap_obj, env->onmessage_string(), ARRAY_SIZE(argv), argv);
}
@@ -428,10 +438,10 @@ UDPWrap* UDPWrap::Unwrap(Local<Object> obj) {
}
-Local<Object> UDPWrap::Instantiate() {
+Local<Object> UDPWrap::Instantiate(Environment* env) {
// If this assert fires then Initialize hasn't been called yet.
- assert(constructor.IsEmpty() == false);
- return NewInstance(constructor);
+ assert(env->udp_constructor_function().IsEmpty() == false);
+ return env->udp_constructor_function()->NewInstance();
}
@@ -442,4 +452,4 @@ uv_udp_t* UDPWrap::UVHandle() {
} // namespace node
-NODE_MODULE(node_udp_wrap, node::UDPWrap::Initialize)
+NODE_MODULE_CONTEXT_AWARE(node_udp_wrap, node::UDPWrap::Initialize)
diff --git a/src/udp_wrap.h b/src/udp_wrap.h
index e0cfc7ba26..b9aa566be2 100644
--- a/src/udp_wrap.h
+++ b/src/udp_wrap.h
@@ -22,15 +22,19 @@
#ifndef SRC_UDP_WRAP_H_
#define SRC_UDP_WRAP_H_
-#include "node.h"
-#include "req_wrap.h"
+#include "env.h"
#include "handle_wrap.h"
+#include "req_wrap.h"
+#include "uv.h"
+#include "v8.h"
namespace node {
class UDPWrap: public HandleWrap {
public:
- static void Initialize(v8::Handle<v8::Object> target);
+ static void Initialize(v8::Handle<v8::Object> target,
+ v8::Handle<v8::Value> unused,
+ v8::Handle<v8::Context> context);
static void GetFD(v8::Local<v8::String>,
const v8::PropertyCallbackInfo<v8::Value>&);
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
@@ -50,11 +54,11 @@ class UDPWrap: public HandleWrap {
static void SetTTL(const v8::FunctionCallbackInfo<v8::Value>& args);
static UDPWrap* Unwrap(v8::Local<v8::Object> obj);
- static v8::Local<v8::Object> Instantiate();
+ static v8::Local<v8::Object> Instantiate(Environment* env);
uv_udp_t* UVHandle();
private:
- explicit UDPWrap(v8::Handle<v8::Object> object);
+ UDPWrap(Environment* env, v8::Handle<v8::Object> object);
virtual ~UDPWrap();
static void DoBind(const v8::FunctionCallbackInfo<v8::Value>& args,
diff --git a/src/util-inl.h b/src/util-inl.h
new file mode 100644
index 0000000000..1ea31d94db
--- /dev/null
+++ b/src/util-inl.h
@@ -0,0 +1,83 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+#ifndef SRC_UTIL_INL_H_
+#define SRC_UTIL_INL_H_
+
+#include "util.h"
+
+namespace node {
+
+template <class TypeName>
+inline v8::Local<TypeName> PersistentToLocal(
+ v8::Isolate* isolate,
+ const v8::Persistent<TypeName>& persistent) {
+ if (persistent.IsWeak()) {
+ return WeakPersistentToLocal(isolate, persistent);
+ } else {
+ return StrongPersistentToLocal(persistent);
+ }
+}
+
+template <class TypeName>
+inline v8::Local<TypeName> StrongPersistentToLocal(
+ const v8::Persistent<TypeName>& persistent) {
+ return *reinterpret_cast<v8::Local<TypeName>*>(
+ const_cast<v8::Persistent<TypeName>*>(&persistent));
+}
+
+template <class TypeName>
+inline v8::Local<TypeName> WeakPersistentToLocal(
+ v8::Isolate* isolate,
+ const v8::Persistent<TypeName>& persistent) {
+ return v8::Local<TypeName>::New(isolate, persistent);
+}
+
+inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
+ const char* data,
+ int length) {
+ return v8::String::NewFromOneByte(isolate,
+ reinterpret_cast<const uint8_t*>(data),
+ v8::String::kNormalString,
+ length);
+}
+
+inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
+ const signed char* data,
+ int length) {
+ return v8::String::NewFromOneByte(isolate,
+ reinterpret_cast<const uint8_t*>(data),
+ v8::String::kNormalString,
+ length);
+}
+
+inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
+ const unsigned char* data,
+ int length) {
+ return v8::String::NewFromOneByte(isolate,
+ reinterpret_cast<const uint8_t*>(data),
+ v8::String::kNormalString,
+ length);
+}
+
+} // namespace node
+
+#endif // SRC_UTIL_INL_H_
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000000..7e71f36c70
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,82 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+#ifndef SRC_UTIL_H_
+#define SRC_UTIL_H_
+
+#include "v8.h"
+#include <stddef.h>
+
+namespace node {
+
+#define OFFSET_OF(TypeName, Field) \
+ (reinterpret_cast<uintptr_t>(&(reinterpret_cast<TypeName*>(8)->Field)) - 8)
+
+#define CONTAINER_OF(Pointer, TypeName, Field) \
+ reinterpret_cast<TypeName*>( \
+ reinterpret_cast<uintptr_t>(Pointer) - OFFSET_OF(TypeName, Field))
+
+#define FIXED_ONE_BYTE_STRING(isolate, string) \
+ (node::OneByteString((isolate), (string), sizeof(string) - 1))
+
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ void operator=(const TypeName&); \
+ TypeName(const TypeName&)
+
+// If persistent.IsWeak() == false, then do not call persistent.Dispose()
+// while the returned Local<T> is still in scope, it will destroy the
+// reference to the object.
+template <class TypeName>
+inline v8::Local<TypeName> PersistentToLocal(
+ v8::Isolate* isolate,
+ const v8::Persistent<TypeName>& persistent);
+
+// Unchecked conversion from a non-weak Persistent<T> to Local<TLocal<T>,
+// use with care!
+//
+// Do not call persistent.Dispose() while the returned Local<T> is still in
+// scope, it will destroy the reference to the object.
+template <class TypeName>
+inline v8::Local<TypeName> StrongPersistentToLocal(
+ const v8::Persistent<TypeName>& persistent);
+
+template <class TypeName>
+inline v8::Local<TypeName> WeakPersistentToLocal(
+ v8::Isolate* isolate,
+ const v8::Persistent<TypeName>& persistent);
+
+// Convenience wrapper around v8::String::NewFromOneByte().
+inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
+ const char* data,
+ int length = -1);
+
+// For the people that compile with -funsigned-char.
+inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
+ const signed char* data,
+ int length = -1);
+
+inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
+ const unsigned char* data,
+ int length = -1);
+
+} // namespace node
+
+#endif // SRC_UTIL_H_
diff --git a/src/uv.cc b/src/uv.cc
index 2da32d4b7e..2759d29671 100644
--- a/src/uv.cc
+++ b/src/uv.cc
@@ -25,6 +25,7 @@
namespace node {
namespace uv {
+using v8::Context;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Handle;
@@ -44,8 +45,9 @@ void ErrName(const FunctionCallbackInfo<Value>& args) {
}
-void Initialize(Handle<Object> target) {
- v8::HandleScope handle_scope(node_isolate);
+void Initialize(Handle<Object> target,
+ Handle<Value> unused,
+ Handle<Context> context) {
target->Set(FIXED_ONE_BYTE_STRING(node_isolate, "errname"),
FunctionTemplate::New(ErrName)->GetFunction());
#define V(name, _) \
@@ -59,4 +61,4 @@ void Initialize(Handle<Object> target) {
} // namespace uv
} // namespace node
-NODE_MODULE(node_uv, node::uv::Initialize)
+NODE_MODULE_CONTEXT_AWARE(node_uv, node::uv::Initialize)