static bool debug_wait_connect = false;
static int debug_port = 5858;
static bool v8_is_profiling = false;
+static node_module* modpending;
+static node_module* modlist_builtin;
+static node_module* modlist_addon;
// used by C++ modules as well
bool no_deprecation = false;
assert(args[1]->IsFunction());
assert(args[2]->IsFunction());
assert(args[3]->IsFunction());
- assert(args[4]->IsFunction());
- assert(args[5]->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>());
- env->set_async_listener_push_function(args[4].As<Function>());
- env->set_async_listener_strip_function(args[5].As<Function>());
Local<Object> async_listener_flag_obj = args[0].As<Object>();
Environment::AsyncListener* async_listener = env->async_listener();
}
+void SetupDomainUse(const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+
+ if (env->using_domains())
+ return;
+ env->set_using_domains(true);
+
+ HandleScope scope(node_isolate);
+ Local<Object> process_object = env->process_object();
+
+ Local<String> tick_callback_function_key =
+ FIXED_ONE_BYTE_STRING(node_isolate, "_tickDomainCallback");
+ Local<Function> tick_callback_function =
+ process_object->Get(tick_callback_function_key).As<Function>();
+
+ if (!tick_callback_function->IsFunction()) {
+ fprintf(stderr, "process._tickDomainCallback assigned to non-function\n");
+ abort();
+ }
+
+ process_object->Set(FIXED_ONE_BYTE_STRING(node_isolate, "_tickCallback"),
+ tick_callback_function);
+ env->set_tick_callback_function(tick_callback_function);
+
+ assert(args[0]->IsArray());
+ assert(args[1]->IsObject());
+
+ env->set_domain_array(args[0].As<Array>());
+
+ Local<Object> domain_flag_obj = args[1].As<Object>();
+ Environment::DomainFlag* domain_flag = env->domain_flag();
+ domain_flag_obj->SetIndexedPropertiesToExternalArrayData(
+ domain_flag->fields(),
+ kExternalUnsignedIntArray,
+ domain_flag->fields_count());
+
+ // Do a little housekeeping.
+ env->process_object()->Delete(
+ FIXED_ONE_BYTE_STRING(args.GetIsolate(), "_setupDomainUse"));
+}
+
+
void SetupNextTick(const FunctionCallbackInfo<Value>& args) {
HandleScope handle_scope(args.GetIsolate());
Environment* env = Environment::GetCurrent(args.GetIsolate());
- assert(args[0]->IsObject() && args[1]->IsFunction());
+ assert(args[0]->IsObject());
+ assert(args[1]->IsFunction());
// Values use to cross communicate with processNextTick.
Local<Object> tick_info_obj = args[0].As<Object>();
}
+Handle<Value> MakeDomainCallback(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());
+
+ 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;
+
+ 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(node_isolate);
+ }
+ }
+
+ bool has_domain = false;
+
+ if (!object.IsEmpty()) {
+ 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.
+ return Undefined(node_isolate);
+ }
+
+ Local<Function> enter =
+ domain->Get(env->enter_string()).As<Function>();
+ assert(enter->IsFunction());
+ enter->Call(domain, 0, NULL);
+
+ if (try_catch.HasCaught()) {
+ return Undefined(node_isolate);
+ }
+ }
+ }
+
+ Local<Value> ret = callback->Call(recv, argc, argv);
+
+ if (try_catch.HasCaught()) {
+ return Undefined(node_isolate);
+ }
+
+ if (has_domain) {
+ Local<Function> exit =
+ domain->Get(env->exit_string()).As<Function>();
+ assert(exit->IsFunction());
+ exit->Call(domain, 0, NULL);
+
+ if (try_catch.HasCaught()) {
+ return Undefined(node_isolate);
+ }
+ }
+
+ if (has_async_queue) {
+ env->async_listener_unload_function()->Call(process, 1, &recv);
+
+ if (try_catch.HasCaught())
+ return Undefined(node_isolate);
+ }
+
+ Environment::TickInfo* tick_info = env->tick_info();
+
+ if (tick_info->last_threw() == 1) {
+ tick_info->set_last_threw(0);
+ return ret;
+ }
+
+ if (tick_info->in_tick()) {
+ return ret;
+ }
+
+ 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(node_isolate);
+ }
+
+ return ret;
+}
+
+
Handle<Value> MakeCallback(Environment* env,
- Handle<Object> object,
+ 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());
try_catch.SetVerbose(true);
// TODO(trevnorris): This is sucky for performance. Fix it.
- bool has_async_queue = object->Has(env->async_queue_string());
+ bool has_async_queue =
+ recv->IsObject() && recv.As<Object>()->Has(env->async_queue_string());
if (has_async_queue) {
- Local<Value> argv[] = { object };
- env->async_listener_load_function()->Call(process, ARRAY_SIZE(argv), argv);
-
+ env->async_listener_load_function()->Call(process, 1, &recv);
if (try_catch.HasCaught())
return Undefined(node_isolate);
}
- Local<Value> ret = callback->Call(object, argc, argv);
+ Local<Value> ret = callback->Call(recv, argc, argv);
if (try_catch.HasCaught()) {
return Undefined(node_isolate);
}
if (has_async_queue) {
- Local<Value> val = object.As<Value>();
- env->async_listener_unload_function()->Call(process, 1, &val);
+ env->async_listener_unload_function()->Call(process, 1, &recv);
if (try_catch.HasCaught())
return Undefined(node_isolate);
// Internal only.
Handle<Value> MakeCallback(Environment* env,
- const Handle<Object> object,
+ Handle<Object> recv,
uint32_t index,
int argc,
Handle<Value> argv[]) {
- Local<Function> callback = object->Get(index).As<Function>();
+ Local<Function> callback = recv->Get(index).As<Function>();
assert(callback->IsFunction());
- return MakeCallback(env, object, callback, argc, argv);
+ return MakeCallback(env, recv.As<Value>(), callback, argc, argv);
}
Handle<Value> MakeCallback(Environment* env,
- const Handle<Object> object,
- const Handle<String> symbol,
+ Handle<Object> recv,
+ Handle<String> symbol,
int argc,
Handle<Value> argv[]) {
- Local<Function> callback = object->Get(symbol).As<Function>();
+ Local<Function> callback = recv->Get(symbol).As<Function>();
assert(callback->IsFunction());
- return MakeCallback(env, object, callback, argc, argv);
+ return MakeCallback(env, recv.As<Value>(), callback, argc, argv);
}
Handle<Value> MakeCallback(Environment* env,
- const Handle<Object> object,
+ Handle<Object> recv,
const char* method,
int argc,
Handle<Value> argv[]) {
Local<String> method_string = OneByteString(node_isolate, method);
- return MakeCallback(env, object, method_string, argc, argv);
+ return MakeCallback(env, recv, method_string, argc, argv);
}
-Handle<Value> MakeCallback(const Handle<Object> object,
+Handle<Value> MakeCallback(Handle<Object> recv,
const char* method,
int argc,
Handle<Value> argv[]) {
- Local<Context> context = object->CreationContext();
+ HandleScope handle_scope(node_isolate); // FIXME(bnoordhuis) Isolate-ify.
+ Local<Context> context = recv->CreationContext();
Environment* env = Environment::GetCurrent(context);
Context::Scope context_scope(context);
- HandleScope handle_scope(env->isolate());
- return handle_scope.Close(MakeCallback(env, object, method, argc, argv));
+ return handle_scope.Close(MakeCallback(env, recv, method, argc, argv));
}
-Handle<Value> MakeCallback(const Handle<Object> object,
- const Handle<String> symbol,
+Handle<Value> MakeCallback(Handle<Object> recv,
+ Handle<String> symbol,
int argc,
Handle<Value> argv[]) {
- Local<Context> context = object->CreationContext();
+ HandleScope handle_scope(node_isolate); // FIXME(bnoordhuis) Isolate-ify.
+ Local<Context> context = recv->CreationContext();
Environment* env = Environment::GetCurrent(context);
Context::Scope context_scope(context);
- HandleScope handle_scope(env->isolate());
- return handle_scope.Close(MakeCallback(env, object, symbol, argc, argv));
+ return handle_scope.Close(MakeCallback(env, recv, symbol, argc, argv));
}
-Handle<Value> MakeCallback(const Handle<Object> object,
- const Handle<Function> callback,
+Handle<Value> MakeCallback(Handle<Object> recv,
+ Handle<Function> callback,
int argc,
Handle<Value> argv[]) {
- Local<Context> context = object->CreationContext();
+ HandleScope handle_scope(node_isolate); // FIXME(bnoordhuis) Isolate-ify.
+ Local<Context> context = recv->CreationContext();
+ Environment* env = Environment::GetCurrent(context);
+ Context::Scope context_scope(context);
+ return handle_scope.Close(
+ MakeCallback(env, recv.As<Value>(), callback, argc, argv));
+}
+
+
+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);
HandleScope handle_scope(env->isolate());
- return handle_scope.Close(MakeCallback(env, object, callback, argc, argv));
+ return handle_scope.Close(
+ MakeDomainCallback(env, recv, callback, argc, argv));
}
return StringBytes::Write(buf, buflen, val, encoding, NULL);
}
-void DisplayExceptionLine(Handle<Message> message) {
- // Prevent re-entry into this function. For example, if there is
- // a throw from a program in vm.runInThisContext(code, filename, true),
- // then we want to show the original failure, not the secondary one.
- static bool displayed_error = false;
-
- if (displayed_error)
+void AppendExceptionLine(Environment* env,
+ Handle<Value> er,
+ Handle<Message> message) {
+ if (message.IsEmpty())
return;
- displayed_error = true;
- uv_tty_reset_mode();
+ HandleScope scope(env->isolate());
+ Local<Object> err_obj;
+ if (!er.IsEmpty() && er->IsObject()) {
+ err_obj = er.As<Object>();
- fprintf(stderr, "\n");
-
- if (!message.IsEmpty()) {
- // Print (filename):(line number): (message).
- String::Utf8Value filename(message->GetScriptResourceName());
- const char* filename_string = *filename;
- int linenum = message->GetLineNumber();
- fprintf(stderr, "%s:%i\n", filename_string, linenum);
- // Print line of source code.
- String::Utf8Value sourceline(message->GetSourceLine());
- const char* sourceline_string = *sourceline;
-
- // Because of how node modules work, all scripts are wrapped with a
- // "function (module, exports, __filename, ...) {"
- // to provide script local variables.
- //
- // When reporting errors on the first line of a script, this wrapper
- // function is leaked to the user. There used to be a hack here to
- // truncate off the first 62 characters, but it caused numerous other
- // problems when vm.runIn*Context() methods were used for non-module
- // code.
- //
- // If we ever decide to re-instate such a hack, the following steps
- // must be taken:
- //
- // 1. Pass a flag around to say "this code was wrapped"
- // 2. Update the stack frame output so that it is also correct.
- //
- // It would probably be simpler to add a line rather than add some
- // number of characters to the first line, since V8 truncates the
- // sourceline to 78 characters, and we end up not providing very much
- // useful debugging info to the user if we remove 62 characters.
-
- int start = message->GetStartColumn();
- int end = message->GetEndColumn();
-
- fprintf(stderr, "%s\n", sourceline_string);
- // Print wavy underline (GetUnderline is deprecated).
- for (int i = 0; i < start; i++) {
- fputc((sourceline_string[i] == '\t') ? '\t' : ' ', stderr);
- }
- for (int i = start; i < end; i++) {
- fputc('^', stderr);
- }
- fputc('\n', stderr);
+ // Do it only once per message
+ if (!err_obj->GetHiddenValue(env->processed_string()).IsEmpty())
+ return;
+ err_obj->SetHiddenValue(env->processed_string(), True(env->isolate()));
}
+
+ static char arrow[1024];
+
+ // Print (filename):(line number): (message).
+ String::Utf8Value filename(message->GetScriptResourceName());
+ const char* filename_string = *filename;
+ int linenum = message->GetLineNumber();
+ // Print line of source code.
+ String::Utf8Value sourceline(message->GetSourceLine());
+ const char* sourceline_string = *sourceline;
+
+ // Because of how node modules work, all scripts are wrapped with a
+ // "function (module, exports, __filename, ...) {"
+ // to provide script local variables.
+ //
+ // When reporting errors on the first line of a script, this wrapper
+ // function is leaked to the user. There used to be a hack here to
+ // truncate off the first 62 characters, but it caused numerous other
+ // problems when vm.runIn*Context() methods were used for non-module
+ // code.
+ //
+ // If we ever decide to re-instate such a hack, the following steps
+ // must be taken:
+ //
+ // 1. Pass a flag around to say "this code was wrapped"
+ // 2. Update the stack frame output so that it is also correct.
+ //
+ // It would probably be simpler to add a line rather than add some
+ // number of characters to the first line, since V8 truncates the
+ // sourceline to 78 characters, and we end up not providing very much
+ // useful debugging info to the user if we remove 62 characters.
+
+ int start = message->GetStartColumn();
+ int end = message->GetEndColumn();
+
+ int off = snprintf(arrow,
+ sizeof(arrow),
+ "%s:%i\n%s\n",
+ filename_string,
+ linenum,
+ sourceline_string);
+ assert(off >= 0);
+
+ // Print wavy underline (GetUnderline is deprecated).
+ for (int i = 0; i < start; i++) {
+ assert(static_cast<size_t>(off) < sizeof(arrow));
+ arrow[off++] = (sourceline_string[i] == '\t') ? '\t' : ' ';
+ }
+ for (int i = start; i < end; i++) {
+ assert(static_cast<size_t>(off) < sizeof(arrow));
+ arrow[off++] = '^';
+ }
+ assert(static_cast<size_t>(off) < sizeof(arrow) - 1);
+ arrow[off++] = '\n';
+ arrow[off] = '\0';
+
+ Local<String> arrow_str = String::NewFromUtf8(env->isolate(), arrow);
+ Local<Value> msg;
+ Local<Value> stack;
+
+ // Allocation failed, just print it out
+ if (arrow_str.IsEmpty() || err_obj.IsEmpty() || !err_obj->IsNativeError())
+ goto print;
+
+ msg = err_obj->Get(env->message_string());
+ stack = err_obj->Get(env->stack_string());
+
+ if (msg.IsEmpty() || stack.IsEmpty())
+ goto print;
+
+ err_obj->Set(env->message_string(),
+ String::Concat(arrow_str, msg->ToString()));
+ err_obj->Set(env->stack_string(),
+ String::Concat(arrow_str, stack->ToString()));
+ return;
+
+ print:
+ if (env->printed_error())
+ return;
+ env->set_printed_error(true);
+ uv_tty_reset_mode();
+ fprintf(stderr, "\n%s", arrow);
}
-static void ReportException(Handle<Value> er, Handle<Message> message) {
- HandleScope scope(node_isolate);
+static void ReportException(Environment* env,
+ Handle<Value> er,
+ Handle<Message> message) {
+ HandleScope scope(env->isolate());
- DisplayExceptionLine(message);
+ AppendExceptionLine(env, er, message);
Local<Value> trace_value;
- if (er->IsUndefined() || er->IsNull()) {
- trace_value = Undefined(node_isolate);
- } else {
- trace_value =
- er->ToObject()->Get(FIXED_ONE_BYTE_STRING(node_isolate, "stack"));
- }
+ if (er->IsUndefined() || er->IsNull())
+ trace_value = Undefined(env->isolate());
+ else
+ trace_value = er->ToObject()->Get(env->stack_string());
String::Utf8Value trace(trace_value);
if (er->IsObject()) {
Local<Object> err_obj = er.As<Object>();
- message = err_obj->Get(FIXED_ONE_BYTE_STRING(node_isolate, "message"));
- name = err_obj->Get(FIXED_ONE_BYTE_STRING(node_isolate, "name"));
+ message = err_obj->Get(env->message_string());
+ name = err_obj->Get(FIXED_ONE_BYTE_STRING(env->isolate(), "name"));
}
if (message.IsEmpty() ||
}
-static void ReportException(const TryCatch& try_catch) {
- ReportException(try_catch.Exception(), try_catch.Message());
+static void ReportException(Environment* env, const TryCatch& try_catch) {
+ ReportException(env, try_catch.Exception(), try_catch.Message());
}
// Executes a str within the current v8 context.
-Local<Value> ExecuteString(Handle<String> source, Handle<Value> filename) {
- HandleScope scope(node_isolate);
+static Local<Value> ExecuteString(Environment* env,
+ Handle<String> source,
+ Handle<Value> filename) {
+ HandleScope scope(env->isolate());
TryCatch try_catch;
// try_catch must be nonverbose to disable FatalException() handler,
Local<v8::Script> script = v8::Script::Compile(source, filename);
if (script.IsEmpty()) {
- ReportException(try_catch);
+ ReportException(env, try_catch);
exit(3);
}
Local<Value> result = script->Run();
if (result.IsEmpty()) {
- ReportException(try_catch);
+ ReportException(env, try_catch);
exit(4);
}
args.GetReturnValue().Set(tuple);
}
+extern "C" void node_module_register(void* m) {
+ struct node_module* mp = reinterpret_cast<struct node_module*>(m);
+
+ if (mp->nm_flags & NM_F_BUILTIN) {
+ mp->nm_link = modlist_builtin;
+ modlist_builtin = mp;
+ } else {
+ assert(modpending == NULL);
+ modpending = mp;
+ }
+}
+
+struct node_module* get_builtin_module(const char* name) {
+ struct node_module* mp;
+
+ for (mp = modlist_builtin; mp != NULL; mp = mp->nm_link) {
+ if (strcmp(mp->nm_modname, name) == 0)
+ break;
+ }
+
+ assert(mp == NULL || (mp->nm_flags & NM_F_BUILTIN) != 0);
+ return (mp);
+}
typedef void (UV_DYNAMIC* extInit)(Handle<Object> exports);
void DLOpen(const FunctionCallbackInfo<Value>& args) {
HandleScope handle_scope(args.GetIsolate());
Environment* env = Environment::GetCurrent(args.GetIsolate());
- char symbol[1024], *base, *pos;
+ struct node_module* mp;
uv_lib_t lib;
- int r;
if (args.Length() < 2) {
- return ThrowError("process.dlopen takes exactly 2 arguments.");
+ ThrowError("process.dlopen takes exactly 2 arguments.");
+ return;
}
Local<Object> module = args[0]->ToObject(); // Cast
return;
}
- String::Utf8Value path(args[1]);
- base = *path;
-
- /* Find the shared library filename within the full path. */
-#ifdef __POSIX__
- pos = strrchr(base, '/');
- if (pos != NULL) {
- base = pos + 1;
- }
-#else // Windows
- for (;;) {
- pos = strpbrk(base, "\\/:");
- if (pos == NULL) {
- break;
- }
- base = pos + 1;
- }
-#endif // __POSIX__
-
- /* Strip the .node extension. */
- pos = strrchr(base, '.');
- if (pos != NULL) {
- *pos = '\0';
- }
-
- /* Add the `_module` suffix to the extension name. */
- r = snprintf(symbol, sizeof symbol, "%s_module", base);
- if (r <= 0 || static_cast<size_t>(r) >= sizeof symbol) {
- return ThrowError("Out of memory.");
- }
-
- /* Replace dashes with underscores. When loading foo-bar.node,
- * look for foo_bar_module, not foo-bar_module.
+ /*
+ * Objects containing v14 or later modules will have registered themselves
+ * on the pending list. Activate all of them now. At present, only one
+ * module per object is supported.
*/
- for (pos = symbol; *pos != '\0'; ++pos) {
- if (*pos == '-')
- *pos = '_';
- }
+ mp = modpending;
+ modpending = NULL;
- node_module_struct *mod;
- if (uv_dlsym(&lib, symbol, reinterpret_cast<void**>(&mod))) {
- char errmsg[1024];
- snprintf(errmsg, sizeof(errmsg), "Symbol %s not found.", symbol);
- return ThrowError(errmsg);
+ if (mp == NULL) {
+ ThrowError("Module did not self-register.");
+ return;
}
-
- if (mod->version != NODE_MODULE_VERSION) {
+ if (mp->nm_version != NODE_MODULE_VERSION) {
char errmsg[1024];
snprintf(errmsg,
sizeof(errmsg),
"Module version mismatch. Expected %d, got %d.",
- NODE_MODULE_VERSION, mod->version);
- return ThrowError(errmsg);
+ NODE_MODULE_VERSION, mp->nm_version);
+ ThrowError(errmsg);
+ return;
}
+ if (mp->nm_flags & NM_F_BUILTIN) {
+ ThrowError("Built-in module self-registered.");
+ return;
+ }
+
+ mp->nm_dso_handle = lib.handle;
+ mp->nm_link = modlist_addon;
+ modlist_addon = mp;
- // Execute the C++ module
- if (mod->register_context_func != NULL) {
- mod->register_context_func(exports, module, env->context());
- } else if (mod->register_func != NULL) {
- mod->register_func(exports, module);
+ if (mp->nm_context_register_func != NULL) {
+ mp->nm_context_register_func(exports, module, env->context(), mp->nm_priv);
+ } else if (mp->nm_register_func != NULL) {
+ mp->nm_register_func(exports, module, mp->nm_priv);
} else {
- return ThrowError("Module has no declared entry point.");
+ ThrowError("Module has no declared entry point.");
+ return;
}
// Tell coverity that 'handle' should not be freed when we return.
fprintf(stderr, "FATAL ERROR: %s\n", message);
}
fflush(stderr);
-#if defined(DEBUG)
abort();
-#endif
- exit(5);
}
if (!fatal_exception_function->IsFunction()) {
// failed before the process._fatalException function was added!
// this is probably pretty bad. Nothing to do but report and exit.
- ReportException(error, message);
+ ReportException(env, error, message);
exit(6);
}
if (fatal_try_catch.HasCaught()) {
// the fatal exception function threw, so we must exit
- ReportException(fatal_try_catch);
+ ReportException(env, fatal_try_catch);
exit(7);
}
if (false == caught->BooleanValue()) {
- ReportException(error, message);
+ ReportException(env, error, message);
exit(1);
}
}
uint32_t l = modules->Length();
modules->Set(l, OneByteString(node_isolate, buf));
- node_module_struct* mod = get_builtin_module(*module_v);
+ node_module* mod = get_builtin_module(*module_v);
if (mod != NULL) {
exports = Object::New();
// Internal bindings don't have a "module" object, only exports.
- assert(mod->register_func == NULL);
- assert(mod->register_context_func != NULL);
+ assert(mod->nm_register_func == NULL);
+ assert(mod->nm_context_register_func != NULL);
Local<Value> unused = Undefined(env->isolate());
- mod->register_context_func(exports, unused, env->context());
+ mod->nm_context_register_func(exports, unused,
+ env->context(), mod->nm_priv);
cache->Set(module, exports);
} else if (!strcmp(*module_v, "constants")) {
exports = Object::New();
NODE_SET_METHOD(process, "_setupAsyncListener", SetupAsyncListener);
NODE_SET_METHOD(process, "_setupNextTick", SetupNextTick);
+ NODE_SET_METHOD(process, "_setupDomainUse", SetupDomainUse);
// values use to cross communicate with processNextTick
Local<Object> tick_info_obj = Object::New();
// are not safe to ignore.
try_catch.SetVerbose(false);
- Local<String> script_name = FIXED_ONE_BYTE_STRING(node_isolate, "node.js");
- Local<Value> f_value = ExecuteString(MainSource(), script_name);
+ Local<String> script_name = FIXED_ONE_BYTE_STRING(env->isolate(), "node.js");
+ Local<Value> f_value = ExecuteString(env, MainSource(), script_name);
if (try_catch.HasCaught()) {
- ReportException(try_catch);
+ ReportException(env, try_catch);
exit(10);
}
assert(f_value->IsFunction());
fprintf(stderr, "%s: %s requires an argument\n", argv[0], arg);
exit(9);
}
- } else if (argv[index + 1] != NULL && argv[index + 1][0] != '-') {
+ } else if ((index + 1 < nargs) &&
+ argv[index + 1] != NULL &&
+ argv[index + 1][0] != '-') {
args_consumed += 1;
eval_string = argv[index + 1];
if (strncmp(eval_string, "\\-", 2) == 0) {
}
-void EmitExit(Environment* env) {
+int EmitExit(Environment* env) {
// process.emit('exit')
HandleScope handle_scope(env->isolate());
Context::Scope context_scope(env->context());
};
MakeCallback(env, process_object, "emit", ARRAY_SIZE(args), args);
- exit(code);
+
+ // Reload exit code, it may be changed by `emit('exit')`
+ return process_object->Get(exitCode)->IntegerValue();
}
V8::SetEntropySource(crypto::EntropySource);
#endif
+ int code;
V8::Initialize();
{
Locker locker(node_isolate);
// be removed.
Context::Scope context_scope(env->context());
uv_run(env->event_loop(), UV_RUN_DEFAULT);
- EmitExit(env);
+ code = EmitExit(env);
RunAtExit(env);
env->Dispose();
env = NULL;
delete[] exec_argv;
exec_argv = NULL;
- return 0;
+ return code;
}