MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at mir/inline-method 3328 lines 110 kB view raw
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}