@@ -64,8 +64,8 @@ namespace node {
V(address_string, "address") \
V(args_string, "args") \
V(argv_string, "argv") \
V(async_queue_string, "_asyncQueue") \
V(async, "async") \
V(async_queue_string, "_asyncQueue") \
V(atime_string, "atime") \
V(birthtime_string, "birthtime") \
V(blksize_string, "blksize") \
@@ -250,9 +250,9 @@ namespace node {
V(zero_return_string, "ZERO_RETURN") \

#define ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V) \
V(async_listener_run_function, v8::Function) \
V(async_listener_load_function, v8::Function) \
V(async_listener_unload_function, v8::Function) \
V(async_hooks_init_function, v8::Function) \
V(async_hooks_pre_function, v8::Function) \
V(async_hooks_post_function, v8::Function) \
V(binding_cache_object, v8::Object) \
V(buffer_constructor_function, v8::Function) \
V(context, v8::Context) \
@@ -286,26 +286,25 @@ RB_HEAD(ares_task_list, ares_task_t);

class Environment {
public:
class AsyncListener {
class AsyncHooks {
public:
inline uint32_t* fields();
inline int fields_count() const;
inline bool has_listener() const;
inline uint32_t watched_providers() const;
inline bool call_init_hook();

private:
friend class Environment; // So we can call the constructor.
inline AsyncListener();
inline AsyncHooks();

enum Fields {
kHasListener,
kWatchedProviders,
// Set this to not zero if the init hook should be called.
kCallInitHook,
kFieldsCount
};

uint32_t fields_[kFieldsCount];

DISALLOW_COPY_AND_ASSIGN(AsyncListener);
DISALLOW_COPY_AND_ASSIGN(AsyncHooks);
};

class DomainFlag {
@@ -395,7 +394,7 @@ class Environment {

inline v8::Isolate* isolate() const;
inline uv_loop_t* event_loop() const;
inline bool has_async_listener() const;
inline bool call_async_init_hook() const;
inline bool in_domain() const;
inline uint32_t watched_providers() const;

@@ -415,7 +414,7 @@ class Environment {
void *arg);
inline void FinishHandleCleanup(uv_handle_t* handle);

inline AsyncListener* async_listener();
inline AsyncHooks* async_hooks();
inline DomainFlag* domain_flag();
inline TickInfo* tick_info();

@@ -492,7 +491,7 @@ class Environment {
uv_idle_t immediate_idle_handle_;
uv_prepare_t idle_prepare_handle_;
uv_check_t idle_check_handle_;
AsyncListener async_listener_count_;
AsyncHooks async_hooks_;
DomainFlag domain_flag_;
TickInfo tick_info_;
uv_timer_t cares_timer_handle_;
@@ -90,13 +90,14 @@ void HandleWrap::Close(const FunctionCallbackInfo<Value>& args) {
HandleWrap::HandleWrap(Environment* env,
Handle<Object> object,
uv_handle_t* handle,
AsyncWrap::ProviderType provider)
: AsyncWrap(env, object, provider),
AsyncWrap::ProviderType provider,
AsyncWrap* parent)
: AsyncWrap(env, object, provider, parent),
flags_(0),
handle__(handle) {
handle__->data = this;
HandleScope scope(env->isolate());
Wrap<HandleWrap>(object, this);
Wrap(object, this);
QUEUE_INSERT_TAIL(env->handle_wrap_queue(), &handle_wrap_queue_);
}

@@ -63,7 +63,8 @@ class HandleWrap : public AsyncWrap {
HandleWrap(Environment* env,
v8::Handle<v8::Object> object,
uv_handle_t* handle,
AsyncWrap::ProviderType provider);
AsyncWrap::ProviderType provider,
AsyncWrap* parent = NULL);
virtual ~HandleWrap();

private:
@@ -131,8 +131,10 @@ static bool use_debug_agent = false;
static bool debug_wait_connect = false;
static int debug_port = 5858;
static bool v8_is_profiling = false;
static bool node_is_initialized = false;
static node_module* modpending;
static node_module* modlist_builtin;
static node_module* modlist_linked;
static node_module* modlist_addon;

#if defined(NODE_HAVE_I18N_SUPPORT)
@@ -907,32 +909,6 @@ Local<Value> WinapiErrnoException(Isolate* isolate,
#endif


void SetupAsyncListener(const FunctionCallbackInfo<Value>& args) {
HandleScope handle_scope(args.GetIsolate());
Environment* env = Environment::GetCurrent(args.GetIsolate());

assert(args[0]->IsObject());
assert(args[1]->IsFunction());
assert(args[2]->IsFunction());
assert(args[3]->IsFunction());

env->set_async_listener_run_function(args[1].As<Function>());
env->set_async_listener_load_function(args[2].As<Function>());
env->set_async_listener_unload_function(args[3].As<Function>());

Local<Object> async_listener_flag_obj = args[0].As<Object>();
Environment::AsyncListener* async_listener = env->async_listener();
async_listener_flag_obj->SetIndexedPropertiesToExternalArrayData(
async_listener->fields(),
kExternalUint32Array,
async_listener->fields_count());

// Do a little housekeeping.
env->process_object()->Delete(
FIXED_ONE_BYTE_STRING(args.GetIsolate(), "_setupAsyncListener"));
}


void SetupDomainUse(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args.GetIsolate());

@@ -1002,152 +978,80 @@ void SetupNextTick(const FunctionCallbackInfo<Value>& args) {
}


Handle<Value> MakeDomainCallback(Environment* env,
Handle<Value> recv,
const Handle<Function> callback,
int argc,
Handle<Value> argv[]) {
Handle<Value> MakeCallback(Environment* env,
Handle<Value> recv,
const Handle<Function> callback,
int argc,
Handle<Value> argv[]) {
// If you hit this assertion, you forgot to enter the v8::Context first.
assert(env->context() == env->isolate()->GetCurrentContext());
CHECK(env->context() == env->isolate()->GetCurrentContext());

Local<Object> process = env->process_object();
Local<Object> object, domain;
Local<Value> domain_v;

TryCatch try_catch;
try_catch.SetVerbose(true);

bool has_async_queue = false;
bool has_domain = false;

if (recv->IsObject()) {
object = recv.As<Object>();
// TODO(trevnorris): This is sucky for performance. Fix it.
has_async_queue = object->Has(env->async_queue_string());
if (has_async_queue) {
env->async_listener_load_function()->Call(process, 1, &recv);

if (try_catch.HasCaught())
return Undefined(env->isolate());
}
Local<Value> async_queue_v = object->Get(env->async_queue_string());
if (async_queue_v->IsObject())
has_async_queue = true;
}

bool has_domain = false;

if (!object.IsEmpty()) {
domain_v = object->Get(env->domain_string());
if (env->using_domains()) {
CHECK(recv->IsObject());
Local<Value> domain_v = object->Get(env->domain_string());
has_domain = domain_v->IsObject();
if (has_domain) {
domain = domain_v.As<Object>();

if (domain->Get(env->disposed_string())->IsTrue()) {
// domain has been disposed of.
if (domain->Get(env->disposed_string())->IsTrue())
return Undefined(env->isolate());
}

Local<Function> enter = domain->Get(env->enter_string()).As<Function>();
if (enter->IsFunction()) {
enter->Call(domain, 0, NULL);
if (try_catch.HasCaught())
return Undefined(env->isolate());
}
}
}

Local<Value> ret = callback->Call(recv, argc, argv);

if (try_catch.HasCaught()) {
return Undefined(env->isolate());
}
TryCatch try_catch;
try_catch.SetVerbose(true);

if (has_domain) {
Local<Function> exit = domain->Get(env->exit_string()).As<Function>();
if (exit->IsFunction()) {
exit->Call(domain, 0, NULL);
Local<Value> enter_v = domain->Get(env->enter_string());
if (enter_v->IsFunction()) {
enter_v.As<Function>()->Call(domain, 0, NULL);
if (try_catch.HasCaught())
return Undefined(env->isolate());
}
}

if (has_async_queue) {
env->async_listener_unload_function()->Call(process, 1, &recv);

try_catch.SetVerbose(false);
env->async_hooks_pre_function()->Call(object, 0, NULL);
if (try_catch.HasCaught())
return Undefined(env->isolate());
}

Environment::TickInfo* tick_info = env->tick_info();

if (tick_info->last_threw() == 1) {
tick_info->set_last_threw(0);
return ret;
FatalError("node:;MakeCallback", "pre hook threw");
try_catch.SetVerbose(true);
}

if (tick_info->in_tick()) {
return ret;
}

if (tick_info->length() == 0) {
env->isolate()->RunMicrotasks();
}

if (tick_info->length() == 0) {
tick_info->set_index(0);
return ret;
}

tick_info->set_in_tick(true);

env->tick_callback_function()->Call(process, 0, NULL);

tick_info->set_in_tick(false);

if (try_catch.HasCaught()) {
tick_info->set_last_threw(true);
return Undefined(env->isolate());
}

return ret;
}


Handle<Value> MakeCallback(Environment* env,
Handle<Value> recv,
const Handle<Function> callback,
int argc,
Handle<Value> argv[]) {
if (env->using_domains())
return MakeDomainCallback(env, recv, callback, argc, argv);

// If you hit this assertion, you forgot to enter the v8::Context first.
assert(env->context() == env->isolate()->GetCurrentContext());

Local<Object> process = env->process_object();

TryCatch try_catch;
try_catch.SetVerbose(true);
Local<Value> ret = callback->Call(recv, argc, argv);

// TODO(trevnorris): This is sucky for performance. Fix it.
bool has_async_queue =
recv->IsObject() && recv.As<Object>()->Has(env->async_queue_string());
if (has_async_queue) {
env->async_listener_load_function()->Call(process, 1, &recv);
try_catch.SetVerbose(false);
env->async_hooks_post_function()->Call(object, 0, NULL);
if (try_catch.HasCaught())
return Undefined(env->isolate());
FatalError("node::MakeCallback", "post hook threw");
try_catch.SetVerbose(true);
}

Local<Value> ret = callback->Call(recv, argc, argv);
if (has_domain) {
Local<Value> exit_v = domain->Get(env->exit_string());
if (exit_v->IsFunction()) {
exit_v.As<Function>()->Call(domain, 0, NULL);
if (try_catch.HasCaught())
return Undefined(env->isolate());
}
}

if (try_catch.HasCaught()) {
return Undefined(env->isolate());
}

if (has_async_queue) {
env->async_listener_unload_function()->Call(process, 1, &recv);

if (try_catch.HasCaught())
return Undefined(env->isolate());
}

Environment::TickInfo* tick_info = env->tick_info();

if (tick_info->in_tick()) {
@@ -1185,10 +1089,9 @@ Handle<Value> MakeCallback(Environment* env,
uint32_t index,
int argc,
Handle<Value> argv[]) {
Local<Function> callback = recv->Get(index).As<Function>();
assert(callback->IsFunction());

return MakeCallback(env, recv.As<Value>(), callback, argc, argv);
Local<Value> cb_v = recv->Get(index);
CHECK(cb_v->IsFunction());
return MakeCallback(env, recv.As<Value>(), cb_v.As<Function>(), argc, argv);
}


@@ -1197,9 +1100,9 @@ Handle<Value> MakeCallback(Environment* env,
Handle<String> symbol,
int argc,
Handle<Value> argv[]) {
Local<Function> callback = recv->Get(symbol).As<Function>();
assert(callback->IsFunction());
return MakeCallback(env, recv.As<Value>(), callback, argc, argv);
Local<Value> cb_v = recv->Get(symbol);
CHECK(cb_v->IsFunction());
return MakeCallback(env, recv.As<Value>(), cb_v.As<Function>(), argc, argv);
}


@@ -1256,20 +1159,6 @@ Handle<Value> MakeCallback(Isolate* isolate,
}


Handle<Value> MakeDomainCallback(Handle<Object> recv,
Handle<Function> callback,
int argc,
Handle<Value> argv[]) {
Local<Context> context = recv->CreationContext();
Environment* env = Environment::GetCurrent(context);
Context::Scope context_scope(context);
EscapableHandleScope handle_scope(env->isolate());
return handle_scope.Escape(Local<Value>::New(
env->isolate(),
MakeDomainCallback(env, recv, callback, argc, argv)));
}


enum encoding ParseEncoding(Isolate* isolate,
Handle<Value> encoding_v,
enum encoding _default) {
@@ -2051,7 +1940,15 @@ extern "C" void node_module_register(void* m) {
if (mp->nm_flags & NM_F_BUILTIN) {
mp->nm_link = modlist_builtin;
modlist_builtin = mp;
} else if (!node_is_initialized) {
// "Linked" modules are included as part of the node project.
// Like builtins they are registered *before* node::Init runs.
mp->nm_flags = NM_F_LINKED;
mp->nm_link = modlist_linked;
modlist_linked = mp;
} else {
// Once node::Init was called we can only register dynamic modules.
// See DLOpen.
assert(modpending == NULL);
modpending = mp;
}
@@ -2069,6 +1966,18 @@ struct node_module* get_builtin_module(const char* name) {
return (mp);
}

struct node_module* get_linked_module(const char* name) {
struct node_module* mp;

for (mp = modlist_linked; mp != NULL; mp = mp->nm_link) {
if (strcmp(mp->nm_modname, name) == 0)
break;
}

CHECK(mp == NULL || (mp->nm_flags & NM_F_LINKED) != 0);
return mp;
}

typedef void (UV_DYNAMIC* extInit)(Handle<Object> exports);

// DLOpen is process.dlopen(module, filename).
@@ -2275,6 +2184,46 @@ static void Binding(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(exports);
}

static void LinkedBinding(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args.GetIsolate());

Local<String> module = args[0]->ToString();

Local<Object> cache = env->binding_cache_object();
Local<Value> exports_v = cache->Get(module);

if (exports_v->IsObject())
return args.GetReturnValue().Set(exports_v.As<Object>());

node::Utf8Value module_v(module);
node_module* mod = get_linked_module(*module_v);

if (mod == NULL) {
char errmsg[1024];
snprintf(errmsg,
sizeof(errmsg),
"No such module was linked: %s",
*module_v);
return env->ThrowError(errmsg);
}

Local<Object> exports = Object::New(env->isolate());

if (mod->nm_context_register_func != NULL) {
mod->nm_context_register_func(exports,
module,
env->context(),
mod->nm_priv);
} else if (mod->nm_register_func != NULL) {
mod->nm_register_func(exports, module, mod->nm_priv);
} else {
return env->ThrowError("Linked module has no declared entry point.");
}

cache->Set(module, exports);

args.GetReturnValue().Set(exports);
}

static void ProcessTitleGetter(Local<String> property,
const PropertyCallbackInfo<Value>& info) {
@@ -2816,8 +2765,8 @@ void SetupProcessObject(Environment* env,
NODE_SET_METHOD(process, "memoryUsage", MemoryUsage);

NODE_SET_METHOD(process, "binding", Binding);
NODE_SET_METHOD(process, "_linkedBinding", LinkedBinding);

NODE_SET_METHOD(process, "_setupAsyncListener", SetupAsyncListener);
NODE_SET_METHOD(process, "_setupNextTick", SetupNextTick);
NODE_SET_METHOD(process, "_setupDomainUse", SetupDomainUse);

@@ -3724,6 +3673,7 @@ int Start(int argc, char** argv) {

int code;
V8::Initialize();
node_is_initialized = true;
{
Locker locker(node_isolate);
Isolate::Scope isolate_scope(node_isolate);
@@ -347,6 +347,7 @@ typedef void (*addon_context_register_func)(
void* priv);

#define NM_F_BUILTIN 0x01
#define NM_F_LINKED 0x02

struct node_module {
int nm_version;
@@ -361,6 +362,7 @@ struct node_module {
};

node_module* get_builtin_module(const char *name);
node_module* get_linked_module(const char *name);

extern "C" NODE_EXTERN void node_module_register(void* mod);

@@ -39,9 +39,6 @@

process.EventEmitter = EventEmitter; // process.EventEmitter is deprecated

// Setup the tracing module
NativeModule.require('tracing')._nodeInitialization(process);

// do this good and early, since it handles errors.
startup.processFatal();

@@ -229,14 +226,8 @@
};

startup.processFatal = function() {
var tracing = NativeModule.require('tracing');
var _errorHandler = tracing._errorHandler;
// Cleanup
delete tracing._errorHandler;

process._fatalException = function(er) {
// First run through error handlers from asyncListener.
var caught = _errorHandler(er);
var caught;

if (process.domain && process.domain._errorHandler)
caught = process.domain._errorHandler(er) || caught;
@@ -258,11 +249,7 @@

// if we handled an error, then make sure any ticks get processed
} else {
var t = setImmediate(process._tickCallback);
// Complete hack to make sure any errors thrown from async
// listeners don't cause an infinite loop.
if (t._asyncQueue)
t._asyncQueue = [];
NativeModule.require('timers').setImmediate(process._tickCallback);
}

return caught;
@@ -296,12 +283,7 @@
};

startup.processNextTick = function() {
var tracing = NativeModule.require('tracing');
var nextTickQueue = [];
var asyncFlags = tracing._asyncFlags;
var _runAsyncQueue = tracing._runAsyncQueue;
var _loadAsyncQueue = tracing._loadAsyncQueue;
var _unloadAsyncQueue = tracing._unloadAsyncQueue;
var microtasksScheduled = false;

// Used to run V8's micro task queue.
@@ -315,10 +297,6 @@
var kIndex = 0;
var kLength = 1;

// For asyncFlags.
// *Must* match Environment::AsyncListeners::Fields in src/env.h
var kCount = 0;

process.nextTick = nextTick;
// Needs to be accessible from beyond this scope.
process._tickCallback = _tickCallback;
@@ -365,26 +343,21 @@
// Run callbacks that have no domain.
// Using domains will cause this to be overridden.
function _tickCallback() {
var callback, hasQueue, threw, tock;
var callback, threw, tock;

scheduleMicrotasks();

while (tickInfo[kIndex] < tickInfo[kLength]) {
tock = nextTickQueue[tickInfo[kIndex]++];
callback = tock.callback;
threw = true;
hasQueue = !!tock._asyncQueue;
if (hasQueue)
_loadAsyncQueue(tock);
try {
callback();
threw = false;
} finally {
if (threw)
tickDone();
}
if (hasQueue)
_unloadAsyncQueue(tock);
if (1e4 < tickInfo[kIndex])
tickDone();
}
@@ -393,17 +366,14 @@
}

function _tickDomainCallback() {
var callback, domain, hasQueue, threw, tock;
var callback, domain, threw, tock;

scheduleMicrotasks();

while (tickInfo[kIndex] < tickInfo[kLength]) {
tock = nextTickQueue[tickInfo[kIndex]++];
callback = tock.callback;
domain = tock.domain;
hasQueue = !!tock._asyncQueue;
if (hasQueue)
_loadAsyncQueue(tock);
if (domain)
domain.enter();
threw = true;
@@ -414,8 +384,6 @@
if (threw)
tickDone();
}
if (hasQueue)
_unloadAsyncQueue(tock);
if (1e4 < tickInfo[kIndex])
tickDone();
if (domain)
@@ -432,13 +400,9 @@

var obj = {
callback: callback,
domain: process.domain || null,
_asyncQueue: undefined
domain: process.domain || null
};

if (asyncFlags[kCount] > 0)
_runAsyncQueue(obj);

nextTickQueue.push(obj);
tickInfo[kLength]++;
}
@@ -205,7 +205,7 @@ class ContextifyContext {
if (wrapper.IsEmpty())
return scope.Escape(Local<Value>::New(env->isolate(), Handle<Value>()));

Wrap<ContextifyContext>(wrapper, this);
Wrap(wrapper, this);
return scope.Escape(wrapper);
}

@@ -151,7 +151,8 @@ template int SSLWrap<TLSCallbacks>::TLSExtStatusCallback(SSL* s, void* arg);


static void crypto_threadid_cb(CRYPTO_THREADID* tid) {
CRYPTO_THREADID_set_numeric(tid, uv_thread_self());
assert(sizeof(uv_thread_t) <= sizeof(void*)); // NOLINT(runtime/sizeof)
CRYPTO_THREADID_set_pointer(tid, reinterpret_cast<void*>(uv_thread_self()));
}


@@ -71,11 +71,15 @@ class FSReqWrap: public ReqWrap<uv_fs_t> {
void* operator new(size_t size) { return new char[size]; }
void* operator new(size_t size, char* storage) { return storage; }

FSReqWrap(Environment* env, const char* syscall, char* data = NULL)
: ReqWrap<uv_fs_t>(env, Object::New(env->isolate())),
FSReqWrap(Environment* env,
Local<Object> req,
const char* syscall,
char* data = NULL)
: ReqWrap(env, req, AsyncWrap::PROVIDER_FSREQWRAP),
syscall_(syscall),
data_(data),
dest_len_(0) {
Wrap(object(), this);
}

void ReleaseEarly() {
@@ -98,6 +102,11 @@ class FSReqWrap: public ReqWrap<uv_fs_t> {
};


static void NewFSReqWrap(const FunctionCallbackInfo<Value>& args) {
CHECK(args.IsConstructCall());
}


#define ASSERT_OFFSET(a) \
if (!(a)->IsUndefined() && !(a)->IsNull() && !IsInt64((a)->NumberValue())) { \
return env->ThrowTypeError("Not an integer"); \
@@ -256,35 +265,35 @@ struct fs_req_wrap {
};


#define ASYNC_DEST_CALL(func, callback, dest_path, ...) \
#define ASYNC_DEST_CALL(func, req, dest_path, ...) \
Environment* env = Environment::GetCurrent(args.GetIsolate()); \
FSReqWrap* req_wrap; \
char* dest_str = (dest_path); \
int dest_len = dest_str == NULL ? 0 : strlen(dest_str); \
char* storage = new char[sizeof(*req_wrap) + dest_len]; \
req_wrap = new(storage) FSReqWrap(env, #func); \
CHECK(req->IsObject()); \
req_wrap = new(storage) FSReqWrap(env, req.As<Object>(), #func); \
req_wrap->dest_len(dest_len); \
if (dest_str != NULL) { \
memcpy(const_cast<char*>(req_wrap->dest()), \
dest_str, \
dest_len + 1); \
} \
int err = uv_fs_ ## func(env->event_loop() , \
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); \
uv_fs_t* uv_req = &req_wrap->req_; \
uv_req->result = err; \
uv_req->path = NULL; \
After(uv_req); \
} \
args.GetReturnValue().Set(req_wrap->persistent());

#define ASYNC_CALL(func, callback, ...) \
ASYNC_DEST_CALL(func, callback, NULL, __VA_ARGS__) \
#define ASYNC_CALL(func, req, ...) \
ASYNC_DEST_CALL(func, req, NULL, __VA_ARGS__) \

#define SYNC_DEST_CALL(func, path, dest, ...) \
fs_req_wrap req_wrap; \
@@ -321,7 +330,7 @@ static void Close(const FunctionCallbackInfo<Value>& args) {

int fd = args[0]->Int32Value();

if (args[1]->IsFunction()) {
if (args[1]->IsObject()) {
ASYNC_CALL(close, args[1], fd)
} else {
SYNC_CALL(close, 0, fd)
@@ -437,7 +446,7 @@ static void Stat(const FunctionCallbackInfo<Value>& args) {

node::Utf8Value path(args[0]);

if (args[1]->IsFunction()) {
if (args[1]->IsObject()) {
ASYNC_CALL(stat, args[1], *path)
} else {
SYNC_CALL(stat, *path, *path)
@@ -457,7 +466,7 @@ static void LStat(const FunctionCallbackInfo<Value>& args) {

node::Utf8Value path(args[0]);

if (args[1]->IsFunction()) {
if (args[1]->IsObject()) {
ASYNC_CALL(lstat, args[1], *path)
} else {
SYNC_CALL(lstat, *path, *path)
@@ -476,7 +485,7 @@ static void FStat(const FunctionCallbackInfo<Value>& args) {

int fd = args[0]->Int32Value();

if (args[1]->IsFunction()) {
if (args[1]->IsObject()) {
ASYNC_CALL(fstat, args[1], fd)
} else {
SYNC_CALL(fstat, 0, fd)
@@ -514,7 +523,7 @@ static void Symlink(const FunctionCallbackInfo<Value>& args) {
}
}

if (args[3]->IsFunction()) {
if (args[3]->IsObject()) {
ASYNC_DEST_CALL(symlink, args[3], *path, *dest, *path, flags)
} else {
SYNC_DEST_CALL(symlink, *dest, *path, *dest, *path, flags)
@@ -538,7 +547,7 @@ static void Link(const FunctionCallbackInfo<Value>& args) {
node::Utf8Value orig_path(args[0]);
node::Utf8Value new_path(args[1]);

if (args[2]->IsFunction()) {
if (args[2]->IsObject()) {
ASYNC_DEST_CALL(link, args[2], *new_path, *orig_path, *new_path)
} else {
SYNC_DEST_CALL(link, *orig_path, *new_path, *orig_path, *new_path)
@@ -556,7 +565,7 @@ static void ReadLink(const FunctionCallbackInfo<Value>& args) {

node::Utf8Value path(args[0]);

if (args[1]->IsFunction()) {
if (args[1]->IsObject()) {
ASYNC_CALL(readlink, args[1], *path)
} else {
SYNC_CALL(readlink, *path, *path)
@@ -583,7 +592,7 @@ static void Rename(const FunctionCallbackInfo<Value>& args) {
node::Utf8Value old_path(args[0]);
node::Utf8Value new_path(args[1]);

if (args[2]->IsFunction()) {
if (args[2]->IsObject()) {
ASYNC_DEST_CALL(rename, args[2], *new_path, *old_path, *new_path)
} else {
SYNC_DEST_CALL(rename, *old_path, *new_path, *old_path, *new_path)
@@ -603,7 +612,7 @@ static void FTruncate(const FunctionCallbackInfo<Value>& args) {
ASSERT_TRUNCATE_LENGTH(args[1]);
int64_t len = GET_TRUNCATE_LENGTH(args[1]);

if (args[2]->IsFunction()) {
if (args[2]->IsObject()) {
ASYNC_CALL(ftruncate, args[2], fd, len)
} else {
SYNC_CALL(ftruncate, 0, fd, len)
@@ -620,7 +629,7 @@ static void Fdatasync(const FunctionCallbackInfo<Value>& args) {

int fd = args[0]->Int32Value();

if (args[1]->IsFunction()) {
if (args[1]->IsObject()) {
ASYNC_CALL(fdatasync, args[1], fd)
} else {
SYNC_CALL(fdatasync, 0, fd)
@@ -637,7 +646,7 @@ static void Fsync(const FunctionCallbackInfo<Value>& args) {

int fd = args[0]->Int32Value();

if (args[1]->IsFunction()) {
if (args[1]->IsObject()) {
ASYNC_CALL(fsync, args[1], fd)
} else {
SYNC_CALL(fsync, 0, fd)
@@ -655,7 +664,7 @@ static void Unlink(const FunctionCallbackInfo<Value>& args) {

node::Utf8Value path(args[0]);

if (args[1]->IsFunction()) {
if (args[1]->IsObject()) {
ASYNC_CALL(unlink, args[1], *path)
} else {
SYNC_CALL(unlink, *path, *path)
@@ -673,7 +682,7 @@ static void RMDir(const FunctionCallbackInfo<Value>& args) {

node::Utf8Value path(args[0]);

if (args[1]->IsFunction()) {
if (args[1]->IsObject()) {
ASYNC_CALL(rmdir, args[1], *path)
} else {
SYNC_CALL(rmdir, *path, *path)
@@ -691,7 +700,7 @@ static void MKDir(const FunctionCallbackInfo<Value>& args) {
node::Utf8Value path(args[0]);
int mode = static_cast<int>(args[1]->Int32Value());

if (args[2]->IsFunction()) {
if (args[2]->IsObject()) {
ASYNC_CALL(mkdir, args[2], *path, mode)
} else {
SYNC_CALL(mkdir, *path, *path, mode)
@@ -709,7 +718,7 @@ static void ReadDir(const FunctionCallbackInfo<Value>& args) {

node::Utf8Value path(args[0]);

if (args[1]->IsFunction()) {
if (args[1]->IsObject()) {
ASYNC_CALL(scandir, args[1], *path, 0 /*flags*/)
} else {
SYNC_CALL(scandir, *path, *path, 0 /*flags*/)
@@ -758,7 +767,7 @@ static void Open(const FunctionCallbackInfo<Value>& args) {
int flags = args[1]->Int32Value();
int mode = static_cast<int>(args[2]->Int32Value());

if (args[3]->IsFunction()) {
if (args[3]->IsObject()) {
ASYNC_CALL(open, args[3], *path, flags, mode)
} else {
SYNC_CALL(open, *path, *path, flags, mode)
@@ -790,7 +799,7 @@ static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
size_t off = args[2]->Uint32Value();
size_t len = args[3]->Uint32Value();
int64_t pos = GET_OFFSET(args[4]);
Local<Value> cb = args[5];
Local<Value> req = args[5];

if (off > buffer_length)
return env->ThrowRangeError("offset out of bounds");
@@ -805,8 +814,8 @@ static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {

uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);

if (cb->IsFunction()) {
ASYNC_CALL(write, cb, fd, &uvbuf, 1, pos)
if (req->IsObject()) {
ASYNC_CALL(write, req, fd, &uvbuf, 1, pos)
return;
}

@@ -830,7 +839,7 @@ static void WriteString(const FunctionCallbackInfo<Value>& args) {
if (!args[0]->IsInt32())
return env->ThrowTypeError("First argument must be file descriptor");

Local<Value> cb;
Local<Value> req;
Local<Value> string = args[1];
int fd = args[0]->Int32Value();
char* buf = NULL;
@@ -852,26 +861,26 @@ static void WriteString(const FunctionCallbackInfo<Value>& args) {
must_free = true;
}
pos = GET_OFFSET(args[2]);
cb = args[4];
req = args[4];

uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);

if (!cb->IsFunction()) {
if (!req->IsObject()) {
SYNC_CALL(write, NULL, fd, &uvbuf, 1, pos)
if (must_free)
delete[] buf;
return args.GetReturnValue().Set(SYNC_RESULT);
}

FSReqWrap* req_wrap = new FSReqWrap(env, "write", must_free ? buf : NULL);
FSReqWrap* req_wrap =
new FSReqWrap(env, req.As<Object>(), "write", must_free ? buf : NULL);
int err = uv_fs_write(env->event_loop(),
&req_wrap->req_,
fd,
&uvbuf,
1,
pos,
After);
req_wrap->object()->Set(env->oncomplete_string(), cb);
req_wrap->Dispatched();
if (err < 0) {
uv_fs_t* req = &req_wrap->req_;
@@ -906,7 +915,7 @@ static void Read(const FunctionCallbackInfo<Value>& args) {

int fd = args[0]->Int32Value();

Local<Value> cb;
Local<Value> req;

size_t len;
int64_t pos;
@@ -936,10 +945,10 @@ static void Read(const FunctionCallbackInfo<Value>& args) {

uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);

cb = args[5];
req = args[5];

if (cb->IsFunction()) {
ASYNC_CALL(read, cb, fd, &uvbuf, 1, pos);
if (req->IsObject()) {
ASYNC_CALL(read, req, fd, &uvbuf, 1, pos);
} else {
SYNC_CALL(read, 0, fd, &uvbuf, 1, pos)
args.GetReturnValue().Set(SYNC_RESULT);
@@ -960,7 +969,7 @@ static void Chmod(const FunctionCallbackInfo<Value>& args) {
node::Utf8Value path(args[0]);
int mode = static_cast<int>(args[1]->Int32Value());

if (args[2]->IsFunction()) {
if (args[2]->IsObject()) {
ASYNC_CALL(chmod, args[2], *path, mode);
} else {
SYNC_CALL(chmod, *path, *path, mode);
@@ -981,7 +990,7 @@ static void FChmod(const FunctionCallbackInfo<Value>& args) {
int fd = args[0]->Int32Value();
int mode = static_cast<int>(args[1]->Int32Value());

if (args[2]->IsFunction()) {
if (args[2]->IsObject()) {
ASYNC_CALL(fchmod, args[2], fd, mode);
} else {
SYNC_CALL(fchmod, 0, fd, mode);
@@ -1014,7 +1023,7 @@ static void Chown(const FunctionCallbackInfo<Value>& args) {
uv_uid_t uid = static_cast<uv_uid_t>(args[1]->Uint32Value());
uv_gid_t gid = static_cast<uv_gid_t>(args[2]->Uint32Value());

if (args[3]->IsFunction()) {
if (args[3]->IsObject()) {
ASYNC_CALL(chown, args[3], *path, uid, gid);
} else {
SYNC_CALL(chown, *path, *path, uid, gid);
@@ -1047,7 +1056,7 @@ static void FChown(const FunctionCallbackInfo<Value>& args) {
uv_uid_t uid = static_cast<uv_uid_t>(args[1]->Uint32Value());
uv_gid_t gid = static_cast<uv_gid_t>(args[2]->Uint32Value());

if (args[3]->IsFunction()) {
if (args[3]->IsObject()) {
ASYNC_CALL(fchown, args[3], fd, uid, gid);
} else {
SYNC_CALL(fchown, 0, fd, uid, gid);
@@ -1077,7 +1086,7 @@ static void UTimes(const FunctionCallbackInfo<Value>& args) {
const double atime = static_cast<double>(args[1]->NumberValue());
const double mtime = static_cast<double>(args[2]->NumberValue());

if (args[3]->IsFunction()) {
if (args[3]->IsObject()) {
ASYNC_CALL(utime, args[3], *path, atime, mtime);
} else {
SYNC_CALL(utime, *path, *path, atime, mtime);
@@ -1106,7 +1115,7 @@ static void FUTimes(const FunctionCallbackInfo<Value>& args) {
const double atime = static_cast<double>(args[1]->NumberValue());
const double mtime = static_cast<double>(args[2]->NumberValue());

if (args[3]->IsFunction()) {
if (args[3]->IsObject()) {
ASYNC_CALL(futime, args[3], fd, atime, mtime);
} else {
SYNC_CALL(futime, 0, fd, atime, mtime);
@@ -1164,6 +1173,14 @@ void InitFs(Handle<Object> target,
NODE_SET_METHOD(target, "futimes", FUTimes);

StatWatcher::Initialize(env, target);

// Create FunctionTemplate for FSReqWrap
Local<FunctionTemplate> fst =
FunctionTemplate::New(env->isolate(), NewFSReqWrap);
fst->InstanceTemplate()->SetInternalFieldCount(1);
fst->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "FSReqWrap"));
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "FSReqWrap"),
fst->GetFunction());
}

} // end namespace node
@@ -21,6 +21,7 @@

#include "pipe_wrap.h"

#include "async-wrap.h"
#include "env.h"
#include "env-inl.h"
#include "handle_wrap.h"
@@ -37,6 +38,7 @@ namespace node {
using v8::Boolean;
using v8::Context;
using v8::EscapableHandleScope;
using v8::External;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
@@ -50,21 +52,37 @@ using v8::String;
using v8::Undefined;
using v8::Value;


// TODO(bnoordhuis) share with TCPWrap?
typedef class ReqWrap<uv_connect_t> ConnectWrap;
class PipeConnectWrap : public ReqWrap<uv_connect_t> {
public:
PipeConnectWrap(Environment* env, Local<Object> req_wrap_obj);
};


PipeConnectWrap::PipeConnectWrap(Environment* env, Local<Object> req_wrap_obj)
: ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_PIPEWRAP) {
Wrap(req_wrap_obj, this);
}


static void NewPipeConnectWrap(const FunctionCallbackInfo<Value>& args) {
CHECK(args.IsConstructCall());
}


uv_pipe_t* PipeWrap::UVHandle() {
return &handle_;
}


Local<Object> PipeWrap::Instantiate(Environment* env) {
Local<Object> PipeWrap::Instantiate(Environment* env, AsyncWrap* parent) {
EscapableHandleScope 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();
Local<Value> ptr = External::New(env->isolate(), parent);
Local<Object> instance = constructor->NewInstance(1, &ptr);
assert(!instance.IsEmpty());
return handle_scope.Escape(instance);
}
@@ -119,6 +137,14 @@ void PipeWrap::Initialize(Handle<Object> target,

target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "Pipe"), t->GetFunction());
env->set_pipe_constructor_template(t);

// Create FunctionTemplate for PipeConnectWrap.
Local<FunctionTemplate> cwt =
FunctionTemplate::New(env->isolate(), NewPipeConnectWrap);
cwt->InstanceTemplate()->SetInternalFieldCount(1);
cwt->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "PipeConnectWrap"));
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "PipeConnectWrap"),
cwt->GetFunction());
}


@@ -127,17 +153,25 @@ 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 handle_scope(args.GetIsolate());
Environment* env = Environment::GetCurrent(args.GetIsolate());
new PipeWrap(env, args.This(), args[0]->IsTrue());
if (args[0]->IsExternal()) {
void* ptr = args[0].As<External>()->Value();
new PipeWrap(env, args.This(), false, static_cast<AsyncWrap*>(ptr));
} else {
new PipeWrap(env, args.This(), args[0]->IsTrue(), NULL);
}
}


PipeWrap::PipeWrap(Environment* env, Handle<Object> object, bool ipc)
PipeWrap::PipeWrap(Environment* env,
Handle<Object> object,
bool ipc,
AsyncWrap* parent)
: StreamWrap(env,
object,
reinterpret_cast<uv_stream_t*>(&handle_),
AsyncWrap::PROVIDER_PIPEWRAP) {
AsyncWrap::PROVIDER_PIPEWRAP,
parent) {
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.
@@ -209,7 +243,7 @@ void PipeWrap::OnConnection(uv_stream_t* handle, int status) {
}

// Instanciate the client javascript object and handle.
Local<Object> client_obj = Instantiate(env);
Local<Object> client_obj = Instantiate(env, pipe_wrap);

// Unwrap the client javascript object.
PipeWrap* wrap = Unwrap<PipeWrap>(client_obj);
@@ -224,7 +258,7 @@ void PipeWrap::OnConnection(uv_stream_t* handle, int status) {

// TODO(bnoordhuis) Maybe share this with TCPWrap?
void PipeWrap::AfterConnect(uv_connect_t* req, int status) {
ConnectWrap* req_wrap = static_cast<ConnectWrap*>(req->data);
PipeConnectWrap* req_wrap = static_cast<PipeConnectWrap*>(req->data);
PipeWrap* wrap = static_cast<PipeWrap*>(req->handle->data);
assert(req_wrap->env() == wrap->env());
Environment* env = wrap->env();
@@ -287,9 +321,7 @@ void PipeWrap::Connect(const FunctionCallbackInfo<Value>& args) {
Local<Object> req_wrap_obj = args[0].As<Object>();
node::Utf8Value name(args[1]);

ConnectWrap* req_wrap = new ConnectWrap(env,
req_wrap_obj,
AsyncWrap::PROVIDER_CONNECTWRAP);
PipeConnectWrap* req_wrap = new PipeConnectWrap(env, req_wrap_obj);
uv_pipe_connect(&req_wrap->req_,
&wrap->handle_,
*name,
@@ -22,6 +22,7 @@
#ifndef SRC_PIPE_WRAP_H_
#define SRC_PIPE_WRAP_H_

#include "async-wrap.h"
#include "env.h"
#include "stream_wrap.h"

@@ -31,13 +32,16 @@ class PipeWrap : public StreamWrap {
public:
uv_pipe_t* UVHandle();

static v8::Local<v8::Object> Instantiate(Environment* env);
static v8::Local<v8::Object> Instantiate(Environment* env, AsyncWrap* parent);
static void Initialize(v8::Handle<v8::Object> target,
v8::Handle<v8::Value> unused,
v8::Handle<v8::Context> context);

private:
PipeWrap(Environment* env, v8::Handle<v8::Object> object, bool ipc);
PipeWrap(Environment* env,
v8::Handle<v8::Object> object,
bool ipc,
AsyncWrap* parent);

static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Bind(const v8::FunctionCallbackInfo<v8::Value>& args);
@@ -36,8 +36,8 @@ class ReqWrap : public AsyncWrap {
public:
ReqWrap(Environment* env,
v8::Handle<v8::Object> object,
AsyncWrap::ProviderType provider = AsyncWrap::PROVIDER_REQWRAP)
: AsyncWrap(env, object, AsyncWrap::PROVIDER_REQWRAP) {
AsyncWrap::ProviderType provider)
: AsyncWrap(env, object, provider) {
if (env->in_domain())
object->Set(env->domain_string(), env->domain_array()->Get(0));

@@ -446,6 +446,9 @@ bool HasExternalData(Environment* env, Local<Object> obj) {
return obj->HasIndexedPropertiesInExternalArrayData();
}

void IsTypedArray(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(args[0]->IsTypedArray());
}

void AllocTruncate(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args.GetIsolate());
@@ -547,6 +550,7 @@ void Initialize(Handle<Object> exports,
NODE_SET_METHOD(exports, "truncate", AllocTruncate);

NODE_SET_METHOD(exports, "hasExternalData", HasExternalData);
NODE_SET_METHOD(exports, "isTypedArray", IsTypedArray);

exports->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kMaxLength"),
Uint32::NewFromUnsigned(env->isolate(), kMaxLength));
@@ -43,6 +43,7 @@ using v8::Array;
using v8::Context;
using v8::EscapableHandleScope;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Handle;
using v8::HandleScope;
using v8::Integer;
@@ -56,11 +57,37 @@ using v8::Undefined;
using v8::Value;


void StreamWrap::Initialize(Handle<Object> target,
Handle<Value> unused,
Handle<Context> context) {
Environment* env = Environment::GetCurrent(context);

Local<FunctionTemplate> sw =
FunctionTemplate::New(env->isolate(), ShutdownWrap::NewShutdownWrap);
sw->InstanceTemplate()->SetInternalFieldCount(1);
sw->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "ShutdownWrap"));
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "ShutdownWrap"),
sw->GetFunction());

Local<FunctionTemplate> ww =
FunctionTemplate::New(env->isolate(), WriteWrap::NewWriteWrap);
ww->InstanceTemplate()->SetInternalFieldCount(1);
ww->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "WriteWrap"));
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "WriteWrap"),
ww->GetFunction());
}


StreamWrap::StreamWrap(Environment* env,
Local<Object> object,
uv_stream_t* stream,
AsyncWrap::ProviderType provider)
: HandleWrap(env, object, reinterpret_cast<uv_handle_t*>(stream), provider),
AsyncWrap::ProviderType provider,
AsyncWrap* parent)
: HandleWrap(env,
object,
reinterpret_cast<uv_handle_t*>(stream),
provider,
parent),
stream_(stream),
default_callbacks_(this),
callbacks_(&default_callbacks_),
@@ -89,6 +116,7 @@ void StreamWrap::UpdateWriteQueueSize() {
object()->Set(env()->write_queue_size_string(), write_queue_size);
}


void StreamWrap::ReadStart(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args.GetIsolate());
HandleScope scope(env->isolate());
@@ -122,12 +150,14 @@ void StreamWrap::OnAlloc(uv_handle_t* handle,


template <class WrapType, class UVType>
static Local<Object> AcceptHandle(Environment* env, uv_stream_t* pipe) {
static Local<Object> AcceptHandle(Environment* env,
uv_stream_t* pipe,
AsyncWrap* parent) {
EscapableHandleScope scope(env->isolate());
Local<Object> wrap_obj;
UVType* handle;

wrap_obj = WrapType::Instantiate(env);
wrap_obj = WrapType::Instantiate(env, parent);
if (wrap_obj.IsEmpty())
return Local<Object>();

@@ -560,9 +590,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(env,
req_wrap_obj,
AsyncWrap::PROVIDER_SHUTDOWNWRAP);
ShutdownWrap* req_wrap = new ShutdownWrap(env, req_wrap_obj);
int err = wrap->callbacks()->DoShutdown(req_wrap, AfterShutdown);
req_wrap->Dispatched();
if (err)
@@ -722,11 +750,11 @@ void StreamWrapCallbacks::DoRead(uv_stream_t* handle,

Local<Object> pending_obj;
if (pending == UV_TCP) {
pending_obj = AcceptHandle<TCPWrap, uv_tcp_t>(env, handle);
pending_obj = AcceptHandle<TCPWrap, uv_tcp_t>(env, handle, wrap());
} else if (pending == UV_NAMED_PIPE) {
pending_obj = AcceptHandle<PipeWrap, uv_pipe_t>(env, handle);
pending_obj = AcceptHandle<PipeWrap, uv_pipe_t>(env, handle, wrap());
} else if (pending == UV_UDP) {
pending_obj = AcceptHandle<UDPWrap, uv_udp_t>(env, handle);
pending_obj = AcceptHandle<UDPWrap, uv_udp_t>(env, handle, wrap());
} else {
assert(pending == UV_UNKNOWN_HANDLE);
}
@@ -744,3 +772,5 @@ int StreamWrapCallbacks::DoShutdown(ShutdownWrap* req_wrap, uv_shutdown_cb cb) {
}

} // namespace node

NODE_MODULE_CONTEXT_AWARE_BUILTIN(stream_wrap, node::StreamWrap::Initialize)
@@ -33,15 +33,26 @@ namespace node {
// Forward declaration
class StreamWrap;

typedef class ReqWrap<uv_shutdown_t> ShutdownWrap;
class ShutdownWrap : public ReqWrap<uv_shutdown_t> {
public:
ShutdownWrap(Environment* env, v8::Local<v8::Object> req_wrap_obj)
: ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_SHUTDOWNWRAP) {
Wrap(req_wrap_obj, this);
}

static void NewShutdownWrap(const v8::FunctionCallbackInfo<v8::Value>& args) {
CHECK(args.IsConstructCall());
}
};

class WriteWrap: public ReqWrap<uv_write_t> {
public:
// TODO(trevnorris): WrapWrap inherits from ReqWrap, which I've globbed
// into the same provider. How should these be broken apart?
WriteWrap(Environment* env, v8::Local<v8::Object> obj, StreamWrap* wrap)
: ReqWrap<uv_write_t>(env, obj),
: ReqWrap(env, obj, AsyncWrap::PROVIDER_WRITEWRAP),
wrap_(wrap) {
Wrap(obj, this);
}

void* operator new(size_t size, char* storage) { return storage; }
@@ -54,6 +65,10 @@ class WriteWrap: public ReqWrap<uv_write_t> {
return wrap_;
}

static void NewWriteWrap(const v8::FunctionCallbackInfo<v8::Value>& args) {
CHECK(args.IsConstructCall());
}

private:
// People should not be using the non-placement new and delete operator on a
// WriteWrap. Ensure this never happens.
@@ -105,6 +120,10 @@ class StreamWrapCallbacks {

class StreamWrap : public HandleWrap {
public:
static void Initialize(v8::Handle<v8::Object> target,
v8::Handle<v8::Value> unused,
v8::Handle<v8::Context> context);

void OverrideCallbacks(StreamWrapCallbacks* callbacks, bool gc) {
StreamWrapCallbacks* old = callbacks_;
callbacks_ = callbacks;
@@ -158,7 +177,8 @@ class StreamWrap : public HandleWrap {
StreamWrap(Environment* env,
v8::Local<v8::Object> object,
uv_stream_t* stream,
AsyncWrap::ProviderType provider);
AsyncWrap::ProviderType provider,
AsyncWrap* parent = NULL);

~StreamWrap() {
if (!callbacks_gc_ && callbacks_ != &default_callbacks_) {
@@ -38,6 +38,7 @@ namespace node {

using v8::Context;
using v8::EscapableHandleScope;
using v8::External;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
@@ -52,15 +53,31 @@ using v8::Undefined;
using v8::Value;
using v8::Boolean;

typedef class ReqWrap<uv_connect_t> ConnectWrap;

class TCPConnectWrap : public ReqWrap<uv_connect_t> {
public:
TCPConnectWrap(Environment* env, Local<Object> req_wrap_obj);
};

Local<Object> TCPWrap::Instantiate(Environment* env) {

TCPConnectWrap::TCPConnectWrap(Environment* env, Local<Object> req_wrap_obj)
: ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_TCPWRAP) {
Wrap(req_wrap_obj, this);
}


static void NewTCPConnectWrap(const FunctionCallbackInfo<Value>& args) {
CHECK(args.IsConstructCall());
}


Local<Object> TCPWrap::Instantiate(Environment* env, AsyncWrap* parent) {
EscapableHandleScope 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();
Local<Value> ptr = External::New(env->isolate(), parent);
Local<Object> instance = constructor->NewInstance(1, &ptr);
assert(instance.IsEmpty() == false);
return handle_scope.Escape(instance);
}
@@ -135,6 +152,14 @@ void TCPWrap::Initialize(Handle<Object> target,

target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "TCP"), t->GetFunction());
env->set_tcp_constructor_template(t);

// Create FunctionTemplate for TCPConnectWrap.
Local<FunctionTemplate> cwt =
FunctionTemplate::New(env->isolate(), NewTCPConnectWrap);
cwt->InstanceTemplate()->SetInternalFieldCount(1);
cwt->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "TCPConnectWrap"));
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "TCPConnectWrap"),
cwt->GetFunction());
}


@@ -148,18 +173,26 @@ 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 handle_scope(args.GetIsolate());
Environment* env = Environment::GetCurrent(args.GetIsolate());
TCPWrap* wrap = new TCPWrap(env, args.This());
TCPWrap* wrap;
if (args.Length() == 0) {
wrap = new TCPWrap(env, args.This(), NULL);
} else if (args[0]->IsExternal()) {
void* ptr = args[0].As<External>()->Value();
wrap = new TCPWrap(env, args.This(), static_cast<AsyncWrap*>(ptr));
} else {
UNREACHABLE();
}
assert(wrap);
}


TCPWrap::TCPWrap(Environment* env, Handle<Object> object)
TCPWrap::TCPWrap(Environment* env, Handle<Object> object, AsyncWrap* parent)
: StreamWrap(env,
object,
reinterpret_cast<uv_stream_t*>(&handle_),
AsyncWrap::PROVIDER_TCPWRAP) {
AsyncWrap::PROVIDER_TCPWRAP,
parent) {
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.
@@ -342,7 +375,8 @@ void TCPWrap::OnConnection(uv_stream_t* handle, int status) {

if (status == 0) {
// Instantiate the client javascript object and handle.
Local<Object> client_obj = Instantiate(env);
Local<Object> client_obj =
Instantiate(env, static_cast<AsyncWrap*>(tcp_wrap));

// Unwrap the client javascript object.
TCPWrap* wrap = Unwrap<TCPWrap>(client_obj);
@@ -359,7 +393,7 @@ void TCPWrap::OnConnection(uv_stream_t* handle, int status) {


void TCPWrap::AfterConnect(uv_connect_t* req, int status) {
ConnectWrap* req_wrap = static_cast<ConnectWrap*>(req->data);
TCPConnectWrap* req_wrap = static_cast<TCPConnectWrap*>(req->data);
TCPWrap* wrap = static_cast<TCPWrap*>(req->handle->data);
assert(req_wrap->env() == wrap->env());
Environment* env = wrap->env();
@@ -404,9 +438,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(env,
req_wrap_obj,
AsyncWrap::PROVIDER_CONNECTWRAP);
TCPConnectWrap* req_wrap = new TCPConnectWrap(env, req_wrap_obj);
err = uv_tcp_connect(&req_wrap->req_,
&wrap->handle_,
reinterpret_cast<const sockaddr*>(&addr),
@@ -438,9 +470,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(env,
req_wrap_obj,
AsyncWrap::PROVIDER_CONNECTWRAP);
TCPConnectWrap* req_wrap = new TCPConnectWrap(env, req_wrap_obj);
err = uv_tcp_connect(&req_wrap->req_,
&wrap->handle_,
reinterpret_cast<const sockaddr*>(&addr),
@@ -22,22 +22,23 @@
#ifndef SRC_TCP_WRAP_H_
#define SRC_TCP_WRAP_H_

#include "async-wrap.h"
#include "env.h"
#include "stream_wrap.h"

namespace node {

class TCPWrap : public StreamWrap {
public:
static v8::Local<v8::Object> Instantiate(Environment* env);
static v8::Local<v8::Object> Instantiate(Environment* env, AsyncWrap* parent);
static void Initialize(v8::Handle<v8::Object> target,
v8::Handle<v8::Value> unused,
v8::Handle<v8::Context> context);

uv_tcp_t* UVHandle();

private:
TCPWrap(Environment* env, v8::Handle<v8::Object> object);
TCPWrap(Environment* env, v8::Handle<v8::Object> object, AsyncWrap* parent);
~TCPWrap();

static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
@@ -78,7 +78,7 @@ TLSCallbacks::TLSCallbacks(Environment* env,
error_(NULL),
cycle_depth_(0),
eof_(false) {
node::Wrap<TLSCallbacks>(object(), this);
node::Wrap(object(), this);
MakeWeak(this);

// Initialize queue for clearIn writes
@@ -34,6 +34,8 @@
namespace node {

using v8::Context;
using v8::EscapableHandleScope;
using v8::External;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
@@ -62,8 +64,9 @@ class SendWrap : public ReqWrap<uv_udp_send_t> {
SendWrap::SendWrap(Environment* env,
Local<Object> req_wrap_obj,
bool have_callback)
: ReqWrap<uv_udp_send_t>(env, req_wrap_obj),
: ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_UDPWRAP),
have_callback_(have_callback) {
Wrap(req_wrap_obj, this);
}


@@ -72,7 +75,12 @@ inline bool SendWrap::have_callback() const {
}


UDPWrap::UDPWrap(Environment* env, Handle<Object> object)
static void NewSendWrap(const FunctionCallbackInfo<Value>& args) {
assert(args.IsConstructCall());
}


UDPWrap::UDPWrap(Environment* env, Handle<Object> object, AsyncWrap* parent)
: HandleWrap(env,
object,
reinterpret_cast<uv_handle_t*>(&handle_),
@@ -124,14 +132,29 @@ void UDPWrap::Initialize(Handle<Object> target,

target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "UDP"), t->GetFunction());
env->set_udp_constructor_function(t->GetFunction());

// Create FunctionTemplate for SendWrap
Local<FunctionTemplate> swt =
FunctionTemplate::New(env->isolate(), NewSendWrap);
swt->InstanceTemplate()->SetInternalFieldCount(1);
swt->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "SendWrap"));
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "SendWrap"),
swt->GetFunction());
}


void UDPWrap::New(const FunctionCallbackInfo<Value>& args) {
assert(args.IsConstructCall());
HandleScope handle_scope(args.GetIsolate());
CHECK(args.IsConstructCall());
Environment* env = Environment::GetCurrent(args.GetIsolate());
new UDPWrap(env, args.This());
if (args.Length() == 0) {
new UDPWrap(env, args.This(), NULL);
} else if (args[0]->IsExternal()) {
new UDPWrap(env,
args.This(),
static_cast<AsyncWrap*>(args[0].As<External>()->Value()));
} else {
UNREACHABLE();
}
}


@@ -429,10 +452,12 @@ void UDPWrap::OnRecv(uv_udp_t* handle,
}


Local<Object> UDPWrap::Instantiate(Environment* env) {
Local<Object> UDPWrap::Instantiate(Environment* env, AsyncWrap* parent) {
// If this assert fires then Initialize hasn't been called yet.
assert(env->udp_constructor_function().IsEmpty() == false);
return env->udp_constructor_function()->NewInstance();
EscapableHandleScope scope(env->isolate());
Local<Value> ptr = External::New(env->isolate(), parent);
return scope.Escape(env->udp_constructor_function()->NewInstance(1, &ptr));
}


@@ -22,6 +22,7 @@
#ifndef SRC_UDP_WRAP_H_
#define SRC_UDP_WRAP_H_

#include "async-wrap.h"
#include "env.h"
#include "handle_wrap.h"
#include "req_wrap.h"
@@ -53,11 +54,11 @@ class UDPWrap: public HandleWrap {
static void SetBroadcast(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetTTL(const v8::FunctionCallbackInfo<v8::Value>& args);

static v8::Local<v8::Object> Instantiate(Environment* env);
static v8::Local<v8::Object> Instantiate(Environment* env, AsyncWrap* parent);
uv_udp_t* UVHandle();

private:
UDPWrap(Environment* env, v8::Handle<v8::Object> object);
UDPWrap(Environment* env, v8::Handle<v8::Object> object, AsyncWrap* parent);
virtual ~UDPWrap();

static void DoBind(const v8::FunctionCallbackInfo<v8::Value>& args,
@@ -1 +1,6 @@
prefix internet

test-dns : PASS,FLAKY

[$system==solaris]
test-http-dns-fail : PASS,FLAKY
@@ -632,8 +632,9 @@ var getaddrinfoCallbackCalled = false;

console.log('looking up nodejs.org...');

var req = {};
var err = process.binding('cares_wrap').getaddrinfo(req, 'nodejs.org', 4);
var cares = process.binding('cares_wrap');
var req = new cares.GetAddrInfoReqWrap();
var err = cares.getaddrinfo(req, 'nodejs.org', 4);

req.oncomplete = function(err, domains) {
assert.strictEqual(err, 0);
@@ -1 +1,17 @@
prefix simple

test-crypto-domains : PASS,FLAKY

[$system==win32]
test-timers-first-fire : PASS,FLAKY

[$system==linux]
test-fs-readfile-error : PASS,FLAKY
test-net-GH-5504 : PASS,FLAKY
test-stdin-script-child : PASS,FLAKY
test-util-debug : PASS,FLAKY

[$system==macos]

[$system==solaris]
test-debug-signal-cluster : PASS,FLAKY

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.