You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1118 lines
36 KiB
1118 lines
36 KiB
#include "node.h"
|
|
|
|
#if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
|
|
|
|
#include "env.h"
|
|
#include "http_parser.h"
|
|
#include "util.h"
|
|
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#ifdef __POSIX__
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#define NODE_VERSION "JSB2.0" //cjh added
|
|
|
|
static inline const char *errno_string(int errorno) {
|
|
#define ERRNO_CASE(e) \
|
|
case e: return #e;
|
|
switch (errorno) {
|
|
#ifdef EACCES
|
|
ERRNO_CASE(EACCES);
|
|
#endif
|
|
|
|
#ifdef EADDRINUSE
|
|
ERRNO_CASE(EADDRINUSE);
|
|
#endif
|
|
|
|
#ifdef EADDRNOTAVAIL
|
|
ERRNO_CASE(EADDRNOTAVAIL);
|
|
#endif
|
|
|
|
#ifdef EAFNOSUPPORT
|
|
ERRNO_CASE(EAFNOSUPPORT);
|
|
#endif
|
|
|
|
#ifdef EAGAIN
|
|
ERRNO_CASE(EAGAIN);
|
|
#endif
|
|
|
|
#ifdef EWOULDBLOCK
|
|
#if EAGAIN != EWOULDBLOCK
|
|
ERRNO_CASE(EWOULDBLOCK);
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef EALREADY
|
|
ERRNO_CASE(EALREADY);
|
|
#endif
|
|
|
|
#ifdef EBADF
|
|
ERRNO_CASE(EBADF);
|
|
#endif
|
|
|
|
#ifdef EBADMSG
|
|
ERRNO_CASE(EBADMSG);
|
|
#endif
|
|
|
|
#ifdef EBUSY
|
|
ERRNO_CASE(EBUSY);
|
|
#endif
|
|
|
|
#ifdef ECANCELED
|
|
ERRNO_CASE(ECANCELED);
|
|
#endif
|
|
|
|
#ifdef ECHILD
|
|
ERRNO_CASE(ECHILD);
|
|
#endif
|
|
|
|
#ifdef ECONNABORTED
|
|
ERRNO_CASE(ECONNABORTED);
|
|
#endif
|
|
|
|
#ifdef ECONNREFUSED
|
|
ERRNO_CASE(ECONNREFUSED);
|
|
#endif
|
|
|
|
#ifdef ECONNRESET
|
|
ERRNO_CASE(ECONNRESET);
|
|
#endif
|
|
|
|
#ifdef EDEADLK
|
|
ERRNO_CASE(EDEADLK);
|
|
#endif
|
|
|
|
#ifdef EDESTADDRREQ
|
|
ERRNO_CASE(EDESTADDRREQ);
|
|
#endif
|
|
|
|
#ifdef EDOM
|
|
ERRNO_CASE(EDOM);
|
|
#endif
|
|
|
|
#ifdef EDQUOT
|
|
ERRNO_CASE(EDQUOT);
|
|
#endif
|
|
|
|
#ifdef EEXIST
|
|
ERRNO_CASE(EEXIST);
|
|
#endif
|
|
|
|
#ifdef EFAULT
|
|
ERRNO_CASE(EFAULT);
|
|
#endif
|
|
|
|
#ifdef EFBIG
|
|
ERRNO_CASE(EFBIG);
|
|
#endif
|
|
|
|
#ifdef EHOSTUNREACH
|
|
ERRNO_CASE(EHOSTUNREACH);
|
|
#endif
|
|
|
|
#ifdef EIDRM
|
|
ERRNO_CASE(EIDRM);
|
|
#endif
|
|
|
|
#ifdef EILSEQ
|
|
ERRNO_CASE(EILSEQ);
|
|
#endif
|
|
|
|
#ifdef EINPROGRESS
|
|
ERRNO_CASE(EINPROGRESS);
|
|
#endif
|
|
|
|
#ifdef EINTR
|
|
ERRNO_CASE(EINTR);
|
|
#endif
|
|
|
|
#ifdef EINVAL
|
|
ERRNO_CASE(EINVAL);
|
|
#endif
|
|
|
|
#ifdef EIO
|
|
ERRNO_CASE(EIO);
|
|
#endif
|
|
|
|
#ifdef EISCONN
|
|
ERRNO_CASE(EISCONN);
|
|
#endif
|
|
|
|
#ifdef EISDIR
|
|
ERRNO_CASE(EISDIR);
|
|
#endif
|
|
|
|
#ifdef ELOOP
|
|
ERRNO_CASE(ELOOP);
|
|
#endif
|
|
|
|
#ifdef EMFILE
|
|
ERRNO_CASE(EMFILE);
|
|
#endif
|
|
|
|
#ifdef EMLINK
|
|
ERRNO_CASE(EMLINK);
|
|
#endif
|
|
|
|
#ifdef EMSGSIZE
|
|
ERRNO_CASE(EMSGSIZE);
|
|
#endif
|
|
|
|
#ifdef EMULTIHOP
|
|
ERRNO_CASE(EMULTIHOP);
|
|
#endif
|
|
|
|
#ifdef ENAMETOOLONG
|
|
ERRNO_CASE(ENAMETOOLONG);
|
|
#endif
|
|
|
|
#ifdef ENETDOWN
|
|
ERRNO_CASE(ENETDOWN);
|
|
#endif
|
|
|
|
#ifdef ENETRESET
|
|
ERRNO_CASE(ENETRESET);
|
|
#endif
|
|
|
|
#ifdef ENETUNREACH
|
|
ERRNO_CASE(ENETUNREACH);
|
|
#endif
|
|
|
|
#ifdef ENFILE
|
|
ERRNO_CASE(ENFILE);
|
|
#endif
|
|
|
|
#ifdef ENOBUFS
|
|
ERRNO_CASE(ENOBUFS);
|
|
#endif
|
|
|
|
#ifdef ENODATA
|
|
ERRNO_CASE(ENODATA);
|
|
#endif
|
|
|
|
#ifdef ENODEV
|
|
ERRNO_CASE(ENODEV);
|
|
#endif
|
|
|
|
#ifdef ENOENT
|
|
ERRNO_CASE(ENOENT);
|
|
#endif
|
|
|
|
#ifdef ENOEXEC
|
|
ERRNO_CASE(ENOEXEC);
|
|
#endif
|
|
|
|
#ifdef ENOLINK
|
|
ERRNO_CASE(ENOLINK);
|
|
#endif
|
|
|
|
#ifdef ENOLCK
|
|
#if ENOLINK != ENOLCK
|
|
ERRNO_CASE(ENOLCK);
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef ENOMEM
|
|
ERRNO_CASE(ENOMEM);
|
|
#endif
|
|
|
|
#ifdef ENOMSG
|
|
ERRNO_CASE(ENOMSG);
|
|
#endif
|
|
|
|
#ifdef ENOPROTOOPT
|
|
ERRNO_CASE(ENOPROTOOPT);
|
|
#endif
|
|
|
|
#ifdef ENOSPC
|
|
ERRNO_CASE(ENOSPC);
|
|
#endif
|
|
|
|
#ifdef ENOSR
|
|
ERRNO_CASE(ENOSR);
|
|
#endif
|
|
|
|
#ifdef ENOSTR
|
|
ERRNO_CASE(ENOSTR);
|
|
#endif
|
|
|
|
#ifdef ENOSYS
|
|
ERRNO_CASE(ENOSYS);
|
|
#endif
|
|
|
|
#ifdef ENOTCONN
|
|
ERRNO_CASE(ENOTCONN);
|
|
#endif
|
|
|
|
#ifdef ENOTDIR
|
|
ERRNO_CASE(ENOTDIR);
|
|
#endif
|
|
|
|
#ifdef ENOTEMPTY
|
|
#if ENOTEMPTY != EEXIST
|
|
ERRNO_CASE(ENOTEMPTY);
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef ENOTSOCK
|
|
ERRNO_CASE(ENOTSOCK);
|
|
#endif
|
|
|
|
#ifdef ENOTSUP
|
|
ERRNO_CASE(ENOTSUP);
|
|
#else
|
|
#ifdef EOPNOTSUPP
|
|
ERRNO_CASE(EOPNOTSUPP);
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef ENOTTY
|
|
ERRNO_CASE(ENOTTY);
|
|
#endif
|
|
|
|
#ifdef ENXIO
|
|
ERRNO_CASE(ENXIO);
|
|
#endif
|
|
|
|
#ifdef EOVERFLOW
|
|
ERRNO_CASE(EOVERFLOW);
|
|
#endif
|
|
|
|
#ifdef EPERM
|
|
ERRNO_CASE(EPERM);
|
|
#endif
|
|
|
|
#ifdef EPIPE
|
|
ERRNO_CASE(EPIPE);
|
|
#endif
|
|
|
|
#ifdef EPROTO
|
|
ERRNO_CASE(EPROTO);
|
|
#endif
|
|
|
|
#ifdef EPROTONOSUPPORT
|
|
ERRNO_CASE(EPROTONOSUPPORT);
|
|
#endif
|
|
|
|
#ifdef EPROTOTYPE
|
|
ERRNO_CASE(EPROTOTYPE);
|
|
#endif
|
|
|
|
#ifdef ERANGE
|
|
ERRNO_CASE(ERANGE);
|
|
#endif
|
|
|
|
#ifdef EROFS
|
|
ERRNO_CASE(EROFS);
|
|
#endif
|
|
|
|
#ifdef ESPIPE
|
|
ERRNO_CASE(ESPIPE);
|
|
#endif
|
|
|
|
#ifdef ESRCH
|
|
ERRNO_CASE(ESRCH);
|
|
#endif
|
|
|
|
#ifdef ESTALE
|
|
ERRNO_CASE(ESTALE);
|
|
#endif
|
|
|
|
#ifdef ETIME
|
|
ERRNO_CASE(ETIME);
|
|
#endif
|
|
|
|
#ifdef ETIMEDOUT
|
|
ERRNO_CASE(ETIMEDOUT);
|
|
#endif
|
|
|
|
#ifdef ETXTBSY
|
|
ERRNO_CASE(ETXTBSY);
|
|
#endif
|
|
|
|
#ifdef EXDEV
|
|
ERRNO_CASE(EXDEV);
|
|
#endif
|
|
|
|
default: return "";
|
|
}
|
|
}
|
|
|
|
#ifdef __POSIX__
|
|
void RegisterSignalHandler(int signal,
|
|
void (*handler)(int signal),
|
|
bool reset_handler) {
|
|
struct sigaction sa;
|
|
memset(&sa, 0, sizeof(sa));
|
|
sa.sa_handler = handler;
|
|
#ifndef __FreeBSD__
|
|
// FreeBSD has a nasty bug with SA_RESETHAND reseting the SA_SIGINFO, that is
|
|
// in turn set for a libthr wrapper. This leads to a crash.
|
|
// Work around the issue by manually setting SIG_DFL in the signal handler
|
|
sa.sa_flags = reset_handler ? SA_RESETHAND : 0;
|
|
#endif
|
|
sigfillset(&sa.sa_mask);
|
|
CHECK_EQ(sigaction(signal, &sa, nullptr), 0);
|
|
}
|
|
#endif // __POSIX__
|
|
|
|
using namespace v8;
|
|
|
|
namespace node {
|
|
|
|
static bool v8_is_profiling = false;
|
|
|
|
Local<Value> ErrnoException(Isolate *isolate,
|
|
int errorno,
|
|
const char *syscall,
|
|
const char *msg,
|
|
const char *path) {
|
|
Environment *env = Environment::GetCurrent(isolate);
|
|
|
|
Local<Value> e;
|
|
Local<String> estring = OneByteString(env->isolate(), errno_string(errorno));
|
|
if (msg == nullptr || msg[0] == '\0') {
|
|
msg = strerror(errorno);
|
|
}
|
|
Local<String> message = OneByteString(env->isolate(), msg);
|
|
|
|
Local<String> cons =
|
|
String::Concat(env->isolate(), estring, FIXED_ONE_BYTE_STRING(env->isolate(), ", "));
|
|
cons = String::Concat(env->isolate(), cons, message);
|
|
|
|
Local<String> path_string;
|
|
if (path != nullptr) {
|
|
// IDEA(bnoordhuis) It's questionable to interpret the file path as UTF-8.
|
|
path_string = String::NewFromUtf8(env->isolate(), path, v8::NewStringType::kNormal).ToLocalChecked();
|
|
}
|
|
|
|
if (path_string.IsEmpty() == false) {
|
|
cons = String::Concat(env->isolate(), cons, FIXED_ONE_BYTE_STRING(env->isolate(), " '"));
|
|
cons = String::Concat(env->isolate(), cons, path_string);
|
|
cons = String::Concat(env->isolate(), cons, FIXED_ONE_BYTE_STRING(env->isolate(), "'"));
|
|
}
|
|
e = Exception::Error(cons);
|
|
|
|
Local<Object> obj = e->ToObject(env->context()).ToLocalChecked();
|
|
obj->Set(env->context(), env->errno_string(), Integer::New(env->isolate(), errorno)).Check();
|
|
obj->Set(env->context(), env->code_string(), estring).Check();
|
|
|
|
if (path_string.IsEmpty() == false) {
|
|
obj->Set(env->context(), env->path_string(), path_string).Check();
|
|
}
|
|
|
|
if (syscall != nullptr) {
|
|
obj->Set(env->context(), env->syscall_string(), OneByteString(env->isolate(), syscall)).Check();
|
|
}
|
|
|
|
return e;
|
|
}
|
|
|
|
static Local<String> StringFromPath(Isolate *isolate, const char *path) {
|
|
#ifdef _WIN32
|
|
if (strncmp(path, "\\\\?\\UNC\\", 8) == 0) {
|
|
return String::Concat(isolate, FIXED_ONE_BYTE_STRING(isolate, "\\\\"),
|
|
String::NewFromUtf8(isolate, path + 8).ToLocalChecked());
|
|
} else if (strncmp(path, "\\\\?\\", 4) == 0) {
|
|
return String::NewFromUtf8(isolate, path + 4).ToLocalChecked();
|
|
}
|
|
#endif
|
|
|
|
return String::NewFromUtf8(isolate, path, v8::NewStringType::kNormal).ToLocalChecked();
|
|
}
|
|
|
|
Local<Value> UVException(Isolate *isolate,
|
|
int errorno,
|
|
const char *syscall,
|
|
const char *msg,
|
|
const char *path) {
|
|
return UVException(isolate, errorno, syscall, msg, path, nullptr);
|
|
}
|
|
|
|
Local<Value> UVException(Isolate *isolate,
|
|
int errorno,
|
|
const char *syscall,
|
|
const char *msg,
|
|
const char *path,
|
|
const char *dest) {
|
|
Environment *env = Environment::GetCurrent(isolate);
|
|
|
|
if (!msg || !msg[0])
|
|
msg = uv_strerror(errorno);
|
|
|
|
Local<String> js_code = OneByteString(isolate, uv_err_name(errorno));
|
|
Local<String> js_syscall = OneByteString(isolate, syscall);
|
|
Local<String> js_path;
|
|
Local<String> js_dest;
|
|
|
|
Local<String> js_msg = js_code;
|
|
js_msg = String::Concat(isolate, js_msg, FIXED_ONE_BYTE_STRING(isolate, ": "));
|
|
js_msg = String::Concat(isolate, js_msg, OneByteString(isolate, msg));
|
|
js_msg = String::Concat(isolate, js_msg, FIXED_ONE_BYTE_STRING(isolate, ", "));
|
|
js_msg = String::Concat(isolate, js_msg, js_syscall);
|
|
|
|
if (path != nullptr) {
|
|
js_path = StringFromPath(isolate, path);
|
|
|
|
js_msg = String::Concat(isolate, js_msg, FIXED_ONE_BYTE_STRING(isolate, " '"));
|
|
js_msg = String::Concat(isolate, js_msg, js_path);
|
|
js_msg = String::Concat(isolate, js_msg, FIXED_ONE_BYTE_STRING(isolate, "'"));
|
|
}
|
|
|
|
if (dest != nullptr) {
|
|
js_dest = StringFromPath(isolate, dest);
|
|
|
|
js_msg = String::Concat(isolate, js_msg, FIXED_ONE_BYTE_STRING(isolate, " -> '"));
|
|
js_msg = String::Concat(isolate, js_msg, js_dest);
|
|
js_msg = String::Concat(isolate, js_msg, FIXED_ONE_BYTE_STRING(isolate, "'"));
|
|
}
|
|
|
|
Local<Object> e = Exception::Error(js_msg)->ToObject(isolate->GetCurrentContext()).ToLocalChecked();
|
|
|
|
e->Set(isolate->GetCurrentContext(), env->errno_string(), Integer::New(isolate, errorno)).Check();
|
|
e->Set(isolate->GetCurrentContext(), env->code_string(), js_code).Check();
|
|
e->Set(isolate->GetCurrentContext(), env->syscall_string(), js_syscall).Check();
|
|
if (!js_path.IsEmpty())
|
|
e->Set(isolate->GetCurrentContext(), env->path_string(), js_path).Check();
|
|
if (!js_dest.IsEmpty())
|
|
e->Set(isolate->GetCurrentContext(), env->dest_string(), js_dest).Check();
|
|
|
|
return e;
|
|
}
|
|
|
|
MaybeLocal<Value> MakeCallback(Environment *env,
|
|
Local<Value> recv,
|
|
const Local<Function> callback,
|
|
int argc,
|
|
Local<Value> argv[],
|
|
async_context asyncContext) {
|
|
// If you hit this assertion, you forgot to enter the v8::Context first.
|
|
CHECK_EQ(env->context(), env->isolate()->GetCurrentContext());
|
|
|
|
Local<Object> object;
|
|
|
|
// Environment::AsyncCallbackScope callback_scope(env);
|
|
// bool disposed_domain = false;
|
|
//
|
|
// if (recv->IsObject()) {
|
|
// object = recv.As<Object>();
|
|
// }
|
|
//
|
|
// if (env->using_domains()) {
|
|
// CHECK(recv->IsObject());
|
|
// disposed_domain = DomainEnter(env, object);
|
|
// if (disposed_domain) return Undefined(env->isolate());
|
|
// }
|
|
|
|
MaybeLocal<Value> ret;
|
|
|
|
// {
|
|
// AsyncHooks::ExecScope exec_scope(env, asyncContext.async_id,
|
|
// asyncContext.trigger_async_id);
|
|
//
|
|
// if (asyncContext.async_id != 0) {
|
|
// if (!AsyncWrap::EmitBefore(env, asyncContext.async_id))
|
|
// return Local<Value>();
|
|
// }
|
|
//
|
|
// ret = callback->Call(env->context(), recv, argc, argv);
|
|
//
|
|
// if (ret.IsEmpty()) {
|
|
// // NOTE: For backwards compatibility with public API we return Undefined()
|
|
// // if the top level call threw.
|
|
// return callback_scope.in_makecallback() ?
|
|
// ret : Undefined(env->isolate());
|
|
// }
|
|
//
|
|
// if (asyncContext.async_id != 0) {
|
|
// if (!AsyncWrap::EmitAfter(env, asyncContext.async_id))
|
|
// return Local<Value>();
|
|
// }
|
|
// }
|
|
//
|
|
// if (env->using_domains()) {
|
|
// disposed_domain = DomainExit(env, object);
|
|
// if (disposed_domain) return Undefined(env->isolate());
|
|
// }
|
|
//
|
|
// if (callback_scope.in_makecallback()) {
|
|
// return ret;
|
|
// }
|
|
//
|
|
// Environment::TickInfo* tick_info = env->tick_info();
|
|
//
|
|
// if (tick_info->length() == 0) {
|
|
// env->isolate()->RunMicrotasks();
|
|
// }
|
|
//
|
|
// // Make sure the stack unwound properly. If there are nested MakeCallback's
|
|
// // then it should return early and not reach this code.
|
|
// CHECK_EQ(env->current_async_id(), asyncContext.async_id);
|
|
// CHECK_EQ(env->trigger_id(), asyncContext.trigger_async_id);
|
|
//
|
|
// Local<Object> process = env->process_object();
|
|
//
|
|
// if (tick_info->length() == 0) {
|
|
// tick_info->set_index(0);
|
|
// return ret;
|
|
// }
|
|
//
|
|
// if (env->tick_callback_function()->Call(process, 0, nullptr).IsEmpty()) {
|
|
// return Undefined(env->isolate());
|
|
// }
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Public MakeCallback()s
|
|
|
|
MaybeLocal<Value> MakeCallback(Isolate *isolate,
|
|
Local<Object> recv,
|
|
const char *method,
|
|
int argc,
|
|
Local<Value> argv[],
|
|
async_context asyncContext) {
|
|
Local<String> method_string =
|
|
String::NewFromUtf8(isolate, method, v8::NewStringType::kNormal)
|
|
.ToLocalChecked();
|
|
return MakeCallback(isolate, recv, method_string, argc, argv, asyncContext);
|
|
}
|
|
|
|
MaybeLocal<Value> MakeCallback(Isolate *isolate,
|
|
Local<Object> recv,
|
|
Local<String> symbol,
|
|
int argc,
|
|
Local<Value> argv[],
|
|
async_context asyncContext) {
|
|
Local<Value> callback_v = recv->Get(isolate->GetCurrentContext(), symbol).ToLocalChecked();
|
|
if (callback_v.IsEmpty()) return Local<Value>();
|
|
if (!callback_v->IsFunction()) return Local<Value>();
|
|
Local<Function> callback = callback_v.As<Function>();
|
|
return MakeCallback(isolate, recv, callback, argc, argv, asyncContext);
|
|
}
|
|
|
|
MaybeLocal<Value> MakeCallback(Isolate *isolate,
|
|
Local<Object> recv,
|
|
Local<Function> callback,
|
|
int argc,
|
|
Local<Value> argv[],
|
|
async_context asyncContext) {
|
|
// Observe the following two subtleties:
|
|
//
|
|
// 1. The environment is retrieved from the callback function's context.
|
|
// 2. The context to enter is retrieved from the environment.
|
|
//
|
|
// Because of the AssignToContext() call in src/node_contextify.cc,
|
|
// the two contexts need not be the same.
|
|
Environment *env = Environment::GetCurrent(callback->GetCreationContext().ToLocalChecked());
|
|
Context::Scope context_scope(env->context());
|
|
return MakeCallback(env, recv.As<Value>(), callback, argc, argv,
|
|
asyncContext);
|
|
}
|
|
|
|
// Legacy MakeCallback()s
|
|
|
|
Local<Value> MakeCallback(Isolate *isolate,
|
|
Local<Object> recv,
|
|
const char *method,
|
|
int argc,
|
|
Local<Value> *argv) {
|
|
EscapableHandleScope handle_scope(isolate);
|
|
return handle_scope.Escape(
|
|
MakeCallback(isolate, recv, method, argc, argv, {0, 0})
|
|
.FromMaybe(Local<Value>()));
|
|
}
|
|
|
|
Local<Value> MakeCallback(Isolate *isolate,
|
|
Local<Object> recv,
|
|
Local<String> symbol,
|
|
int argc,
|
|
Local<Value> *argv) {
|
|
EscapableHandleScope handle_scope(isolate);
|
|
return handle_scope.Escape(
|
|
MakeCallback(isolate, recv, symbol, argc, argv, {0, 0})
|
|
.FromMaybe(Local<Value>()));
|
|
}
|
|
|
|
Local<Value> MakeCallback(Isolate *isolate,
|
|
Local<Object> recv,
|
|
Local<Function> callback,
|
|
int argc,
|
|
Local<Value> *argv) {
|
|
EscapableHandleScope handle_scope(isolate);
|
|
return handle_scope.Escape(
|
|
MakeCallback(isolate, recv, callback, argc, argv, {0, 0})
|
|
.FromMaybe(Local<Value>()));
|
|
}
|
|
|
|
IsolateData *CreateIsolateData(Isolate *isolate, uv_loop_t *loop) {
|
|
return new IsolateData(isolate, loop);
|
|
}
|
|
|
|
void FreeIsolateData(IsolateData *isolate_data) {
|
|
delete isolate_data;
|
|
}
|
|
|
|
Environment *CreateEnvironment(IsolateData *isolate_data,
|
|
Local<Context> context,
|
|
int argc,
|
|
const char *const *argv,
|
|
int exec_argc,
|
|
const char *const *exec_argv) {
|
|
Isolate *isolate = context->GetIsolate();
|
|
HandleScope handle_scope(isolate);
|
|
Context::Scope context_scope(context);
|
|
auto env = new Environment(isolate_data, context);
|
|
env->Start(argc, argv, exec_argc, exec_argv, v8_is_profiling);
|
|
return env;
|
|
}
|
|
|
|
void FreeEnvironment(Environment *env) {
|
|
delete env;
|
|
}
|
|
|
|
NO_RETURN void Abort() {
|
|
DumpBacktrace(stderr);
|
|
fflush(stderr);
|
|
ABORT_NO_BACKTRACE();
|
|
}
|
|
|
|
NO_RETURN void Assert(const char *const (*args)[4]) {
|
|
auto filename = (*args)[0];
|
|
auto linenum = (*args)[1];
|
|
auto message = (*args)[2];
|
|
auto function = (*args)[3];
|
|
|
|
char exepath[256];
|
|
size_t exepath_size = sizeof(exepath);
|
|
if (uv_exepath(exepath, &exepath_size))
|
|
snprintf(exepath, sizeof(exepath), "node");
|
|
|
|
char pid[12] = {0};
|
|
#ifndef _WIN32
|
|
snprintf(pid, sizeof(pid), "[%u]", getpid());
|
|
#endif
|
|
|
|
SE_LOGE("%s%s: %s:%s:%s%s Assertion `%s' failed.\n",
|
|
exepath, pid, filename, linenum,
|
|
function, *function ? ":" : "", message);
|
|
|
|
Abort();
|
|
}
|
|
|
|
static void Abort(const FunctionCallbackInfo<Value> &args) {
|
|
Abort();
|
|
}
|
|
|
|
#define READONLY_PROPERTY(obj, str, var) \
|
|
do { \
|
|
obj->DefineOwnProperty(env->context(), \
|
|
OneByteString(env->isolate(), str), \
|
|
var, \
|
|
v8::ReadOnly) \
|
|
.FromJust(); \
|
|
} while (0)
|
|
|
|
#define READONLY_DONT_ENUM_PROPERTY(obj, str, var) \
|
|
do { \
|
|
obj->DefineOwnProperty(env->context(), \
|
|
OneByteString(env->isolate(), str), \
|
|
var, \
|
|
static_cast<v8::PropertyAttribute>(v8::ReadOnly | \
|
|
v8::DontEnum)) \
|
|
.FromJust(); \
|
|
} while (0)
|
|
|
|
static void ProcessTitleGetter(Local<Name> property,
|
|
const PropertyCallbackInfo<Value> &info) {
|
|
char buffer[512];
|
|
uv_get_process_title(buffer, sizeof(buffer));
|
|
info.GetReturnValue().Set(String::NewFromUtf8(info.GetIsolate(), buffer, v8::NewStringType::kNormal).ToLocalChecked());
|
|
}
|
|
|
|
static void ProcessTitleSetter(Local<Name> property,
|
|
Local<Value> value,
|
|
const PropertyCallbackInfo<void> &info) {
|
|
node::Utf8Value title(info.GetIsolate(), value);
|
|
// REFINE(piscisaureus): protect with a lock
|
|
uv_set_process_title(*title);
|
|
}
|
|
|
|
void SetupProcessObject(Environment *env,
|
|
int argc,
|
|
const char *const *argv,
|
|
int exec_argc,
|
|
const char *const *exec_argv) {
|
|
HandleScope scope(env->isolate());
|
|
|
|
Local<Object> process = env->process_object();
|
|
|
|
auto title_string = FIXED_ONE_BYTE_STRING(env->isolate(), "title");
|
|
CHECK(process->SetAccessor(env->context(),
|
|
title_string,
|
|
ProcessTitleGetter,
|
|
ProcessTitleSetter,
|
|
env->as_external())
|
|
.FromJust());
|
|
|
|
// process.version
|
|
READONLY_PROPERTY(process,
|
|
"version",
|
|
FIXED_ONE_BYTE_STRING(env->isolate(), NODE_VERSION));
|
|
|
|
// process.moduleLoadList
|
|
READONLY_PROPERTY(process,
|
|
"moduleLoadList",
|
|
env->module_load_list_array());
|
|
|
|
// process.versions
|
|
Local<Object> versions = Object::New(env->isolate());
|
|
READONLY_PROPERTY(process, "versions", versions);
|
|
|
|
const char http_parser_version[] = NODE_STRINGIFY(HTTP_PARSER_VERSION_MAJOR) "." NODE_STRINGIFY(HTTP_PARSER_VERSION_MINOR) "." NODE_STRINGIFY(HTTP_PARSER_VERSION_PATCH);
|
|
READONLY_PROPERTY(versions,
|
|
"http_parser",
|
|
FIXED_ONE_BYTE_STRING(env->isolate(), http_parser_version));
|
|
|
|
// +1 to get rid of the leading 'v'
|
|
READONLY_PROPERTY(versions,
|
|
"node",
|
|
OneByteString(env->isolate(), NODE_VERSION));
|
|
READONLY_PROPERTY(versions,
|
|
"v8",
|
|
OneByteString(env->isolate(), V8::GetVersion()));
|
|
READONLY_PROPERTY(versions,
|
|
"uv",
|
|
OneByteString(env->isolate(), uv_version_string()));
|
|
|
|
SE_LOGD("libuv version: %s\n", uv_version_string());
|
|
// READONLY_PROPERTY(versions,
|
|
// "zlib",
|
|
// FIXED_ONE_BYTE_STRING(env->isolate(), ZLIB_VERSION));
|
|
// READONLY_PROPERTY(versions,
|
|
// "ares",
|
|
// FIXED_ONE_BYTE_STRING(env->isolate(), ARES_VERSION_STR));
|
|
|
|
// const char node_modules_version[] = NODE_STRINGIFY(NODE_MODULE_VERSION);
|
|
// READONLY_PROPERTY(
|
|
// versions,
|
|
// "modules",
|
|
// FIXED_ONE_BYTE_STRING(env->isolate(), node_modules_version));
|
|
|
|
// process._promiseRejectEvent
|
|
Local<Object> promiseRejectEvent = Object::New(env->isolate());
|
|
READONLY_DONT_ENUM_PROPERTY(process,
|
|
"_promiseRejectEvent",
|
|
promiseRejectEvent);
|
|
READONLY_PROPERTY(promiseRejectEvent,
|
|
"unhandled",
|
|
Integer::New(env->isolate(),
|
|
v8::kPromiseRejectWithNoHandler));
|
|
READONLY_PROPERTY(promiseRejectEvent,
|
|
"handled",
|
|
Integer::New(env->isolate(),
|
|
v8::kPromiseHandlerAddedAfterReject));
|
|
|
|
//#if HAVE_OPENSSL
|
|
// // Stupid code to slice out the version string.
|
|
// { // NOLINT(whitespace/braces)
|
|
// size_t i, j, k;
|
|
// int c;
|
|
// for (i = j = 0, k = sizeof(OPENSSL_VERSION_TEXT) - 1; i < k; ++i) {
|
|
// c = OPENSSL_VERSION_TEXT[i];
|
|
// if ('0' <= c && c <= '9') {
|
|
// for (j = i + 1; j < k; ++j) {
|
|
// c = OPENSSL_VERSION_TEXT[j];
|
|
// if (c == ' ')
|
|
// break;
|
|
// }
|
|
// break;
|
|
// }
|
|
// }
|
|
// READONLY_PROPERTY(
|
|
// versions,
|
|
// "openssl",
|
|
// OneByteString(env->isolate(), &OPENSSL_VERSION_TEXT[i], j - i));
|
|
// }
|
|
//#endif
|
|
|
|
// process.arch
|
|
READONLY_PROPERTY(process, "arch", OneByteString(env->isolate(), "x64")); //IDEA: cjh
|
|
|
|
// process.platform
|
|
READONLY_PROPERTY(process,
|
|
"platform",
|
|
OneByteString(env->isolate(), "macOS")); //IDEA: cjh
|
|
|
|
// process.release
|
|
Local<Object> release = Object::New(env->isolate());
|
|
READONLY_PROPERTY(process, "release", release);
|
|
READONLY_PROPERTY(release, "name", OneByteString(env->isolate(), "node"));
|
|
|
|
// if this is a release build and no explicit base has been set
|
|
// substitute the standard release download URL
|
|
#ifndef NODE_RELEASE_URLBASE
|
|
#if NODE_VERSION_IS_RELEASE
|
|
#define NODE_RELEASE_URLBASE "https://nodejs.org/download/release/"
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(NODE_RELEASE_URLBASE)
|
|
#define NODE_RELEASE_URLPFX NODE_RELEASE_URLBASE "v" NODE_VERSION_STRING "/"
|
|
#define NODE_RELEASE_URLFPFX NODE_RELEASE_URLPFX "node-v" NODE_VERSION_STRING
|
|
|
|
READONLY_PROPERTY(release,
|
|
"sourceUrl",
|
|
OneByteString(env->isolate(),
|
|
NODE_RELEASE_URLFPFX ".tar.gz"));
|
|
READONLY_PROPERTY(release,
|
|
"headersUrl",
|
|
OneByteString(env->isolate(),
|
|
NODE_RELEASE_URLFPFX "-headers.tar.gz"));
|
|
#ifdef _WIN32
|
|
READONLY_PROPERTY(release,
|
|
"libUrl",
|
|
OneByteString(env->isolate(),
|
|
strcmp(NODE_ARCH, "ia32") ? NODE_RELEASE_URLPFX "win-" NODE_ARCH "/node.lib"
|
|
: NODE_RELEASE_URLPFX
|
|
"win-x86/node.lib"));
|
|
#endif
|
|
#endif
|
|
|
|
// process.argv
|
|
Local<Array> arguments = Array::New(env->isolate(), argc);
|
|
for (int i = 0; i < argc; ++i) {
|
|
arguments->Set(env->context(), i, String::NewFromUtf8(env->isolate(), argv[i], v8::NewStringType::kNormal).ToLocalChecked()).Check();
|
|
}
|
|
process->Set(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), "argv"), arguments).Check();
|
|
|
|
// process.execArgv
|
|
Local<Array> exec_arguments = Array::New(env->isolate(), exec_argc);
|
|
for (int i = 0; i < exec_argc; ++i) {
|
|
exec_arguments->Set(env->context(), i, String::NewFromUtf8(env->isolate(), exec_argv[i], v8::NewStringType::kNormal).ToLocalChecked()).Check();
|
|
}
|
|
process->Set(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), "execArgv"),
|
|
exec_arguments)
|
|
.Check();
|
|
|
|
// create process.env
|
|
// Local<ObjectTemplate> process_env_template =
|
|
// ObjectTemplate::New(env->isolate());
|
|
// process_env_template->SetHandler(NamedPropertyHandlerConfiguration(
|
|
// EnvGetter,
|
|
// EnvSetter,
|
|
// EnvQuery,
|
|
// EnvDeleter,
|
|
// EnvEnumerator,
|
|
// env->as_external()));
|
|
//
|
|
// Local<Object> process_env =
|
|
// process_env_template->NewInstance(env->context()).ToLocalChecked();
|
|
// process->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "env"), process_env);
|
|
//
|
|
// READONLY_PROPERTY(process, "pid", Integer::New(env->isolate(), getpid()));
|
|
// READONLY_PROPERTY(process, "features", GetFeatures(env));
|
|
//
|
|
// auto need_immediate_callback_string =
|
|
// FIXED_ONE_BYTE_STRING(env->isolate(), "_needImmediateCallback");
|
|
// CHECK(process->SetAccessor(env->context(), need_immediate_callback_string,
|
|
// NeedImmediateCallbackGetter,
|
|
// NeedImmediateCallbackSetter,
|
|
// env->as_external()).FromJust());
|
|
//
|
|
// // -e, --eval
|
|
// if (eval_string) {
|
|
// READONLY_PROPERTY(process,
|
|
// "_eval",
|
|
// String::NewFromUtf8(env->isolate(), eval_string));
|
|
// }
|
|
//
|
|
// // -p, --print
|
|
// if (print_eval) {
|
|
// READONLY_PROPERTY(process, "_print_eval", True(env->isolate()));
|
|
// }
|
|
//
|
|
// // -c, --check
|
|
// if (syntax_check_only) {
|
|
// READONLY_PROPERTY(process, "_syntax_check_only", True(env->isolate()));
|
|
// }
|
|
//
|
|
// // -i, --interactive
|
|
// if (force_repl) {
|
|
// READONLY_PROPERTY(process, "_forceRepl", True(env->isolate()));
|
|
// }
|
|
|
|
// // -r, --require
|
|
// if (!preload_modules.empty()) {
|
|
// Local<Array> array = Array::New(env->isolate());
|
|
// for (unsigned int i = 0; i < preload_modules.size(); ++i) {
|
|
// Local<String> module = String::NewFromUtf8(env->isolate(),
|
|
// preload_modules[i].c_str());
|
|
// array->Set(i, module);
|
|
// }
|
|
// READONLY_PROPERTY(process,
|
|
// "_preload_modules",
|
|
// array);
|
|
//
|
|
// preload_modules.clear();
|
|
// }
|
|
//
|
|
// // --no-deprecation
|
|
// if (no_deprecation) {
|
|
// READONLY_PROPERTY(process, "noDeprecation", True(env->isolate()));
|
|
// }
|
|
//
|
|
// // --no-warnings
|
|
// if (no_process_warnings) {
|
|
// READONLY_PROPERTY(process, "noProcessWarnings", True(env->isolate()));
|
|
// }
|
|
//
|
|
// // --trace-warnings
|
|
// if (trace_warnings) {
|
|
// READONLY_PROPERTY(process, "traceProcessWarnings", True(env->isolate()));
|
|
// }
|
|
//
|
|
// // --throw-deprecation
|
|
// if (throw_deprecation) {
|
|
// READONLY_PROPERTY(process, "throwDeprecation", True(env->isolate()));
|
|
// }
|
|
//
|
|
//#ifdef NODE_NO_BROWSER_GLOBALS
|
|
// // configure --no-browser-globals
|
|
// READONLY_PROPERTY(process, "_noBrowserGlobals", True(env->isolate()));
|
|
//#endif // NODE_NO_BROWSER_GLOBALS
|
|
//
|
|
// // --prof-process
|
|
// if (prof_process) {
|
|
// READONLY_PROPERTY(process, "profProcess", True(env->isolate()));
|
|
// }
|
|
//
|
|
// // --trace-deprecation
|
|
// if (trace_deprecation) {
|
|
// READONLY_PROPERTY(process, "traceDeprecation", True(env->isolate()));
|
|
// }
|
|
//
|
|
// // REFINE(refack): move the following 3 to `node_config`
|
|
// // --inspect-brk
|
|
// if (debug_options.wait_for_connect()) {
|
|
// READONLY_DONT_ENUM_PROPERTY(process,
|
|
// "_breakFirstLine", True(env->isolate()));
|
|
// }
|
|
//
|
|
// // --inspect --debug-brk
|
|
// if (debug_options.deprecated_invocation()) {
|
|
// READONLY_DONT_ENUM_PROPERTY(process,
|
|
// "_deprecatedDebugBrk", True(env->isolate()));
|
|
// }
|
|
//
|
|
// // --debug or, --debug-brk without --inspect
|
|
// if (debug_options.invalid_invocation()) {
|
|
// READONLY_DONT_ENUM_PROPERTY(process,
|
|
// "_invalidDebug", True(env->isolate()));
|
|
// }
|
|
//
|
|
// // --security-revert flags
|
|
//#define V(code, _, __) \
|
|
//do { \
|
|
//if (IsReverted(REVERT_ ## code)) { \
|
|
//READONLY_PROPERTY(process, "REVERT_" #code, True(env->isolate())); \
|
|
//} \
|
|
//} while (0);
|
|
// REVERSIONS(V)
|
|
//#undef V
|
|
//
|
|
// size_t exec_path_len = 2 * PATH_MAX;
|
|
// char* exec_path = new char[exec_path_len];
|
|
// Local<String> exec_path_value;
|
|
// if (uv_exepath(exec_path, &exec_path_len) == 0) {
|
|
// exec_path_value = String::NewFromUtf8(env->isolate(),
|
|
// exec_path,
|
|
// String::kNormalString,
|
|
// exec_path_len);
|
|
// } else {
|
|
// exec_path_value = String::NewFromUtf8(env->isolate(), argv[0]);
|
|
// }
|
|
// process->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "execPath"),
|
|
// exec_path_value);
|
|
// delete[] exec_path;
|
|
//
|
|
// auto debug_port_string = FIXED_ONE_BYTE_STRING(env->isolate(), "debugPort");
|
|
// CHECK(process->SetAccessor(env->context(),
|
|
// debug_port_string,
|
|
// DebugPortGetter,
|
|
// DebugPortSetter,
|
|
// env->as_external()).FromJust());
|
|
//
|
|
// // define various internal methods
|
|
// env->SetMethod(process,
|
|
// "_startProfilerIdleNotifier",
|
|
// StartProfilerIdleNotifier);
|
|
// env->SetMethod(process,
|
|
// "_stopProfilerIdleNotifier",
|
|
// StopProfilerIdleNotifier);
|
|
// env->SetMethod(process, "_getActiveRequests", GetActiveRequests);
|
|
// env->SetMethod(process, "_getActiveHandles", GetActiveHandles);
|
|
// env->SetMethod(process, "reallyExit", Exit);
|
|
// env->SetMethod(process, "abort", Abort);
|
|
// env->SetMethod(process, "chdir", Chdir);
|
|
// env->SetMethod(process, "cwd", Cwd);
|
|
//
|
|
// env->SetMethod(process, "umask", Umask);
|
|
//
|
|
//#if defined(__POSIX__) && !defined(__ANDROID__)
|
|
// env->SetMethod(process, "getuid", GetUid);
|
|
// env->SetMethod(process, "geteuid", GetEUid);
|
|
// env->SetMethod(process, "setuid", SetUid);
|
|
// env->SetMethod(process, "seteuid", SetEUid);
|
|
//
|
|
// env->SetMethod(process, "setgid", SetGid);
|
|
// env->SetMethod(process, "setegid", SetEGid);
|
|
// env->SetMethod(process, "getgid", GetGid);
|
|
// env->SetMethod(process, "getegid", GetEGid);
|
|
//
|
|
// env->SetMethod(process, "getgroups", GetGroups);
|
|
// env->SetMethod(process, "setgroups", SetGroups);
|
|
// env->SetMethod(process, "initgroups", InitGroups);
|
|
//#endif // __POSIX__ && !defined(__ANDROID__)
|
|
//
|
|
// env->SetMethod(process, "_kill", Kill);
|
|
//
|
|
// env->SetMethod(process, "_debugProcess", DebugProcess);
|
|
// env->SetMethod(process, "_debugPause", DebugPause);
|
|
// env->SetMethod(process, "_debugEnd", DebugEnd);
|
|
//
|
|
// env->SetMethod(process, "hrtime", Hrtime);
|
|
//
|
|
// env->SetMethod(process, "cpuUsage", CPUUsage);
|
|
//
|
|
// env->SetMethod(process, "dlopen", DLOpen);
|
|
//
|
|
// env->SetMethod(process, "uptime", Uptime);
|
|
// env->SetMethod(process, "memoryUsage", MemoryUsage);
|
|
//
|
|
// env->SetMethod(process, "binding", Binding);
|
|
// env->SetMethod(process, "_linkedBinding", LinkedBinding);
|
|
//
|
|
// env->SetMethod(process, "_setupProcessObject", SetupProcessObject);
|
|
// env->SetMethod(process, "_setupNextTick", SetupNextTick);
|
|
// env->SetMethod(process, "_setupPromises", SetupPromises);
|
|
// env->SetMethod(process, "_setupDomainUse", SetupDomainUse);
|
|
|
|
// pre-set _events object for faster emit checks
|
|
Local<Object> events_obj = Object::New(env->isolate());
|
|
CHECK(events_obj->SetPrototype(env->context(),
|
|
Null(env->isolate()))
|
|
.FromJust());
|
|
process->Set(env->context(), env->events_string(), events_obj).Check();
|
|
}
|
|
|
|
#undef READONLY_PROPERTY
|
|
|
|
} // namespace node
|
|
|
|
#endif // #if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
|
|
|