mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-08 09:24:41 +00:00
270 lines
12 KiB
C
Vendored
270 lines
12 KiB
C
Vendored
/**
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
#ifndef HERMES_NAPI_HERMES_NAPI_H
|
|
#define HERMES_NAPI_HERMES_NAPI_H
|
|
|
|
#include "hermes/napi/node_api.h"
|
|
|
|
//===========================================================================
|
|
// Host integration interface
|
|
//===========================================================================
|
|
|
|
/// Abstract interface that the host application can provide to integrate
|
|
/// with its runtime environment. This covers async work scheduling
|
|
/// (napi_create_async_work / napi_queue_async_work), thread-safe
|
|
/// function dispatch, libuv event loop access, and fatal exception
|
|
/// handling. Fields left as nullptr preserve default behavior — in
|
|
/// particular, async work and thread-safe function APIs will return
|
|
/// napi_generic_failure if the relevant callbacks are not provided.
|
|
///
|
|
/// The host is responsible for the lifetime of this struct — it must
|
|
/// outlive the napi_env that references it.
|
|
struct hermes_napi_host {
|
|
/// Schedule \p execute to run on a worker thread. When execute
|
|
/// completes, schedule \p complete to run on the main (JS) thread.
|
|
/// \p data is passed through to both callbacks.
|
|
/// \p complete receives \p status == 0 on success, or
|
|
/// napi_cancelled if the work was cancelled.
|
|
void (*post_work)(
|
|
void *loop_data,
|
|
void *work_data,
|
|
void (*execute)(void *work_data),
|
|
void (*complete)(void *work_data, napi_status status));
|
|
|
|
/// Cancel a previously posted work item. The event loop should
|
|
/// attempt to cancel the work. If successful, the complete callback
|
|
/// from post_work should be called with status == napi_cancelled.
|
|
/// Returns true if cancellation was initiated, false if the work
|
|
/// has already started or completed.
|
|
bool (*cancel_work)(void *loop_data, void *work_data);
|
|
|
|
/// Schedule \p callback to run on the main (JS) thread.
|
|
/// This is used by thread-safe functions to dispatch queued calls.
|
|
/// \p data is passed through to the callback.
|
|
void (*post_task)(
|
|
void *loop_data,
|
|
void *task_data,
|
|
void (*callback)(void *task_data));
|
|
|
|
/// Opaque data pointer passed as the first argument to post_work,
|
|
/// cancel_work, and post_task. Typically the host's event loop
|
|
/// instance.
|
|
void *data;
|
|
|
|
/// If non-null, napi_get_uv_event_loop() returns this pointer.
|
|
/// The host is responsible for the lifetime — it must outlive the
|
|
/// napi_env. Embedders without libuv leave this nullptr (the
|
|
/// default), in which case napi_get_uv_event_loop() returns
|
|
/// napi_generic_failure.
|
|
struct uv_loop_s *uv_loop;
|
|
|
|
/// If non-null, called by napi_fatal_exception() instead of aborting.
|
|
/// The host typically routes this to
|
|
/// process.emit('uncaughtException', err).
|
|
/// Receives the host data pointer, the napi_env, and the error value.
|
|
/// When null (the default), napi_fatal_exception() prints the error
|
|
/// and calls abort() via hermes_fatal().
|
|
void (*fatal_exception)(void *data, napi_env env, napi_value err);
|
|
|
|
/// Hold a long-lived reference on the event loop. The host should
|
|
/// keep the loop alive until a matching unref_loop call. Used by
|
|
/// threadsafe functions to model libuv-style "ref" semantics: while
|
|
/// any tsfn in an env is referenced, the env holds one ref so
|
|
/// producer threads can dispatch into JS without racing the loop's
|
|
/// shutdown.
|
|
///
|
|
/// Contract: within a single napi_env, ref_loop / unref_loop calls
|
|
/// are paired and NEVER nested — every ref_loop is followed by a
|
|
/// matching unref_loop before the next ref_loop from that env. The
|
|
/// env coalesces all referenced tsfns into one ref/unref pair, so an
|
|
/// env contributes at most one outstanding ref at a time.
|
|
///
|
|
/// Across distinct envs sharing the same host, multiple unmatched
|
|
/// refs may be in flight concurrently — one per env that has any
|
|
/// referenced tsfn — so the host implementation must accept
|
|
/// concurrent unmatched ref_loop calls (typically via a refcount
|
|
/// or its existing source-tracking mechanism).
|
|
///
|
|
/// Optional — when null, TSFN ref/unref are tracked for API
|
|
/// compatibility only and have no effect on loop lifetime.
|
|
/// Must be paired with unref_loop.
|
|
void (*ref_loop)(void *loop_data);
|
|
|
|
/// Release a long-lived loop reference previously taken by ref_loop.
|
|
/// Optional; null only if ref_loop is also null.
|
|
void (*unref_loop)(void *loop_data);
|
|
};
|
|
|
|
typedef hermes_napi_host hermes_napi_event_loop;
|
|
|
|
//===========================================================================
|
|
// Environment lifecycle (public API)
|
|
//===========================================================================
|
|
|
|
/// Create a new NAPI environment backed by a Hermes Runtime.
|
|
/// The \p hermes_runtime parameter is an opaque pointer to a
|
|
/// hermes::vm::Runtime instance.
|
|
///
|
|
/// The env is owned by the Runtime and is automatically torn down and
|
|
/// freed when the Runtime is destroyed. The caller must keep the
|
|
/// Runtime alive for as long as it uses the returned pointer, and must
|
|
/// not free the env itself.
|
|
///
|
|
/// Finalizer semantics at Runtime teardown:
|
|
///
|
|
/// Finalizers registered via napi_wrap, napi_add_finalizer,
|
|
/// napi_create_external, etc. are guaranteed to be invoked exactly
|
|
/// once with the live env that owns the wrapped object. We never
|
|
/// invoke user finalizers with env == nullptr.
|
|
///
|
|
/// Callbacks fire in one of two contexts, both with a non-null env:
|
|
///
|
|
/// - Unrestricted: the wrapped object was collected while the GC
|
|
/// heap was fully functional — either during normal operation
|
|
/// (collection happens, callback is drained at the next
|
|
/// NAPI_PREAMBLE / drainJobs) or during the env's shutdown
|
|
/// phase (cleanup hooks, persistent-reference finalizers, the
|
|
/// instance-data finalizer, or thread-safe-function cleanup
|
|
/// transitively triggered a GC; the callback is drained at the
|
|
/// end of shutdown). The callback may freely allocate, call
|
|
/// into JS, and use the env as in any other context.
|
|
///
|
|
/// - Restricted: the wrapped object was still reachable from JS
|
|
/// roots at teardown and was finalized by
|
|
/// getHeap().finalizeAll() itself. The callback is drained
|
|
/// after finalizeAll, with the GC heap in a post-mortem state.
|
|
/// Any NAPI call that would allocate or run JavaScript returns
|
|
/// napi_cannot_run_js instead of executing. A spec-conformant
|
|
/// finalizer (which only frees native resources — free(),
|
|
/// close(), delete, refcount decrement) is unaffected. A
|
|
/// finalizer that tries to call back into JS receives the
|
|
/// error code and may choose to log it.
|
|
///
|
|
/// The optional \p host provides host integration callbacks (async work,
|
|
/// thread-safe functions, etc.); if nullptr, those APIs return
|
|
/// napi_generic_failure.
|
|
NAPI_EXTERN napi_env NAPI_CDECL
|
|
hermes_napi_create_env(void *hermes_runtime, hermes_napi_host *host = nullptr);
|
|
|
|
/// Get the last module registered via the deprecated napi_module_register().
|
|
/// Returns nullptr if no module has been registered.
|
|
NAPI_EXTERN const napi_module *NAPI_CDECL
|
|
hermes_napi_get_last_registered_module();
|
|
|
|
/// Load a NAPI addon from a shared library at \p path.
|
|
///
|
|
/// This function:
|
|
/// 1. Opens the shared library via dlopen().
|
|
/// 2. Looks up the `napi_register_module_v1` symbol (modern approach).
|
|
/// If not found, falls back to the deprecated `napi_module_register()`
|
|
/// approach (checking `hermes_napi_get_last_registered_module()`).
|
|
/// 3. Creates an empty `exports` object in the caller's env.
|
|
/// 4. Calls the module's init function with (env, exports).
|
|
/// 5. Stores the resulting exports object in \p result.
|
|
///
|
|
/// The caller must provide a valid \p env with an open handle scope.
|
|
/// The module's CallbackBundles are owned by the caller's env.
|
|
///
|
|
/// Returns napi_ok on success, or an error status on failure (with a
|
|
/// pending exception set on the env).
|
|
NAPI_EXTERN napi_status NAPI_CDECL
|
|
hermes_napi_load_module(napi_env env, const char *path, napi_value *result);
|
|
|
|
//===========================================================================
|
|
// Script execution
|
|
//===========================================================================
|
|
|
|
/// Flags for hermes_run_script(). The first field is the struct
|
|
/// size for ABI-stable extensibility — newer versions can append
|
|
/// fields without breaking older callers.
|
|
struct hermes_run_script_flags {
|
|
/// Size of this struct in bytes. Must be set to
|
|
/// sizeof(hermes_run_script_flags) by the caller.
|
|
size_t struct_size;
|
|
/// Run in strict mode.
|
|
bool strict;
|
|
/// Enable TypeScript support.
|
|
bool enable_ts;
|
|
/// Keep the compiled bytecode alive for the lifetime of the Runtime,
|
|
/// even after all references to it are gone. This lets the engine
|
|
/// avoid copying certain parts of the buffer, resulting in faster
|
|
/// load times. Do not set this for short-lived modules (e.g. REPL
|
|
/// input) — they would accumulate and never be freed.
|
|
bool persistent;
|
|
};
|
|
|
|
/// Compile and run JavaScript source in a single call.
|
|
///
|
|
/// \p data and \p size describe a UTF-8 source buffer. If the last
|
|
/// byte is '\0', the source is used zero-copy (actual source length
|
|
/// is size-1). Otherwise, an internal copy is made to add the null
|
|
/// terminator required by the compiler.
|
|
///
|
|
/// The runtime takes ownership of the buffer: \p finalize_cb is
|
|
/// called with (\p data, \p size, \p finalize_hint) when the buffer
|
|
/// is no longer needed. Pass NULL for \p finalize_cb if the buffer
|
|
/// is static or externally managed.
|
|
///
|
|
/// \p source_url appears in stack traces (NULL → empty string).
|
|
/// \p flags controls compilation options (NULL → all defaults).
|
|
///
|
|
/// Returns napi_ok on success, napi_pending_exception on JS or
|
|
/// compile error.
|
|
NAPI_EXTERN napi_status NAPI_CDECL hermes_run_script(
|
|
napi_env env,
|
|
const uint8_t *data,
|
|
size_t size,
|
|
void (*finalize_cb)(const uint8_t *data, size_t size, void *hint),
|
|
void *finalize_hint,
|
|
const char *source_url,
|
|
const hermes_run_script_flags *flags,
|
|
napi_value *result);
|
|
|
|
//===========================================================================
|
|
// Pre-compiled bytecode
|
|
//===========================================================================
|
|
|
|
/// Flags for hermes_run_bytecode(). The first field is the struct
|
|
/// size for ABI-stable extensibility — newer versions can append
|
|
/// fields without breaking older callers.
|
|
struct hermes_bytecode_flags {
|
|
size_t struct_size;
|
|
/// Keep the bytecode alive for the lifetime of the Runtime, even
|
|
/// after all references to it are gone. This lets the engine avoid
|
|
/// copying certain parts of the buffer, resulting in faster load
|
|
/// times. Do not set this for short-lived modules (e.g. REPL
|
|
/// input) — they would accumulate and never be freed.
|
|
bool persistent;
|
|
bool hides_epilogue;
|
|
bool funcs_are_builtins;
|
|
};
|
|
|
|
/// Run pre-compiled Hermes bytecode.
|
|
///
|
|
/// \p data and \p size describe the bytecode buffer. The runtime
|
|
/// takes ownership: \p finalize_cb is called with (\p data, \p size,
|
|
/// \p finalize_hint) when the buffer is no longer needed. Pass NULL
|
|
/// for \p finalize_cb if the buffer is static or externally managed.
|
|
///
|
|
/// \p source_url appears in stack traces (NULL → empty string).
|
|
/// \p flags controls runtime module behavior (NULL → all defaults).
|
|
///
|
|
/// Returns napi_ok on success, napi_pending_exception on JS error,
|
|
/// or napi_generic_failure on bytecode validation failure.
|
|
NAPI_EXTERN napi_status NAPI_CDECL hermes_run_bytecode(
|
|
napi_env env,
|
|
const uint8_t *data,
|
|
size_t size,
|
|
void (*finalize_cb)(const uint8_t *data, size_t size, void *hint),
|
|
void *finalize_hint,
|
|
const char *source_url,
|
|
const hermes_bytecode_flags *flags,
|
|
napi_value *result);
|
|
|
|
#endif // HERMES_NAPI_HERMES_NAPI_H
|