diff --git a/doc/api/embedding.md b/doc/api/embedding.md index 3c50c137e68550..c2af6840d4ea3e 100644 --- a/doc/api/embedding.md +++ b/doc/api/embedding.md @@ -233,6 +233,62 @@ added: REPLACEME This is an opaque pointer that represents a Node.js platform instance. Node.js allows only a single platform instance per process. +##### `node_embedding_exit_code` + + + +> Stability: 1 - Experimental + +The exit code returned from the C Node.js embedding APIs. + +```c +typedef enum { + node_embedding_exit_code_ok = 0, + node_embedding_exit_code_generic_user_error = 1, + node_embedding_exit_code_internal_js_parse_error = 3, + node_embedding_exit_code_internal_js_evaluation_failure = 4, + node_embedding_exit_code_v8_fatal_error = 5, + node_embedding_exit_code_invalid_fatal_exception_monkey_patching = 6, + node_embedding_exit_code_exception_in_fatal_exception_handler = 7, + node_embedding_exit_code_invalid_command_line_argument = 9, + node_embedding_exit_code_bootstrap_failure = 10, + node_embedding_exit_code_invalid_command_line_argument2 = 12, + node_embedding_exit_code_unsettled_top_level_await = 13, + node_embedding_exit_code_startup_snapshot_failure = 14, + node_embedding_exit_code_abort = 134, +} node_embedding_exit_code; +``` + +These values match to the C++ `node::ExitCode` enum that are used as Node.js +process exit codes. + +- `node_embedding_exit_code_ok` - No issues. +- `node_embedding_exit_code_generic_user_error` - It was originally intended for + uncaught JS exceptions from the user land but we actually use this for all + kinds of generic errors. +- `node_embedding_exit_code_internal_js_parse_error` - It is unused because we + pre-compile all builtins during snapshot building, when we exit with 1 if + there's any error. +- `node_embedding_exit_code_internal_js_evaluation_failure` - It is actually + unused. We exit with 1 in this case. +- `node_embedding_exit_code_v8_fatal_error` - It is actually unused. We exit + with 133 (128+`SIGTRAP`) or 134 (128+`SIGABRT`) in this case. +- `node_embedding_exit_code_invalid_fatal_exception_monkey_patching` +- `node_embedding_exit_code_exception_in_fatal_exception_handler` +- `node_embedding_exit_code_invalid_command_line_argument` +- `node_embedding_exit_code_bootstrap_failure` +- `node_embedding_exit_code_invalid_command_line_argument2` - This was intended + for invalid inspector arguments but is actually now just a duplicate of + `node_embedding_exit_code_invalid_command_line_argument`. +- `node_embedding_exit_code_unsettled_top_level_await` - +- `node_embedding_exit_code_startup_snapshot_failure` - +- `node_embedding_exit_code_abort` - If the process exits from unhandled signals + e.g. `SIGABRT`, `SIGTRAP`, typically the exit codes are 128 + signal number. + We also exit with certain error codes directly for legacy reasons. Here we + define those that are used to normalize the exit code on Windows. + ##### `node_embedding_platform_flags` + +> Stability: 1 - Experimental + +The state of the completed `Promise`. + +```c +typedef enum { + node_embedding_promise_state_pending = 0, + node_embedding_promise_state_fulfilled = 1, + node_embedding_promise_state_rejected = 2, +} node_embedding_promise_state; +``` + +These values match to `v8::Promise::PromiseState` enum and indicate the internal +state of a `Promise` object. + +- `node_embedding_promise_state_pending` - The Promise is still awaiting to + be completed. +- `node_embedding_promise_state_fulfilled` - The Promise was successfully + fulfilled. +- `node_embedding_promise_state_rejected` - The Promise was rejected due an + error. + #### Callback types ##### `node_embedding_event_loop_predicate` @@ -1148,13 +1230,13 @@ added: REPLACEME Runs Node.js runtime instance event loop. ```c -napi_status NAPI_CDECL +node_embedding_exit_code NAPI_CDECL node_embedding_runtime_run_event_loop(node_embedding_runtime runtime); ``` - `[in] runtime`: The Node.js runtime instance. -Returns `napi_ok` if there were no issues. +Returns `node_embedding_exit_code_ok` if there were no issues. The function exits when there are no more tasks to process in the loop. @@ -1170,7 +1252,7 @@ Runs Node.js runtime instance event loop while there tasks to process and the provided predicate returns true. ```c -napi_status NAPI_CDECL +node_embedding_exit_code NAPI_CDECL node_embedding_runtime_run_event_loop_while( node_embedding_runtime runtime, node_embedding_runtime_event_loop_predicate predicate, @@ -1192,7 +1274,7 @@ node_embedding_runtime_run_event_loop_while( - `[out] has_more_work`: `true` if the runtime event loop has more tasks after returning from the function. -Returns `napi_ok` if there were no issues. +Returns `node_embedding_exit_code_ok` if there were no issues. ##### `node_embedding_runtime_await_promise` @@ -1207,20 +1289,23 @@ with a success of a failure. It blocks the thread if there are to tasks in the loop and the promise is not completed. ```c -napi_status NAPI_CDECL +node_embedding_exit_code NAPI_CDECL node_embedding_runtime_await_promise(node_embedding_runtime runtime, napi_value promise, + node_embedding_promise_state* state, napi_value* result, bool* has_more_work); ``` - `[in] runtime`: The Node.js runtime instance. - `[in] promise`: The promise to complete. -- `[out] result`: Result of the `promise` completion. +- `[out] state`: The state of the `promise` upon the return from the function. +- `[out] result`: Result of the `promise` completion. It is either fulfilled or + rejected value depending on `state`. - `[out] has_more_work`: `true` if the runtime event loop has more tasks after returning from the function. -Returns `napi_ok` if there were no issues. +Returns `node_embedding_exit_code_ok` if there were no issues. ### JavaScript/Native interop APIs @@ -1237,7 +1322,7 @@ added: REPLACEME Sets the Node-API version for the Node.js runtime instance. ```c -napi_status NAPI_CDECL +node_embedding_exit_code NAPI_CDECL node_runtime_set_node_api_version(node_embedding_runtime runtime, int32_t node_api_version); ``` @@ -1245,7 +1330,7 @@ node_runtime_set_node_api_version(node_embedding_runtime runtime, - `[in] runtime`: The Node.js runtime instance. - `[in] node_api_version`: The version of the Node-API. -Returns `napi_ok` if there were no issues. +Returns `node_embedding_exit_code_ok` if there were no issues. By default it is using the Node-API version 8. @@ -1260,15 +1345,15 @@ added: REPLACEME Gets `napi_env` associated with the Node.js runtime instance. ```c -napi_status NAPI_CDECL +node_embedding_exit_code NAPI_CDECL node_embedding_runtime_get_node_api_env(node_runtime embedding_runtime, - napi_env* env); + napi_env* env); ``` - `[in] runtime`: The Node.js runtime instance. -- `[out] env`: An instance of `napi_env`. +- `[out] env`: An instance of Node API environment. -Returns `napi_ok` if there were no issues. +Returns `node_embedding_exit_code_ok` if there were no issues. ##### `node_embedding_runtime_open_scope` @@ -1281,13 +1366,13 @@ added: REPLACEME Opens V8 Isolate and Context scope associated with the Node.js runtime instance. ```c -napi_status NAPI_CDECL +node_embedding_exit_code NAPI_CDECL node_embedding_runtime_open_scope(node_embedding_runtime runtime); ``` - `[in] runtime`: The Node.js runtime instance. -Returns `napi_ok` if there were no issues. +Returns `node_embedding_exit_code_ok` if there were no issues. Any Node-API function call requires the runtime scope to be opened for the current thread. @@ -1309,13 +1394,13 @@ Closes V8 Isolate and Context scope associated with the Node.js runtime instance. ```c -napi_status NAPI_CDECL +node_embedding_exit_code NAPI_CDECL node_embedding_runtime_close_scope(node_embedding_runtime runtime); ``` - `[in] runtime`: The Node.js embedding_runtime instance. -Returns `napi_ok` if there were no issues. +Returns `node_embedding_exit_code_ok` if there were no issues. Any Node-API function call requires the runtime scope to be opened for the current thread. Each opened runtime scoped must be closed in the end. diff --git a/src/node_embedding_api.cc b/src/node_embedding_api.cc index 8a3827dd537ebf..2d41cdc82e0dc9 100644 --- a/src/node_embedding_api.cc +++ b/src/node_embedding_api.cc @@ -18,8 +18,7 @@ "Argument must not be null: " #platform, \ __FILE__, \ __LINE__, \ - 1, \ - napi_invalid_arg) \ + node_embedding_exit_code_generic_user_error) \ : reinterpret_cast(platform) #define EMBEDDED_RUNTIME(runtime) \ @@ -27,8 +26,7 @@ "Argument must not be null: " #runtime, \ __FILE__, \ __LINE__, \ - 1, \ - napi_invalid_arg) \ + node_embedding_exit_code_generic_user_error) \ : reinterpret_cast(runtime) #define ARG_NOT_NULL(arg) \ @@ -38,8 +36,7 @@ "Argument must not be null: " #arg, \ __FILE__, \ __LINE__, \ - 1, \ - napi_invalid_arg); \ + node_embedding_exit_code_generic_user_error); \ } \ } while (false) @@ -50,8 +47,7 @@ "Expression returned false: " #expr, \ __FILE__, \ __LINE__, \ - 1, \ - napi_generic_failure); \ + node_embedding_exit_code_generic_user_error); \ } \ } while (false) @@ -114,30 +110,29 @@ class CStringArray { class EmbeddedErrorHandling { public: - static napi_status SetErrorHandler(node_embedding_error_handler error_handler, - void* error_handler_data); + static node_embedding_exit_code SetErrorHandler( + node_embedding_error_handler error_handler, void* error_handler_data); - static napi_status HandleError(const std::string& message, - int32_t exit_code, - napi_status status); + static node_embedding_exit_code HandleError( + const std::string& message, node_embedding_exit_code exit_code); - static napi_status HandleError(const std::vector& messages, - int32_t exit_code, - napi_status status); + static node_embedding_exit_code HandleError( + const std::vector& messages, + node_embedding_exit_code exit_code); - static napi_status HandleError(const char* message, - const char* filename, - int32_t line, - int32_t exit_code, - napi_status status); + static node_embedding_exit_code HandleError( + const char* message, + const char* filename, + int32_t line, + node_embedding_exit_code exit_code); static std::string FormatString(const char* format, ...); - static napi_status DefaultErrorHandler(void* handler_data, - const char* messages[], - size_t messages_size, - int32_t exit_code, - napi_status status); + static node_embedding_exit_code DefaultErrorHandler( + void* handler_data, + const char* messages[], + size_t messages_size, + node_embedding_exit_code exit_code); static node_embedding_error_handler error_handler() { return error_handler_ ? error_handler_ : DefaultErrorHandler; @@ -159,23 +154,23 @@ class EmbeddedPlatform { EmbeddedPlatform(const EmbeddedPlatform&) = delete; EmbeddedPlatform& operator=(const EmbeddedPlatform&) = delete; - napi_status DeleteMe(); + node_embedding_exit_code DeleteMe(); - napi_status IsInitialized(bool* result); + node_embedding_exit_code IsInitialized(bool* result); - napi_status SetFlags(node_embedding_platform_flags flags); + node_embedding_exit_code SetFlags(node_embedding_platform_flags flags); - napi_status SetArgs(int32_t argc, char* argv[]); + node_embedding_exit_code SetArgs(int32_t argc, char* argv[]); - napi_status Initialize(bool* early_return); + node_embedding_exit_code Initialize(bool* early_return); - napi_status GetArgs(node_embedding_get_args_callback get_args, - void* get_args_data); + node_embedding_exit_code GetArgs(node_embedding_get_args_callback get_args, + void* get_args_data); - napi_status GetExecArgs(node_embedding_get_args_callback get_args, - void* get_args_data); + node_embedding_exit_code GetExecArgs( + node_embedding_get_args_callback get_args, void* get_args_data); - napi_status CreateRuntime(node_embedding_runtime* result); + node_embedding_exit_code CreateRuntime(node_embedding_runtime* result); node::InitializationResult* init_result() { return init_result_.get(); } @@ -228,52 +223,55 @@ class EmbeddedRuntime { public: explicit EmbeddedRuntime(EmbeddedPlatform* platform); - napi_status DeleteMe(); + node_embedding_exit_code DeleteMe(); - napi_status IsInitialized(bool* result); + node_embedding_exit_code IsInitialized(bool* result); - napi_status SetFlags(node_embedding_runtime_flags flags); + node_embedding_exit_code SetFlags(node_embedding_runtime_flags flags); - napi_status SetArgs(int32_t argc, const char* argv[]); + node_embedding_exit_code SetArgs(int32_t argc, const char* argv[]); - napi_status SetExecArgs(int32_t argc, const char* argv[]); + node_embedding_exit_code SetExecArgs(int32_t argc, const char* argv[]); - napi_status SetPreloadCallback(node_embedding_preload_callback preload_cb, - void* preload_cb_data); + node_embedding_exit_code SetPreloadCallback( + node_embedding_preload_callback preload_cb, void* preload_cb_data); - napi_status SetSnapshotBlob(const uint8_t* snapshot, size_t size); + node_embedding_exit_code SetSnapshotBlob(const uint8_t* snapshot, + size_t size); - napi_status OnCreateSnapshotBlob( + node_embedding_exit_code OnCreateSnapshotBlob( node_embedding_store_blob_callback store_blob_cb, void* store_blob_cb_data, node_embedding_snapshot_flags snapshot_flags); - napi_status AddModule( + node_embedding_exit_code AddModule( const char* module_name, node_embedding_initialize_module_callback init_module_cb, void* init_module_cb_data, int32_t module_node_api_version); - napi_status Initialize(const char* main_script); + node_embedding_exit_code Initialize(const char* main_script); - napi_status RunEventLoop(); + node_embedding_exit_code RunEventLoop(); - napi_status RunEventLoopWhile(node_embedding_event_loop_predicate predicate, - void* predicate_data, - node_embedding_event_loop_run_mode run_mode, - bool* has_more_work); + node_embedding_exit_code RunEventLoopWhile( + node_embedding_event_loop_predicate predicate, + void* predicate_data, + node_embedding_event_loop_run_mode run_mode, + bool* has_more_work); - napi_status AwaitPromise(napi_value promise, - napi_value* result, - bool* has_more_work); + node_embedding_exit_code AwaitPromise(napi_value promise, + node_embedding_promise_state* state, + napi_value* result, + bool* has_more_work); - napi_status SetNodeApiVersion(int32_t node_api_version); + node_embedding_exit_code SetNodeApiVersion(int32_t node_api_version); - napi_status GetNodeApiEnv(napi_env* env); + node_embedding_exit_code GetNodeApiEnv(napi_env* env); - napi_status OpenScope(); + node_embedding_exit_code OpenScope(); - napi_status CloseScope(); + node_embedding_exit_code CloseScope(); bool IsScopeOpened() const; @@ -339,62 +337,54 @@ class EmbeddedRuntime { // EmbeddedErrorHandling implementation. //----------------------------------------------------------------------------- -napi_status EmbeddedErrorHandling::SetErrorHandler( +node_embedding_exit_code EmbeddedErrorHandling::SetErrorHandler( node_embedding_error_handler error_handler, void* error_handler_data) { error_handler_ = error_handler; error_handler_data_ = error_handler_data; - return napi_ok; + return node_embedding_exit_code_ok; } -napi_status EmbeddedErrorHandling::HandleError(const std::string& message, - int32_t exit_code, - napi_status status) { +node_embedding_exit_code EmbeddedErrorHandling::HandleError( + const std::string& message, node_embedding_exit_code exit_code) { const char* message_c_str = message.c_str(); - return error_handler()( - error_handler_data_, &message_c_str, 1, exit_code, status); + return error_handler()(error_handler_data_, &message_c_str, 1, exit_code); } -napi_status EmbeddedErrorHandling::HandleError( +node_embedding_exit_code EmbeddedErrorHandling::HandleError( const std::vector& messages, - int32_t exit_code, - napi_status status) { + node_embedding_exit_code exit_code) { CStringArray message_arr(messages); - return error_handler()(error_handler_data_, - message_arr.c_strs(), - message_arr.size(), - exit_code, - status); -} - -napi_status EmbeddedErrorHandling::HandleError(const char* message, - const char* filename, - int32_t line, - int32_t exit_code, - napi_status status) { + return error_handler()( + error_handler_data_, message_arr.c_strs(), message_arr.size(), exit_code); +} + +node_embedding_exit_code EmbeddedErrorHandling::HandleError( + const char* message, + const char* filename, + int32_t line, + node_embedding_exit_code exit_code) { return HandleError( - FormatString("Error: %s at %s:%d", message, filename, line), - exit_code, - status); + FormatString("Error: %s at %s:%d", message, filename, line), exit_code); } -napi_status EmbeddedErrorHandling::DefaultErrorHandler(void* /*handler_data*/, - const char* messages[], - size_t messages_size, - int32_t exit_code, - napi_status status) { +node_embedding_exit_code EmbeddedErrorHandling::DefaultErrorHandler( + void* /*handler_data*/, + const char* messages[], + size_t messages_size, + node_embedding_exit_code exit_code) { if (exit_code != 0) { for (size_t i = 0; i < messages_size; ++i) { fprintf(stderr, "%s\n", messages[i]); } fflush(stderr); - exit(exit_code); + node::Exit(static_cast(exit_code)); } else { for (size_t i = 0; i < messages_size; ++i) { fprintf(stdout, "%s\n", messages[i]); } fflush(stdout); } - return status; + return exit_code; } std::string EmbeddedErrorHandling::FormatString(const char* format, ...) { @@ -413,7 +403,7 @@ std::string EmbeddedErrorHandling::FormatString(const char* format, ...) { // EmbeddedPlatform implementation. //----------------------------------------------------------------------------- -napi_status EmbeddedPlatform::DeleteMe() { +node_embedding_exit_code EmbeddedPlatform::DeleteMe() { if (v8_is_initialized_ && !v8_is_uninitialized_) { v8::V8::Dispose(); v8::V8::DisposePlatform(); @@ -422,36 +412,37 @@ napi_status EmbeddedPlatform::DeleteMe() { } delete this; - return napi_ok; + return node_embedding_exit_code_ok; } -napi_status EmbeddedPlatform::IsInitialized(bool* result) { +node_embedding_exit_code EmbeddedPlatform::IsInitialized(bool* result) { ARG_NOT_NULL(result); *result = is_initialized_; - return napi_ok; + return node_embedding_exit_code_ok; } -napi_status EmbeddedPlatform::SetFlags(node_embedding_platform_flags flags) { +node_embedding_exit_code EmbeddedPlatform::SetFlags( + node_embedding_platform_flags flags) { ASSERT(!is_initialized_); flags_ = flags; optional_bits_.flags = true; - return napi_ok; + return node_embedding_exit_code_ok; } -napi_status EmbeddedPlatform::SetArgs(int32_t argc, char* argv[]) { +node_embedding_exit_code EmbeddedPlatform::SetArgs(int32_t argc, char* argv[]) { ARG_NOT_NULL(argv); ASSERT(!is_initialized_); args_.assign(argv, argv + argc); optional_bits_.args = true; - return napi_ok; + return node_embedding_exit_code_ok; } -napi_status EmbeddedPlatform::Initialize(bool* early_return) { +node_embedding_exit_code EmbeddedPlatform::Initialize(bool* early_return) { ASSERT(!is_initialized_); is_initialized_ = true; - // TODO: (vmoroz) default initialize args_. + // TODO(vmoroz): default initialize args_. if (!optional_bits_.flags) { flags_ = node_embedding_platform_no_flags; @@ -461,9 +452,9 @@ napi_status EmbeddedPlatform::Initialize(bool* early_return) { args_, GetProcessInitializationFlags(flags_)); if (init_result_->exit_code() != 0 || !init_result_->errors().empty()) { - return EmbeddedErrorHandling::HandleError(init_result_->errors(), - init_result_->exit_code(), - napi_generic_failure); + return EmbeddedErrorHandling::HandleError( + init_result_->errors(), + static_cast(init_result_->exit_code())); } if (early_return != nullptr) { @@ -473,7 +464,7 @@ napi_status EmbeddedPlatform::Initialize(bool* early_return) { } if (init_result_->early_return()) { - return init_result_->exit_code() == 0 ? napi_ok : napi_generic_failure; + return static_cast(init_result_->exit_code()); } int32_t thread_pool_size = @@ -484,10 +475,10 @@ napi_status EmbeddedPlatform::Initialize(bool* early_return) { v8_is_initialized_ = true; - return napi_ok; + return node_embedding_exit_code_ok; } -napi_status EmbeddedPlatform::GetArgs( +node_embedding_exit_code EmbeddedPlatform::GetArgs( node_embedding_get_args_callback get_args_cb, void* get_args_cb_data) { ARG_NOT_NULL(get_args_cb); ASSERT(is_initialized_); @@ -495,10 +486,10 @@ napi_status EmbeddedPlatform::GetArgs( v8impl::CStringArray args(init_result_->args()); get_args_cb(get_args_cb_data, args.argc(), args.argv()); - return napi_ok; + return node_embedding_exit_code_ok; } -napi_status EmbeddedPlatform::GetExecArgs( +node_embedding_exit_code EmbeddedPlatform::GetExecArgs( node_embedding_get_args_callback get_args_cb, void* get_args_cb_data) { ARG_NOT_NULL(get_args_cb); ASSERT(is_initialized_); @@ -506,10 +497,11 @@ napi_status EmbeddedPlatform::GetExecArgs( v8impl::CStringArray args(init_result_->exec_args()); get_args_cb(get_args_cb_data, args.argc(), args.argv()); - return napi_ok; + return node_embedding_exit_code_ok; } -napi_status EmbeddedPlatform::CreateRuntime(node_embedding_runtime* result) { +node_embedding_exit_code EmbeddedPlatform::CreateRuntime( + node_embedding_runtime* result) { ARG_NOT_NULL(result); ASSERT(is_initialized_); ASSERT(v8_is_initialized_); @@ -519,7 +511,7 @@ napi_status EmbeddedPlatform::CreateRuntime(node_embedding_runtime* result) { *result = reinterpret_cast(runtime.release()); - return napi_ok; + return node_embedding_exit_code_ok; } node::ProcessInitializationFlags::Flags @@ -574,16 +566,17 @@ EmbeddedPlatform::GetProcessInitializationFlags( EmbeddedRuntime::EmbeddedRuntime(EmbeddedPlatform* platform) : platform_(platform) {} -napi_status EmbeddedRuntime::DeleteMe() { +node_embedding_exit_code EmbeddedRuntime::DeleteMe() { ASSERT(!IsScopeOpened()); { v8impl::IsolateLocker isolate_locker(env_setup_.get()); - int32_t ret = node::SpinEventLoop(env_setup_->env()).FromMaybe(1); - if (ret != 0) { + node_embedding_exit_code exit_code = static_cast( + node::SpinEventLoop(env_setup_->env()).FromMaybe(1)); + if (exit_code != node_embedding_exit_code_ok) { return EmbeddedErrorHandling::HandleError( - "Failed while closing the runtime", ret, napi_generic_failure); + "Failed while closing the runtime", exit_code); } } @@ -593,45 +586,48 @@ napi_status EmbeddedRuntime::DeleteMe() { if (create_snapshot_) { node::EmbedderSnapshotData::Pointer snapshot = env_setup->CreateSnapshot(); ASSERT(snapshot); - // TODO: (vmoroz) handle error conditions. + // TODO(vmoroz): handle error conditions. create_snapshot_(snapshot.get()); } node::Stop(env_setup->env()); - return napi_ok; + return node_embedding_exit_code_ok; } -napi_status EmbeddedRuntime::IsInitialized(bool* result) { +node_embedding_exit_code EmbeddedRuntime::IsInitialized(bool* result) { ARG_NOT_NULL(result); *result = is_initialized_; - return napi_ok; + return node_embedding_exit_code_ok; } -napi_status EmbeddedRuntime::SetFlags(node_embedding_runtime_flags flags) { +node_embedding_exit_code EmbeddedRuntime::SetFlags( + node_embedding_runtime_flags flags) { ASSERT(!is_initialized_); flags_ = flags; optional_bits_.flags = true; - return napi_ok; + return node_embedding_exit_code_ok; } -napi_status EmbeddedRuntime::SetArgs(int32_t argc, const char* argv[]) { +node_embedding_exit_code EmbeddedRuntime::SetArgs(int32_t argc, + const char* argv[]) { ARG_NOT_NULL(argv); ASSERT(!is_initialized_); args_.assign(argv, argv + argc); optional_bits_.args = true; - return napi_ok; + return node_embedding_exit_code_ok; } -napi_status EmbeddedRuntime::SetExecArgs(int32_t argc, const char* argv[]) { +node_embedding_exit_code EmbeddedRuntime::SetExecArgs(int32_t argc, + const char* argv[]) { ARG_NOT_NULL(argv); ASSERT(!is_initialized_); exec_args_.assign(argv, argv + argc); optional_bits_.exec_args = true; - return napi_ok; + return node_embedding_exit_code_ok; } -napi_status EmbeddedRuntime::SetPreloadCallback( +node_embedding_exit_code EmbeddedRuntime::SetPreloadCallback( node_embedding_preload_callback preload_cb, void* preload_cb_data) { ASSERT(!is_initialized_); @@ -653,20 +649,20 @@ napi_status EmbeddedRuntime::SetPreloadCallback( preload_cb_ = {}; } - return napi_ok; + return node_embedding_exit_code_ok; } -napi_status EmbeddedRuntime::SetSnapshotBlob(const uint8_t* snapshot, - size_t size) { +node_embedding_exit_code EmbeddedRuntime::SetSnapshotBlob( + const uint8_t* snapshot, size_t size) { ARG_NOT_NULL(snapshot); ASSERT(!is_initialized_); snapshot_ = node::EmbedderSnapshotData::FromBlob( std::string_view(reinterpret_cast(snapshot), size)); - return napi_ok; + return node_embedding_exit_code_ok; } -napi_status EmbeddedRuntime::OnCreateSnapshotBlob( +node_embedding_exit_code EmbeddedRuntime::OnCreateSnapshotBlob( node_embedding_store_blob_callback store_blob_cb, void* store_blob_cb_data, node_embedding_snapshot_flags snapshot_flags) { @@ -687,10 +683,10 @@ napi_status EmbeddedRuntime::OnCreateSnapshotBlob( static_cast(node::SnapshotFlags::kWithoutCodeCache)); } - return napi_ok; + return node_embedding_exit_code_ok; } -napi_status EmbeddedRuntime::AddModule( +node_embedding_exit_code EmbeddedRuntime::AddModule( const char* module_name, node_embedding_initialize_module_callback init_module_cb, void* init_module_cb_data, @@ -708,14 +704,13 @@ napi_status EmbeddedRuntime::AddModule( return EmbeddedErrorHandling::HandleError( EmbeddedErrorHandling::FormatString( "Module with name '%s' is already added.", module_name), - 1, - napi_invalid_arg); + node_embedding_exit_code_generic_user_error); } - return napi_ok; + return node_embedding_exit_code_ok; } -napi_status EmbeddedRuntime::Initialize(const char* main_script) { +node_embedding_exit_code EmbeddedRuntime::Initialize(const char* main_script) { ASSERT(!is_initialized_); is_initialized_ = true; @@ -745,7 +740,8 @@ napi_status EmbeddedRuntime::Initialize(const char* main_script) { } if (env_setup_ == nullptr || !errors.empty()) { - return EmbeddedErrorHandling::HandleError(errors, 1, napi_generic_failure); + return EmbeddedErrorHandling::HandleError( + errors, node_embedding_exit_code_generic_user_error); } v8impl::IsolateLocker isolate_locker(env_setup_.get()); @@ -764,20 +760,20 @@ napi_status EmbeddedRuntime::Initialize(const char* main_script) { : node::LoadEnvironment( node_env, std::string_view(main_script), preload_cb_); - if (ret.IsEmpty()) return napi_pending_exception; + if (ret.IsEmpty()) return node_embedding_exit_code_generic_user_error; - return napi_ok; + return node_embedding_exit_code_ok; } -napi_status EmbeddedRuntime::RunEventLoop() { +node_embedding_exit_code EmbeddedRuntime::RunEventLoop() { if (node::SpinEventLoopWithoutCleanup(env_setup_->env()).IsNothing()) { - return napi_closing; + return node_embedding_exit_code_generic_user_error; } - return napi_ok; + return node_embedding_exit_code_ok; } -napi_status EmbeddedRuntime::RunEventLoopWhile( +node_embedding_exit_code EmbeddedRuntime::RunEventLoopWhile( node_embedding_event_loop_predicate predicate, void* predicate_data, node_embedding_event_loop_run_mode run_mode, @@ -793,7 +789,7 @@ napi_status EmbeddedRuntime::RunEventLoopWhile( return predicate(predicate_data, has_work); }) .IsNothing()) { - return napi_closing; + return node_embedding_exit_code_generic_user_error; } } @@ -801,84 +797,91 @@ napi_status EmbeddedRuntime::RunEventLoopWhile( *has_more_work = uv_loop_alive(env_setup_->env()->event_loop()); } - return napi_ok; + return node_embedding_exit_code_ok; } -napi_status EmbeddedRuntime::AwaitPromise(napi_value promise, - napi_value* result, - bool* has_more_work) { - NAPI_PREAMBLE(node_api_env_); - CHECK_ARG(node_api_env_, result); - - v8::EscapableHandleScope scope(node_api_env_->isolate); - - v8::Local promise_value = v8impl::V8LocalValueFromJsValue(promise); - if (promise_value.IsEmpty() || !promise_value->IsPromise()) - return napi_invalid_arg; - v8::Local promise_object = promise_value.As(); - - v8::Local rejected = - v8::Boolean::New(node_api_env_->isolate, false); - v8::Local err_handler = - v8::Function::New( - node_api_env_->context(), - [](const v8::FunctionCallbackInfo& info) { return; }, - rejected) - .ToLocalChecked(); - - if (promise_object->Catch(node_api_env_->context(), err_handler).IsEmpty()) - return napi_pending_exception; - - if (node::SpinEventLoopWithoutCleanup( - env_setup_->env(), - UV_RUN_ONCE, - [&promise_object](bool /*has_work*/) { - return promise_object->State() == - v8::Promise::PromiseState::kPending; - }) - .IsNothing()) - return napi_closing; +node_embedding_exit_code EmbeddedRuntime::AwaitPromise( + napi_value promise, + node_embedding_promise_state* state, + napi_value* result, + bool* has_more_work) { + napi_status status = [&]() { + NAPI_PREAMBLE(node_api_env_); + CHECK_ARG(node_api_env_, state); + CHECK_ARG(node_api_env_, result); + + v8::EscapableHandleScope scope(node_api_env_->isolate); + + v8::Local promise_value = + v8impl::V8LocalValueFromJsValue(promise); + if (promise_value.IsEmpty() || !promise_value->IsPromise()) + return napi_invalid_arg; + v8::Local promise_object = promise_value.As(); + + v8::Local rejected = + v8::Boolean::New(node_api_env_->isolate, false); + v8::Local err_handler = + v8::Function::New( + node_api_env_->context(), + [](const v8::FunctionCallbackInfo& info) { return; }, + rejected) + .ToLocalChecked(); + + if (promise_object->Catch(node_api_env_->context(), err_handler).IsEmpty()) + return napi_pending_exception; - *result = - v8impl::JsValueFromV8LocalValue(scope.Escape(promise_object->Result())); + if (node::SpinEventLoopWithoutCleanup( + env_setup_->env(), + UV_RUN_ONCE, + [&promise_object](bool /*has_work*/) { + return promise_object->State() == + v8::Promise::PromiseState::kPending; + }) + .IsNothing()) + return napi_closing; - if (has_more_work != nullptr) { - *has_more_work = uv_loop_alive(env_setup_->env()->event_loop()); - } + *state = static_cast(promise_object->State()); + *result = + v8impl::JsValueFromV8LocalValue(scope.Escape(promise_object->Result())); - if (promise_object->State() == v8::Promise::PromiseState::kRejected) - return napi_pending_exception; + if (has_more_work != nullptr) { + *has_more_work = uv_loop_alive(env_setup_->env()->event_loop()); + } - return napi_ok; + return napi_ok; + }(); + return (status == napi_ok) ? node_embedding_exit_code_ok + : node_embedding_exit_code_generic_user_error; } -napi_status EmbeddedRuntime::SetNodeApiVersion(int32_t node_api_version) { +node_embedding_exit_code EmbeddedRuntime::SetNodeApiVersion( + int32_t node_api_version) { ASSERT(!is_initialized_); node_api_version_ = node_api_version; - return napi_ok; + return node_embedding_exit_code_ok; } -napi_status EmbeddedRuntime::GetNodeApiEnv(napi_env* env) { +node_embedding_exit_code EmbeddedRuntime::GetNodeApiEnv(napi_env* env) { ARG_NOT_NULL(env); *env = node_api_env_; - return napi_ok; + return node_embedding_exit_code_ok; } -napi_status EmbeddedRuntime::OpenScope() { +node_embedding_exit_code EmbeddedRuntime::OpenScope() { if (isolate_locker_.has_value()) { ASSERT(isolate_locker_->IsLocked()); isolate_locker_->IncrementLockCount(); } else { isolate_locker_.emplace(env_setup_.get()); } - return napi_ok; + return node_embedding_exit_code_ok; } -napi_status EmbeddedRuntime::CloseScope() { +node_embedding_exit_code EmbeddedRuntime::CloseScope() { ASSERT(isolate_locker_.has_value()); ASSERT(isolate_locker_->IsLocked()); if (isolate_locker_->DecrementLockCount()) isolate_locker_.reset(); - return napi_ok; + return node_embedding_exit_code_ok; } bool EmbeddedRuntime::IsScopeOpened() const { @@ -999,94 +1002,95 @@ void EmbeddedRuntime::RegisterModules() { } // end of anonymous namespace } // end of namespace v8impl -int32_t NAPI_CDECL node_embedding_run_nodejs_main(int32_t argc, char* argv[]) { - return node::Start(argc, argv); +node_embedding_exit_code NAPI_CDECL +node_embedding_run_nodejs_main(int32_t argc, char* argv[]) { + return static_cast(node::Start(argc, argv)); } -napi_status NAPI_CDECL node_embedding_on_error( +node_embedding_exit_code NAPI_CDECL node_embedding_on_error( node_embedding_error_handler error_handler, void* error_handler_data) { return v8impl::EmbeddedErrorHandling::SetErrorHandler(error_handler, error_handler_data); } -napi_status NAPI_CDECL node_embedding_create_platform( +node_embedding_exit_code NAPI_CDECL node_embedding_create_platform( int32_t api_version, node_embedding_platform* result) { ARG_NOT_NULL(result); *result = reinterpret_cast( new v8impl::EmbeddedPlatform(api_version)); - return napi_ok; + return node_embedding_exit_code_ok; } -napi_status NAPI_CDECL +node_embedding_exit_code NAPI_CDECL node_embedding_delete_platform(node_embedding_platform platform) { return EMBEDDED_PLATFORM(platform)->DeleteMe(); } -napi_status NAPI_CDECL node_embedding_platform_is_initialized( +node_embedding_exit_code NAPI_CDECL node_embedding_platform_is_initialized( node_embedding_platform platform, bool* result) { return EMBEDDED_PLATFORM(platform)->IsInitialized(result); } -napi_status NAPI_CDECL node_embedding_platform_set_flags( +node_embedding_exit_code NAPI_CDECL node_embedding_platform_set_flags( node_embedding_platform platform, node_embedding_platform_flags flags) { return EMBEDDED_PLATFORM(platform)->SetFlags(flags); } -napi_status NAPI_CDECL node_embedding_platform_set_args( +node_embedding_exit_code NAPI_CDECL node_embedding_platform_set_args( node_embedding_platform platform, int32_t argc, char* argv[]) { return EMBEDDED_PLATFORM(platform)->SetArgs(argc, argv); } -napi_status NAPI_CDECL node_embedding_platform_initialize( +node_embedding_exit_code NAPI_CDECL node_embedding_platform_initialize( node_embedding_platform platform, bool* early_return) { return EMBEDDED_PLATFORM(platform)->Initialize(early_return); } -napi_status NAPI_CDECL +node_embedding_exit_code NAPI_CDECL node_embedding_platform_get_args(node_embedding_platform platform, node_embedding_get_args_callback get_args, void* get_args_data) { return EMBEDDED_PLATFORM(platform)->GetArgs(get_args, get_args_data); } -napi_status NAPI_CDECL +node_embedding_exit_code NAPI_CDECL node_embedding_platform_get_exec_args(node_embedding_platform platform, node_embedding_get_args_callback get_args, void* get_args_data) { return EMBEDDED_PLATFORM(platform)->GetExecArgs(get_args, get_args_data); } -napi_status NAPI_CDECL node_embedding_create_runtime( +node_embedding_exit_code NAPI_CDECL node_embedding_create_runtime( node_embedding_platform platform, node_embedding_runtime* result) { return EMBEDDED_PLATFORM(platform)->CreateRuntime(result); } -napi_status NAPI_CDECL +node_embedding_exit_code NAPI_CDECL node_embedding_delete_runtime(node_embedding_runtime runtime) { return EMBEDDED_RUNTIME(runtime)->DeleteMe(); } -napi_status NAPI_CDECL node_embedding_runtime_is_initialized( +node_embedding_exit_code NAPI_CDECL node_embedding_runtime_is_initialized( node_embedding_runtime runtime, bool* result) { return EMBEDDED_RUNTIME(runtime)->IsInitialized(result); } -napi_status NAPI_CDECL node_embedding_runtime_set_flags( +node_embedding_exit_code NAPI_CDECL node_embedding_runtime_set_flags( node_embedding_runtime runtime, node_embedding_runtime_flags flags) { return EMBEDDED_RUNTIME(runtime)->SetFlags(flags); } -napi_status NAPI_CDECL node_embedding_runtime_set_args( +node_embedding_exit_code NAPI_CDECL node_embedding_runtime_set_args( node_embedding_runtime runtime, int32_t argc, const char* argv[]) { return EMBEDDED_RUNTIME(runtime)->SetArgs(argc, argv); } -napi_status NAPI_CDECL node_embedding_runtime_set_exec_args( +node_embedding_exit_code NAPI_CDECL node_embedding_runtime_set_exec_args( node_embedding_runtime runtime, int32_t argc, const char* argv[]) { return EMBEDDED_RUNTIME(runtime)->SetExecArgs(argc, argv); } -napi_status NAPI_CDECL +node_embedding_exit_code NAPI_CDECL node_embedding_runtime_on_preload(node_embedding_runtime runtime, node_embedding_preload_callback preload_cb, void* preload_cb_data) { @@ -1094,12 +1098,12 @@ node_embedding_runtime_on_preload(node_embedding_runtime runtime, preload_cb_data); } -napi_status NAPI_CDECL node_embedding_runtime_use_snapshot( +node_embedding_exit_code NAPI_CDECL node_embedding_runtime_use_snapshot( node_embedding_runtime runtime, const uint8_t* snapshot, size_t size) { return EMBEDDED_RUNTIME(runtime)->SetSnapshotBlob(snapshot, size); } -napi_status NAPI_CDECL node_embedding_runtime_on_create_snapshot( +node_embedding_exit_code NAPI_CDECL node_embedding_runtime_on_create_snapshot( node_embedding_runtime runtime, node_embedding_store_blob_callback store_blob_cb, void* store_blob_cb_data, @@ -1108,7 +1112,7 @@ napi_status NAPI_CDECL node_embedding_runtime_on_create_snapshot( store_blob_cb, store_blob_cb_data, snapshot_flags); } -NAPI_EXTERN napi_status NAPI_CDECL node_embedding_runtime_add_module( +node_embedding_exit_code NAPI_CDECL node_embedding_runtime_add_module( node_embedding_runtime runtime, const char* module_name, node_embedding_initialize_module_callback init_module_cb, @@ -1120,17 +1124,17 @@ NAPI_EXTERN napi_status NAPI_CDECL node_embedding_runtime_add_module( module_node_api_version); } -napi_status NAPI_CDECL node_embedding_runtime_initialize( +node_embedding_exit_code NAPI_CDECL node_embedding_runtime_initialize( node_embedding_runtime runtime, const char* main_script) { return EMBEDDED_RUNTIME(runtime)->Initialize(main_script); } -napi_status NAPI_CDECL +node_embedding_exit_code NAPI_CDECL node_embedding_runtime_run_event_loop(node_embedding_runtime runtime) { return EMBEDDED_RUNTIME(runtime)->RunEventLoop(); } -napi_status NAPI_CDECL node_embedding_runtime_run_event_loop_while( +node_embedding_exit_code NAPI_CDECL node_embedding_runtime_run_event_loop_while( node_embedding_runtime runtime, node_embedding_event_loop_predicate predicate, void* predicate_data, @@ -1140,31 +1144,32 @@ napi_status NAPI_CDECL node_embedding_runtime_run_event_loop_while( predicate, predicate_data, run_mode, has_more_work); } -napi_status NAPI_CDECL +node_embedding_exit_code NAPI_CDECL node_embedding_runtime_await_promise(node_embedding_runtime runtime, napi_value promise, + node_embedding_promise_state* state, napi_value* result, bool* has_more_work) { return EMBEDDED_RUNTIME(runtime)->AwaitPromise( - promise, result, has_more_work); + promise, state, result, has_more_work); } -napi_status NAPI_CDECL node_embedding_runtime_set_node_api_version( +node_embedding_exit_code NAPI_CDECL node_embedding_runtime_set_node_api_version( node_embedding_runtime runtime, int32_t node_api_version) { return EMBEDDED_RUNTIME(runtime)->SetNodeApiVersion(node_api_version); } -napi_status NAPI_CDECL node_embedding_runtime_get_node_api_env( +node_embedding_exit_code NAPI_CDECL node_embedding_runtime_get_node_api_env( node_embedding_runtime runtime, napi_env* env) { return EMBEDDED_RUNTIME(runtime)->GetNodeApiEnv(env); } -napi_status NAPI_CDECL +node_embedding_exit_code NAPI_CDECL node_embedding_runtime_open_scope(node_embedding_runtime runtime) { return EMBEDDED_RUNTIME(runtime)->OpenScope(); } -napi_status NAPI_CDECL +node_embedding_exit_code NAPI_CDECL node_embedding_runtime_close_scope(node_embedding_runtime runtime) { return EMBEDDED_RUNTIME(runtime)->CloseScope(); } diff --git a/src/node_embedding_api.h b/src/node_embedding_api.h index 544755ce78dda8..b6e880581af9d5 100644 --- a/src/node_embedding_api.h +++ b/src/node_embedding_api.h @@ -29,6 +29,38 @@ EXTERN_C_START typedef struct node_embedding_platform__* node_embedding_platform; typedef struct node_embedding_runtime__* node_embedding_runtime; +typedef enum { + node_embedding_exit_code_ok = 0, + // 1 was intended for uncaught JS exceptions from the user land but we + // actually use this for all kinds of generic errors. + node_embedding_exit_code_generic_user_error = 1, + // 2 is unused + // 3 is actually unused because we pre-compile all builtins during + // snapshot building, when we exit with 1 if there's any error. + node_embedding_exit_code_internal_js_parse_error = 3, + // 4 is actually unused. We exit with 1 in this case. + node_embedding_exit_code_internal_js_evaluation_failure = 4, + // 5 is actually unused. We exit with 133 (128+SIGTRAP) or 134 + // (128+SIGABRT) in this case. + node_embedding_exit_code_v8_fatal_error = 5, + node_embedding_exit_code_invalid_fatal_exception_monkey_patching = 6, + node_embedding_exit_code_exception_in_fatal_exception_handler = 7, + // 8 is unused + node_embedding_exit_code_invalid_command_line_argument = 9, + node_embedding_exit_code_bootstrap_failure = 10, + // 11 is unused + // This was intended for invalid inspector arguments but is actually now + // just a duplicate of node_embedding_exit_code_invalid_command_line_argument + node_embedding_exit_code_invalid_command_line_argument2 = 12, + node_embedding_exit_code_unsettled_top_level_await = 13, + node_embedding_exit_code_startup_snapshot_failure = 14, + // If the process exits from unhandled signals e.g. SIGABRT, SIGTRAP, + // typically the exit codes are 128 + signal number. We also exit with + // certain error codes directly for legacy reasons. Here we define those + // that are used to normalize the exit code on Windows. + node_embedding_exit_code_abort = 134, +} node_embedding_exit_code; + typedef enum { node_embedding_platform_no_flags = 0, // Enable stdio inheritance, which is disabled by default. @@ -131,16 +163,21 @@ typedef enum { node_embedding_event_loop_run_nowait = 2, } node_embedding_event_loop_run_mode; +typedef enum { + node_embedding_promise_state_pending = 0, + node_embedding_promise_state_fulfilled = 1, + node_embedding_promise_state_rejected = 2, +} node_embedding_promise_state; + //============================================================================== // Callbacks //============================================================================== -typedef napi_status(NAPI_CDECL* node_embedding_error_handler)( +typedef node_embedding_exit_code(NAPI_CDECL* node_embedding_error_handler)( void* handler_data, const char* messages[], size_t messages_size, - int32_t exit_code, - napi_status status); + node_embedding_exit_code exit_code); typedef void(NAPI_CDECL* node_embedding_get_args_callback)(void* cb_data, int32_t argc, @@ -170,15 +207,15 @@ typedef bool(NAPI_CDECL* node_embedding_event_loop_predicate)( // Runs Node.js main function as if it is invoked from Node.js CLI without any // embedder customizations. -NAPI_EXTERN int32_t NAPI_CDECL node_embedding_run_nodejs_main(int32_t argc, - char* argv[]); +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL +node_embedding_run_nodejs_main(int32_t argc, char* argv[]); //------------------------------------------------------------------------------ // Error handling functions. //------------------------------------------------------------------------------ // Sets the global error handing for the Node.js embedding API. -NAPI_EXTERN napi_status NAPI_CDECL node_embedding_on_error( +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL node_embedding_on_error( node_embedding_error_handler error_handler, void* error_handler_data); //------------------------------------------------------------------------------ @@ -186,37 +223,43 @@ NAPI_EXTERN napi_status NAPI_CDECL node_embedding_on_error( //------------------------------------------------------------------------------ // Creates a new Node.js platform instance. -NAPI_EXTERN napi_status NAPI_CDECL node_embedding_create_platform( +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL node_embedding_create_platform( int32_t api_version, node_embedding_platform* result); // Deletes the Node.js platform instance. -NAPI_EXTERN napi_status NAPI_CDECL +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL node_embedding_delete_platform(node_embedding_platform platform); // Checks if the Node.js platform is initialized. -NAPI_EXTERN napi_status NAPI_CDECL node_embedding_platform_is_initialized( - node_embedding_platform platform, bool* result); +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL +node_embedding_platform_is_initialized(node_embedding_platform platform, + bool* result); // Sets the flags for the Node.js platform initialization. -NAPI_EXTERN napi_status NAPI_CDECL node_embedding_platform_set_flags( - node_embedding_platform platform, node_embedding_platform_flags flags); +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL +node_embedding_platform_set_flags(node_embedding_platform platform, + node_embedding_platform_flags flags); // Sets the CLI arguments for the Node.js platform initialization. -NAPI_EXTERN napi_status NAPI_CDECL node_embedding_platform_set_args( - node_embedding_platform platform, int32_t argc, char* argv[]); +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL +node_embedding_platform_set_args(node_embedding_platform platform, + int32_t argc, + char* argv[]); // Initializes the Node.js platform. -NAPI_EXTERN napi_status NAPI_CDECL node_embedding_platform_initialize( - node_embedding_platform platform, bool* early_return); +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL +node_embedding_platform_initialize(node_embedding_platform platform, + bool* early_return); // Gets the parsed list of non-Node.js arguments. -NAPI_EXTERN napi_status NAPI_CDECL +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL node_embedding_platform_get_args(node_embedding_platform platform, node_embedding_get_args_callback get_args_cb, void* get_args_cb_data); // Gets the parsed list of Node.js arguments. -NAPI_EXTERN napi_status NAPI_CDECL node_embedding_platform_get_exec_args( +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL +node_embedding_platform_get_exec_args( node_embedding_platform platform, node_embedding_get_args_callback get_args_cb, void* get_args_cb_data); @@ -226,41 +269,48 @@ NAPI_EXTERN napi_status NAPI_CDECL node_embedding_platform_get_exec_args( //------------------------------------------------------------------------------ // Creates a new Node.js runtime instance. -NAPI_EXTERN napi_status NAPI_CDECL node_embedding_create_runtime( +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL node_embedding_create_runtime( node_embedding_platform platform, node_embedding_runtime* result); // Deletes the Node.js runtime instance. -NAPI_EXTERN napi_status NAPI_CDECL +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL node_embedding_delete_runtime(node_embedding_runtime runtime); // Checks if the Node.js runtime is initialized. -NAPI_EXTERN napi_status NAPI_CDECL node_embedding_runtime_is_initialized( - node_embedding_runtime runtime, bool* result); +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL +node_embedding_runtime_is_initialized(node_embedding_runtime runtime, + bool* result); // Sets the flags for the Node.js runtime initialization. -NAPI_EXTERN napi_status NAPI_CDECL node_embedding_runtime_set_flags( - node_embedding_runtime runtime, node_embedding_runtime_flags flags); +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL +node_embedding_runtime_set_flags(node_embedding_runtime runtime, + node_embedding_runtime_flags flags); // Sets the non-Node.js CLI arguments for the Node.js runtime initialization. -NAPI_EXTERN napi_status NAPI_CDECL node_embedding_runtime_set_args( +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL node_embedding_runtime_set_args( node_embedding_runtime runtime, int32_t argc, const char* argv[]); // Sets the Node.js CLI arguments for the Node.js runtime initialization. -NAPI_EXTERN napi_status NAPI_CDECL node_embedding_runtime_set_exec_args( - node_embedding_runtime runtime, int32_t argc, const char* argv[]); +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL +node_embedding_runtime_set_exec_args(node_embedding_runtime runtime, + int32_t argc, + const char* argv[]); // Sets the preload callback for the Node.js runtime initialization. -NAPI_EXTERN napi_status NAPI_CDECL +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL node_embedding_runtime_on_preload(node_embedding_runtime runtime, node_embedding_preload_callback preload_cb, void* preload_cb_data); // Sets the snapshot for the Node.js runtime initialization. -NAPI_EXTERN napi_status NAPI_CDECL node_embedding_runtime_use_snapshot( - node_embedding_runtime runtime, const uint8_t* snapshot, size_t size); +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL +node_embedding_runtime_use_snapshot(node_embedding_runtime runtime, + const uint8_t* snapshot, + size_t size); // Sets the snapshot creation parameters for the Node.js runtime initialization. -NAPI_EXTERN napi_status NAPI_CDECL node_embedding_runtime_on_create_snapshot( +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL +node_embedding_runtime_on_create_snapshot( node_embedding_runtime runtime, node_embedding_store_blob_callback store_blob_cb, void* store_blob_cb_data, @@ -269,7 +319,8 @@ NAPI_EXTERN napi_status NAPI_CDECL node_embedding_runtime_on_create_snapshot( // Adds a new module to the Node.js runtime. // It is accessed as process._linkedBinding(module_name) in the main JS and in // the related worker threads. -NAPI_EXTERN napi_status NAPI_CDECL node_embedding_runtime_add_module( +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL +node_embedding_runtime_add_module( node_embedding_runtime runtime, const char* module_name, node_embedding_initialize_module_callback init_module_cb, @@ -277,8 +328,9 @@ NAPI_EXTERN napi_status NAPI_CDECL node_embedding_runtime_add_module( int32_t module_node_api_version); // Initializes the Node.js runtime. -NAPI_EXTERN napi_status NAPI_CDECL node_embedding_runtime_initialize( - node_embedding_runtime runtime, const char* main_script); +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL +node_embedding_runtime_initialize(node_embedding_runtime runtime, + const char* main_script); //------------------------------------------------------------------------------ // Node.js runtime functions for the event loop. @@ -286,13 +338,14 @@ NAPI_EXTERN napi_status NAPI_CDECL node_embedding_runtime_initialize( // Runs the Node.js runtime event loop. // It does not block the calling thread. -NAPI_EXTERN napi_status NAPI_CDECL +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL node_embedding_runtime_run_event_loop(node_embedding_runtime runtime); // Runs the Node.js runtime event loop until the predicate returns false. // It may block the calling thread depending on the is_thread_blocking // parameter. -NAPI_EXTERN napi_status NAPI_CDECL node_embedding_runtime_run_event_loop_while( +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL +node_embedding_runtime_run_event_loop_while( node_embedding_runtime runtime, node_embedding_event_loop_predicate predicate, void* predicate_data, @@ -301,9 +354,10 @@ NAPI_EXTERN napi_status NAPI_CDECL node_embedding_runtime_run_event_loop_while( // Runs the Node.js runtime event loop until the promise is resolved. // It may block the calling thread. -NAPI_EXTERN napi_status NAPI_CDECL +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL node_embedding_runtime_await_promise(node_embedding_runtime runtime, napi_value promise, + node_embedding_promise_state* state, napi_value* result, bool* has_more_work); @@ -312,20 +366,22 @@ node_embedding_runtime_await_promise(node_embedding_runtime runtime, //------------------------------------------------------------------------------ // Sets the Node-API version for the Node.js runtime initialization. -NAPI_EXTERN napi_status NAPI_CDECL node_embedding_runtime_set_node_api_version( - node_embedding_runtime runtime, int32_t node_api_version); +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL +node_embedding_runtime_set_node_api_version(node_embedding_runtime runtime, + int32_t node_api_version); // Gets the Node-API environment associated with the initialized Node.js // runtime. -NAPI_EXTERN napi_status NAPI_CDECL node_embedding_runtime_get_node_api_env( - node_embedding_runtime runtime, napi_env* env); +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL +node_embedding_runtime_get_node_api_env(node_embedding_runtime runtime, + napi_env* env); // Opens a new Node-API scope for the current thread. -NAPI_EXTERN napi_status NAPI_CDECL +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL node_embedding_runtime_open_scope(node_embedding_runtime runtime); // Closes the current Node-API scope for the current thread. -NAPI_EXTERN napi_status NAPI_CDECL +NAPI_EXTERN node_embedding_exit_code NAPI_CDECL node_embedding_runtime_close_scope(node_embedding_runtime runtime); EXTERN_C_END @@ -358,25 +414,24 @@ inline constexpr node_embedding_snapshot_flags operator|( #endif // SRC_NODE_EMBEDDING_API_H_ -// TODO: (vmoroz) Add exit code enum. Replace napi_status with the exit code. -// TODO: (vmoroz) Remove the main_script parameter from the initialize function. -// TODO: (vmoroz) Add startup callback with process and require parameters. -// TODO: (vmoroz) Generate the main script based on the runtime settings. -// TODO: (vmoroz) Set the global inspector for a specific environment. -// TODO: (vmoroz) Start workers from C++. -// TODO: (vmoroz) Worker to inherit parent inspector. -// TODO: (vmoroz) Cancel pending tasks on delete env. -// TODO: (vmoroz) The runtime delete must avoid pumping tasks. -// TODO: (vmoroz) Can we initialize platform again if it returns early? -// TODO: (vmoroz) Add simpler threading model - without open/close scope. -// TODO: (vmoroz) Simplify API use for simple default cases. -// TODO: (vmoroz) Test passing the V8 thread pool size. -// TODO: (vmoroz) Make the args story simpler or clear named. -// TODO: (vmoroz) Consider to have one function to retrieve the both arg types. -// TODO: (vmoroz) Consider to have one function to set the both arg types. -// TODO: (vmoroz) Single runtime by default vs multiple runtimes on demand. -// TODO: (vmoroz) Add a way to terminate the runtime. -// TODO: (vmoroz) Allow to provide custom thread pool from the app. -// TODO: (vmoroz) Follow the UV example that integrates UV loop with QT loop. -// TODO: (vmoroz) Consider adding a v-table for the API functions to simplify +// TODO(vmoroz): Remove the main_script parameter from the initialize function. +// TODO(vmoroz): Add startup callback with process and require parameters. +// TODO(vmoroz): Generate the main script based on the runtime settings. +// TODO(vmoroz): Set the global inspector for a specific environment. +// TODO(vmoroz): Start workers from C++. +// TODO(vmoroz): Worker to inherit parent inspector. +// TODO(vmoroz): Cancel pending tasks on delete env. +// TODO(vmoroz): The runtime delete must avoid pumping tasks. +// TODO(vmoroz): Can we initialize platform again if it returns early? +// TODO(vmoroz): Add simpler threading model - without open/close scope. +// TODO(vmoroz): Simplify API use for simple default cases. +// TODO(vmoroz): Test passing the V8 thread pool size. +// TODO(vmoroz): Make the args story simpler or clear named. +// TODO(vmoroz): Consider to have one function to retrieve the both arg types. +// TODO(vmoroz): Consider to have one function to set the both arg types. +// TODO(vmoroz): Single runtime by default vs multiple runtimes on demand. +// TODO(vmoroz): Add a way to terminate the runtime. +// TODO(vmoroz): Allow to provide custom thread pool from the app. +// TODO(vmoroz): Follow the UV example that integrates UV loop with QT loop. +// TODO(vmoroz): Consider adding a v-table for the API functions to simplify // binding with other languages. diff --git a/test/embedding/embedtest_modules_node_api.cc b/test/embedding/embedtest_modules_node_api.cc index fa7ead2e4f96ca..4154de42b1df10 100644 --- a/test/embedding/embedtest_modules_node_api.cc +++ b/test/embedding/embedtest_modules_node_api.cc @@ -167,8 +167,9 @@ extern "C" int32_t test_main_modules_node_api(int32_t argc, char* argv[]) { size_t bufferlen; CHECK(napi_call_function(env, global, import, 1, &es6, &es6_promise)); + node_embedding_promise_state es6_promise_state; CHECK(node_embedding_runtime_await_promise( - runtime, es6_promise, &es6_module, nullptr)); + runtime, es6_promise, &es6_promise_state, &es6_module, nullptr)); CHECK(napi_get_property(env, es6_module, value, &es6_result)); CHECK(napi_get_value_string_utf8( diff --git a/test/embedding/embedtest_node_api.cc b/test/embedding/embedtest_node_api.cc index 462984332dac16..d16ece19bd9ea8 100644 --- a/test/embedding/embedtest_node_api.cc +++ b/test/embedding/embedtest_node_api.cc @@ -33,13 +33,15 @@ extern "C" int32_t test_main_node_api(int32_t argc, char* argv[]) { napi_status AddUtf8String(std::string& str, napi_env env, napi_value value) { size_t str_size = 0; - napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, &str_size); + napi_status status = + napi_get_value_string_utf8(env, value, nullptr, 0, &str_size); if (status != napi_ok) { return status; } size_t offset = str.size(); str.resize(offset + str_size); - status = napi_get_value_string_utf8(env, value, &str[0] + offset, str_size + 1, &str_size); + status = napi_get_value_string_utf8( + env, value, &str[0] + offset, str_size + 1, &str_size); return status; } @@ -166,14 +168,12 @@ int32_t waitMeWithCheese(napi_env env, node_embedding_runtime runtime) { FAIL("Result is not a Promise\n"); } - napi_status r = node_embedding_runtime_await_promise( - runtime, promise, &result, nullptr); - if (r != napi_ok && r != napi_pending_exception) { - FAIL("Failed awaiting promise: %d\n", r); - } + node_embedding_promise_state promise_state; + CHECK(node_embedding_runtime_await_promise( + runtime, promise, &promise_state, &result, nullptr)); const char* expected; - if (r == napi_ok) + if (promise_state == node_embedding_promise_state_fulfilled) expected = "waited with cheese"; else expected = "waited without cheese"; diff --git a/test/embedding/embedtest_node_api.h b/test/embedding/embedtest_node_api.h index ad1612b7385311..6b12e5b6586fe7 100644 --- a/test/embedding/embedtest_node_api.h +++ b/test/embedding/embedtest_node_api.h @@ -15,20 +15,20 @@ extern "C" inline void NAPI_CDECL GetArgsVector(void* data, static_cast*>(data)->assign(argv, argv + argc); } -extern "C" inline napi_status NAPI_CDECL HandleTestError(void* handler_data, - const char* messages[], - size_t messages_size, - int32_t exit_code, - napi_status status) { +extern "C" inline node_embedding_exit_code NAPI_CDECL +HandleTestError(void* handler_data, + const char* messages[], + size_t messages_size, + node_embedding_exit_code exit_code) { auto exe_name = static_cast(handler_data); if (exit_code != 0) { for (size_t i = 0; i < messages_size; ++i) fprintf(stderr, "%s: %s\n", exe_name, messages[i]); - exit(exit_code); + exit(static_cast(exit_code)); } else { for (size_t i = 0; i < messages_size; ++i) printf("%s\n", messages[i]); } - return status; + return exit_code; } #endif @@ -39,7 +39,7 @@ napi_status AddUtf8String(std::string& str, napi_env env, napi_value value); #define CHECK(expr) \ do { \ - if ((expr) != napi_ok) { \ + if ((expr) != node_embedding_exit_code_ok) { \ fprintf(stderr, "Failed: %s\n", #expr); \ fprintf(stderr, "File: %s\n", __FILE__); \ fprintf(stderr, "Line: %d\n", __LINE__); \ @@ -73,7 +73,7 @@ napi_status AddUtf8String(std::string& str, napi_env env, napi_value value); #endif // TEST_EMBEDDING_EMBEDTEST_NODE_API_H_ -// TODO: (vmoroz) Enable the test_main_modules_node_api test. -// TODO: (vmoroz) Test failure in Preload callback. -// TODO: (vmoroz) Test failure in linked modules. -// TODO: (vmoroz) Make sure that delete call matches the create call. +// TODO(vmoroz): Enable the test_main_modules_node_api test. +// TODO(vmoroz): Test failure in Preload callback. +// TODO(vmoroz): Test failure in linked modules. +// TODO(vmoroz): Make sure that delete call matches the create call.