MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1// TODO: split into multiple files
2
3#include <compat.h> // IWYU pragma: keep
4
5#ifdef _WIN32
6#define WIN32_LEAN_AND_MEAN
7#include <windows.h>
8#define NAPI_DLOPEN(name, flags) ((void*)LoadLibraryA(name))
9#define NAPI_DLSYM(handle, name) ((void*)GetProcAddress((HMODULE)(handle), (name)))
10#define NAPI_DLERROR() "LoadLibrary failed"
11#define NAPI_RTLD_NOW 0
12#define NAPI_RTLD_LOCAL 0
13#define NAPI_RTLD_GLOBAL 0
14#else
15#include <dlfcn.h>
16#define NAPI_DLOPEN(name, flags) dlopen((name), (flags))
17#define NAPI_DLSYM(handle, name) dlsym((handle), (name))
18#define NAPI_DLERROR() dlerror()
19#define NAPI_RTLD_NOW RTLD_NOW
20#define NAPI_RTLD_LOCAL RTLD_LOCAL
21#define NAPI_RTLD_GLOBAL RTLD_GLOBAL
22#endif
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <stdint.h>
28#include <uthash.h>
29#include <uv.h>
30
31#if defined(__has_include)
32#if __has_include(<uchar.h>)
33#include <uchar.h>
34#else
35typedef uint16_t char16_t;
36#endif
37#else
38typedef uint16_t char16_t;
39#endif
40
41#include "ant.h"
42#include "ptr.h"
43#include "descriptors.h"
44#include "errors.h"
45#include "internal.h"
46#include "silver/engine.h"
47
48#include "modules/buffer.h"
49#include "modules/date.h"
50#include "modules/napi.h"
51#include "gc/objects.h"
52#include "gc/roots.h"
53#include "gc/modules.h"
54#include "utf8.h"
55
56typedef struct napi_cleanup_hook_entry {
57 napi_cleanup_hook hook;
58 void *arg;
59 struct napi_cleanup_hook_entry *next;
60} napi_cleanup_hook_entry_t;
61
62typedef struct ant_napi_env__ {
63 ant_t *js;
64 napi_extended_error_info last_error;
65 char last_error_msg[256];
66 bool has_pending_exception;
67 napi_value pending_exception;
68 uint32_t version;
69 void *instance_data;
70 node_api_basic_finalize instance_data_finalize_cb;
71 void *instance_data_finalize_hint;
72 napi_cleanup_hook_entry_t *cleanup_hooks;
73 struct napi_ref__ *refs;
74 struct napi_deferred__ *deferreds;
75 struct napi_threadsafe_function__ *tsfns;
76 int open_handle_scopes;
77 ant_value_t *handle_slots;
78 size_t handle_slots_len;
79 size_t handle_slots_cap;
80} ant_napi_env_t;
81
82typedef struct napi_callback_binding {
83 ant_napi_env_t *env;
84 napi_callback cb;
85 void *data;
86} napi_callback_binding_t;
87
88struct napi_callback_info__ {
89 ant_napi_env_t *env;
90 const napi_value *argv;
91 size_t argc;
92 napi_value this_arg;
93 napi_value new_target;
94 void *data;
95};
96
97struct napi_ref__ {
98 ant_napi_env_t *env;
99 ant_value_t ref_val;
100 napi_value value;
101 uint32_t refcount;
102 struct napi_ref__ *next;
103 struct napi_ref__ *prev;
104};
105
106struct napi_deferred__ {
107 ant_napi_env_t *env;
108 ant_value_t promise_val;
109 bool settled;
110 struct napi_deferred__ *next;
111 struct napi_deferred__ *prev;
112};
113
114struct napi_handle_scope__ {
115 ant_napi_env_t *env;
116 size_t gc_root_mark;
117 size_t handle_slots_mark;
118};
119
120struct napi_escapable_handle_scope__ {
121 ant_napi_env_t *env;
122 size_t gc_root_mark;
123 size_t handle_slots_mark;
124 bool escaped;
125 ant_value_t escaped_val;
126};
127
128struct napi_async_context__ {
129 ant_napi_env_t *env;
130};
131
132struct napi_callback_scope__ {
133 ant_napi_env_t *env;
134};
135
136typedef struct napi_external_entry {
137 uint64_t id;
138 void *data;
139 node_api_basic_finalize finalize_cb;
140 void *finalize_hint;
141 UT_hash_handle hh;
142} napi_external_entry_t;
143
144typedef struct napi_wrap_entry {
145 uint64_t id;
146 void *native_object;
147 node_api_basic_finalize finalize_cb;
148 void *finalize_hint;
149 void *attached_data;
150 node_api_basic_finalize attached_finalize_cb;
151 void *attached_finalize_hint;
152 bool has_wrap;
153 UT_hash_handle hh;
154} napi_wrap_entry_t;
155
156typedef struct napi_async_work_impl {
157 ant_napi_env_t *env;
158 napi_async_execute_callback execute;
159 napi_async_complete_callback complete;
160 void *data;
161 uv_work_t req;
162 bool queued;
163 bool delete_after_complete;
164} napi_async_work_impl_t;
165
166typedef struct napi_tsfn_item {
167 void *data;
168 struct napi_tsfn_item *next;
169} napi_tsfn_item_t;
170
171struct napi_threadsafe_function__ {
172 ant_napi_env_t *env;
173 ant_value_t func_val;
174 napi_threadsafe_function_call_js call_js_cb;
175 node_api_basic_finalize thread_finalize_cb;
176 void *thread_finalize_data;
177 void *context;
178 size_t max_queue_size;
179 size_t queue_size;
180 size_t thread_count;
181 bool closing;
182 bool aborted;
183 uv_async_t async;
184 uv_mutex_t mutex;
185 napi_tsfn_item_t *head;
186 napi_tsfn_item_t *tail;
187 struct napi_threadsafe_function__ *next;
188 struct napi_threadsafe_function__ *prev;
189};
190
191typedef napi_value(NAPI_CDECL* napi_register_module_v1_fn)(
192 napi_env env, napi_value exports
193);
194
195typedef struct napi_native_lib {
196 void *handle;
197 struct napi_native_lib *next;
198} napi_native_lib_t;
199
200typedef enum {
201 napi_key_include_prototypes = 0,
202 napi_key_own_only = 1,
203} napi_key_collection_mode;
204
205typedef enum {
206 napi_key_all_properties = 0,
207 napi_key_writable = 1 << 0,
208 napi_key_enumerable = 1 << 1,
209 napi_key_configurable = 1 << 2,
210 napi_key_skip_strings = 1 << 3,
211 napi_key_skip_symbols = 1 << 4,
212} napi_key_filter;
213
214typedef enum {
215 napi_key_keep_numbers = 0,
216 napi_key_numbers_to_strings = 1,
217} napi_key_conversion;
218
219typedef struct {
220 uint8_t sign;
221 uint8_t pad[3];
222 uint32_t limb_count;
223 uint32_t limbs[];
224} napi_bigint_payload_t;
225
226enum { NAPI_CALLBACK_NATIVE_TAG = 0x4e43424bu }; // NCBK
227
228static ant_napi_env_t *g_napi_env = NULL;
229static napi_external_entry_t *g_napi_externals = NULL;
230static napi_wrap_entry_t *g_napi_wraps = NULL;
231
232static uint64_t g_napi_external_next_id = 1;
233static uint64_t g_napi_wrap_next_id = 1;
234static int64_t g_napi_external_memory = 0;
235
236static napi_native_lib_t *g_napi_native_libs = NULL;
237static napi_module *g_pending_napi_module = NULL;
238
239static const napi_node_version g_napi_node_version = {
240 .major = 25,
241 .minor = 9,
242 .patch = 0,
243 .release = "ant",
244};
245
246static const char *napi_status_text(napi_status status) {
247switch (status) {
248 case napi_ok: return "ok";
249 case napi_invalid_arg: return "invalid argument";
250 case napi_object_expected: return "object expected";
251 case napi_string_expected: return "string expected";
252 case napi_name_expected: return "name expected";
253 case napi_function_expected: return "function expected";
254 case napi_number_expected: return "number expected";
255 case napi_boolean_expected: return "boolean expected";
256 case napi_array_expected: return "array expected";
257 case napi_generic_failure: return "generic failure";
258 case napi_pending_exception: return "pending exception";
259 case napi_cancelled: return "cancelled";
260 case napi_escape_called_twice: return "escape called twice";
261 case napi_handle_scope_mismatch: return "handle scope mismatch";
262 case napi_callback_scope_mismatch: return "callback scope mismatch";
263 case napi_queue_full: return "queue full";
264 case napi_closing: return "closing";
265 case napi_bigint_expected: return "bigint expected";
266 case napi_date_expected: return "date expected";
267 case napi_arraybuffer_expected: return "arraybuffer expected";
268 case napi_detachable_arraybuffer_expected: return "detachable arraybuffer expected";
269 case napi_would_deadlock: return "would deadlock";
270 case napi_no_external_buffers_allowed: return "no external buffers allowed";
271 case napi_cannot_run_js: return "cannot run js";
272 default: return "unknown";
273}}
274
275static napi_status napi_set_last_raw(napi_env env, napi_status status, const char *message) {
276 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
277 if (!nenv) return status;
278
279 const char *msg = message ? message : napi_status_text(status);
280 snprintf(nenv->last_error_msg, sizeof(nenv->last_error_msg), "%s", msg);
281
282 nenv->last_error.error_message = nenv->last_error_msg;
283 nenv->last_error.engine_reserved = NULL;
284 nenv->last_error.engine_error_code = 0;
285 nenv->last_error.error_code = status;
286
287 if (status != napi_ok) {
288 }
289
290 return status;
291}
292
293static napi_status napi_set_last(napi_env env, napi_status status, const char *message) {
294 return napi_set_last_raw(env, status, message);
295}
296
297static ant_napi_env_t *napi_get_or_create_env(ant_t *js) {
298 if (!g_napi_env) {
299 g_napi_env = (ant_napi_env_t *)calloc(1, sizeof(*g_napi_env));
300 if (!g_napi_env) return NULL;
301 g_napi_env->version = 8;
302 napi_set_last((napi_env)g_napi_env, napi_ok, NULL);
303 }
304 g_napi_env->js = js;
305 return g_napi_env;
306}
307
308napi_env ant_napi_get_env(ant_t *js) {
309 return (napi_env)napi_get_or_create_env(js);
310}
311
312void gc_mark_napi(ant_t *js, gc_mark_fn mark) {
313 if (!g_napi_env || g_napi_env->js != js) return;
314 ant_napi_env_t *nenv = g_napi_env;
315
316 if (nenv->has_pending_exception)
317 mark(js, (ant_value_t)nenv->pending_exception);
318
319 for (struct napi_ref__ *r = nenv->refs; r; r = r->next)
320 if (r->refcount > 0) mark(js, r->ref_val);
321
322 for (struct napi_deferred__ *d = nenv->deferreds; d; d = d->next)
323 if (!d->settled) mark(js, d->promise_val);
324
325 for (struct napi_threadsafe_function__ *t = nenv->tsfns; t; t = t->next) mark(js, t->func_val);
326 for (size_t i = 0; i < nenv->handle_slots_len; i++) mark(js, nenv->handle_slots[i]);
327}
328
329void gc_clear_napi_weak_refs(ant_t *js, bool minor) {
330 if (!g_napi_env || g_napi_env->js != js) return;
331 ant_napi_env_t *nenv = g_napi_env;
332
333 for (struct napi_ref__ *r = nenv->refs; r; r = r->next) {
334 if (r->refcount > 0 || !r->value) continue;
335 ant_value_t value = (ant_value_t)r->value;
336 ant_object_t *obj = is_object_type(value) ? js_obj_ptr(value) : NULL;
337 if (obj && (!minor || obj->generation == 0) && !gc_obj_is_marked(obj)) r->value = 0;
338 }
339}
340
341static inline napi_value napi_scope_pin(ant_napi_env_t *nenv, napi_value val) {
342 ant_value_t v = (ant_value_t)val;
343 if (!nenv || !is_object_type(v)) return val;
344
345 if (nenv->handle_slots_len >= nenv->handle_slots_cap) {
346 size_t new_cap = nenv->handle_slots_cap ? nenv->handle_slots_cap * 2 : 256;
347 ant_value_t *new_slots = realloc(nenv->handle_slots, new_cap * sizeof(ant_value_t));
348 if (!new_slots) return val;
349 nenv->handle_slots = new_slots;
350 nenv->handle_slots_cap = new_cap;
351 }
352 nenv->handle_slots[nenv->handle_slots_len++] = v;
353 return val;
354}
355
356#define NAPI_RETURN(nenv, val) napi_scope_pin((nenv), (napi_value)(val))
357
358static void napi_mark_pending_exception(napi_env env, napi_value exception) {
359 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
360 if (!nenv) return;
361 nenv->has_pending_exception = true;
362 nenv->pending_exception = exception;
363}
364
365NAPI_EXTERN napi_status NAPI_CDECL napi_throw(napi_env env, napi_value error) {
366 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
367 if (!nenv || !nenv->js) return napi_set_last(env, napi_invalid_arg, "invalid env");
368 if (nenv->has_pending_exception || nenv->js->thrown_exists)
369 return napi_set_last(env, napi_pending_exception, "pending exception");
370 js_throw(nenv->js, (ant_value_t)error);
371 napi_mark_pending_exception(env, error);
372 return napi_set_last_raw(env, napi_ok, NULL);
373}
374
375static napi_status napi_check_pending_from_result(napi_env env, ant_value_t result) {
376 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
377 if (!nenv || !nenv->js) return napi_set_last(env, napi_invalid_arg, "invalid env");
378
379 if (is_err(result) || nenv->js->thrown_exists) {
380 napi_mark_pending_exception(
381 env,
382 nenv->js->thrown_exists ? nenv->js->thrown_value : result
383 );
384 napi_set_last_raw(env, napi_pending_exception, "pending exception");
385 return napi_pending_exception;
386 }
387 return napi_set_last(env, napi_ok, NULL);
388}
389
390static napi_status napi_return_pending_if_any(napi_env env) {
391 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
392 if (!nenv || !nenv->js) return napi_set_last(env, napi_invalid_arg, "invalid env");
393
394 if (nenv->has_pending_exception) {
395 napi_set_last_raw(env, napi_pending_exception, "pending exception");
396 return napi_pending_exception;
397 }
398
399 if (nenv->js->thrown_exists) {
400 napi_mark_pending_exception(env, (napi_value)nenv->js->thrown_value);
401 napi_set_last_raw(env, napi_pending_exception, "pending exception");
402 return napi_pending_exception;
403 }
404
405 return napi_set_last(env, napi_ok, NULL);
406}
407
408static bool napi_slot_get_u64(ant_t *js, ant_value_t obj, internal_slot_t slot, uint64_t *out) {
409 ant_value_t value = js_get_slot(obj, slot);
410 if (vtype(value) != T_NUM) return false;
411 *out = (uint64_t)js_getnum(value);
412 return true;
413}
414
415static void napi_slot_set_u64(ant_t *js, ant_value_t obj, internal_slot_t slot, uint64_t v) {
416 js_set_slot(obj, slot, js_mknum((double)v));
417}
418
419static napi_external_entry_t *napi_find_external(ant_t *js, napi_value value) {
420 if (!is_object_type((ant_value_t)value)) return NULL;
421 uint64_t id = 0;
422 if (!napi_slot_get_u64(js, (ant_value_t)value, SLOT_NAPI_EXTERNAL_ID, &id)) return NULL;
423 napi_external_entry_t *entry = NULL;
424 HASH_FIND(hh, g_napi_externals, &id, sizeof(id), entry);
425 return entry;
426}
427
428static napi_wrap_entry_t *napi_find_wrap(ant_t *js, napi_value value) {
429 if (!is_object_type((ant_value_t)value)) return NULL;
430 uint64_t id = 0;
431 if (!napi_slot_get_u64(js, (ant_value_t)value, SLOT_NAPI_WRAP_ID, &id)) return NULL;
432 napi_wrap_entry_t *entry = NULL;
433 HASH_FIND(hh, g_napi_wraps, &id, sizeof(id), entry);
434 return entry;
435}
436
437static bool napi_get_typedarray_data(
438 ant_t *js,
439 napi_value value,
440 TypedArrayData **out
441) {
442 TypedArrayData *ta = buffer_get_typedarray_data((ant_value_t)value);
443 if (!ta || !ta->buffer || ta->buffer->is_detached) return false;
444 *out = ta;
445 return true;
446}
447
448static bool napi_to_ant_typedarray_type(
449 napi_typedarray_type in,
450 TypedArrayType *out
451) {
452 switch (in) {
453 case napi_int8_array: *out = TYPED_ARRAY_INT8; return true;
454 case napi_uint8_array: *out = TYPED_ARRAY_UINT8; return true;
455 case napi_uint8_clamped_array: *out = TYPED_ARRAY_UINT8_CLAMPED; return true;
456 case napi_int16_array: *out = TYPED_ARRAY_INT16; return true;
457 case napi_uint16_array: *out = TYPED_ARRAY_UINT16; return true;
458 case napi_int32_array: *out = TYPED_ARRAY_INT32; return true;
459 case napi_uint32_array: *out = TYPED_ARRAY_UINT32; return true;
460 case napi_float32_array: *out = TYPED_ARRAY_FLOAT32; return true;
461 case napi_float64_array: *out = TYPED_ARRAY_FLOAT64; return true;
462 case napi_bigint64_array: *out = TYPED_ARRAY_BIGINT64; return true;
463 case napi_biguint64_array: *out = TYPED_ARRAY_BIGUINT64; return true;
464 default: return false;
465 }
466}
467
468static napi_typedarray_type napi_from_ant_typedarray_type(TypedArrayType in) {
469 switch (in) {
470 case TYPED_ARRAY_INT8: return napi_int8_array;
471 case TYPED_ARRAY_UINT8: return napi_uint8_array;
472 case TYPED_ARRAY_UINT8_CLAMPED: return napi_uint8_clamped_array;
473 case TYPED_ARRAY_INT16: return napi_int16_array;
474 case TYPED_ARRAY_UINT16: return napi_uint16_array;
475 case TYPED_ARRAY_INT32: return napi_int32_array;
476 case TYPED_ARRAY_UINT32: return napi_uint32_array;
477 case TYPED_ARRAY_FLOAT32: return napi_float32_array;
478 case TYPED_ARRAY_FLOAT64: return napi_float64_array;
479 case TYPED_ARRAY_BIGINT64: return napi_bigint64_array;
480 case TYPED_ARRAY_BIGUINT64: return napi_biguint64_array;
481 default: return napi_uint8_array;
482 }
483}
484
485static int napi_desc_flags(napi_property_attributes attributes) {
486 int flags = 0;
487 if (attributes & napi_writable) flags |= JS_DESC_W;
488 if (attributes & napi_enumerable) flags |= JS_DESC_E;
489 if (attributes & napi_configurable) flags |= JS_DESC_C;
490 return flags;
491}
492
493static ant_value_t napi_callback_trampoline(ant_t *js, ant_value_t *args, int nargs) {
494 ant_value_t current = js_getcurrentfunc(js);
495 napi_callback_binding_t *binding = (napi_callback_binding_t *)js_get_native(current, NAPI_CALLBACK_NATIVE_TAG);
496 if (!binding || !binding->cb) return js_mkundef();
497
498 ant_napi_env_t *nenv = binding->env ? binding->env : napi_get_or_create_env(js);
499 if (!nenv) return js_mkerr(js, "napi OOM");
500
501 struct napi_callback_info__ info = {
502 .env = nenv,
503 .argv = (const napi_value *)args,
504 .argc = (size_t)(nargs < 0 ? 0 : nargs),
505 .this_arg = (napi_value)js_getthis(js),
506 .new_target = (napi_value)sv_vm_get_new_target(js->vm, js),
507 .data = binding->data,
508 };
509
510 napi_value ret = binding->cb((napi_env)nenv, (napi_callback_info)&info);
511 if (nenv->has_pending_exception) {
512 ant_value_t ex = (ant_value_t)nenv->pending_exception;
513 nenv->has_pending_exception = false;
514 nenv->pending_exception = (napi_value)js_mkundef();
515 return js_throw(js, ex);
516 }
517
518 if (js->thrown_exists) {
519 return js_throw(js, js->thrown_value);
520 }
521
522 if ((ant_value_t)ret == 0) return js_mkundef();
523 return (ant_value_t)ret;
524}
525
526static napi_status napi_create_function_common(
527 napi_env env,
528 const char *utf8name,
529 size_t length,
530 napi_callback cb,
531 void *data,
532 napi_value *result
533) {
534 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
535 if (!nenv || !nenv->js || !cb || !result) {
536 return napi_set_last(env, napi_invalid_arg, "invalid argument");
537 }
538
539 napi_callback_binding_t *binding = (napi_callback_binding_t *)calloc(1, sizeof(*binding));
540 if (!binding) return napi_set_last(env, napi_generic_failure, "out of memory");
541
542 binding->env = nenv;
543 binding->cb = cb;
544 binding->data = data;
545
546 ant_value_t fn = js_heavy_mkfun_native(nenv->js, napi_callback_trampoline, binding, NAPI_CALLBACK_NATIVE_TAG);
547 js_mark_constructor(fn, true);
548 if (utf8name && utf8name[0]) {
549 size_t nlen = (length == NAPI_AUTO_LENGTH) ? strlen(utf8name) : length;
550 js_set(nenv->js, fn, "name", js_mkstr(nenv->js, utf8name, nlen));
551 }
552
553 *result = NAPI_RETURN(nenv, fn);
554 return napi_set_last(env, napi_ok, NULL);
555}
556
557static ant_value_t napi_make_string(ant_t *js, const char *s, size_t len) {
558 if (!s) return js_mkstr(js, "", 0);
559 if (len == NAPI_AUTO_LENGTH) len = strlen(s);
560 return js_mkstr(js, s, len);
561}
562
563static bool napi_checked_add_size(size_t a, size_t b, size_t *out) {
564 if (a > SIZE_MAX - b) return false;
565 *out = a + b;
566 return true;
567}
568
569static bool napi_checked_mul_size(size_t a, size_t b, size_t *out) {
570 if (a != 0 && b > SIZE_MAX / a) return false;
571 *out = a * b;
572 return true;
573}
574
575static bool napi_make_bigint_limbs(
576 ant_t *js,
577 const uint32_t *limbs,
578 size_t count,
579 bool negative,
580 ant_value_t *out
581) {
582 uint32_t zero = 0;
583 if (!out) return false;
584
585 if (!limbs || count == 0) {
586 limbs = &zero;
587 count = 1;
588 }
589
590 while (count > 1 && limbs[count - 1] == 0) count--;
591 if (count == 1 && limbs[0] == 0) negative = false;
592 if (count > UINT32_MAX) return false;
593
594 size_t limbs_bytes = 0;
595 if (!napi_checked_mul_size(count, sizeof(uint32_t), &limbs_bytes)) return false;
596
597 size_t payload_size = 0;
598 if (!napi_checked_add_size(offsetof(napi_bigint_payload_t, limbs), limbs_bytes, &payload_size)) {
599 return false;
600 }
601
602 napi_bigint_payload_t *payload = (napi_bigint_payload_t *)js_type_alloc(
603 js, ANT_ALLOC_BIGINT, payload_size,
604 _Alignof(napi_bigint_payload_t)
605 );
606
607 if (!payload) return false;
608 payload->sign = negative ? 1 : 0;
609 payload->pad[0] = 0;
610 payload->pad[1] = 0;
611 payload->pad[2] = 0;
612 payload->limb_count = (uint32_t)count;
613 memcpy(payload->limbs, limbs, limbs_bytes);
614 *out = mkval(T_BIGINT, (uint64_t)(uintptr_t)payload);
615
616 return true;
617}
618
619static const napi_bigint_payload_t *napi_bigint_payload(napi_value value) {
620 return (const napi_bigint_payload_t *)(uintptr_t)vdata((ant_value_t)value);
621}
622
623static const uint32_t *napi_bigint_limbs(napi_value value, size_t *count) {
624 const napi_bigint_payload_t *payload = napi_bigint_payload(value);
625 if (!payload) {
626 if (count) *count = 0;
627 return NULL;
628 }
629
630 size_t limb_count = payload->limb_count;
631 if (limb_count == 0) limb_count = 1;
632
633 while (limb_count > 1 && payload->limbs[limb_count - 1] == 0) limb_count--;
634 if (count) *count = limb_count;
635
636 return payload->limbs;
637}
638
639static bool napi_bigint_is_negative(napi_value value) {
640 const napi_bigint_payload_t *payload = napi_bigint_payload(value);
641 return payload && payload->sign == 1;
642}
643
644static bool napi_bigint_limbs_is_zero(const uint32_t *limbs, size_t count) {
645 return count <= 1 && (!limbs || limbs[0] == 0);
646}
647
648static uint64_t napi_bigint_low_u64(const uint32_t *limbs, size_t count) {
649 uint64_t out = 0;
650 if (count > 0 && limbs) out |= (uint64_t)limbs[0];
651 if (count > 1 && limbs) out |= ((uint64_t)limbs[1] << 32);
652 return out;
653}
654
655static bool napi_parse_index_key(const char *str, size_t len, uint32_t *out) {
656 if (!str || len == 0) return false;
657 if (len > 1 && str[0] == '0') return false;
658
659 uint64_t acc = 0;
660 for (size_t i = 0; i < len; i++) {
661 if (str[i] < '0' || str[i] > '9') return false;
662 acc = (acc * 10) + (uint64_t)(str[i] - '0');
663 if (acc > UINT32_MAX) return false;
664 }
665
666 if (out) *out = (uint32_t)acc;
667 return true;
668}
669
670static bool napi_seen_has_key(ant_t *js, ant_value_t seen, ant_value_t key) {
671 if (vtype(key) == T_SYMBOL) {
672 return lkp_sym(js, seen, (ant_offset_t)vdata(key)) != 0;
673 }
674
675 size_t len = 0;
676 const char *str = js_getstr(js, key, &len);
677 return str && lkp(js, seen, str, len) != 0;
678}
679
680static bool napi_seen_add_key(ant_t *js, ant_value_t seen, ant_value_t key) {
681 ant_value_t res = js_setprop(js, seen, key, js_true);
682 return !is_err(res);
683}
684
685static bool napi_key_passes_filter(const ant_shape_prop_t *prop, napi_key_filter key_filter) {
686 if (!prop) return false;
687 if ((key_filter & napi_key_writable) && !(prop->attrs & ANT_PROP_ATTR_WRITABLE)) return false;
688 if ((key_filter & napi_key_enumerable) && !(prop->attrs & ANT_PROP_ATTR_ENUMERABLE)) return false;
689 if ((key_filter & napi_key_configurable) && !(prop->attrs & ANT_PROP_ATTR_CONFIGURABLE)) return false;
690 return true;
691}
692
693static ant_value_t napi_convert_property_key(
694 ant_t *js,
695 ant_value_t key,
696 napi_key_conversion key_conversion
697) {
698 if (key_conversion != napi_key_keep_numbers || vtype(key) != T_STR) return key;
699
700 size_t len = 0;
701 const char *str = js_getstr(js, key, &len);
702 uint32_t idx = 0;
703 if (!str || !napi_parse_index_key(str, len, &idx)) return key;
704 return js_mknum((double)idx);
705}
706
707static napi_status napi_create_date_common(napi_env env, double time, napi_value *result) {
708 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
709 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
710
711 ant_t *js = nenv->js;
712 ant_value_t ctor = js_get(js, js_glob(js), "Date");
713 if (!is_callable(ctor)) return napi_set_last(env, napi_generic_failure, "Date constructor unavailable");
714
715 ant_value_t obj = js_mkobj(js);
716 ant_value_t proto = js_get(js, ctor, "prototype");
717 if (is_object_type(proto)) js_set_proto_init(obj, proto);
718
719 ant_value_t argv[1] = {js_mknum(time)};
720 ant_value_t saved = js->new_target;
721 js->new_target = ctor;
722 ant_value_t out = sv_vm_call(js->vm, js, ctor, obj, argv, 1, NULL, true);
723 js->new_target = saved;
724
725 if (is_err(out) || js->thrown_exists) return napi_check_pending_from_result(env, out);
726 *result = NAPI_RETURN(nenv, is_object_type(out) ? out : obj);
727 return napi_set_last(env, napi_ok, NULL);
728}
729
730static napi_status napi_make_error_object(
731 napi_env env,
732 const char *name,
733 napi_value msg,
734 napi_value *result
735) {
736 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
737 if (!nenv || !nenv->js || !result) {
738 return napi_set_last(env, napi_invalid_arg, "invalid argument");
739 }
740
741 ant_t *js = nenv->js;
742 ant_value_t message = (ant_value_t)msg;
743 if (vtype(message) != T_STR) {
744 message = coerce_to_str(js, message);
745 if (is_err(message)) return napi_check_pending_from_result(env, message);
746 }
747
748 ant_value_t err = js_mkobj(js);
749 js_set(js, err, "name", js_mkstr(js, name, strlen(name)));
750 js_set(js, err, "message", message);
751
752 ant_value_t proto = js_get_ctor_proto(js, name, strlen(name));
753 if (is_object_type(proto)) js_set_proto_init(err, proto);
754
755 *result = NAPI_RETURN(nenv, err);
756 return napi_set_last(env, napi_ok, NULL);
757}
758
759static napi_status napi_throw_with_message(
760 napi_env env,
761 js_err_type_t err_type,
762 const char *msg
763) {
764 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
765 if (!nenv || !nenv->js) return napi_set_last(env, napi_invalid_arg, "invalid env");
766
767 ant_value_t error = js_mkerr_typed(nenv->js, err_type, "%s", msg ? msg : "");
768 if (is_err(error) && nenv->js->thrown_exists) {
769 napi_mark_pending_exception(env, (napi_value)nenv->js->thrown_value);
770 return napi_pending_exception;
771 }
772 if (is_err(error)) return napi_set_last(env, napi_generic_failure, "failed to create error");
773 return napi_throw(env, (napi_value)error);
774}
775
776static void napi_tsfn_maybe_finish(struct napi_threadsafe_function__ *tsfn);
777
778static void napi_tsfn_async_cb(uv_async_t *handle) {
779 struct napi_threadsafe_function__ *tsfn = (struct napi_threadsafe_function__ *)handle->data;
780 if (!tsfn || !tsfn->env || !tsfn->env->js) return;
781
782 ant_t *js = tsfn->env->js;
783 for (;;) {
784 napi_tsfn_item_t *item = NULL;
785
786 uv_mutex_lock(&tsfn->mutex);
787 if (tsfn->head) {
788 item = tsfn->head;
789 tsfn->head = item->next;
790 if (!tsfn->head) tsfn->tail = NULL;
791 tsfn->queue_size--;
792 }
793 bool done = tsfn->closing && tsfn->queue_size == 0;
794 uv_mutex_unlock(&tsfn->mutex);
795
796 if (!item) {
797 if (done) napi_tsfn_maybe_finish(tsfn);
798 break;
799 }
800
801 ant_value_t cb = tsfn->func_val;
802 if (tsfn->call_js_cb) {
803 tsfn->call_js_cb((napi_env)tsfn->env, (napi_value)cb, tsfn->context, item->data);
804 } else if (is_callable(cb)) {
805 sv_vm_call(js->vm, js, cb, js_mkundef(), NULL, 0, NULL, false);
806 }
807
808 free(item);
809 }
810}
811
812static void napi_tsfn_close_cb(uv_handle_t *handle) {
813 struct napi_threadsafe_function__ *tsfn = (struct napi_threadsafe_function__ *)handle->data;
814 if (!tsfn) return;
815
816 if (tsfn->thread_finalize_cb) {
817 tsfn->thread_finalize_cb((napi_env)tsfn->env, tsfn->thread_finalize_data, NULL);
818 }
819
820 if (tsfn->env) {
821 if (tsfn->prev) tsfn->prev->next = tsfn->next;
822 else if (tsfn->env->tsfns == tsfn) tsfn->env->tsfns = tsfn->next;
823 if (tsfn->next) tsfn->next->prev = tsfn->prev;
824 }
825
826 if (tsfn->env && tsfn->env->js) {
827 tsfn->func_val = js_mkundef();
828 }
829
830 uv_mutex_destroy(&tsfn->mutex);
831 free(tsfn);
832}
833
834static void napi_tsfn_maybe_finish(struct napi_threadsafe_function__ *tsfn) {
835 if (!tsfn) return;
836 uv_close((uv_handle_t *)&tsfn->async, napi_tsfn_close_cb);
837}
838
839static void napi_async_work_execute_cb(uv_work_t *req) {
840 napi_async_work_impl_t *work = (napi_async_work_impl_t *)req->data;
841 if (!work || !work->execute) return;
842 work->execute((napi_env)work->env, work->data);
843}
844
845static void napi_async_work_after_cb(uv_work_t *req, int status) {
846 napi_async_work_impl_t *work = (napi_async_work_impl_t *)req->data;
847 if (!work) return;
848
849 work->queued = false;
850 if (work->complete) {
851 napi_status st = (status == UV_ECANCELED) ? napi_cancelled : napi_ok;
852 work->complete((napi_env)work->env, st, work->data);
853 }
854
855 if (work->delete_after_complete) free(work);
856}
857
858static ant_value_t napi_dlopen_common(ant_t *js, ant_value_t module_obj, const char *filename) {
859 napi_env env = ant_napi_get_env(js);
860 if (!env) return js_mkerr(js, "napi env allocation failed");
861
862 if (!is_object_type(module_obj)) return js_mkerr(js, "process.dlopen module must be an object");
863 if (!filename || !filename[0]) return js_mkerr(js, "process.dlopen filename must be a non-empty string");
864
865 g_pending_napi_module = NULL;
866 void *handle = NAPI_DLOPEN(filename, NAPI_RTLD_NOW | NAPI_RTLD_GLOBAL | NAPI_RTLD_LOCAL);
867 if (!handle) {
868 const char *msg = NAPI_DLERROR();
869 return js_mkerr(js, "Failed to load native module '%s': %s", filename, msg ? msg : "unknown");
870 }
871
872 napi_register_module_v1_fn reg_fn = (napi_register_module_v1_fn)NAPI_DLSYM(handle, "napi_register_module_v1");
873 ant_value_t exports = js_get(js, module_obj, "exports");
874
875 if (!is_object_type(exports)) {
876 exports = js_mkobj(js);
877 js_set(js, module_obj, "exports", exports);
878 }
879
880 ant_value_t ret = js_mkundef();
881 if (reg_fn) ret = (ant_value_t)reg_fn(env, (napi_value)exports);
882 else if (g_pending_napi_module && g_pending_napi_module->nm_register_func) {
883 ret = (ant_value_t)g_pending_napi_module->nm_register_func(env, (napi_value)exports);
884 } else return js_mkerr(js, "No N-API registration entrypoint found in '%s'", filename);
885
886 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
887 if (nenv->has_pending_exception || js->thrown_exists) {
888 ant_value_t ex = nenv->has_pending_exception
889 ? (ant_value_t)nenv->pending_exception
890 : js->thrown_value;
891 nenv->has_pending_exception = false;
892 nenv->pending_exception = (napi_value)js_mkundef();
893 return js_throw(js, ex);
894 }
895
896 if (is_object_type(ret)) exports = ret;
897 js_set(js, module_obj, "exports", exports);
898 js_set(js, module_obj, "loaded", js_true);
899
900 napi_native_lib_t *node = (napi_native_lib_t *)calloc(1, sizeof(*node));
901 if (node) {
902 node->handle = handle;
903 node->next = g_napi_native_libs;
904 g_napi_native_libs = node;
905 }
906
907 return exports;
908}
909
910ant_value_t napi_process_dlopen_js(ant_t *js, ant_value_t *args, int nargs) {
911 if (nargs < 2) return js_mkerr(js, "process.dlopen(module, filename) requires 2 arguments");
912 if (!is_object_type(args[0])) return js_mkerr(js, "process.dlopen module must be an object");
913 if (vtype(args[1]) != T_STR) return js_mkerr(js, "process.dlopen filename must be a string");
914
915 size_t path_len = 0;
916 const char *path = js_getstr(js, args[1], &path_len);
917 if (!path || path_len == 0) return js_mkerr(js, "process.dlopen filename must be non-empty");
918
919 ant_value_t loaded = napi_dlopen_common(js, args[0], path);
920 if (is_err(loaded)) return loaded;
921 return js_mkundef();
922}
923
924ant_value_t napi_load_native_module(ant_t *js, const char *module_path, ant_value_t ns) {
925 if (!module_path) return js_mkerr(js, "native module path is null");
926
927 ant_value_t module_obj = js_mkobj(js);
928 ant_value_t exports_obj = js_mkobj(js);
929 js_set(js, module_obj, "exports", exports_obj);
930 js_set(js, module_obj, "filename", js_mkstr(js, module_path, strlen(module_path)));
931 js_set(js, module_obj, "id", js_mkstr(js, module_path, strlen(module_path)));
932 js_set(js, module_obj, "loaded", js_false);
933
934 ant_value_t process_obj = js_get(js, js_glob(js), "process");
935 ant_value_t dlopen_fn = is_object_type(process_obj) ? js_get(js, process_obj, "dlopen") : js_mkundef();
936
937 if (is_callable(dlopen_fn)) {
938 ant_value_t argv[2] = {module_obj, js_mkstr(js, module_path, strlen(module_path))};
939 ant_value_t dl_res = sv_vm_call(js->vm, js, dlopen_fn, process_obj, argv, 2, NULL, false);
940 if (is_err(dl_res) || js->thrown_exists) return js_throw(js, js->thrown_value);
941 } else {
942 ant_value_t load_res = napi_dlopen_common(js, module_obj, module_path);
943 if (is_err(load_res)) return load_res;
944 }
945
946 ant_value_t exports_val = js_get(js, module_obj, "exports");
947 if (!is_object_type(ns)) return exports_val;
948
949 setprop_cstr(js, ns, "default", 7, exports_val);
950 js_set_slot(ns, SLOT_DEFAULT, exports_val);
951
952 if (!is_object_type(exports_val)) return exports_val;
953 ant_iter_t iter = js_prop_iter_begin(js, exports_val);
954 const char *key = NULL;
955 size_t key_len = 0;
956 ant_value_t value = js_mkundef();
957
958 while (js_prop_iter_next(&iter, &key, &key_len, &value)) {
959 if (key_len == 7 && memcmp(key, "default", 7) == 0) continue;
960 setprop_cstr(js, ns, key, key_len, value);
961 }
962 js_prop_iter_end(&iter);
963
964 return exports_val;
965}
966
967NAPI_EXTERN napi_status NAPI_CDECL napi_get_last_error_info(
968 node_api_basic_env env,
969 const napi_extended_error_info **result
970) {
971 if (!env || !result) return napi_invalid_arg;
972 *result = &((ant_napi_env_t *)env)->last_error;
973 return napi_ok;
974}
975
976NAPI_EXTERN napi_status NAPI_CDECL napi_get_undefined(napi_env env, napi_value *result) {
977 if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
978 *result = (napi_value)js_mkundef();
979 return napi_set_last(env, napi_ok, NULL);
980}
981
982NAPI_EXTERN napi_status NAPI_CDECL napi_get_null(napi_env env, napi_value *result) {
983 if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
984 *result = (napi_value)js_mknull();
985 return napi_set_last(env, napi_ok, NULL);
986}
987
988NAPI_EXTERN napi_status NAPI_CDECL napi_get_global(napi_env env, napi_value *result) {
989 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
990 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
991 *result = NAPI_RETURN(nenv, js_glob(nenv->js));
992 return napi_set_last(env, napi_ok, NULL);
993}
994
995NAPI_EXTERN napi_status NAPI_CDECL napi_get_boolean(napi_env env, bool value, napi_value *result) {
996 if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
997 *result = (napi_value)js_bool(value);
998 return napi_set_last(env, napi_ok, NULL);
999}
1000
1001NAPI_EXTERN napi_status NAPI_CDECL napi_create_object(napi_env env, napi_value *result) {
1002 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1003 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1004 *result = NAPI_RETURN(nenv, js_mkobj(nenv->js));
1005 return napi_set_last(env, napi_ok, NULL);
1006}
1007
1008NAPI_EXTERN napi_status NAPI_CDECL napi_create_array(napi_env env, napi_value *result) {
1009 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1010 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1011 *result = NAPI_RETURN(nenv, js_mkarr(nenv->js));
1012 return napi_set_last(env, napi_ok, NULL);
1013}
1014
1015NAPI_EXTERN napi_status NAPI_CDECL napi_create_array_with_length(
1016 napi_env env,
1017 size_t length,
1018 napi_value *result
1019) {
1020 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1021 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1022 ant_value_t arr = js_mkarr(nenv->js);
1023 ant_value_t r = js_setprop(
1024 nenv->js, arr,
1025 js_mkstr(nenv->js, "length", 6),
1026 js_mknum((double)length)
1027 );
1028 if (is_err(r) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, r);
1029 *result = NAPI_RETURN(nenv, arr);
1030 return napi_set_last(env, napi_ok, NULL);
1031}
1032
1033NAPI_EXTERN napi_status NAPI_CDECL napi_create_double(napi_env env, double value, napi_value *result) {
1034 if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1035 *result = (napi_value)js_mknum(value);
1036 return napi_set_last(env, napi_ok, NULL);
1037}
1038
1039NAPI_EXTERN napi_status NAPI_CDECL napi_create_int32(napi_env env, int32_t value, napi_value *result) {
1040 if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1041 *result = (napi_value)js_mknum((double)value);
1042 return napi_set_last(env, napi_ok, NULL);
1043}
1044
1045NAPI_EXTERN napi_status NAPI_CDECL napi_create_uint32(napi_env env, uint32_t value, napi_value *result) {
1046 if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1047 *result = (napi_value)js_mknum((double)value);
1048 return napi_set_last(env, napi_ok, NULL);
1049}
1050
1051NAPI_EXTERN napi_status NAPI_CDECL napi_create_int64(napi_env env, int64_t value, napi_value *result) {
1052 if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1053 *result = (napi_value)js_mknum((double)value);
1054 return napi_set_last(env, napi_ok, NULL);
1055}
1056
1057NAPI_EXTERN napi_status NAPI_CDECL napi_create_string_latin1(
1058 napi_env env,
1059 const char *str,
1060 size_t length,
1061 napi_value *result
1062) {
1063 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1064 if (!nenv || !nenv->js || !result || !str) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1065 *result = NAPI_RETURN(nenv, napi_make_string(nenv->js, str, length));
1066 return napi_set_last(env, napi_ok, NULL);
1067}
1068
1069NAPI_EXTERN napi_status NAPI_CDECL napi_create_string_utf8(
1070 napi_env env,
1071 const char *str,
1072 size_t length,
1073 napi_value *result
1074) {
1075 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1076 if (!nenv || !nenv->js || !result || !str) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1077 *result = NAPI_RETURN(nenv, napi_make_string(nenv->js, str, length));
1078 return napi_set_last(env, napi_ok, NULL);
1079}
1080
1081NAPI_EXTERN napi_status NAPI_CDECL napi_create_date(
1082 napi_env env,
1083 double time,
1084 napi_value *result
1085) {
1086 return napi_create_date_common(env, time, result);
1087}
1088
1089NAPI_EXTERN napi_status NAPI_CDECL napi_create_bigint_int64(
1090 napi_env env,
1091 int64_t value,
1092 napi_value *result
1093) {
1094 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1095 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1096
1097 uint64_t magnitude = value < 0
1098 ? (uint64_t)(-(value + 1)) + 1
1099 : (uint64_t)value;
1100
1101 uint32_t limbs[2] = {
1102 (uint32_t)(magnitude & 0xffffffffu),
1103 (uint32_t)(magnitude >> 32)
1104 };
1105
1106 size_t count = limbs[1] == 0 ? 1 : 2;
1107 ant_value_t out = js_mkundef();
1108
1109 if (!napi_make_bigint_limbs(nenv->js, limbs, count, value < 0, &out)) {
1110 return napi_set_last(env, napi_generic_failure, "out of memory");
1111 }
1112
1113 *result = NAPI_RETURN(nenv, out);
1114 return napi_set_last(env, napi_ok, NULL);
1115}
1116
1117NAPI_EXTERN napi_status NAPI_CDECL napi_create_bigint_uint64(
1118 napi_env env,
1119 uint64_t value,
1120 napi_value *result
1121) {
1122 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1123 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1124
1125 uint32_t limbs[2] = {
1126 (uint32_t)(value & 0xffffffffu),
1127 (uint32_t)(value >> 32)
1128 };
1129 size_t count = limbs[1] == 0 ? 1 : 2;
1130
1131 ant_value_t out = js_mkundef();
1132 if (!napi_make_bigint_limbs(nenv->js, limbs, count, false, &out)) {
1133 return napi_set_last(env, napi_generic_failure, "out of memory");
1134 }
1135
1136 *result = NAPI_RETURN(nenv, out);
1137 return napi_set_last(env, napi_ok, NULL);
1138}
1139
1140NAPI_EXTERN napi_status NAPI_CDECL napi_create_bigint_words(
1141 napi_env env,
1142 int sign_bit,
1143 size_t word_count,
1144 const uint64_t *words,
1145 napi_value *result
1146) {
1147 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1148 if (!nenv || !nenv->js || !result || (word_count > 0 && !words)) {
1149 return napi_set_last(env, napi_invalid_arg, "invalid argument");
1150 }
1151
1152 size_t limb_count = 1;
1153 if (word_count > 0 && !napi_checked_mul_size(word_count, 2, &limb_count)) {
1154 return napi_set_last(env, napi_invalid_arg, "word count overflow");
1155 }
1156 uint32_t *limbs = (uint32_t *)calloc(limb_count, sizeof(uint32_t));
1157 if (!limbs) return napi_set_last(env, napi_generic_failure, "out of memory");
1158
1159 if (word_count == 0) limbs[0] = 0;
1160 else for (size_t i = 0; i < word_count; i++) {
1161 limbs[i * 2] = (uint32_t)(words[i] & 0xffffffffu);
1162 limbs[(i * 2) + 1] = (uint32_t)(words[i] >> 32);
1163 }
1164
1165 ant_value_t out = js_mkundef();
1166 bool ok = napi_make_bigint_limbs(nenv->js, limbs, limb_count, sign_bit != 0, &out);
1167 free(limbs);
1168 if (!ok) return napi_set_last(env, napi_generic_failure, "out of memory");
1169
1170 *result = NAPI_RETURN(nenv, out);
1171 return napi_set_last(env, napi_ok, NULL);
1172}
1173
1174NAPI_EXTERN napi_status NAPI_CDECL napi_create_symbol(
1175 napi_env env,
1176 napi_value description,
1177 napi_value *result
1178) {
1179 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1180 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1181
1182 const char *desc = NULL;
1183 if (vtype((ant_value_t)description) == T_STR) {
1184 desc = js_getstr(nenv->js, (ant_value_t)description, NULL);
1185 } else if (!is_undefined((ant_value_t)description) && !is_null((ant_value_t)description)) {
1186 ant_value_t s = coerce_to_str(nenv->js, (ant_value_t)description);
1187 if (is_err(s) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, s);
1188 desc = js_getstr(nenv->js, s, NULL);
1189 }
1190
1191 *result = NAPI_RETURN(nenv, js_mksym(nenv->js, desc));
1192 return napi_set_last(env, napi_ok, NULL);
1193}
1194
1195NAPI_EXTERN napi_status NAPI_CDECL napi_create_function(
1196 napi_env env,
1197 const char *utf8name,
1198 size_t length,
1199 napi_callback cb,
1200 void *data,
1201 napi_value *result
1202) {
1203 return napi_create_function_common(env, utf8name, length, cb, data, result);
1204}
1205
1206NAPI_EXTERN napi_status NAPI_CDECL napi_create_error(
1207 napi_env env,
1208 napi_value code,
1209 napi_value msg,
1210 napi_value *result
1211) {
1212 return napi_make_error_object(env, "Error", msg, result);
1213}
1214
1215NAPI_EXTERN napi_status NAPI_CDECL napi_create_type_error(
1216 napi_env env,
1217 napi_value code,
1218 napi_value msg,
1219 napi_value *result
1220) {
1221 return napi_make_error_object(env, "TypeError", msg, result);
1222}
1223
1224NAPI_EXTERN napi_status NAPI_CDECL napi_create_range_error(
1225 napi_env env,
1226 napi_value code,
1227 napi_value msg,
1228 napi_value *result
1229) {
1230 return napi_make_error_object(env, "RangeError", msg, result);
1231}
1232
1233NAPI_EXTERN napi_status NAPI_CDECL napi_create_external(
1234 napi_env env,
1235 void *data,
1236 node_api_basic_finalize finalize_cb,
1237 void *finalize_hint,
1238 napi_value *result
1239) {
1240 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1241 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1242
1243 napi_external_entry_t *entry = (napi_external_entry_t *)calloc(1, sizeof(*entry));
1244 if (!entry) return napi_set_last(env, napi_generic_failure, "out of memory");
1245
1246 entry->id = g_napi_external_next_id++;
1247 entry->data = data;
1248 entry->finalize_cb = finalize_cb;
1249 entry->finalize_hint = finalize_hint;
1250 HASH_ADD(hh, g_napi_externals, id, sizeof(entry->id), entry);
1251
1252 ant_value_t obj = js_mkobj(nenv->js);
1253 napi_slot_set_u64(nenv->js, obj, SLOT_NAPI_EXTERNAL_ID, entry->id);
1254 *result = NAPI_RETURN(nenv, obj);
1255
1256 return napi_set_last(env, napi_ok, NULL);
1257}
1258
1259NAPI_EXTERN napi_status NAPI_CDECL napi_create_promise(
1260 napi_env env,
1261 napi_deferred *deferred,
1262 napi_value *promise
1263) {
1264 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1265 if (!nenv || !nenv->js || !deferred || !promise) {
1266 return napi_set_last(env, napi_invalid_arg, "invalid argument");
1267 }
1268
1269 struct napi_deferred__ *def = (struct napi_deferred__ *)calloc(1, sizeof(*def));
1270 if (!def) return napi_set_last(env, napi_generic_failure, "out of memory");
1271
1272 ant_value_t p = js_mkpromise(nenv->js);
1273 def->env = nenv;
1274 def->promise_val = p;
1275 def->settled = false;
1276
1277 def->prev = NULL;
1278 def->next = nenv->deferreds;
1279 if (nenv->deferreds) nenv->deferreds->prev = def;
1280 nenv->deferreds = def;
1281
1282 *deferred = (napi_deferred)def;
1283 *promise = (napi_value)p;
1284 return napi_set_last(env, napi_ok, NULL);
1285}
1286
1287NAPI_EXTERN napi_status NAPI_CDECL napi_resolve_deferred(
1288 napi_env env,
1289 napi_deferred deferred,
1290 napi_value resolution
1291) {
1292 struct napi_deferred__ *def = (struct napi_deferred__ *)deferred;
1293 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1294 if (!nenv || !nenv->js || !def || def->settled) {
1295 return napi_set_last(env, napi_invalid_arg, "invalid deferred");
1296 }
1297
1298 ant_value_t promise = def->promise_val;
1299 js_resolve_promise(nenv->js, promise, (ant_value_t)resolution);
1300 def->settled = true;
1301 def->promise_val = js_mkundef();
1302
1303 if (def->prev) def->prev->next = def->next;
1304 else if (nenv->deferreds == def) nenv->deferreds = def->next;
1305 if (def->next) def->next->prev = def->prev;
1306
1307 return napi_set_last(env, napi_ok, NULL);
1308}
1309
1310NAPI_EXTERN napi_status NAPI_CDECL napi_reject_deferred(
1311 napi_env env,
1312 napi_deferred deferred,
1313 napi_value rejection
1314) {
1315 struct napi_deferred__ *def = (struct napi_deferred__ *)deferred;
1316 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1317 if (!nenv || !nenv->js || !def || def->settled) {
1318 return napi_set_last(env, napi_invalid_arg, "invalid deferred");
1319 }
1320
1321 ant_value_t promise = def->promise_val;
1322 js_reject_promise(nenv->js, promise, (ant_value_t)rejection);
1323 def->settled = true;
1324 def->promise_val = js_mkundef();
1325
1326 if (def->prev) def->prev->next = def->next;
1327 else if (nenv->deferreds == def) nenv->deferreds = def->next;
1328 if (def->next) def->next->prev = def->prev;
1329
1330 return napi_set_last(env, napi_ok, NULL);
1331}
1332
1333NAPI_EXTERN napi_status NAPI_CDECL napi_create_buffer(
1334 napi_env env,
1335 size_t length,
1336 void **data,
1337 napi_value *result
1338) {
1339 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1340 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1341
1342 ArrayBufferData *buf = create_array_buffer_data(length);
1343 if (!buf) return napi_set_last(env, napi_generic_failure, "allocation failed");
1344
1345 ant_value_t value = create_typed_array(nenv->js, TYPED_ARRAY_UINT8, buf, 0, length, "Buffer");
1346 if (is_err(value)) return napi_check_pending_from_result(env, value);
1347
1348 if (data) *data = buf->data;
1349 *result = NAPI_RETURN(nenv, value);
1350 return napi_set_last(env, napi_ok, NULL);
1351}
1352
1353NAPI_EXTERN napi_status NAPI_CDECL napi_create_buffer_copy(
1354 napi_env env,
1355 size_t length,
1356 const void *data,
1357 void **result_data,
1358 napi_value *result
1359) {
1360 void *buf_ptr = NULL;
1361 napi_status st = napi_create_buffer(env, length, &buf_ptr, result);
1362 if (st != napi_ok) return st;
1363
1364 if (length > 0 && data && buf_ptr) memcpy(buf_ptr, data, length);
1365 if (result_data) *result_data = buf_ptr;
1366 return napi_set_last(env, napi_ok, NULL);
1367}
1368
1369NAPI_EXTERN napi_status NAPI_CDECL napi_create_external_buffer(
1370 napi_env env,
1371 size_t length,
1372 void *data,
1373 node_api_basic_finalize finalize_cb,
1374 void *finalize_hint,
1375 napi_value *result
1376) {
1377 (void)finalize_cb;
1378 (void)finalize_hint;
1379 return napi_create_buffer_copy(env, length, data, NULL, result);
1380}
1381
1382NAPI_EXTERN napi_status NAPI_CDECL napi_create_arraybuffer(
1383 napi_env env,
1384 size_t byte_length,
1385 void **data,
1386 napi_value *result
1387) {
1388 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1389 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1390
1391 ArrayBufferData *ab = create_array_buffer_data(byte_length);
1392 if (!ab) return napi_set_last(env, napi_generic_failure, "allocation failed");
1393
1394 ant_value_t ab_obj = create_arraybuffer_obj(nenv->js, ab);
1395 free_array_buffer_data(ab);
1396
1397 if (data) *data = ab->data;
1398 *result = NAPI_RETURN(nenv, ab_obj);
1399 return napi_set_last(env, napi_ok, NULL);
1400}
1401
1402NAPI_EXTERN napi_status NAPI_CDECL napi_create_external_arraybuffer(
1403 napi_env env,
1404 void *external_data,
1405 size_t byte_length,
1406 node_api_basic_finalize finalize_cb,
1407 void *finalize_hint,
1408 napi_value *result
1409) {
1410 (void)finalize_cb;
1411 (void)finalize_hint;
1412 void *out = NULL;
1413 napi_status st = napi_create_arraybuffer(env, byte_length, &out, result);
1414 if (st != napi_ok) return st;
1415 if (external_data && out && byte_length > 0) memcpy(out, external_data, byte_length);
1416 return napi_set_last(env, napi_ok, NULL);
1417}
1418
1419NAPI_EXTERN napi_status NAPI_CDECL napi_set_instance_data(
1420 napi_env env,
1421 void *data,
1422 node_api_basic_finalize finalize_cb,
1423 void *finalize_hint
1424) {
1425 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1426 if (!nenv) return napi_set_last(env, napi_invalid_arg, "invalid env");
1427
1428 nenv->instance_data = data;
1429 nenv->instance_data_finalize_cb = finalize_cb;
1430 nenv->instance_data_finalize_hint = finalize_hint;
1431 return napi_set_last(env, napi_ok, NULL);
1432}
1433
1434NAPI_EXTERN napi_status NAPI_CDECL napi_get_instance_data(
1435 napi_env env,
1436 void **data
1437) {
1438 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1439 if (!nenv || !data) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1440
1441 *data = nenv->instance_data;
1442 return napi_set_last(env, napi_ok, NULL);
1443}
1444
1445NAPI_EXTERN napi_status NAPI_CDECL napi_create_typedarray(
1446 napi_env env,
1447 napi_typedarray_type type,
1448 size_t length,
1449 napi_value arraybuffer,
1450 size_t byte_offset,
1451 napi_value *result
1452) {
1453 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1454 if (!nenv || !nenv->js || !result || !is_object_type((ant_value_t)arraybuffer)) {
1455 return napi_set_last(env, napi_invalid_arg, "invalid argument");
1456 }
1457
1458 ArrayBufferData *ab = buffer_get_arraybuffer_data((ant_value_t)arraybuffer);
1459 if (!ab || ab->is_detached) return napi_set_last(env, napi_arraybuffer_expected, "invalid arraybuffer");
1460
1461 TypedArrayType ta_type;
1462 if (!napi_to_ant_typedarray_type(type, &ta_type)) {
1463 return napi_set_last(env, napi_invalid_arg, "invalid typedarray type");
1464 }
1465
1466 size_t element_size = 1;
1467 switch (ta_type) {
1468 case TYPED_ARRAY_INT16:
1469 case TYPED_ARRAY_UINT16: element_size = 2; break;
1470 case TYPED_ARRAY_INT32:
1471 case TYPED_ARRAY_UINT32:
1472 case TYPED_ARRAY_FLOAT32: element_size = 4; break;
1473 case TYPED_ARRAY_FLOAT64:
1474 case TYPED_ARRAY_BIGINT64:
1475 case TYPED_ARRAY_BIGUINT64: element_size = 8; break;
1476 default: break;
1477 }
1478
1479 size_t byte_len = length * element_size;
1480 if (byte_offset + byte_len > ab->length) {
1481 return napi_set_last(env, napi_invalid_arg, "typedarray out of bounds");
1482 }
1483
1484 ant_value_t out = create_typed_array_with_buffer(
1485 nenv->js,
1486 ta_type,
1487 ab,
1488 byte_offset,
1489 length,
1490 buffer_typedarray_type_name(ta_type),
1491 (ant_value_t)arraybuffer
1492 );
1493
1494 if (is_err(out)) return napi_check_pending_from_result(env, out);
1495 *result = NAPI_RETURN(nenv, out);
1496 return napi_set_last(env, napi_ok, NULL);
1497}
1498
1499NAPI_EXTERN napi_status NAPI_CDECL napi_create_reference(
1500 napi_env env,
1501 napi_value value,
1502 uint32_t initial_refcount,
1503 napi_ref *result
1504) {
1505 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1506 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1507
1508 struct napi_ref__ *ref = (struct napi_ref__ *)calloc(1, sizeof(*ref));
1509 if (!ref) return napi_set_last(env, napi_generic_failure, "out of memory");
1510
1511 ref->env = nenv;
1512 ref->value = value;
1513 ref->refcount = initial_refcount;
1514 ref->ref_val = (initial_refcount > 0) ? (ant_value_t)value : js_mkundef();
1515
1516 ref->prev = NULL;
1517 ref->next = nenv->refs;
1518 if (nenv->refs) nenv->refs->prev = ref;
1519 nenv->refs = ref;
1520
1521 *result = (napi_ref)ref;
1522 return napi_set_last(env, napi_ok, NULL);
1523}
1524
1525NAPI_EXTERN napi_status NAPI_CDECL napi_delete_reference(
1526 node_api_basic_env env,
1527 napi_ref ref
1528) {
1529 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1530 struct napi_ref__ *r = (struct napi_ref__ *)ref;
1531 if (!nenv || !nenv->js || !r) return napi_set_last((napi_env)env, napi_invalid_arg, "invalid argument");
1532
1533 if (r->prev) r->prev->next = r->next;
1534 else if (nenv->refs == r) nenv->refs = r->next;
1535 if (r->next) r->next->prev = r->prev;
1536
1537 r->ref_val = js_mkundef();
1538 free(r);
1539 return napi_set_last((napi_env)env, napi_ok, NULL);
1540}
1541
1542NAPI_EXTERN napi_status NAPI_CDECL napi_reference_ref(
1543 napi_env env,
1544 napi_ref ref,
1545 uint32_t *result
1546) {
1547 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1548 struct napi_ref__ *r = (struct napi_ref__ *)ref;
1549
1550 if (!nenv || !nenv->js || !r)
1551 return napi_set_last(env, napi_invalid_arg, "invalid argument");
1552
1553 if (!r->value) {
1554 if (result) *result = 0;
1555 return napi_set_last(env, napi_ok, NULL);
1556 }
1557
1558 if (r->refcount == 0) r->ref_val = (ant_value_t)r->value;
1559 r->refcount++;
1560 if (result) *result = r->refcount;
1561
1562 return napi_set_last(env, napi_ok, NULL);
1563}
1564
1565NAPI_EXTERN napi_status NAPI_CDECL napi_reference_unref(
1566 napi_env env,
1567 napi_ref ref,
1568 uint32_t *result
1569) {
1570 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1571 struct napi_ref__ *r = (struct napi_ref__ *)ref;
1572 if (!nenv || !nenv->js || !r) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1573 if (r->refcount == 0) return napi_set_last(env, napi_invalid_arg, "reference count already zero");
1574
1575 r->refcount--;
1576 if (r->refcount == 0) r->ref_val = js_mkundef();
1577 if (result) *result = r->refcount;
1578
1579 return napi_set_last(env, napi_ok, NULL);
1580}
1581
1582NAPI_EXTERN napi_status NAPI_CDECL napi_get_reference_value(
1583 napi_env env,
1584 napi_ref ref,
1585 napi_value *result
1586) {
1587 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1588 struct napi_ref__ *r = (struct napi_ref__ *)ref;
1589 if (!nenv || !nenv->js || !r || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1590
1591 if (r->refcount > 0) *result = NAPI_RETURN(nenv, r->ref_val);
1592 else *result = r->value ? NAPI_RETURN(nenv, r->value) : 0;
1593
1594 return napi_set_last(env, napi_ok, NULL);
1595}
1596
1597NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_double(
1598 napi_env env,
1599 napi_value value,
1600 double *result
1601) {
1602 if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1603 if (vtype((ant_value_t)value) != T_NUM) return napi_set_last(env, napi_number_expected, "number expected");
1604 *result = js_getnum((ant_value_t)value);
1605 return napi_set_last(env, napi_ok, NULL);
1606}
1607
1608NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_int32(
1609 napi_env env,
1610 napi_value value,
1611 int32_t *result
1612) {
1613 if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1614 if (vtype((ant_value_t)value) != T_NUM) return napi_set_last(env, napi_number_expected, "number expected");
1615 *result = (int32_t)js_getnum((ant_value_t)value);
1616 return napi_set_last(env, napi_ok, NULL);
1617}
1618
1619NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_uint32(
1620 napi_env env,
1621 napi_value value,
1622 uint32_t *result
1623) {
1624 if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1625 if (vtype((ant_value_t)value) != T_NUM) return napi_set_last(env, napi_number_expected, "number expected");
1626 *result = (uint32_t)js_getnum((ant_value_t)value);
1627 return napi_set_last(env, napi_ok, NULL);
1628}
1629
1630NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_int64(
1631 napi_env env,
1632 napi_value value,
1633 int64_t *result
1634) {
1635 if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1636 if (vtype((ant_value_t)value) != T_NUM) return napi_set_last(env, napi_number_expected, "number expected");
1637 *result = (int64_t)js_getnum((ant_value_t)value);
1638 return napi_set_last(env, napi_ok, NULL);
1639}
1640
1641NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_bool(
1642 napi_env env,
1643 napi_value value,
1644 bool *result
1645) {
1646 if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1647 if (vtype((ant_value_t)value) != T_BOOL) return napi_set_last(env, napi_boolean_expected, "boolean expected");
1648 *result = ((ant_value_t)value == js_true);
1649 return napi_set_last(env, napi_ok, NULL);
1650}
1651
1652static napi_status napi_get_string_common(
1653 napi_env env,
1654 napi_value value,
1655 char *buf,
1656 size_t bufsize,
1657 size_t *result
1658) {
1659 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1660 if (!nenv || !nenv->js) return napi_set_last(env, napi_invalid_arg, "invalid env");
1661 if (vtype((ant_value_t)value) != T_STR) return napi_set_last(env, napi_string_expected, "string expected");
1662
1663 size_t len = 0;
1664 const char *str = js_getstr(nenv->js, (ant_value_t)value, &len);
1665 if (!str) return napi_set_last(env, napi_string_expected, "string expected");
1666
1667 if (result) *result = len;
1668 if (!buf || bufsize == 0) return napi_set_last(env, napi_ok, NULL);
1669
1670 size_t n = (len < (bufsize - 1)) ? len : (bufsize - 1);
1671 memcpy(buf, str, n);
1672 buf[n] = '\0';
1673 return napi_set_last(env, napi_ok, NULL);
1674}
1675
1676NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_string_utf8(
1677 napi_env env,
1678 napi_value value,
1679 char *buf,
1680 size_t bufsize,
1681 size_t *result
1682) {
1683 return napi_get_string_common(env, value, buf, bufsize, result);
1684}
1685
1686NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_string_latin1(
1687 napi_env env,
1688 napi_value value,
1689 char *buf,
1690 size_t bufsize,
1691 size_t *result
1692) {
1693 return napi_get_string_common(env, value, buf, bufsize, result);
1694}
1695
1696NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_string_utf16(
1697 napi_env env,
1698 napi_value value,
1699 char16_t *buf,
1700 size_t bufsize,
1701 size_t *result
1702) {
1703 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1704 if (!nenv || !nenv->js) return napi_set_last(env, napi_invalid_arg, "invalid env");
1705 if (vtype((ant_value_t)value) != T_STR) return napi_set_last(env, napi_string_expected, "string expected");
1706
1707 size_t byte_len = 0;
1708 const char *str = js_getstr(nenv->js, (ant_value_t)value, &byte_len);
1709 if (!str) return napi_set_last(env, napi_string_expected, "string expected");
1710
1711 size_t utf16_len = utf16_strlen(str, byte_len);
1712 if (result) *result = utf16_len;
1713 if (!buf || bufsize == 0) return napi_set_last(env, napi_ok, NULL);
1714
1715 size_t n = utf16_len < (bufsize - 1) ? utf16_len : (bufsize - 1);
1716 for (size_t i = 0; i < n; i++) buf[i] = (char16_t)utf16_code_unit_at(str, byte_len, i);
1717 buf[n] = 0;
1718 return napi_set_last(env, napi_ok, NULL);
1719}
1720
1721NAPI_EXTERN napi_status NAPI_CDECL napi_get_date_value(
1722 napi_env env,
1723 napi_value value,
1724 double *result
1725) {
1726 if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1727 if (!is_date_instance((ant_value_t)value)) return napi_set_last(env, napi_date_expected, "date expected");
1728
1729 ant_value_t time_val = js_get_slot((ant_value_t)value, SLOT_DATA);
1730 *result = vtype(time_val) == T_NUM ? js_getnum(time_val) : JS_NAN;
1731 return napi_set_last(env, napi_ok, NULL);
1732}
1733
1734NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_bigint_int64(
1735 napi_env env,
1736 napi_value value,
1737 int64_t *result,
1738 bool *lossless
1739) {
1740 if (!env || !result || !lossless) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1741 if (vtype((ant_value_t)value) != T_BIGINT) return napi_set_last(env, napi_bigint_expected, "bigint expected");
1742
1743 size_t limb_count = 0;
1744 const uint32_t *limbs = napi_bigint_limbs(value, &limb_count);
1745 uint64_t magnitude = napi_bigint_low_u64(limbs, limb_count);
1746 bool negative = napi_bigint_is_negative(value) && !napi_bigint_limbs_is_zero(limbs, limb_count);
1747 uint64_t bits = negative ? (uint64_t)(~magnitude + 1) : magnitude;
1748
1749 *result = (int64_t)bits;
1750 *lossless = limb_count <= 2
1751 && ((!negative && magnitude <= (uint64_t)INT64_MAX)
1752 || (negative && magnitude <= (UINT64_C(1) << 63)));
1753 return napi_set_last(env, napi_ok, NULL);
1754}
1755
1756NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_bigint_uint64(
1757 napi_env env,
1758 napi_value value,
1759 uint64_t *result,
1760 bool *lossless
1761) {
1762 if (!env || !result || !lossless) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1763 if (vtype((ant_value_t)value) != T_BIGINT) return napi_set_last(env, napi_bigint_expected, "bigint expected");
1764
1765 size_t limb_count = 0;
1766 const uint32_t *limbs = napi_bigint_limbs(value, &limb_count);
1767 uint64_t magnitude = napi_bigint_low_u64(limbs, limb_count);
1768 bool negative = napi_bigint_is_negative(value) && !napi_bigint_limbs_is_zero(limbs, limb_count);
1769
1770 *result = negative ? (uint64_t)(~magnitude + 1) : magnitude;
1771 *lossless = !negative && limb_count <= 2;
1772 return napi_set_last(env, napi_ok, NULL);
1773}
1774
1775NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_bigint_words(
1776 napi_env env,
1777 napi_value value,
1778 int *sign_bit,
1779 size_t *word_count,
1780 uint64_t *words
1781) {
1782 if (!env || !word_count) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1783 if (vtype((ant_value_t)value) != T_BIGINT) return napi_set_last(env, napi_bigint_expected, "bigint expected");
1784
1785 size_t limb_count = 0;
1786 const uint32_t *limbs = napi_bigint_limbs(value, &limb_count);
1787 size_t actual_words = limb_count == 0 ? 0 : (limb_count + 1) / 2;
1788 size_t capacity = words ? *word_count : 0;
1789
1790 if (sign_bit) {
1791 bool negative = napi_bigint_is_negative(value) && !napi_bigint_limbs_is_zero(limbs, limb_count);
1792 *sign_bit = negative ? 1 : 0;
1793 }
1794
1795 if (words) {
1796 size_t n = capacity < actual_words ? capacity : actual_words;
1797 for (size_t i = 0; i < n; i++) {
1798 uint64_t lo = i * 2 < limb_count ? (uint64_t)limbs[i * 2] : 0;
1799 uint64_t hi = (i * 2 + 1) < limb_count ? (uint64_t)limbs[i * 2 + 1] : 0;
1800 words[i] = lo | (hi << 32);
1801 }}
1802
1803 *word_count = actual_words;
1804 return napi_set_last(env, napi_ok, NULL);
1805}
1806
1807NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_external(
1808 napi_env env,
1809 napi_value value,
1810 void **result
1811) {
1812 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1813 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1814 napi_external_entry_t *entry = napi_find_external(nenv->js, value);
1815 if (!entry) return napi_set_last(env, napi_invalid_arg, "not an external");
1816 *result = entry->data;
1817 return napi_set_last(env, napi_ok, NULL);
1818}
1819
1820NAPI_EXTERN napi_status NAPI_CDECL napi_get_cb_info(
1821 napi_env env,
1822 napi_callback_info cbinfo,
1823 size_t *argc,
1824 napi_value *argv,
1825 napi_value *this_arg,
1826 void **data
1827) {
1828 struct napi_callback_info__ *info = (struct napi_callback_info__ *)cbinfo;
1829 if (!env || !info) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1830
1831 if (argc) {
1832 size_t requested = *argc;
1833 if (argv) {
1834 size_t ncopy = requested < info->argc ? requested : info->argc;
1835 if (ncopy > 0) memcpy(argv, info->argv, ncopy * sizeof(napi_value));
1836 for (size_t i = ncopy; i < requested; i++) argv[i] = (napi_value)js_mkundef();
1837 }
1838 *argc = info->argc;
1839 }
1840
1841 if (this_arg) *this_arg = info->this_arg;
1842 if (data) *data = info->data;
1843 return napi_set_last(env, napi_ok, NULL);
1844}
1845
1846NAPI_EXTERN napi_status NAPI_CDECL napi_get_new_target(
1847 napi_env env,
1848 napi_callback_info cbinfo,
1849 napi_value *result
1850) {
1851 struct napi_callback_info__ *info = (struct napi_callback_info__ *)cbinfo;
1852 if (!env || !info || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1853
1854 ant_value_t nt = (ant_value_t)info->new_target;
1855 *result = is_undefined(nt) ? (napi_value)0 : info->new_target;
1856 return napi_set_last(env, napi_ok, NULL);
1857}
1858
1859NAPI_EXTERN napi_status NAPI_CDECL napi_get_array_length(
1860 napi_env env,
1861 napi_value value,
1862 uint32_t *result
1863) {
1864 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1865 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1866
1867 ant_value_t v = (ant_value_t)value;
1868 if (vtype(v) == T_ARR) {
1869 *result = (uint32_t)js_arr_len(nenv->js, v);
1870 return napi_set_last(env, napi_ok, NULL);
1871 }
1872
1873 ant_value_t len = js_get(nenv->js, v, "length");
1874 if (is_err(len) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, len);
1875 if (vtype(len) != T_NUM) return napi_set_last(env, napi_array_expected, "array expected");
1876 *result = (uint32_t)js_getnum(len);
1877 return napi_set_last(env, napi_ok, NULL);
1878}
1879
1880NAPI_EXTERN napi_status NAPI_CDECL napi_get_buffer_info(
1881 napi_env env,
1882 napi_value value,
1883 void **data,
1884 size_t *length
1885) {
1886 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1887 if (!nenv || !nenv->js) return napi_set_last(env, napi_invalid_arg, "invalid env");
1888
1889 TypedArrayData *ta = NULL;
1890 if (!napi_get_typedarray_data(nenv->js, value, &ta)) {
1891 return napi_set_last(env, napi_invalid_arg, "not a buffer");
1892 }
1893
1894 if (data) *data = ta->buffer->data + ta->byte_offset;
1895 if (length) *length = ta->byte_length;
1896 return napi_set_last(env, napi_ok, NULL);
1897}
1898
1899NAPI_EXTERN napi_status NAPI_CDECL napi_get_arraybuffer_info(
1900 napi_env env,
1901 napi_value arraybuffer,
1902 void **data,
1903 size_t *byte_length
1904) {
1905 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1906 if (!nenv || !nenv->js) return napi_set_last(env, napi_invalid_arg, "invalid env");
1907 if (!is_object_type((ant_value_t)arraybuffer)) return napi_set_last(env, napi_arraybuffer_expected, "arraybuffer expected");
1908
1909 ArrayBufferData *ab = buffer_get_arraybuffer_data((ant_value_t)arraybuffer);
1910 if (!ab || ab->is_detached) return napi_set_last(env, napi_arraybuffer_expected, "arraybuffer expected");
1911
1912 if (data) *data = ab->data;
1913 if (byte_length) *byte_length = ab->length;
1914 return napi_set_last(env, napi_ok, NULL);
1915}
1916
1917NAPI_EXTERN napi_status NAPI_CDECL napi_get_typedarray_info(
1918 napi_env env,
1919 napi_value typedarray,
1920 napi_typedarray_type *type,
1921 size_t *length,
1922 void **data,
1923 napi_value *arraybuffer,
1924 size_t *byte_offset
1925) {
1926 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1927 if (!nenv || !nenv->js) return napi_set_last(env, napi_invalid_arg, "invalid env");
1928
1929 TypedArrayData *ta = NULL;
1930 if (!napi_get_typedarray_data(nenv->js, typedarray, &ta)) {
1931 return napi_set_last(env, napi_invalid_arg, "typedarray expected");
1932 }
1933
1934 if (type) *type = napi_from_ant_typedarray_type(ta->type);
1935 if (length) *length = ta->length;
1936 if (data) *data = ta->buffer->data + ta->byte_offset;
1937 if (arraybuffer) {
1938 ant_value_t buffer = js_get(nenv->js, (ant_value_t)typedarray, "buffer");
1939 if (is_err(buffer) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, buffer);
1940 *arraybuffer = NAPI_RETURN(nenv, buffer);
1941 }
1942 if (byte_offset) *byte_offset = ta->byte_offset;
1943 return napi_set_last(env, napi_ok, NULL);
1944}
1945
1946NAPI_EXTERN napi_status NAPI_CDECL napi_get_prototype(
1947 napi_env env,
1948 napi_value object,
1949 napi_value *result
1950) {
1951 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1952 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
1953 ant_value_t proto = js_get_proto(nenv->js, (ant_value_t)object);
1954 if (is_err(proto) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, proto);
1955 *result = NAPI_RETURN(nenv, proto);
1956 return napi_set_last(env, napi_ok, NULL);
1957}
1958
1959NAPI_EXTERN napi_status NAPI_CDECL napi_get_property_names(
1960 napi_env env,
1961 napi_value object,
1962 napi_value *result
1963) {
1964 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1965 if (!nenv || !nenv->js || !result || !is_object_type((ant_value_t)object)) {
1966 return napi_set_last(env, napi_invalid_arg, "invalid argument");
1967 }
1968
1969 ant_value_t out = js_mkarr(nenv->js);
1970 ant_iter_t iter = js_prop_iter_begin(nenv->js, (ant_value_t)object);
1971 const char *key = NULL;
1972 size_t key_len = 0;
1973
1974 while (js_prop_iter_next(&iter, &key, &key_len, NULL)) {
1975 js_arr_push(nenv->js, out, js_mkstr(nenv->js, key, key_len));
1976 }
1977 js_prop_iter_end(&iter);
1978
1979 *result = NAPI_RETURN(nenv, out);
1980 return napi_set_last(env, napi_ok, NULL);
1981}
1982
1983NAPI_EXTERN napi_status NAPI_CDECL napi_get_all_property_names(
1984 napi_env env,
1985 napi_value object,
1986 napi_key_collection_mode key_mode,
1987 napi_key_filter key_filter,
1988 napi_key_conversion key_conversion,
1989 napi_value *result
1990) {
1991 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
1992 if (!nenv || !nenv->js || !result || !is_object_type((ant_value_t)object)) {
1993 return napi_set_last(env, napi_invalid_arg, "invalid argument");
1994 }
1995
1996 ant_t *js = nenv->js;
1997 ant_value_t out = js_mkarr(js);
1998 ant_value_t seen = js_mkobj(js);
1999 ant_value_t current = (ant_value_t)object;
2000
2001 while (is_object_type(current)) {
2002 ant_iter_t iter = js_prop_iter_begin(js, current);
2003 ant_value_t key = js_mkundef();
2004
2005 while (js_prop_iter_next_val(&iter, &key, NULL)) {
2006 ant_object_t *obj_ptr = js_obj_ptr(js_as_obj(current));
2007 if (!obj_ptr || !obj_ptr->shape || iter.off == 0) continue;
2008
2009 const ant_shape_prop_t *prop = ant_shape_prop_at(obj_ptr->shape, (uint32_t)(iter.off - 1));
2010 if (!napi_key_passes_filter(prop, key_filter)) continue;
2011
2012 uint8_t key_type = vtype(key);
2013 if ((key_filter & napi_key_skip_strings) && key_type != T_SYMBOL) continue;
2014 if ((key_filter & napi_key_skip_symbols) && key_type == T_SYMBOL) continue;
2015 if (napi_seen_has_key(js, seen, key)) continue;
2016 if (!napi_seen_add_key(js, seen, key)) {
2017 js_prop_iter_end(&iter);
2018 return napi_set_last(env, napi_generic_failure, "failed to collect property names");
2019 }
2020
2021 js_arr_push(js, out, napi_convert_property_key(js, key, key_conversion));
2022 if (js->thrown_exists) {
2023 js_prop_iter_end(&iter);
2024 return napi_check_pending_from_result(env, js_mkundef());
2025 }}
2026
2027 js_prop_iter_end(&iter);
2028 if (key_mode == napi_key_own_only) break;
2029 current = js_get_proto(js, current);
2030 if (is_err(current) || js->thrown_exists) return napi_check_pending_from_result(env, current);
2031 }
2032
2033 *result = NAPI_RETURN(nenv, out);
2034 return napi_set_last(env, napi_ok, NULL);
2035}
2036
2037NAPI_EXTERN napi_status NAPI_CDECL napi_get_version(
2038 node_api_basic_env env,
2039 uint32_t *result
2040) {
2041 if (!env || !result) return napi_set_last((napi_env)env, napi_invalid_arg, "invalid argument");
2042 *result = 8;
2043 return napi_set_last((napi_env)env, napi_ok, NULL);
2044}
2045
2046NAPI_EXTERN napi_status NAPI_CDECL napi_get_node_version(
2047 node_api_basic_env env,
2048 const napi_node_version **version
2049) {
2050 if (!env || !version) return napi_set_last((napi_env)env, napi_invalid_arg, "invalid argument");
2051 *version = &g_napi_node_version;
2052 return napi_set_last((napi_env)env, napi_ok, NULL);
2053}
2054
2055NAPI_EXTERN napi_status NAPI_CDECL napi_set_property(
2056 napi_env env,
2057 napi_value object,
2058 napi_value key,
2059 napi_value value
2060) {
2061 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2062 if (!nenv || !nenv->js || !is_object_type((ant_value_t)object)) {
2063 return napi_set_last(env, napi_invalid_arg, "invalid argument");
2064 }
2065 ant_value_t r = js_setprop(nenv->js, (ant_value_t)object, (ant_value_t)key, (ant_value_t)value);
2066 if (is_err(r) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, r);
2067 return napi_set_last(env, napi_ok, NULL);
2068}
2069
2070NAPI_EXTERN napi_status NAPI_CDECL napi_get_property(
2071 napi_env env,
2072 napi_value object,
2073 napi_value key,
2074 napi_value *result
2075) {
2076 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2077 if (!nenv || !nenv->js || !result || !is_object_type((ant_value_t)object)) {
2078 return napi_set_last(env, napi_invalid_arg, "invalid argument");
2079 }
2080
2081 ant_value_t k = (ant_value_t)key;
2082 if (vtype(k) == T_SYMBOL) {
2083 ant_offset_t off = lkp_sym_proto(nenv->js, (ant_value_t)object, (ant_offset_t)vdata(k));
2084 ant_value_t out = off ? js_propref_load(nenv->js, off) : js_mkundef();
2085 if (is_err(out) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, out);
2086 *result = NAPI_RETURN(nenv, out);
2087 return napi_set_last(env, napi_ok, NULL);
2088 }
2089
2090 ant_value_t kstr = coerce_to_str(nenv->js, k);
2091 if (is_err(kstr)) return napi_check_pending_from_result(env, kstr);
2092
2093 size_t klen = 0;
2094 const char *ks = js_getstr(nenv->js, kstr, &klen);
2095 if (!ks) return napi_set_last(env, napi_string_expected, "string expected");
2096
2097 char *name = (char *)malloc(klen + 1);
2098 if (!name) return napi_set_last(env, napi_generic_failure, "out of memory");
2099 memcpy(name, ks, klen);
2100 name[klen] = '\0';
2101
2102 ant_value_t out = js_getprop_fallback(nenv->js, (ant_value_t)object, name);
2103 free(name);
2104 if (is_err(out) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, out);
2105 *result = NAPI_RETURN(nenv, out);
2106 return napi_set_last(env, napi_ok, NULL);
2107}
2108
2109NAPI_EXTERN napi_status NAPI_CDECL napi_has_property(
2110 napi_env env,
2111 napi_value object,
2112 napi_value key,
2113 bool *result
2114) {
2115 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2116 if (!nenv || !nenv->js || !result || !is_object_type((ant_value_t)object)) {
2117 return napi_set_last(env, napi_invalid_arg, "invalid argument");
2118 }
2119
2120 ant_value_t k = (ant_value_t)key;
2121 if (vtype(k) == T_SYMBOL) {
2122 *result = lkp_sym_proto(nenv->js, (ant_value_t)object, (ant_offset_t)vdata(k)) != 0;
2123 return napi_set_last(env, napi_ok, NULL);
2124 }
2125
2126 ant_value_t kstr = coerce_to_str(nenv->js, k);
2127 if (is_err(kstr) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, kstr);
2128 size_t len = 0;
2129 const char *s = js_getstr(nenv->js, kstr, &len);
2130 *result = s && lkp_proto(nenv->js, (ant_value_t)object, s, len) != 0;
2131 return napi_set_last(env, napi_ok, NULL);
2132}
2133
2134NAPI_EXTERN napi_status NAPI_CDECL napi_delete_property(
2135 napi_env env,
2136 napi_value object,
2137 napi_value key,
2138 bool *result
2139) {
2140 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2141 if (!nenv || !nenv->js || !result || !is_object_type((ant_value_t)object)) {
2142 return napi_set_last(env, napi_invalid_arg, "invalid argument");
2143 }
2144
2145 ant_value_t k = (ant_value_t)key;
2146 ant_value_t del_result = js_mkundef();
2147
2148 if (vtype(k) == T_SYMBOL) {
2149 del_result = js_delete_sym_prop(nenv->js, (ant_value_t)object, k);
2150 } else {
2151 ant_value_t kstr = coerce_to_str(nenv->js, k);
2152 if (is_err(kstr) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, kstr);
2153 size_t len = 0;
2154 const char *s = js_getstr(nenv->js, kstr, &len);
2155 del_result = js_delete_prop(nenv->js, (ant_value_t)object, s, len);
2156 }
2157
2158 if (is_err(del_result) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, del_result);
2159 *result = js_truthy(nenv->js, del_result);
2160 return napi_set_last(env, napi_ok, NULL);
2161}
2162
2163NAPI_EXTERN napi_status NAPI_CDECL napi_set_named_property(
2164 napi_env env,
2165 napi_value object,
2166 const char *utf8name,
2167 napi_value value
2168) {
2169 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2170 if (!nenv || !nenv->js || !utf8name || !is_object_type((ant_value_t)object)) {
2171 return napi_set_last(env, napi_invalid_arg, "invalid argument");
2172 }
2173 js_set(nenv->js, (ant_value_t)object, utf8name, (ant_value_t)value);
2174 return napi_return_pending_if_any(env);
2175}
2176
2177NAPI_EXTERN napi_status NAPI_CDECL napi_get_named_property(
2178 napi_env env,
2179 napi_value object,
2180 const char *utf8name,
2181 napi_value *result
2182) {
2183 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2184 if (!nenv || !nenv->js || !result || !utf8name || !is_object_type((ant_value_t)object)) {
2185 return napi_set_last(env, napi_invalid_arg, "invalid argument");
2186 }
2187 ant_value_t out = js_getprop_fallback(nenv->js, (ant_value_t)object, utf8name);
2188 if (is_err(out) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, out);
2189 *result = NAPI_RETURN(nenv, out);
2190 return napi_set_last(env, napi_ok, NULL);
2191}
2192
2193NAPI_EXTERN napi_status NAPI_CDECL napi_has_named_property(
2194 napi_env env,
2195 napi_value object,
2196 const char *utf8name,
2197 bool *result
2198) {
2199 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2200 if (!nenv || !nenv->js || !result || !utf8name || !is_object_type((ant_value_t)object)) {
2201 return napi_set_last(env, napi_invalid_arg, "invalid argument");
2202 }
2203 *result = lkp_proto(nenv->js, (ant_value_t)object, utf8name, strlen(utf8name)) != 0;
2204 return napi_set_last(env, napi_ok, NULL);
2205}
2206
2207NAPI_EXTERN napi_status NAPI_CDECL napi_set_element(
2208 napi_env env,
2209 napi_value object,
2210 uint32_t index,
2211 napi_value value
2212) {
2213 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2214 if (!nenv || !nenv->js || !is_object_type((ant_value_t)object)) {
2215 return napi_set_last(env, napi_invalid_arg, "invalid argument");
2216 }
2217 char idx[32];
2218 int n = snprintf(idx, sizeof(idx), "%u", index);
2219 if (n < 0) return napi_set_last(env, napi_generic_failure, "index conversion failed");
2220 ant_value_t key = js_mkstr(nenv->js, idx, (size_t)n);
2221 ant_value_t r = js_setprop(
2222 nenv->js, (ant_value_t)object,
2223 key, (ant_value_t)value
2224 );
2225 if (is_err(r) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, r);
2226 return napi_set_last(env, napi_ok, NULL);
2227}
2228
2229NAPI_EXTERN napi_status NAPI_CDECL napi_get_element(
2230 napi_env env,
2231 napi_value object,
2232 uint32_t index,
2233 napi_value *result
2234) {
2235 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2236 if (!nenv || !nenv->js || !result || !is_object_type((ant_value_t)object)) {
2237 return napi_set_last(env, napi_invalid_arg, "invalid argument");
2238 }
2239 char idx[32];
2240 snprintf(idx, sizeof(idx), "%u", index);
2241 ant_value_t out = js_get(nenv->js, (ant_value_t)object, idx);
2242 if (is_err(out) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, out);
2243 *result = NAPI_RETURN(nenv, out);
2244 return napi_set_last(env, napi_ok, NULL);
2245}
2246
2247NAPI_EXTERN napi_status NAPI_CDECL napi_has_element(
2248 napi_env env,
2249 napi_value object,
2250 uint32_t index,
2251 bool *result
2252) {
2253 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2254 if (!nenv || !nenv->js || !result || !is_object_type((ant_value_t)object)) {
2255 return napi_set_last(env, napi_invalid_arg, "invalid argument");
2256 }
2257 char idx[32];
2258 snprintf(idx, sizeof(idx), "%u", index);
2259 *result = lkp_proto(nenv->js, (ant_value_t)object, idx, strlen(idx)) != 0;
2260 return napi_set_last(env, napi_ok, NULL);
2261}
2262
2263NAPI_EXTERN napi_status NAPI_CDECL napi_delete_element(
2264 napi_env env,
2265 napi_value object,
2266 uint32_t index,
2267 bool *result
2268) {
2269 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2270 if (!nenv || !nenv->js || !result || !is_object_type((ant_value_t)object)) {
2271 return napi_set_last(env, napi_invalid_arg, "invalid argument");
2272 }
2273 char idx[32];
2274 snprintf(idx, sizeof(idx), "%u", index);
2275 ant_value_t del = js_delete_prop(nenv->js, (ant_value_t)object, idx, strlen(idx));
2276 if (is_err(del) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, del);
2277 *result = js_truthy(nenv->js, del);
2278 return napi_set_last(env, napi_ok, NULL);
2279}
2280
2281NAPI_EXTERN napi_status NAPI_CDECL napi_define_properties(
2282 napi_env env,
2283 napi_value object,
2284 size_t property_count,
2285 const napi_property_descriptor *properties
2286) {
2287 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2288 if (!nenv || !nenv->js || !is_object_type((ant_value_t)object) || (property_count > 0 && !properties)) {
2289 return napi_set_last(env, napi_invalid_arg, "invalid argument");
2290 }
2291
2292 for (size_t i = 0; i < property_count; i++) {
2293 const napi_property_descriptor *p = &properties[i];
2294 ant_value_t key = js_mkundef();
2295 const char *key_str = NULL;
2296 size_t key_len = 0;
2297
2298 if (p->utf8name) {
2299 key_str = p->utf8name;
2300 key_len = strlen(p->utf8name);
2301 key = js_mkstr(nenv->js, key_str, key_len);
2302 } else key = (ant_value_t)p->name;
2303
2304 bool is_symbol = (vtype(key) == T_SYMBOL);
2305 if (!is_symbol && !key_str) {
2306 if (vtype(key) != T_STR) continue;
2307 key_str = js_getstr(nenv->js, key, &key_len);
2308 }
2309
2310 ant_value_t value = js_mkundef();
2311 if (p->method) {
2312 napi_value fn = 0;
2313 napi_status st = napi_create_function_common(
2314 env, p->utf8name,
2315 NAPI_AUTO_LENGTH,
2316 p->method, p->data, &fn
2317 );
2318 if (st != napi_ok) return st;
2319 value = (ant_value_t)fn;
2320 } else if (p->getter || p->setter) {
2321 napi_value getter_fn = 0;
2322 napi_value setter_fn = 0;
2323
2324 if (p->getter) {
2325 napi_status st = napi_create_function_common(env, p->utf8name, NAPI_AUTO_LENGTH, p->getter, p->data, &getter_fn);
2326 if (st != napi_ok) return st;
2327 }
2328
2329 if (p->setter) {
2330 napi_status st = napi_create_function_common(env, p->utf8name, NAPI_AUTO_LENGTH, p->setter, p->data, &setter_fn);
2331 if (st != napi_ok) return st;
2332 }
2333
2334 int flags = napi_desc_flags(p->attributes);
2335 ant_value_t desc_obj = js_as_obj((ant_value_t)object);
2336
2337 if (is_symbol) {
2338 if (p->getter) js_set_sym_getter_desc(nenv->js, desc_obj, key, (ant_value_t)getter_fn, flags);
2339 if (p->setter) js_set_sym_setter_desc(nenv->js, desc_obj, key, (ant_value_t)setter_fn, flags);
2340 } else js_set_accessor_desc(
2341 nenv->js, desc_obj,
2342 key_str, key_len,
2343 p->getter ? (ant_value_t)getter_fn : js_mkundef(),
2344 p->setter ? (ant_value_t)setter_fn : js_mkundef(),
2345 flags
2346 );
2347
2348 if (nenv->js->thrown_exists) return napi_check_pending_from_result(env, js_mkundef());
2349 continue;
2350 } else value = (ant_value_t)p->value;
2351
2352 if (is_symbol) js_set_sym(nenv->js, (ant_value_t)object, key, value);
2353 else {
2354 js_set(nenv->js, (ant_value_t)object, key_str, value);
2355 js_set_descriptor(nenv->js, js_as_obj((ant_value_t)object), key_str, key_len, napi_desc_flags(p->attributes));
2356 }
2357
2358 if (nenv->js->thrown_exists) return napi_check_pending_from_result(env, js_mkundef());
2359 }
2360
2361 return napi_set_last(env, napi_ok, NULL);
2362}
2363
2364NAPI_EXTERN napi_status NAPI_CDECL napi_define_class(
2365 napi_env env,
2366 const char *utf8name,
2367 size_t length,
2368 napi_callback constructor,
2369 void *data,
2370 size_t property_count,
2371 const napi_property_descriptor *properties,
2372 napi_value *result
2373) {
2374 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2375 if (!nenv || !nenv->js || !constructor || !result) {
2376 return napi_set_last(env, napi_invalid_arg, "invalid argument");
2377 }
2378
2379 napi_status st = napi_create_function_common(
2380 env, utf8name, length, constructor, data, result
2381 );
2382 if (st != napi_ok) return st;
2383
2384 ant_value_t ctor = (ant_value_t)*result;
2385 js_mark_constructor(ctor, true);
2386
2387 ant_value_t proto = js_get(nenv->js, ctor, "prototype");
2388 if (is_err(proto) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, proto);
2389 if (!is_object_type(proto)) {
2390 proto = js_mkobj(nenv->js);
2391 js_set(nenv->js, ctor, "prototype", proto);
2392 if (nenv->js->thrown_exists) return napi_check_pending_from_result(env, js_mkundef());
2393 }
2394
2395 for (size_t i = 0; i < property_count; i++) {
2396 napi_property_descriptor tmp = properties[i];
2397 bool is_static = (tmp.attributes & napi_static) != 0;
2398 tmp.attributes = (napi_property_attributes)(tmp.attributes & ~napi_static);
2399 st = napi_define_properties(env, (napi_value)(is_static ? ctor : proto), 1, &tmp);
2400 if (st != napi_ok) return st;
2401 }
2402
2403 return napi_set_last(env, napi_ok, NULL);
2404}
2405
2406NAPI_EXTERN napi_status NAPI_CDECL napi_has_own_property(
2407 napi_env env,
2408 napi_value object,
2409 napi_value key,
2410 bool *result
2411) {
2412 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2413 if (!nenv || !nenv->js || !result || !is_object_type((ant_value_t)object)) {
2414 return napi_set_last(env, napi_invalid_arg, "invalid argument");
2415 }
2416
2417 ant_value_t k = (ant_value_t)key;
2418 if (vtype(k) == T_SYMBOL) {
2419 *result = lkp_sym(nenv->js, (ant_value_t)object, (ant_offset_t)vdata(k)) != 0;
2420 return napi_set_last(env, napi_ok, NULL);
2421 }
2422
2423 ant_value_t kstr = coerce_to_str(nenv->js, k);
2424 if (is_err(kstr) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, kstr);
2425 size_t len = 0;
2426 const char *s = js_getstr(nenv->js, kstr, &len);
2427 *result = s && lkp(nenv->js, (ant_value_t)object, s, len) != 0;
2428 return napi_set_last(env, napi_ok, NULL);
2429}
2430
2431NAPI_EXTERN napi_status NAPI_CDECL napi_typeof(
2432 napi_env env,
2433 napi_value value,
2434 napi_valuetype *result
2435) {
2436 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2437 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
2438
2439 ant_value_t v = (ant_value_t)value;
2440 uint8_t t = vtype(v);
2441
2442 if (napi_find_external(nenv->js, value)) {
2443 *result = napi_external;
2444 return napi_set_last(env, napi_ok, NULL);
2445 }
2446
2447 switch (t) {
2448 case T_UNDEF: *result = napi_undefined; break;
2449 case T_NULL: *result = napi_null; break;
2450 case T_BOOL: *result = napi_boolean; break;
2451 case T_NUM: *result = napi_number; break;
2452 case T_STR: *result = napi_string; break;
2453 case T_SYMBOL: *result = napi_symbol; break;
2454 case T_FUNC:
2455 case T_CFUNC: *result = napi_function; break;
2456 case T_BIGINT: *result = napi_bigint; break;
2457 default: *result = napi_object; break;
2458 }
2459
2460 return napi_set_last(env, napi_ok, NULL);
2461}
2462
2463NAPI_EXTERN napi_status NAPI_CDECL napi_is_array(
2464 napi_env env,
2465 napi_value value,
2466 bool *result
2467) {
2468 if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
2469 *result = vtype((ant_value_t)value) == T_ARR;
2470 return napi_set_last(env, napi_ok, NULL);
2471}
2472
2473NAPI_EXTERN napi_status NAPI_CDECL napi_is_date(
2474 napi_env env,
2475 napi_value value,
2476 bool *result
2477) {
2478 if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
2479 *result = is_date_instance((ant_value_t)value);
2480 return napi_set_last(env, napi_ok, NULL);
2481}
2482
2483NAPI_EXTERN napi_status NAPI_CDECL napi_is_arraybuffer(
2484 napi_env env,
2485 napi_value value,
2486 bool *result
2487) {
2488 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2489 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
2490 if (!is_object_type((ant_value_t)value)) { *result = false; return napi_set_last(env, napi_ok, NULL); }
2491
2492 *result = buffer_get_arraybuffer_data((ant_value_t)value) != NULL;
2493 return napi_set_last(env, napi_ok, NULL);
2494}
2495
2496NAPI_EXTERN napi_status NAPI_CDECL napi_is_buffer(
2497 napi_env env,
2498 napi_value value,
2499 bool *result
2500) {
2501 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2502 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
2503
2504 TypedArrayData *ta = NULL;
2505 if (!napi_get_typedarray_data(nenv->js, value, &ta)) {
2506 *result = false;
2507 return napi_set_last(env, napi_ok, NULL);
2508 }
2509
2510 ant_value_t buffer_proto = js_get_ctor_proto(nenv->js, "Buffer", 6);
2511 *result = is_object_type(buffer_proto)
2512 && proto_chain_contains(nenv->js, (ant_value_t)value, buffer_proto);
2513 return napi_set_last(env, napi_ok, NULL);
2514}
2515
2516NAPI_EXTERN napi_status NAPI_CDECL napi_is_typedarray(
2517 napi_env env,
2518 napi_value value,
2519 bool *result
2520) {
2521 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2522 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
2523 TypedArrayData *ta = NULL;
2524 *result = napi_get_typedarray_data(nenv->js, value, &ta);
2525 return napi_set_last(env, napi_ok, NULL);
2526}
2527
2528NAPI_EXTERN napi_status NAPI_CDECL napi_is_dataview(
2529 napi_env env,
2530 napi_value value,
2531 bool *result
2532) {
2533 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2534 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
2535 if (!is_object_type((ant_value_t)value)) {
2536 *result = false;
2537 } else {
2538 *result = buffer_get_dataview_data((ant_value_t)value) != NULL;
2539 }
2540 return napi_set_last(env, napi_ok, NULL);
2541}
2542
2543NAPI_EXTERN napi_status NAPI_CDECL napi_is_error(
2544 napi_env env,
2545 napi_value value,
2546 bool *result
2547) {
2548 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2549 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
2550 if (!is_object_type((ant_value_t)value)) {
2551 *result = false;
2552 } else {
2553 ant_value_t et = js_get_slot((ant_value_t)value, SLOT_ERR_TYPE);
2554 *result = vtype(et) == T_NUM;
2555 }
2556 return napi_set_last(env, napi_ok, NULL);
2557}
2558
2559NAPI_EXTERN napi_status NAPI_CDECL napi_is_promise(
2560 napi_env env,
2561 napi_value value,
2562 bool *is_promise
2563) {
2564 if (!env || !is_promise) return napi_set_last(env, napi_invalid_arg, "invalid argument");
2565 *is_promise = vtype((ant_value_t)value) == T_PROMISE;
2566 return napi_set_last(env, napi_ok, NULL);
2567}
2568
2569NAPI_EXTERN napi_status NAPI_CDECL napi_instanceof(
2570 napi_env env,
2571 napi_value object,
2572 napi_value constructor,
2573 bool *result
2574) {
2575 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2576 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
2577 ant_value_t r = do_instanceof(nenv->js, (ant_value_t)object, (ant_value_t)constructor);
2578 if (is_err(r) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, r);
2579 *result = js_truthy(nenv->js, r);
2580 return napi_set_last(env, napi_ok, NULL);
2581}
2582
2583NAPI_EXTERN napi_status NAPI_CDECL napi_strict_equals(
2584 napi_env env,
2585 napi_value lhs,
2586 napi_value rhs,
2587 bool *result
2588) {
2589 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2590 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
2591 *result = strict_eq_values(nenv->js, (ant_value_t)lhs, (ant_value_t)rhs);
2592 return napi_set_last(env, napi_ok, NULL);
2593}
2594
2595NAPI_EXTERN napi_status NAPI_CDECL napi_call_function(
2596 napi_env env,
2597 napi_value recv,
2598 napi_value func,
2599 size_t argc,
2600 const napi_value *argv,
2601 napi_value *result
2602) {
2603 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2604 if (!nenv || !nenv->js || !is_callable((ant_value_t)func)) {
2605 return napi_set_last(env, napi_invalid_arg, "invalid argument");
2606 }
2607
2608 ant_value_t out = sv_vm_call(
2609 nenv->js->vm,
2610 nenv->js,
2611 (ant_value_t)func,
2612 (ant_value_t)recv,
2613 (ant_value_t *)argv,
2614 (int)argc,
2615 NULL,
2616 false
2617 );
2618
2619 if (is_err(out) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, out);
2620 if (result) *result = NAPI_RETURN(nenv, out);
2621 return napi_set_last(env, napi_ok, NULL);
2622}
2623
2624NAPI_EXTERN napi_status NAPI_CDECL napi_new_instance(
2625 napi_env env,
2626 napi_value constructor,
2627 size_t argc,
2628 const napi_value *argv,
2629 napi_value *result
2630) {
2631 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2632 if (!nenv || !nenv->js || !result || !is_callable((ant_value_t)constructor)) {
2633 return napi_set_last(env, napi_invalid_arg, "invalid argument");
2634 }
2635
2636 ant_value_t ctor = (ant_value_t)constructor;
2637 ant_value_t obj = js_mkobj(nenv->js);
2638 ant_value_t proto = js_get(nenv->js, ctor, "prototype");
2639 if (is_object_type(proto)) js_set_proto_init(obj, proto);
2640
2641 ant_value_t saved = nenv->js->new_target;
2642 nenv->js->new_target = ctor;
2643 ant_value_t out = sv_vm_call(
2644 nenv->js->vm,
2645 nenv->js,
2646 ctor,
2647 obj,
2648 (ant_value_t *)argv,
2649 (int)argc,
2650 NULL,
2651 true
2652 );
2653 nenv->js->new_target = saved;
2654
2655 if (is_err(out) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, out);
2656 *result = NAPI_RETURN(nenv, (is_object_type(out) ? out : obj));
2657 return napi_set_last(env, napi_ok, NULL);
2658}
2659
2660NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_bool(
2661 napi_env env,
2662 napi_value value,
2663 napi_value *result
2664) {
2665 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2666 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
2667 bool truthy = js_truthy(nenv->js, (ant_value_t)value);
2668 if (nenv->js->thrown_exists) return napi_check_pending_from_result(env, js_mkundef());
2669 *result = NAPI_RETURN(nenv, js_bool(truthy));
2670 return napi_set_last(env, napi_ok, NULL);
2671}
2672
2673NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_number(
2674 napi_env env,
2675 napi_value value,
2676 napi_value *result
2677) {
2678 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2679 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
2680 double num = js_to_number(nenv->js, (ant_value_t)value);
2681 if (nenv->js->thrown_exists) return napi_check_pending_from_result(env, js_mkundef());
2682 *result = NAPI_RETURN(nenv, js_mknum(num));
2683 return napi_set_last(env, napi_ok, NULL);
2684}
2685
2686NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_object(
2687 napi_env env,
2688 napi_value value,
2689 napi_value *result
2690) {
2691 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2692 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
2693
2694 if (is_object_type((ant_value_t)value)) {
2695 *result = value;
2696 return napi_set_last(env, napi_ok, NULL);
2697 }
2698
2699 ant_value_t obj_ctor = js_get(nenv->js, js_glob(nenv->js), "Object");
2700 if (is_err(obj_ctor) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, obj_ctor);
2701 if (!is_callable(obj_ctor)) return napi_set_last(env, napi_generic_failure, "Object constructor missing");
2702 ant_value_t arg = (ant_value_t)value;
2703 ant_value_t out = sv_vm_call(nenv->js->vm, nenv->js, obj_ctor, js_mkundef(), &arg, 1, NULL, false);
2704 if (is_err(out) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, out);
2705 *result = NAPI_RETURN(nenv, out);
2706 return napi_set_last(env, napi_ok, NULL);
2707}
2708
2709NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_string(
2710 napi_env env,
2711 napi_value value,
2712 napi_value *result
2713) {
2714 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2715 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
2716 ant_value_t out = coerce_to_str(nenv->js, (ant_value_t)value);
2717 if (is_err(out) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, out);
2718 *result = NAPI_RETURN(nenv, out);
2719 return napi_set_last(env, napi_ok, NULL);
2720}
2721
2722NAPI_EXTERN napi_status NAPI_CDECL napi_throw_error(
2723 napi_env env,
2724 const char *code,
2725 const char *msg
2726) {
2727 (void)code;
2728 return napi_throw_with_message(env, JS_ERR_GENERIC, msg ? msg : "");
2729}
2730
2731NAPI_EXTERN napi_status NAPI_CDECL napi_throw_type_error(
2732 napi_env env,
2733 const char *code,
2734 const char *msg
2735) {
2736 (void)code;
2737 return napi_throw_with_message(env, JS_ERR_TYPE, msg ? msg : "");
2738}
2739
2740NAPI_EXTERN napi_status NAPI_CDECL napi_throw_range_error(
2741 napi_env env,
2742 const char *code,
2743 const char *msg
2744) {
2745 (void)code;
2746 return napi_throw_with_message(env, JS_ERR_RANGE, msg ? msg : "");
2747}
2748
2749NAPI_EXTERN napi_status NAPI_CDECL napi_is_exception_pending(
2750 napi_env env,
2751 bool *result
2752) {
2753 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2754 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
2755 *result = nenv->has_pending_exception || nenv->js->thrown_exists;
2756 return napi_set_last_raw(env, napi_ok, NULL);
2757}
2758
2759NAPI_EXTERN napi_status NAPI_CDECL napi_get_and_clear_last_exception(
2760 napi_env env,
2761 napi_value *result
2762) {
2763 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2764 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
2765
2766 if (nenv->has_pending_exception) {
2767 *result = nenv->pending_exception;
2768 nenv->has_pending_exception = false;
2769 nenv->pending_exception = (napi_value)js_mkundef();
2770 } else if (nenv->js->thrown_exists) {
2771 *result = NAPI_RETURN(nenv, nenv->js->thrown_value);
2772 nenv->js->thrown_exists = false;
2773 nenv->js->thrown_value = js_mkundef();
2774 nenv->js->thrown_stack = js_mkundef();
2775 } else {
2776 *result = NAPI_RETURN(nenv, js_mkundef());
2777 }
2778
2779 return napi_set_last(env, napi_ok, NULL);
2780}
2781
2782NAPI_EXTERN void NAPI_CDECL napi_fatal_error(
2783 const char *location,
2784 size_t location_len,
2785 const char *message,
2786 size_t message_len
2787) {
2788 fprintf(
2789 stderr,
2790 "N-API fatal error at %.*s: %.*s\n",
2791 (int)location_len,
2792 location ? location : "",
2793 (int)message_len,
2794 message ? message : ""
2795 );
2796 abort();
2797}
2798
2799NAPI_EXTERN napi_status NAPI_CDECL napi_fatal_exception(napi_env env, napi_value err) {
2800 return napi_throw(env, err);
2801}
2802
2803NAPI_EXTERN napi_status NAPI_CDECL napi_wrap(
2804 napi_env env,
2805 napi_value js_object,
2806 void *native_object,
2807 node_api_basic_finalize finalize_cb,
2808 void *finalize_hint,
2809 napi_ref *result
2810) {
2811 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2812 if (!nenv || !nenv->js || !is_object_type((ant_value_t)js_object)) {
2813 return napi_set_last(env, napi_invalid_arg, "invalid argument");
2814 }
2815
2816 napi_wrap_entry_t *entry = napi_find_wrap(nenv->js, js_object);
2817 if (!entry) {
2818 entry = (napi_wrap_entry_t *)calloc(1, sizeof(*entry));
2819 if (!entry) return napi_set_last(env, napi_generic_failure, "out of memory");
2820 entry->id = g_napi_wrap_next_id++;
2821 HASH_ADD(hh, g_napi_wraps, id, sizeof(entry->id), entry);
2822 napi_slot_set_u64(nenv->js, (ant_value_t)js_object, SLOT_NAPI_WRAP_ID, entry->id);
2823 }
2824
2825 entry->native_object = native_object;
2826 entry->finalize_cb = finalize_cb;
2827 entry->finalize_hint = finalize_hint;
2828 entry->has_wrap = true;
2829
2830 if (result) {
2831 return napi_create_reference(env, js_object, 0, result);
2832 }
2833 return napi_set_last(env, napi_ok, NULL);
2834}
2835
2836NAPI_EXTERN napi_status NAPI_CDECL napi_add_finalizer(
2837 napi_env env,
2838 napi_value js_object,
2839 void *finalize_data,
2840 node_api_basic_finalize finalize_cb,
2841 void *finalize_hint,
2842 napi_ref *result
2843) {
2844 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2845 if (!nenv || !nenv->js || !is_object_type((ant_value_t)js_object)) {
2846 return napi_set_last(env, napi_invalid_arg, "invalid argument");
2847 }
2848
2849 napi_wrap_entry_t *entry = napi_find_wrap(nenv->js, js_object);
2850 if (!entry) {
2851 entry = (napi_wrap_entry_t *)calloc(1, sizeof(*entry));
2852 if (!entry) return napi_set_last(env, napi_generic_failure, "out of memory");
2853 entry->id = g_napi_wrap_next_id++;
2854 HASH_ADD(hh, g_napi_wraps, id, sizeof(entry->id), entry);
2855 napi_slot_set_u64(nenv->js, (ant_value_t)js_object, SLOT_NAPI_WRAP_ID, entry->id);
2856 }
2857
2858 entry->attached_data = finalize_data;
2859 entry->attached_finalize_cb = finalize_cb;
2860 entry->attached_finalize_hint = finalize_hint;
2861
2862 if (result) return napi_create_reference(env, js_object, 0, result);
2863 return napi_set_last(env, napi_ok, NULL);
2864}
2865
2866NAPI_EXTERN napi_status NAPI_CDECL napi_unwrap(
2867 napi_env env,
2868 napi_value js_object,
2869 void **result
2870) {
2871 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2872 if (!nenv || !nenv->js || !result || !is_object_type((ant_value_t)js_object)) {
2873 return napi_set_last(env, napi_invalid_arg, "invalid argument");
2874 }
2875 napi_wrap_entry_t *entry = napi_find_wrap(nenv->js, js_object);
2876 if (!entry || !entry->has_wrap) return napi_set_last(env, napi_invalid_arg, "object not wrapped");
2877 *result = entry->native_object;
2878 return napi_set_last(env, napi_ok, NULL);
2879}
2880
2881NAPI_EXTERN napi_status NAPI_CDECL napi_remove_wrap(
2882 napi_env env,
2883 napi_value js_object,
2884 void **result
2885) {
2886 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2887 if (!nenv || !nenv->js || !is_object_type((ant_value_t)js_object)) {
2888 return napi_set_last(env, napi_invalid_arg, "invalid argument");
2889 }
2890
2891 napi_wrap_entry_t *entry = napi_find_wrap(nenv->js, js_object);
2892 if (!entry || !entry->has_wrap) return napi_set_last(env, napi_invalid_arg, "object not wrapped");
2893
2894 if (result) *result = entry->native_object;
2895 entry->native_object = NULL;
2896 entry->finalize_cb = NULL;
2897 entry->finalize_hint = NULL;
2898 entry->has_wrap = false;
2899
2900 if (!entry->attached_finalize_cb) {
2901 HASH_DEL(g_napi_wraps, entry);
2902 free(entry);
2903 js_set_slot((ant_value_t)js_object, SLOT_NAPI_WRAP_ID, js_mkundef());
2904 }
2905 return napi_set_last(env, napi_ok, NULL);
2906}
2907
2908NAPI_EXTERN napi_status NAPI_CDECL napi_open_handle_scope(
2909 napi_env env,
2910 napi_handle_scope *result
2911) {
2912 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2913 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
2914 struct napi_handle_scope__ *scope = (struct napi_handle_scope__ *)calloc(1, sizeof(*scope));
2915 if (!scope) return napi_set_last(env, napi_generic_failure, "out of memory");
2916 scope->env = nenv;
2917 scope->gc_root_mark = gc_root_scope(nenv->js);
2918 scope->handle_slots_mark = nenv->handle_slots_len;
2919 nenv->open_handle_scopes++;
2920 *result = (napi_handle_scope)scope;
2921 return napi_set_last(env, napi_ok, NULL);
2922}
2923
2924NAPI_EXTERN napi_status NAPI_CDECL napi_close_handle_scope(
2925 napi_env env,
2926 napi_handle_scope scope
2927) {
2928 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2929 if (!nenv || !scope) return napi_set_last(env, napi_invalid_arg, "invalid argument");
2930 struct napi_handle_scope__ *s = (struct napi_handle_scope__ *)scope;
2931 if (nenv->js) gc_pop_roots(nenv->js, s->gc_root_mark);
2932 nenv->handle_slots_len = s->handle_slots_mark;
2933 if (nenv->open_handle_scopes > 0) nenv->open_handle_scopes--;
2934 free(scope);
2935 return napi_set_last(env, napi_ok, NULL);
2936}
2937
2938NAPI_EXTERN napi_status NAPI_CDECL napi_open_escapable_handle_scope(
2939 napi_env env,
2940 napi_escapable_handle_scope *result
2941) {
2942 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2943 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
2944 struct napi_escapable_handle_scope__ *scope = (struct napi_escapable_handle_scope__ *)calloc(1, sizeof(*scope));
2945 if (!scope) return napi_set_last(env, napi_generic_failure, "out of memory");
2946 scope->env = nenv;
2947 scope->gc_root_mark = gc_root_scope(nenv->js);
2948 scope->handle_slots_mark = nenv->handle_slots_len;
2949 scope->escaped = false;
2950 scope->escaped_val = js_mkundef();
2951 nenv->open_handle_scopes++;
2952 *result = (napi_escapable_handle_scope)scope;
2953 return napi_set_last(env, napi_ok, NULL);
2954}
2955
2956NAPI_EXTERN napi_status NAPI_CDECL napi_close_escapable_handle_scope(
2957 napi_env env,
2958 napi_escapable_handle_scope scope
2959) {
2960 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2961 if (!nenv || !scope) return napi_set_last(env, napi_invalid_arg, "invalid argument");
2962 struct napi_escapable_handle_scope__ *s = (struct napi_escapable_handle_scope__ *)scope;
2963 if (nenv->js) gc_pop_roots(nenv->js, s->gc_root_mark);
2964 nenv->handle_slots_len = s->handle_slots_mark;
2965 if (nenv->open_handle_scopes > 0) nenv->open_handle_scopes--;
2966 free(scope);
2967 return napi_set_last(env, napi_ok, NULL);
2968}
2969
2970NAPI_EXTERN napi_status NAPI_CDECL napi_escape_handle(
2971 napi_env env,
2972 napi_escapable_handle_scope scope,
2973 napi_value escapee,
2974 napi_value *result
2975) {
2976 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2977 struct napi_escapable_handle_scope__ *esc = (struct napi_escapable_handle_scope__ *)scope;
2978 if (!nenv || !nenv->js || !esc || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
2979 if (esc->escaped) return napi_set_last(env, napi_escape_called_twice, "escape already called");
2980 esc->escaped = true;
2981 esc->escaped_val = (ant_value_t)escapee;
2982 gc_push_root(nenv->js, &esc->escaped_val);
2983 *result = escapee;
2984 return napi_set_last(env, napi_ok, NULL);
2985}
2986
2987NAPI_EXTERN napi_status NAPI_CDECL napi_create_async_work(
2988 napi_env env,
2989 napi_value async_resource,
2990 napi_value async_resource_name,
2991 napi_async_execute_callback execute,
2992 napi_async_complete_callback complete,
2993 void *data,
2994 napi_async_work *result
2995) {
2996 (void)async_resource;
2997 (void)async_resource_name;
2998 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
2999 if (!nenv || !nenv->js || !execute || !result) {
3000 return napi_set_last(env, napi_invalid_arg, "invalid argument");
3001 }
3002
3003 napi_async_work_impl_t *work = (napi_async_work_impl_t *)calloc(1, sizeof(*work));
3004 if (!work) return napi_set_last(env, napi_generic_failure, "out of memory");
3005
3006 work->env = nenv;
3007 work->execute = execute;
3008 work->complete = complete;
3009 work->data = data;
3010 work->req.data = work;
3011
3012 *result = (napi_async_work)work;
3013 return napi_set_last(env, napi_ok, NULL);
3014}
3015
3016NAPI_EXTERN napi_status NAPI_CDECL napi_delete_async_work(
3017 napi_env env,
3018 napi_async_work work
3019) {
3020 (void)env;
3021 napi_async_work_impl_t *w = (napi_async_work_impl_t *)work;
3022 if (!w) return napi_set_last(env, napi_invalid_arg, "invalid argument");
3023 if (w->queued) {
3024 w->delete_after_complete = true;
3025 return napi_set_last(env, napi_ok, NULL);
3026 }
3027 free(w);
3028 return napi_set_last(env, napi_ok, NULL);
3029}
3030
3031NAPI_EXTERN napi_status NAPI_CDECL napi_queue_async_work(
3032 node_api_basic_env env,
3033 napi_async_work work
3034) {
3035 napi_async_work_impl_t *w = (napi_async_work_impl_t *)work;
3036 if (!env || !w) return napi_set_last((napi_env)env, napi_invalid_arg, "invalid argument");
3037 if (w->queued) return napi_set_last((napi_env)env, napi_invalid_arg, "already queued");
3038
3039 int rc = uv_queue_work(uv_default_loop(), &w->req, napi_async_work_execute_cb, napi_async_work_after_cb);
3040 if (rc != 0) return napi_set_last((napi_env)env, napi_generic_failure, "uv_queue_work failed");
3041 w->queued = true;
3042 return napi_set_last((napi_env)env, napi_ok, NULL);
3043}
3044
3045NAPI_EXTERN napi_status NAPI_CDECL napi_cancel_async_work(
3046 node_api_basic_env env,
3047 napi_async_work work
3048) {
3049 napi_async_work_impl_t *w = (napi_async_work_impl_t *)work;
3050 if (!env || !w) return napi_set_last((napi_env)env, napi_invalid_arg, "invalid argument");
3051 int rc = uv_cancel((uv_req_t *)&w->req);
3052 if (rc != 0) return napi_set_last((napi_env)env, napi_generic_failure, "uv_cancel failed");
3053 return napi_set_last((napi_env)env, napi_ok, NULL);
3054}
3055
3056NAPI_EXTERN napi_status NAPI_CDECL napi_create_threadsafe_function(
3057 napi_env env,
3058 napi_value func,
3059 napi_value async_resource,
3060 napi_value async_resource_name,
3061 size_t max_queue_size,
3062 size_t initial_thread_count,
3063 void *thread_finalize_data,
3064 napi_finalize thread_finalize_cb,
3065 void *context,
3066 napi_threadsafe_function_call_js call_js_cb,
3067 napi_threadsafe_function *result
3068) {
3069 (void)async_resource;
3070 (void)async_resource_name;
3071 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
3072 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
3073
3074 struct napi_threadsafe_function__ *tsfn =
3075 (struct napi_threadsafe_function__ *)calloc(1, sizeof(*tsfn));
3076 if (!tsfn) return napi_set_last(env, napi_generic_failure, "out of memory");
3077
3078 tsfn->env = nenv;
3079 tsfn->call_js_cb = call_js_cb;
3080 tsfn->thread_finalize_cb = thread_finalize_cb;
3081 tsfn->thread_finalize_data = thread_finalize_data;
3082 tsfn->context = context;
3083 tsfn->max_queue_size = max_queue_size;
3084 tsfn->thread_count = initial_thread_count > 0 ? initial_thread_count : 1;
3085 tsfn->func_val = func ? (ant_value_t)func : js_mkundef();
3086
3087 uv_mutex_init(&tsfn->mutex);
3088 int rc = uv_async_init(uv_default_loop(), &tsfn->async, napi_tsfn_async_cb);
3089 if (rc != 0) {
3090 uv_mutex_destroy(&tsfn->mutex);
3091 free(tsfn);
3092 return napi_set_last(env, napi_generic_failure, "uv_async_init failed");
3093 }
3094 tsfn->async.data = tsfn;
3095
3096 tsfn->prev = NULL;
3097 tsfn->next = nenv->tsfns;
3098 if (nenv->tsfns) nenv->tsfns->prev = tsfn;
3099 nenv->tsfns = tsfn;
3100
3101 *result = (napi_threadsafe_function)tsfn;
3102 return napi_set_last(env, napi_ok, NULL);
3103}
3104
3105NAPI_EXTERN napi_status NAPI_CDECL napi_call_threadsafe_function(
3106 napi_threadsafe_function func,
3107 void *data,
3108 napi_threadsafe_function_call_mode is_blocking
3109) {
3110 (void)is_blocking;
3111 struct napi_threadsafe_function__ *tsfn = (struct napi_threadsafe_function__ *)func;
3112 if (!tsfn) return napi_invalid_arg;
3113
3114 uv_mutex_lock(&tsfn->mutex);
3115 if (tsfn->closing || tsfn->aborted) {
3116 uv_mutex_unlock(&tsfn->mutex);
3117 return napi_closing;
3118 }
3119 if (tsfn->max_queue_size > 0 && tsfn->queue_size >= tsfn->max_queue_size) {
3120 uv_mutex_unlock(&tsfn->mutex);
3121 return napi_queue_full;
3122 }
3123
3124 napi_tsfn_item_t *item = (napi_tsfn_item_t *)calloc(1, sizeof(*item));
3125 if (!item) {
3126 uv_mutex_unlock(&tsfn->mutex);
3127 return napi_generic_failure;
3128 }
3129 item->data = data;
3130 if (!tsfn->head) tsfn->head = item;
3131 else tsfn->tail->next = item;
3132 tsfn->tail = item;
3133 tsfn->queue_size++;
3134 uv_mutex_unlock(&tsfn->mutex);
3135
3136 uv_async_send(&tsfn->async);
3137 return napi_ok;
3138}
3139
3140NAPI_EXTERN napi_status NAPI_CDECL napi_release_threadsafe_function(
3141 napi_threadsafe_function func,
3142 napi_threadsafe_function_release_mode mode
3143) {
3144 struct napi_threadsafe_function__ *tsfn = (struct napi_threadsafe_function__ *)func;
3145 if (!tsfn) return napi_invalid_arg;
3146
3147 uv_mutex_lock(&tsfn->mutex);
3148 if (mode == napi_tsfn_abort) tsfn->aborted = true;
3149 if (tsfn->thread_count > 0) tsfn->thread_count--;
3150 if (tsfn->thread_count == 0 || tsfn->aborted) tsfn->closing = true;
3151 uv_mutex_unlock(&tsfn->mutex);
3152
3153 uv_async_send(&tsfn->async);
3154 return napi_ok;
3155}
3156
3157NAPI_EXTERN napi_status NAPI_CDECL napi_acquire_threadsafe_function(
3158 napi_threadsafe_function func
3159) {
3160 struct napi_threadsafe_function__ *tsfn = (struct napi_threadsafe_function__ *)func;
3161 if (!tsfn) return napi_invalid_arg;
3162 uv_mutex_lock(&tsfn->mutex);
3163 if (tsfn->closing) {
3164 uv_mutex_unlock(&tsfn->mutex);
3165 return napi_closing;
3166 }
3167 tsfn->thread_count++;
3168 uv_mutex_unlock(&tsfn->mutex);
3169 return napi_ok;
3170}
3171
3172NAPI_EXTERN napi_status NAPI_CDECL napi_ref_threadsafe_function(
3173 node_api_basic_env env,
3174 napi_threadsafe_function func
3175) {
3176 (void)env;
3177 struct napi_threadsafe_function__ *tsfn = (struct napi_threadsafe_function__ *)func;
3178 if (!tsfn) return napi_invalid_arg;
3179 uv_ref((uv_handle_t *)&tsfn->async);
3180 return napi_ok;
3181}
3182
3183NAPI_EXTERN napi_status NAPI_CDECL napi_unref_threadsafe_function(
3184 node_api_basic_env env,
3185 napi_threadsafe_function func
3186) {
3187 (void)env;
3188 struct napi_threadsafe_function__ *tsfn = (struct napi_threadsafe_function__ *)func;
3189 if (!tsfn) return napi_invalid_arg;
3190 uv_unref((uv_handle_t *)&tsfn->async);
3191 return napi_ok;
3192}
3193
3194NAPI_EXTERN napi_status NAPI_CDECL napi_get_threadsafe_function_context(
3195 napi_threadsafe_function func,
3196 void **result
3197) {
3198 struct napi_threadsafe_function__ *tsfn = (struct napi_threadsafe_function__ *)func;
3199 if (!tsfn || !result) return napi_invalid_arg;
3200 *result = tsfn->context;
3201 return napi_ok;
3202}
3203
3204NAPI_EXTERN napi_status NAPI_CDECL napi_run_script(
3205 napi_env env,
3206 napi_value script,
3207 napi_value *result
3208) {
3209 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
3210 if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
3211 if (vtype((ant_value_t)script) != T_STR) return napi_set_last(env, napi_string_expected, "script must be string");
3212
3213 size_t len = 0;
3214 const char *src = js_getstr(nenv->js, (ant_value_t)script, &len);
3215 if (!src) return napi_set_last(env, napi_string_expected, "script must be string");
3216
3217 ant_value_t out = js_eval_bytecode_eval(nenv->js, src, len);
3218 if (is_err(out) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, out);
3219 *result = NAPI_RETURN(nenv, out);
3220 return napi_set_last(env, napi_ok, NULL);
3221}
3222
3223NAPI_EXTERN napi_status NAPI_CDECL napi_adjust_external_memory(
3224 node_api_basic_env env,
3225 int64_t change_in_bytes,
3226 int64_t *adjusted_value
3227) {
3228 if (!env) return napi_invalid_arg;
3229 g_napi_external_memory += change_in_bytes;
3230 if (adjusted_value) *adjusted_value = g_napi_external_memory;
3231 return napi_set_last((napi_env)env, napi_ok, NULL);
3232}
3233
3234NAPI_EXTERN napi_status NAPI_CDECL napi_add_env_cleanup_hook(
3235 node_api_basic_env env,
3236 napi_cleanup_hook fun,
3237 void *arg
3238) {
3239 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
3240 if (!nenv || !fun) return napi_set_last((napi_env)env, napi_invalid_arg, "invalid argument");
3241
3242 napi_cleanup_hook_entry_t *entry = (napi_cleanup_hook_entry_t *)calloc(1, sizeof(*entry));
3243 if (!entry) return napi_set_last((napi_env)env, napi_generic_failure, "out of memory");
3244 entry->hook = fun;
3245 entry->arg = arg;
3246 entry->next = nenv->cleanup_hooks;
3247 nenv->cleanup_hooks = entry;
3248 return napi_set_last((napi_env)env, napi_ok, NULL);
3249}
3250
3251NAPI_EXTERN napi_status NAPI_CDECL napi_remove_env_cleanup_hook(
3252 node_api_basic_env env,
3253 napi_cleanup_hook fun,
3254 void *arg
3255) {
3256 ant_napi_env_t *nenv = (ant_napi_env_t *)env;
3257 if (!nenv || !fun) return napi_set_last((napi_env)env, napi_invalid_arg, "invalid argument");
3258
3259 napi_cleanup_hook_entry_t **pp = &nenv->cleanup_hooks;
3260 while (*pp) {
3261 if ((*pp)->hook == fun && (*pp)->arg == arg) {
3262 napi_cleanup_hook_entry_t *victim = *pp;
3263 *pp = victim->next;
3264 free(victim);
3265 return napi_set_last((napi_env)env, napi_ok, NULL);
3266 }
3267 pp = &(*pp)->next;
3268 }
3269 return napi_set_last((napi_env)env, napi_invalid_arg, "cleanup hook not found");
3270}
3271
3272NAPI_EXTERN napi_status NAPI_CDECL napi_open_callback_scope(
3273 napi_env env,
3274 napi_value resource_object,
3275 napi_async_context context,
3276 napi_callback_scope *result
3277) {
3278 (void)resource_object;
3279 (void)context;
3280 if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
3281 struct napi_callback_scope__ *scope = (struct napi_callback_scope__ *)calloc(1, sizeof(*scope));
3282 if (!scope) return napi_set_last(env, napi_generic_failure, "out of memory");
3283 scope->env = (ant_napi_env_t *)env;
3284 *result = (napi_callback_scope)scope;
3285 return napi_set_last(env, napi_ok, NULL);
3286}
3287
3288NAPI_EXTERN napi_status NAPI_CDECL napi_close_callback_scope(
3289 napi_env env,
3290 napi_callback_scope scope
3291) {
3292 (void)env;
3293 if (!scope) return napi_set_last(env, napi_invalid_arg, "invalid argument");
3294 free(scope);
3295 return napi_set_last(env, napi_ok, NULL);
3296}
3297
3298NAPI_EXTERN napi_status NAPI_CDECL napi_async_init(
3299 napi_env env,
3300 napi_value async_resource,
3301 napi_value async_resource_name,
3302 napi_async_context *result
3303) {
3304 (void)async_resource;
3305 (void)async_resource_name;
3306 if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
3307 struct napi_async_context__ *ctx = (struct napi_async_context__ *)calloc(1, sizeof(*ctx));
3308 if (!ctx) return napi_set_last(env, napi_generic_failure, "out of memory");
3309 ctx->env = (ant_napi_env_t *)env;
3310 *result = (napi_async_context)ctx;
3311 return napi_set_last(env, napi_ok, NULL);
3312}
3313
3314NAPI_EXTERN napi_status NAPI_CDECL napi_async_destroy(
3315 napi_env env,
3316 napi_async_context async_context
3317) {
3318 (void)env;
3319 if (!async_context) return napi_set_last(env, napi_invalid_arg, "invalid argument");
3320 free(async_context);
3321 return napi_set_last(env, napi_ok, NULL);
3322}
3323
3324NAPI_EXTERN napi_status NAPI_CDECL napi_make_callback(
3325 napi_env env,
3326 napi_async_context async_context,
3327 napi_value recv,
3328 napi_value func,
3329 size_t argc,
3330 const napi_value *argv,
3331 napi_value *result
3332) {
3333 (void)async_context;
3334 return napi_call_function(env, recv, func, argc, argv, result);
3335}
3336
3337NAPI_EXTERN void NAPI_CDECL napi_module_register(napi_module *mod) {
3338 g_pending_napi_module = mod;
3339}
3340
3341NAPI_EXTERN napi_status NAPI_CDECL napi_get_uv_event_loop(
3342 node_api_basic_env env,
3343 struct uv_loop_s **loop
3344) {
3345 if (!env || !loop) return napi_set_last((napi_env)env, napi_invalid_arg, "invalid argument");
3346 *loop = uv_default_loop();
3347 return napi_set_last((napi_env)env, napi_ok, NULL);
3348}