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