Browse Source

src: add multi-context support

This commit makes it possible to use multiple V8 execution contexts
within a single event loop.  Put another way, handle and request wrap
objects now "remember" the context they belong to and switch back to
that context when the time comes to call into JS land.

This could have been done in a quick and hacky way by calling
v8::Object::GetCreationContext() on the wrap object right before
making a callback but that leaves a fairly wide margin for bugs.

Instead, we make the context explicit through a new Environment class
that encapsulates everything (or almost everything) that belongs to
the context.  Variables that used to be a static or a global are now
members of the aforementioned class.  An additional benefit is that
this approach should make it relatively straightforward to add full
isolate support in due course.

There is no JavaScript API yet but that will be added in the near
future.

This work was graciously sponsored by GitHub, Inc.
v0.11.8-release
Ben Noordhuis 12 years ago
parent
commit
756b622295
  1. 5
      node.gyp
  2. 236
      src/cares_wrap.cc
  3. 289
      src/env-inl.h
  4. 324
      src/env.h
  5. 60
      src/fs_event_wrap.cc
  6. 29
      src/handle_wrap.cc
  7. 14
      src/handle_wrap.h
  8. 720
      src/node.cc
  9. 32
      src/node.h
  10. 53
      src/node.js
  11. 67
      src/node_buffer.cc
  12. 18
      src/node_buffer.h
  13. 127
      src/node_contextify.cc
  14. 277
      src/node_crypto.cc
  15. 56
      src/node_crypto.h
  16. 162
      src/node_file.cc
  17. 5
      src/node_file.h
  18. 192
      src/node_http_parser.cc
  19. 230
      src/node_internals.h
  20. 9
      src/node_os.cc
  21. 49
      src/node_stat_watcher.cc
  22. 9
      src/node_stat_watcher.h
  23. 2
      src/node_version.h
  24. 45
      src/node_wrap.h
  25. 111
      src/node_zlib.cc
  26. 96
      src/pipe_wrap.cc
  27. 10
      src/pipe_wrap.h
  28. 55
      src/process_wrap.cc
  29. 40
      src/req_wrap.h
  30. 43
      src/signal_wrap.cc
  31. 43
      src/smalloc.cc
  32. 129
      src/stream_wrap.cc
  33. 14
      src/stream_wrap.h
  34. 135
      src/tcp_wrap.cc
  35. 10
      src/tcp_wrap.h
  36. 39
      src/timer_wrap.cc
  37. 166
      src/tls_wrap.cc
  38. 13
      src/tls_wrap.h
  39. 31
      src/tty_wrap.cc
  40. 10
      src/tty_wrap.h
  41. 82
      src/udp_wrap.cc
  42. 14
      src/udp_wrap.h
  43. 83
      src/util-inl.h
  44. 82
      src/util.h
  45. 8
      src/uv.cc

5
node.gyp

@ -116,6 +116,8 @@
'src/udp_wrap.cc',
'src/uv.cc',
# headers to make for a more pleasant IDE experience
'src/env.h',
'src/env-inl.h',
'src/handle_wrap.h',
'src/node.h',
'src/node_buffer.h',
@ -124,6 +126,7 @@
'src/node_extensions.h',
'src/node_file.h',
'src/node_http_parser.h',
'src/node_internals.h',
'src/node_javascript.h',
'src/node_root_certs.h',
'src/node_version.h',
@ -139,6 +142,8 @@
'src/string_bytes.h',
'src/stream_wrap.h',
'src/tree.h',
'src/util.h',
'src/util-inl.h',
'deps/http_parser/http_parser.h',
'<(SHARED_INTERMEDIATE_DIR)/node_natives.h',
# javascript files to make for an even more pleasant IDE experience

236
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)

289
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_

324
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_

60
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)

29
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);

14
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;

720
src/node.cc

File diff suppressed because it is too large

32
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) \
}; \
}

53
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]++;
}
};

67
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)

18
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

127
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);

277
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)

56
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);

162
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)

5
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

192
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)

230
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_

9
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)

49
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();
}

9
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

2
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_ */

45
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());
});

111
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)

96
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)

10
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);

55
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)

40
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_;
};

43
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)

43
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)

129
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);
}

14
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_) {

135
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)

10
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);

39
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)

166
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)

13
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);

31
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)

10
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);

82
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)

14
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,

83
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_

82
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_

8
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)

Loading…
Cancel
Save