Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .vscode/c_cpp_properties.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"${workspaceFolder}/node_modules/node-addon-api",
"${workspaceFolder}/node_modules/nan"
],
"defines": ["NAPI_DISABLE_CPP_EXCEPTIONS", "NODE_ADDON_API_ENABLE_MAYBE", "V8_ENABLE_DIRECT_LOCAL"],
"defines": ["NAPI_DISABLE_CPP_EXCEPTIONS", "NODE_ADDON_API_ENABLE_MAYBE", "V8_ENABLE_DIRECT_LOCAL", "NODE_API_RUNTIME_USE_VTABLE", "NAPI_EXPERIMENTAL"],
"clPath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.28.29910\\bin\\Hostx64\\x64\\cl.exe",
"gccPath": "/usr/bin/gcc",
"clangPath": "/usr/bin/clang"
Expand Down
2 changes: 1 addition & 1 deletion packages/emnapi/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ set(EMNAPI_THREADS_SRC
set(EMNAPI_SRC ${ENAPI_BASIC_SRC} ${EMNAPI_THREADS_SRC})

set(EMNAPI_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/include/node")
set(EMNAPI_DEFINES "BUILDING_NODE_EXTENSION")
set(EMNAPI_DEFINES "BUILDING_NODE_EXTENSION" "NODE_API_RUNTIME_USE_VTABLE")
set(V8_DEFINES "V8_ENABLE_DIRECT_LOCAL")

set(EMNAPI_JS_LIB "${CMAKE_CURRENT_SOURCE_DIR}/dist/library_napi.js")
Expand Down
1 change: 1 addition & 0 deletions packages/emnapi/common.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

'defines': [
'BUILDING_NODE_EXTENSION',
'NODE_API_RUNTIME_USE_VTABLE',
'__STDC_FORMAT_MACROS',
'V8_ENABLE_DIRECT_LOCAL',
],
Expand Down
1,043 changes: 832 additions & 211 deletions packages/emnapi/include/node/js_native_api.h

Large diffs are not rendered by default.

576 changes: 565 additions & 11 deletions packages/emnapi/include/node/js_native_api_types.h

Large diffs are not rendered by default.

359 changes: 279 additions & 80 deletions packages/emnapi/include/node/node_api.h

Large diffs are not rendered by default.

206 changes: 206 additions & 0 deletions packages/emnapi/include/node/node_api_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@

#include "js_native_api_types.h"

struct uv_loop_s; // Forward declaration.

typedef napi_value(NAPI_CDECL* napi_addon_register_func)(napi_env env,
napi_value exports);
// False positive: https://github.com/cpplint/cpplint/issues/409
// NOLINTNEXTLINE (readability/casting)
typedef int32_t(NAPI_CDECL* node_api_addon_get_api_version_func)(void);

typedef struct napi_callback_scope__* napi_callback_scope;
Expand Down Expand Up @@ -53,4 +57,206 @@ typedef void(NAPI_CDECL* napi_async_cleanup_hook)(
napi_async_cleanup_hook_handle handle, void* data);
#endif // NAPI_VERSION >= 8

// Used by deprecated registration method napi_module_register.
typedef struct napi_module {
int nm_version;
unsigned int nm_flags;
const char* nm_filename;
napi_addon_register_func nm_register_func;
const char* nm_modname;
void* nm_priv;
void* reserved[4];
} napi_module;

#if defined(NODE_API_MODULE_USE_VTABLE) || defined(NODE_API_RUNTIME_USE_VTABLE)

// Vtable for Node.js module-specific functions
// New functions must be added at the end to maintain backward compatibility.
typedef struct node_api_module_vtable {
void(NAPI_CDECL* module_register)(napi_module* mod);

void(NAPI_CDECL* fatal_error)(const char* location,
size_t location_len,
const char* message,
size_t message_len);

napi_status(NAPI_CDECL* async_init)(napi_env env,
napi_value async_resource,
napi_value async_resource_name,
napi_async_context* result);

napi_status(NAPI_CDECL* async_destroy)(napi_env env,
napi_async_context async_context);

napi_status(NAPI_CDECL* make_callback)(napi_env env,
napi_async_context async_context,
napi_value recv,
napi_value func,
size_t argc,
const napi_value* argv,
napi_value* result);

napi_status(NAPI_CDECL* create_buffer)(napi_env env,
size_t length,
void** data,
napi_value* result);
napi_status(NAPI_CDECL* create_external_buffer)(
napi_env env,
size_t length,
void* data,
node_api_basic_finalize finalize_cb,
void* finalize_hint,
napi_value* result);

napi_status(NAPI_CDECL* create_buffer_copy)(napi_env env,
size_t length,
const void* data,
void** result_data,
napi_value* result);
napi_status(NAPI_CDECL* is_buffer)(napi_env env,
napi_value value,
bool* result);
napi_status(NAPI_CDECL* get_buffer_info)(napi_env env,
napi_value value,
void** data,
size_t* length);

napi_status(NAPI_CDECL* create_async_work)(
napi_env env,
napi_value async_resource,
napi_value async_resource_name,
napi_async_execute_callback execute,
napi_async_complete_callback complete,
void* data,
napi_async_work* result);
napi_status(NAPI_CDECL* delete_async_work)(napi_env env,
napi_async_work work);
napi_status(NAPI_CDECL* queue_async_work)(node_api_basic_env env,
napi_async_work work);
napi_status(NAPI_CDECL* cancel_async_work)(node_api_basic_env env,
napi_async_work work);

napi_status(NAPI_CDECL* get_node_version)(node_api_basic_env env,
const napi_node_version** version);

#if NAPI_VERSION >= 2

napi_status(NAPI_CDECL* get_uv_event_loop)(node_api_basic_env env,
struct uv_loop_s** loop);

#endif // NAPI_VERSION >= 2

#if NAPI_VERSION >= 3

napi_status(NAPI_CDECL* fatal_exception)(napi_env env, napi_value err);

napi_status(NAPI_CDECL* add_env_cleanup_hook)(node_api_basic_env env,
napi_cleanup_hook fun,
void* arg);

napi_status(NAPI_CDECL* remove_env_cleanup_hook)(node_api_basic_env env,
napi_cleanup_hook fun,
void* arg);

napi_status(NAPI_CDECL* open_callback_scope)(napi_env env,
napi_value resource_object,
napi_async_context context,
napi_callback_scope* result);

napi_status(NAPI_CDECL* close_callback_scope)(napi_env env,
napi_callback_scope scope);

#endif // NAPI_VERSION >= 3

#if NAPI_VERSION >= 4

napi_status(NAPI_CDECL* create_threadsafe_function)(
napi_env env,
napi_value func,
napi_value async_resource,
napi_value async_resource_name,
size_t max_queue_size,
size_t initial_thread_count,
void* thread_finalize_data,
napi_finalize thread_finalize_cb,
void* context,
napi_threadsafe_function_call_js call_js_cb,
napi_threadsafe_function* result);

napi_status(NAPI_CDECL* get_threadsafe_function_context)(
napi_threadsafe_function func, void** result);

napi_status(NAPI_CDECL* call_threadsafe_function)(
napi_threadsafe_function func,
void* data,
napi_threadsafe_function_call_mode is_blocking);

napi_status(NAPI_CDECL* acquire_threadsafe_function)(
napi_threadsafe_function func);

napi_status(NAPI_CDECL* release_threadsafe_function)(
napi_threadsafe_function func,
napi_threadsafe_function_release_mode mode);

napi_status(NAPI_CDECL* unref_threadsafe_function)(
node_api_basic_env env, napi_threadsafe_function func);

napi_status(NAPI_CDECL* ref_threadsafe_function)(
node_api_basic_env env, napi_threadsafe_function func);

#endif // NAPI_VERSION >= 4

#if NAPI_VERSION >= 8

napi_status(NAPI_CDECL* add_async_cleanup_hook)(
node_api_basic_env env,
napi_async_cleanup_hook hook,
void* arg,
napi_async_cleanup_hook_handle* remove_handle);

napi_status(NAPI_CDECL* remove_async_cleanup_hook)(
napi_async_cleanup_hook_handle remove_handle);

#endif // NAPI_VERSION >= 8

#if NAPI_VERSION >= 9

napi_status(NAPI_CDECL* get_module_file_name)(node_api_basic_env env,
const char** result);

#endif // NAPI_VERSION >= 9

#if NAPI_VERSION >= 10

napi_status(NAPI_CDECL* create_buffer_from_arraybuffer)(
napi_env env,
napi_value arraybuffer,
size_t byte_offset,
size_t byte_length,
napi_value* result);

#endif // NAPI_VERSION >= 10
} node_api_module_vtable;

#if NAPI_VERSION >= 4

struct napi_threadsafe_function__ {
uint64_t sentinel; // Should be NODE_API_VT_SENTINEL
const struct node_api_module_vtable* module_vtable;
};

#endif // NAPI_VERSION >= 4

#if NAPI_VERSION >= 8

struct napi_async_cleanup_hook_handle__ {
uint64_t sentinel; // Should be NODE_API_VT_SENTINEL
const struct node_api_module_vtable* module_vtable;
};

#endif // NAPI_VERSION >= 8

#endif // defined(NODE_API_MODULE_USE_VTABLE) ||
// defined(NODE_API_RUNTIME_USE_VTABLE)

#endif // SRC_NODE_API_TYPES_H_
22 changes: 22 additions & 0 deletions packages/emnapi/script/sync-header.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const headers = [
'js_native_api_types.h',
'js_native_api.h',
'node_api_types.h',
'node_api.h',
]

const nodeRepo = process.argv[2]

if (!nodeRepo) {
console.error('Usage: node sync-header.js <path-to-node-repo>')
process.exit(1)
}

const fs = require('fs')
const path = require('path')

headers.forEach(header => {
const src = path.join(nodeRepo, 'src', header)
const dest = path.join(__dirname, '../include/node', header)
fs.copyFileSync(src, dest)
})
27 changes: 16 additions & 11 deletions packages/emnapi/src/async_cleanup_hook.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,24 @@ struct async_cleanup_hook_info {
bool started;
};

struct napi_async_cleanup_hook_handle__ {
typedef struct node_api_async_cleanup_hook__ {
uint64_t sentinel;
const struct node_api_module_vtable* module_vtable;

struct async_cleanup_hook_info* handle_;
node_api_basic_env env_;
napi_async_cleanup_hook user_hook_;
void* user_data_;
void (*done_cb_)(void*);
void* done_data_;
};
} node_api_async_cleanup_hook__;

static void _emnapi_ach_handle_hook(void* data, void (*done_cb)(void*), void* done_data) {
napi_async_cleanup_hook_handle handle =
(napi_async_cleanup_hook_handle) (data);
node_api_async_cleanup_hook__* handle =
(node_api_async_cleanup_hook__*) (data);
handle->done_cb_ = done_cb;
handle->done_data_ = done_data;
handle->user_hook_(handle, handle->user_data_);
handle->user_hook_((napi_async_cleanup_hook_handle)handle, handle->user_data_);
}

static void _emnapi_finish_async_cleanup_hook(void* arg) {
Expand Down Expand Up @@ -67,12 +70,14 @@ static void _emnapi_remove_async_environment_cleanup_hook(
EMNAPI_ASSERT_CALL(napi_remove_env_cleanup_hook(info->env, _emnapi_run_async_cleanup_hook, info));
}

static napi_async_cleanup_hook_handle
static node_api_async_cleanup_hook__*
_emnapi_ach_handle_create(node_api_basic_env env,
napi_async_cleanup_hook user_hook,
void* user_data) {
napi_async_cleanup_hook_handle handle =
(napi_async_cleanup_hook_handle) calloc(1, sizeof(struct napi_async_cleanup_hook_handle__));
node_api_async_cleanup_hook__* handle =
(node_api_async_cleanup_hook__*) calloc(1, sizeof(node_api_async_cleanup_hook__));
handle->sentinel = NODE_API_VT_SENTINEL;
handle->module_vtable = NULL; // TODO
handle->env_ = env;
handle->user_hook_ = user_hook;
handle->user_data_ = user_data;
Expand All @@ -90,7 +95,7 @@ static void _emnapi_ach_handle_env_unref(void* arg) {
}

static void
_emnapi_ach_handle_delete(napi_async_cleanup_hook_handle handle) {
_emnapi_ach_handle_delete(node_api_async_cleanup_hook__* handle) {
_emnapi_remove_async_environment_cleanup_hook(handle->handle_);
if (handle->done_cb_ != NULL) handle->done_cb_(handle->done_data_);

Expand All @@ -109,7 +114,7 @@ napi_add_async_cleanup_hook(node_api_basic_env env,
CHECK_ARG(env, hook);

napi_async_cleanup_hook_handle handle =
_emnapi_ach_handle_create(env, hook, arg);
(napi_async_cleanup_hook_handle)_emnapi_ach_handle_create(env, hook, arg);

if (remove_handle != NULL) *remove_handle = handle;

Expand All @@ -120,7 +125,7 @@ napi_status
napi_remove_async_cleanup_hook(napi_async_cleanup_hook_handle remove_handle) {
if (remove_handle == NULL) return napi_invalid_arg;

_emnapi_ach_handle_delete(remove_handle);
_emnapi_ach_handle_delete((node_api_async_cleanup_hook__*)remove_handle);

return napi_ok;
}
Expand Down
5 changes: 4 additions & 1 deletion packages/emnapi/src/js_native_api_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@

typedef struct node_api_base_env__ {
void* vptr;
EMNAPI_NAPI_ENV_FIELDS;
uint64_t sentinel; // Should be NODE_API_VT_SENTINEL
const struct node_api_js_vtable* js_vtable;
const struct node_api_module_vtable* module_vtable;

uint32_t id;
napi_extended_error_info last_error;
} node_api_base_env__;
Expand Down
Loading