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