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 3118 lines 121 kB view raw
1#include <stdlib.h> 2#include <stdio.h> 3#include <string.h> 4#include <ctype.h> 5 6#include "ant.h" 7#include "ptr.h" 8#include "utf8.h" 9#include "utils.h" 10#include "errors.h" 11#include "base64.h" 12#include "internal.h" 13#include "runtime.h" 14#include "gc/roots.h" 15#include "descriptors.h" 16 17#include "silver/engine.h" 18#include "modules/bigint.h" 19#include "modules/buffer.h" 20#include "modules/symbol.h" 21 22#define BUFFER_REGISTRY_INITIAL_CAP 64 23 24// Node compatibility exports only 25// Ant does not enforce these as allocation limits 26#define BUFFER_COMPAT_MAX_LENGTH 4294967296.0 27#define BUFFER_COMPAT_MAX_STRING_LENGTH 536870888.0 28#define BUFFER_COMPAT_INSPECT_MAX_BYTES 50.0 29 30static size_t ta_metadata_bytes = 0; 31static size_t buffer_registry_count = 0; 32static size_t buffer_registry_cap = 0; 33 34static ArrayBufferData **buffer_registry = NULL; 35static ant_value_t g_typedarray_iter_proto = 0; 36 37enum { 38 BUFFER_ARRAYBUFFER_NATIVE_TAG = 0x41425546u, // ABUF 39 BUFFER_TYPEDARRAY_NATIVE_TAG = 0x54594152u, // TYAR 40 BUFFER_DATAVIEW_NATIVE_TAG = 0x44564957u, // DVIW 41}; 42 43static void *ta_meta_alloc(size_t size) { 44 void *ptr = ant_calloc(size); 45 if (!ptr) return NULL; 46 ta_metadata_bytes += size; 47 return ptr; 48} 49 50static void ta_meta_free(void *ptr, size_t size) { 51 if (!ptr) return; 52 if (ta_metadata_bytes >= size) ta_metadata_bytes -= size; 53 else ta_metadata_bytes = 0; 54 free(ptr); 55} 56 57ArrayBufferData *buffer_get_arraybuffer_data(ant_value_t value) { 58 if (!is_object_type(value) || buffer_is_dataview(value)) return NULL; 59 return (ArrayBufferData *)js_get_native(value, BUFFER_ARRAYBUFFER_NATIVE_TAG); 60} 61 62TypedArrayData *buffer_get_typedarray_data(ant_value_t value) { 63 if (vtype(value) == T_TYPEDARRAY) 64 return (TypedArrayData *)js_gettypedarray(value); 65 if (!is_object_type(value)) return NULL; 66 return (TypedArrayData *)js_get_native(value, BUFFER_TYPEDARRAY_NATIVE_TAG); 67} 68 69DataViewData *buffer_get_dataview_data(ant_value_t value) { 70 if (!is_object_type(value)) return NULL; 71 return (DataViewData *)js_get_native(value, BUFFER_DATAVIEW_NATIVE_TAG); 72} 73 74static void arraybuffer_finalize(ant_t *js, ant_object_t *obj) { 75 ant_value_t value = js_obj_from_ptr(obj); 76 ArrayBufferData *data = (ArrayBufferData *)js_get_native(value, BUFFER_ARRAYBUFFER_NATIVE_TAG); 77 if (!data) return; 78 js_clear_native(value, BUFFER_ARRAYBUFFER_NATIVE_TAG); 79 free_array_buffer_data(data); 80} 81 82static void typedarray_finalize(ant_t *js, ant_object_t *obj) { 83 ant_value_t value = js_obj_from_ptr(obj); 84 TypedArrayData *ta_data = (TypedArrayData *)js_get_native(value, BUFFER_TYPEDARRAY_NATIVE_TAG); 85 if (!ta_data) return; 86 js_clear_native(value, BUFFER_TYPEDARRAY_NATIVE_TAG); 87 88 if (ta_data->buffer) free_array_buffer_data(ta_data->buffer); 89 ta_meta_free(ta_data, sizeof(*ta_data)); 90} 91 92static void dataview_finalize(ant_t *js, ant_object_t *obj) { 93 ant_value_t value = js_obj_from_ptr(obj); 94 DataViewData *dv_data = (DataViewData *)js_get_native(value, BUFFER_DATAVIEW_NATIVE_TAG); 95 if (!dv_data) return; 96 js_clear_native(value, BUFFER_DATAVIEW_NATIVE_TAG); 97 98 if (dv_data->buffer) free_array_buffer_data(dv_data->buffer); 99 ta_meta_free(dv_data, sizeof(*dv_data)); 100} 101 102bool buffer_is_dataview(ant_value_t obj) { 103 return js_check_brand(obj, BRAND_DATAVIEW); 104} 105 106bool buffer_is_binary_source(ant_value_t value) { 107 if (vtype(value) == T_TYPEDARRAY) return true; 108 if (!is_object_type(value)) return false; 109 if (buffer_is_dataview(value)) return true; 110 return buffer_get_typedarray_data(value) != NULL || buffer_get_arraybuffer_data(value) != NULL; 111} 112 113bool buffer_source_get_bytes(ant_t *js, ant_value_t value, const uint8_t **out, size_t *len) { 114 if (out) *out = NULL; 115 if (len) *len = 0; 116 if (!buffer_is_binary_source(value)) return false; 117 118 TypedArrayData *ta = buffer_get_typedarray_data(value); 119 120 if (ta) { 121 if (!ta->buffer || ta->buffer->is_detached) { *out = NULL; *len = 0; return true; } 122 *out = ta->buffer->data + ta->byte_offset; 123 *len = ta->byte_length; 124 return true; 125 } 126 127 ArrayBufferData *ab = buffer_get_arraybuffer_data(value); 128 if (ab) { 129 if (ab->is_detached) { *out = NULL; *len = 0; return true; } 130 *out = ab->data; 131 *len = ab->length; 132 return true; 133 } 134 135 if (buffer_is_dataview(value)) { 136 DataViewData *dv = buffer_get_dataview_data(value); 137 if (!dv || !dv->buffer || dv->buffer->is_detached) { *out = NULL; *len = 0; return true; } 138 *out = dv->buffer->data + dv->byte_offset; 139 *len = dv->byte_length; 140 return true; 141 } 142 143 return false; 144} 145 146static bool typedarray_read_value(ant_t *js, const TypedArrayData *ta_data, size_t index, ant_value_t *out) { 147 if (!out || !ta_data || !ta_data->buffer || ta_data->buffer->is_detached || index >= ta_data->length) { 148 return false; 149 } 150 151 uint8_t *data = ta_data->buffer->data + ta_data->byte_offset; 152 switch (ta_data->type) { 153 case TYPED_ARRAY_INT8: *out = js_mknum((double)((int8_t *)data)[index]); return true; 154 case TYPED_ARRAY_UINT8: 155 case TYPED_ARRAY_UINT8_CLAMPED: *out = js_mknum((double)data[index]); return true; 156 case TYPED_ARRAY_INT16: *out = js_mknum((double)((int16_t *)data)[index]); return true; 157 case TYPED_ARRAY_UINT16: *out = js_mknum((double)((uint16_t *)data)[index]); return true; 158 case TYPED_ARRAY_INT32: *out = js_mknum((double)((int32_t *)data)[index]); return true; 159 case TYPED_ARRAY_UINT32: *out = js_mknum((double)((uint32_t *)data)[index]); return true; 160 case TYPED_ARRAY_FLOAT16: *out = js_mknum(half_to_double(((uint16_t *)data)[index])); return true; 161 case TYPED_ARRAY_FLOAT32: *out = js_mknum((double)((float *)data)[index]); return true; 162 case TYPED_ARRAY_FLOAT64: *out = js_mknum(((double *)data)[index]); return true; 163 case TYPED_ARRAY_BIGINT64: *out = bigint_from_int64(js, ((int64_t *)data)[index]); return !is_err(*out); 164 case TYPED_ARRAY_BIGUINT64: *out = bigint_from_uint64(js, ((uint64_t *)data)[index]); return !is_err(*out); 165 default: return false; 166 } 167} 168 169static bool advance_typedarray(ant_t *js, js_iter_t *it, ant_value_t *out) { 170 ant_value_t iter = it->iterator; 171 ant_value_t ta_obj = js_get_slot(iter, SLOT_DATA); 172 ant_value_t state_v = js_get_slot(iter, SLOT_ITER_STATE); 173 uint32_t state = (vtype(state_v) == T_NUM) ? (uint32_t)js_getnum(state_v) : 0; 174 175 uint32_t kind = ITER_STATE_KIND(state); 176 uint32_t idx = ITER_STATE_INDEX(state); 177 178 TypedArrayData *ta = buffer_get_typedarray_data(ta_obj); 179 if (!ta || !ta->buffer || ta->buffer->is_detached || idx >= (uint32_t)ta->length) return false; 180 181 ant_value_t value; 182 if (!typedarray_read_value(js, ta, idx, &value)) return false; 183 184 switch (kind) { 185 case ARR_ITER_KEYS: 186 *out = js_mknum((double)idx); 187 break; 188 case ARR_ITER_ENTRIES: { 189 ant_value_t pair = js_mkarr(js); 190 js_arr_push(js, pair, js_mknum((double)idx)); 191 js_arr_push(js, pair, value); 192 *out = pair; 193 break; 194 } 195 default: 196 *out = value; 197 break; 198 } 199 200 js_set_slot(iter, SLOT_ITER_STATE, js_mknum((double)ITER_STATE_PACK(kind, idx + 1))); 201 return true; 202} 203 204static ant_value_t ta_iter_next(ant_t *js, ant_value_t *args, int nargs) { 205 js_iter_t it = { .iterator = js->this_val }; 206 ant_value_t value; 207 return js_iter_result(js, advance_typedarray(js, &it, &value), value); 208} 209 210static ant_value_t ta_values(ant_t *js, ant_value_t *args, int nargs) { 211 ant_value_t iter = js_mkobj(js); 212 js_set_slot_wb(js, iter, SLOT_DATA, js->this_val); 213 js_set_slot(iter, SLOT_ITER_STATE, js_mknum((double)ITER_STATE_PACK(ARR_ITER_VALUES, 0))); 214 js_set_proto_init(iter, g_typedarray_iter_proto); 215 return iter; 216} 217 218static ant_value_t ta_keys(ant_t *js, ant_value_t *args, int nargs) { 219 ant_value_t iter = js_mkobj(js); 220 js_set_slot_wb(js, iter, SLOT_DATA, js->this_val); 221 js_set_slot(iter, SLOT_ITER_STATE, js_mknum((double)ITER_STATE_PACK(ARR_ITER_KEYS, 0))); 222 js_set_proto_init(iter, g_typedarray_iter_proto); 223 return iter; 224} 225 226static ant_value_t ta_entries(ant_t *js, ant_value_t *args, int nargs) { 227 ant_value_t iter = js_mkobj(js); 228 js_set_slot_wb(js, iter, SLOT_DATA, js->this_val); 229 js_set_slot(iter, SLOT_ITER_STATE, js_mknum((double)ITER_STATE_PACK(ARR_ITER_ENTRIES, 0))); 230 js_set_proto_init(iter, g_typedarray_iter_proto); 231 return iter; 232} 233 234static void register_buffer(ArrayBufferData *data) { 235 if (!data) return; 236 237 if (!buffer_registry) { 238 buffer_registry = calloc(BUFFER_REGISTRY_INITIAL_CAP, sizeof(ArrayBufferData *)); 239 if (!buffer_registry) return; 240 buffer_registry_cap = BUFFER_REGISTRY_INITIAL_CAP; 241 } 242 243 if (buffer_registry_count >= buffer_registry_cap) { 244 size_t new_cap = buffer_registry_cap * 2; 245 ArrayBufferData **new_reg = realloc(buffer_registry, new_cap * sizeof(ArrayBufferData *)); 246 if (!new_reg) return; 247 buffer_registry = new_reg; 248 buffer_registry_cap = new_cap; 249 } 250 251 buffer_registry[buffer_registry_count++] = data; 252} 253 254static void unregister_buffer(ArrayBufferData *data) { 255 if (!data || !buffer_registry) return; 256 257 for (size_t i = 0; i < buffer_registry_count; i++) { 258 if (buffer_registry[i] == data) { 259 buffer_registry[i] = buffer_registry[--buffer_registry_count]; 260 return; 261 }} 262} 263 264static inline ssize_t normalize_index(ssize_t idx, ssize_t len) { 265 if (idx < 0) idx += len; 266 if (idx < 0) return 0; 267 if (idx > len) return len; 268 return idx; 269} 270 271ArrayBufferData *create_array_buffer_data(size_t length) { 272 ArrayBufferData *data = ant_calloc(sizeof(ArrayBufferData) + length); 273 if (!data) return NULL; 274 275 data->data = (uint8_t *)(data + 1); 276 memset(data->data, 0, length); 277 278 data->length = length; 279 data->capacity = length; 280 data->ref_count = 1; 281 data->is_shared = 0; 282 data->is_detached = 0; 283 284 register_buffer(data); 285 return data; 286} 287 288static ArrayBufferData *create_shared_array_buffer_data(size_t length) { 289 ArrayBufferData *data = create_array_buffer_data(length); 290 if (data) data->is_shared = 1; 291 return data; 292} 293 294void free_array_buffer_data(ArrayBufferData *data) { 295 if (!data) return; 296 data->ref_count--; 297 if (data->ref_count <= 0) { 298 unregister_buffer(data); 299 free(data); 300 } 301} 302 303static size_t get_element_size(TypedArrayType type) { 304 static const void *dispatch[] = { 305 &&L_1, &&L_1, &&L_1, &&L_2, &&L_2, 306 &&L_4, &&L_4, &&L_2, &&L_4, &&L_8, &&L_8, &&L_8 307 }; 308 309 if (type > TYPED_ARRAY_BIGUINT64) goto L_1; 310 goto *dispatch[type]; 311 312 L_1: return 1; 313 L_2: return 2; 314 L_4: return 4; 315 L_8: return 8; 316} 317 318const char *buffer_typedarray_type_name(TypedArrayType type) { 319 static const char *const names[] = { 320 "Int8Array", 321 "Uint8Array", 322 "Uint8ClampedArray", 323 "Int16Array", 324 "Uint16Array", 325 "Int32Array", 326 "Uint32Array", 327 "Float16Array", 328 "Float32Array", 329 "Float64Array", 330 "BigInt64Array", 331 "BigUint64Array", 332 }; 333 334 int i = (int)type; 335 if (i < 0 || i >= (int)(sizeof(names) / sizeof(names[0]))) return "Uint8Array"; 336 return names[i]; 337} 338 339static ant_value_t create_typed_array_like( 340 ant_t *js, 341 ant_value_t this_val, 342 TypedArrayType type, 343 ArrayBufferData *buffer, 344 size_t byte_offset, 345 size_t length 346) { 347 ant_value_t ab_obj = create_arraybuffer_obj(js, buffer); 348 ant_value_t out = create_typed_array_with_buffer( 349 js,type, buffer, byte_offset, 350 length, buffer_typedarray_type_name(type), ab_obj 351 ); 352 353 if (is_err(out)) return out; 354 ant_value_t proto = js_get_proto(js, this_val); 355 if (is_special_object(proto)) js_set_proto_init(out, proto); 356 357 return out; 358} 359 360static ant_value_t js_arraybuffer_constructor(ant_t *js, ant_value_t *args, int nargs) { 361 if (vtype(js->new_target) == T_UNDEF) { 362 return js_mkerr_typed(js, JS_ERR_TYPE, "ArrayBuffer constructor requires 'new'"); 363 } 364 size_t length = 0; 365 if (nargs > 0 && vtype(args[0]) == T_NUM) { 366 length = (size_t)js_getnum(args[0]); 367 } 368 369 ArrayBufferData *data = create_array_buffer_data(length); 370 if (!data) { 371 return js_mkerr(js, "Failed to allocate ArrayBuffer"); 372 } 373 374 ant_value_t obj = js_mkobj(js); 375 ant_value_t proto = js_get_ctor_proto(js, "ArrayBuffer", 11); 376 377 if (is_special_object(proto)) js_set_proto_init(obj, proto); 378 js_set_native(obj, data, BUFFER_ARRAYBUFFER_NATIVE_TAG); 379 js_set(js, obj, "byteLength", js_mknum((double)length)); 380 js_set_finalizer(obj, arraybuffer_finalize); 381 382 return obj; 383} 384 385// ArrayBuffer.prototype.slice(begin, end) 386static ant_value_t js_arraybuffer_slice(ant_t *js, ant_value_t *args, int nargs) { 387 ant_value_t this_val = js_getthis(js); 388 ArrayBufferData *data = buffer_get_arraybuffer_data(this_val); 389 if (!data) return js_mkerr(js, "Invalid ArrayBuffer"); 390 if (data->is_detached) return js_mkerr(js, "Cannot slice a detached ArrayBuffer"); 391 392 ssize_t len = (ssize_t)data->length; 393 ssize_t begin = 0, end = len; 394 if (nargs > 0 && vtype(args[0]) == T_NUM) begin = (ssize_t)js_getnum(args[0]); 395 if (nargs > 1 && vtype(args[1]) == T_NUM) end = (ssize_t)js_getnum(args[1]); 396 397 begin = normalize_index(begin, len); 398 end = normalize_index(end, len); 399 if (end < begin) end = begin; 400 401 size_t new_length = (size_t)(end - begin); 402 ArrayBufferData *new_data = create_array_buffer_data(new_length); 403 if (!new_data) return js_mkerr(js, "Failed to allocate new ArrayBuffer"); 404 405 memcpy(new_data->data, data->data + begin, new_length); 406 407 ant_value_t new_obj = js_mkobj(js); 408 ant_value_t proto = js_get_ctor_proto(js, "ArrayBuffer", 11); 409 410 if (is_special_object(proto)) js_set_proto_init(new_obj, proto); 411 js_set_native(new_obj, new_data, BUFFER_ARRAYBUFFER_NATIVE_TAG); 412 js_set(js, new_obj, "byteLength", js_mknum((double)new_length)); 413 js_set_finalizer(new_obj, arraybuffer_finalize); 414 415 return new_obj; 416} 417 418// ArrayBuffer.prototype.transfer(newLength) 419static ant_value_t js_arraybuffer_transfer(ant_t *js, ant_value_t *args, int nargs) { 420 ant_value_t this_val = js_getthis(js); 421 ArrayBufferData *data = buffer_get_arraybuffer_data(this_val); 422 if (!data) return js_mkerr(js, "Invalid ArrayBuffer"); 423 424 if (data->is_detached) { 425 return js_mkerr(js, "Cannot transfer a detached ArrayBuffer"); 426 } 427 428 if (data->is_shared) { 429 return js_mkerr(js, "Cannot transfer a SharedArrayBuffer"); 430 } 431 432 size_t new_length = data->length; 433 if (nargs > 0 && vtype(args[0]) == T_NUM) { 434 new_length = (size_t)js_getnum(args[0]); 435 } 436 437 ArrayBufferData *new_data = create_array_buffer_data(new_length); 438 if (!new_data) return js_mkerr(js, "Failed to allocate new ArrayBuffer"); 439 440 size_t copy_length = data->length < new_length ? data->length : new_length; 441 memcpy(new_data->data, data->data, copy_length); 442 443 data->is_detached = 1; 444 data->length = 0; 445 js_set(js, this_val, "byteLength", js_mknum(0)); 446 447 ant_value_t new_obj = js_mkobj(js); 448 ant_value_t proto = js_get_ctor_proto(js, "ArrayBuffer", 11); 449 450 if (is_special_object(proto)) js_set_proto_init(new_obj, proto); 451 js_set_native(new_obj, new_data, BUFFER_ARRAYBUFFER_NATIVE_TAG); 452 js_set(js, new_obj, "byteLength", js_mknum((double)new_length)); 453 js_set_finalizer(new_obj, arraybuffer_finalize); 454 455 return new_obj; 456} 457 458// ArrayBuffer.prototype.transferToFixedLength(newLength) 459static ant_value_t js_arraybuffer_transferToFixedLength(ant_t *js, ant_value_t *args, int nargs) { 460 return js_arraybuffer_transfer(js, args, nargs); 461} 462 463// ArrayBuffer.prototype.detached getter 464static ant_value_t js_arraybuffer_detached_getter(ant_t *js, ant_value_t *args, int nargs) { 465 ant_value_t this_val = js_getthis(js); 466 ArrayBufferData *data = buffer_get_arraybuffer_data(this_val); 467 if (!data) return js_false; 468 469 return js_bool(data->is_detached); 470} 471 472static ant_value_t js_arraybuffer_byteLength_getter(ant_t *js, ant_value_t *args, int nargs) { 473 (void)args; (void)nargs; 474 ant_value_t this_val = js_getthis(js); 475 ArrayBufferData *data = buffer_get_arraybuffer_data(this_val); 476 if (!data || data->is_detached) return js_mknum(0); 477 return js_mknum((double)data->length); 478} 479 480// ArrayBuffer.isView(value) 481static ant_value_t js_arraybuffer_isView(ant_t *js, ant_value_t *args, int nargs) { 482 if (nargs < 1) return js_false; 483 return js_bool(buffer_is_dataview(args[0]) || buffer_get_typedarray_data(args[0]) != NULL); 484} 485 486static ant_value_t buffer_require_bigint_value(ant_t *js, ant_value_t value) { 487 if (vtype(value) == T_BIGINT) return value; 488 if (is_object_type(value)) { 489 ant_value_t primitive = js_get_slot(value, SLOT_PRIMITIVE); 490 if (vtype(primitive) == T_BIGINT) return primitive; 491 } 492 return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot convert to BigInt"); 493} 494 495static ant_value_t typedarray_write_value(ant_t *js, TypedArrayData *ta_data, size_t index, ant_value_t value) { 496 if (!ta_data || !ta_data->buffer || ta_data->buffer->is_detached || index >= ta_data->length) { 497 return js_mkundef(); 498 } 499 500 uint8_t *data = ta_data->buffer->data + ta_data->byte_offset; 501 switch (ta_data->type) { 502 case TYPED_ARRAY_INT8: ((int8_t *)data)[index] = (int8_t)js_to_number(js, value); return js_mkundef(); 503 case TYPED_ARRAY_UINT8: data[index] = (uint8_t)js_to_number(js, value); return js_mkundef(); 504 case TYPED_ARRAY_UINT8_CLAMPED: data[index] = (uint8_t)js_to_number(js, value); return js_mkundef(); 505 case TYPED_ARRAY_INT16: ((int16_t *)data)[index] = (int16_t)js_to_number(js, value); return js_mkundef(); 506 case TYPED_ARRAY_UINT16: ((uint16_t *)data)[index] = (uint16_t)js_to_number(js, value); return js_mkundef(); 507 case TYPED_ARRAY_INT32: ((int32_t *)data)[index] = (int32_t)js_to_number(js, value); return js_mkundef(); 508 case TYPED_ARRAY_UINT32: ((uint32_t *)data)[index] = (uint32_t)js_to_number(js, value); return js_mkundef(); 509 case TYPED_ARRAY_FLOAT16: ((uint16_t *)data)[index] = double_to_half(js_to_number(js, value)); return js_mkundef(); 510 case TYPED_ARRAY_FLOAT32: ((float *)data)[index] = (float)js_to_number(js, value); return js_mkundef(); 511 case TYPED_ARRAY_FLOAT64: ((double *)data)[index] = js_to_number(js, value); return js_mkundef(); 512 case TYPED_ARRAY_BIGINT64: { 513 ant_value_t bigint = buffer_require_bigint_value(js, value); 514 int64_t wrapped = 0; 515 if (is_err(bigint)) return bigint; 516 if (!bigint_to_int64_wrapping(js, bigint, &wrapped)) { 517 return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot convert to BigInt"); 518 } 519 ((int64_t *)data)[index] = wrapped; 520 return js_mkundef(); 521 } 522 case TYPED_ARRAY_BIGUINT64: { 523 ant_value_t bigint = buffer_require_bigint_value(js, value); 524 uint64_t wrapped = 0; 525 if (is_err(bigint)) return bigint; 526 if (!bigint_to_uint64_wrapping(js, bigint, &wrapped)) { 527 return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot convert to BigInt"); 528 } 529 ((uint64_t *)data)[index] = wrapped; 530 return js_mkundef(); 531 } 532 default: 533 return js_mkundef(); 534 } 535} 536 537static ant_value_t typedarray_index_getter(ant_t *js, ant_value_t obj, const char *key, size_t key_len) { 538 if (key_len == 0 || key_len > 10) return js_mkundef(); 539 540 size_t index = 0; 541 for (size_t i = 0; i < key_len; i++) { 542 char c = key[i]; 543 if (c < '0' || c > '9') return js_mkundef(); 544 index = index * 10 + (c - '0'); 545 } 546 547 TypedArrayData *ta_data = buffer_get_typedarray_data(obj); 548 if (!ta_data || index >= ta_data->length) return js_mkundef(); 549 if (!ta_data->buffer || ta_data->buffer->is_detached) return js_mkundef(); 550 551 ant_value_t value; 552 if (!typedarray_read_value(js, ta_data, index, &value)) return js_mkundef(); 553 return value; 554} 555 556static bool typedarray_index_setter(ant_t *js, ant_value_t obj, const char *key, size_t key_len, ant_value_t value) { 557 if (key_len == 0 || key_len > 10) return false; 558 559 size_t index = 0; 560 for (size_t i = 0; i < key_len; i++) { 561 char c = key[i]; 562 if (c < '0' || c > '9') return false; 563 index = index * 10 + (c - '0'); 564 } 565 566 TypedArrayData *ta_data = buffer_get_typedarray_data(obj); 567 if (!ta_data || index >= ta_data->length) return true; 568 if (!ta_data->buffer || ta_data->buffer->is_detached) return true; 569 570 return !is_err(typedarray_write_value(js, ta_data, index, value)); 571} 572 573static bool typedarray_read_number(const TypedArrayData *ta_data, size_t index, double *out) { 574 if (!ta_data || !ta_data->buffer || ta_data->buffer->is_detached || index >= ta_data->length) return false; 575 uint8_t *data = ta_data->buffer->data + ta_data->byte_offset; 576 577 static const void *dispatch[] = { 578 &&R_INT8, &&R_UINT8, &&R_UINT8, &&R_INT16, &&R_UINT16, 579 &&R_INT32, &&R_UINT32, &&R_FLOAT16, &&R_FLOAT32, &&R_FLOAT64, &&R_FAIL, &&R_FAIL 580 }; 581 582 if (ta_data->type > TYPED_ARRAY_BIGUINT64) goto R_FAIL; 583 goto *dispatch[ta_data->type]; 584 585 R_INT8: *out = (double)((int8_t *)data)[index]; return true; 586 R_UINT8: *out = (double)data[index]; return true; 587 R_INT16: *out = (double)((int16_t *)data)[index]; return true; 588 R_UINT16: *out = (double)((uint16_t *)data)[index]; return true; 589 R_INT32: *out = (double)((int32_t *)data)[index]; return true; 590 R_UINT32: *out = (double)((uint32_t *)data)[index]; return true; 591 R_FLOAT16: *out = half_to_double(((uint16_t *)data)[index]); return true; 592 R_FLOAT32: *out = (double)((float *)data)[index]; return true; 593 R_FLOAT64: *out = ((double *)data)[index]; return true; 594 R_FAIL: return false; 595} 596 597static bool typedarray_write_number(TypedArrayData *ta_data, size_t index, double value) { 598 if (!ta_data || !ta_data->buffer || ta_data->buffer->is_detached || index >= ta_data->length) return false; 599 uint8_t *data = ta_data->buffer->data + ta_data->byte_offset; 600 601 static const void *dispatch[] = { 602 &&W_INT8, &&W_UINT8, &&W_UINT8, &&W_INT16, &&W_UINT16, 603 &&W_INT32, &&W_UINT32, &&W_FLOAT16, &&W_FLOAT32, &&W_FLOAT64, &&W_FAIL, &&W_FAIL 604 }; 605 606 if (ta_data->type > TYPED_ARRAY_BIGUINT64) goto W_FAIL; 607 goto *dispatch[ta_data->type]; 608 609 W_INT8: ((int8_t *)data)[index] = (int8_t)value; return true; 610 W_UINT8: data[index] = (uint8_t)value; return true; 611 W_INT16: ((int16_t *)data)[index] = (int16_t)value; return true; 612 W_UINT16: ((uint16_t *)data)[index] = (uint16_t)value; return true; 613 W_INT32: ((int32_t *)data)[index] = (int32_t)value; return true; 614 W_UINT32: ((uint32_t *)data)[index] = (uint32_t)value; return true; 615 W_FLOAT16: ((uint16_t *)data)[index] = double_to_half(value); return true; 616 W_FLOAT32: ((float *)data)[index] = (float)value; return true; 617 W_FLOAT64: ((double *)data)[index] = value; return true; 618 W_FAIL: return false; 619} 620 621static ant_value_t js_typedarray_every(ant_t *js, ant_value_t *args, int nargs) { 622 if (nargs < 1 || !is_callable(args[0])) 623 return js_mkerr_typed(js, JS_ERR_TYPE, "TypedArray.prototype.every requires a callable"); 624 625 ant_value_t this_val = js_getthis(js); 626 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val); 627 if (!ta_data) return js_mkerr(js, "Invalid TypedArray"); 628 if (!ta_data->buffer || ta_data->buffer->is_detached) 629 return js_mkerr(js, "Cannot operate on a detached TypedArray"); 630 631 ant_value_t callback = args[0]; 632 ant_value_t this_arg = nargs > 1 ? args[1] : js_mkundef(); 633 634 for (size_t i = 0; i < ta_data->length; i++) { 635 ant_value_t value = js_mkundef(); 636 if (!typedarray_read_value(js, ta_data, i, &value)) return js_false; 637 638 ant_value_t call_args[3] = { value, js_mknum((double)i), this_val }; 639 ant_value_t result = sv_vm_call(js->vm, js, callback, this_arg, call_args, 3, NULL, false); 640 if (is_err(result)) return result; 641 if (!js_truthy(js, result)) return js_false; 642 } 643 644 return js_true; 645} 646 647ant_value_t create_arraybuffer_obj(ant_t *js, ArrayBufferData *buffer) { 648 ant_value_t ab_obj = js_mkobj(js); 649 ant_value_t ab_proto = js_get_ctor_proto(js, "ArrayBuffer", 11); 650 if (is_special_object(ab_proto)) js_set_proto_init(ab_obj, ab_proto); 651 652 js_set_native(ab_obj, buffer, BUFFER_ARRAYBUFFER_NATIVE_TAG); 653 js_set(js, ab_obj, "byteLength", js_mknum((double)buffer->length)); 654 js_set_finalizer(ab_obj, arraybuffer_finalize); 655 buffer->ref_count++; 656 657 return ab_obj; 658} 659 660ant_value_t create_typed_array_with_buffer( 661 ant_t *js, TypedArrayType type, ArrayBufferData *buffer, 662 size_t byte_offset, size_t length, const char *type_name, ant_value_t arraybuffer_obj 663) { 664 TypedArrayData *ta_data = ta_meta_alloc(sizeof(TypedArrayData)); 665 if (!ta_data) return js_mkerr(js, "Failed to allocate TypedArray"); 666 667 size_t element_size = get_element_size(type); 668 ta_data->buffer = buffer; 669 ta_data->type = type; 670 ta_data->byte_offset = byte_offset; 671 ta_data->byte_length = length * element_size; 672 ta_data->length = length; 673 buffer->ref_count++; 674 675 ant_value_t obj = js_mkobj(js); 676 ant_value_t proto = js_get_ctor_proto(js, type_name, strlen(type_name)); 677 if (is_special_object(proto)) js_set_proto_init(obj, proto); 678 679 js_set_native(obj, ta_data, BUFFER_TYPEDARRAY_NATIVE_TAG); 680 js_set(js, obj, "length", js_mknum((double)length)); 681 js_set(js, obj, "byteLength", js_mknum((double)(length * element_size))); 682 js_set(js, obj, "byteOffset", js_mknum((double)byte_offset)); 683 js_set(js, obj, "BYTES_PER_ELEMENT", js_mknum((double)element_size)); 684 js_set(js, obj, "buffer", arraybuffer_obj); 685 686 js_set_getter(obj, typedarray_index_getter); 687 js_set_setter(obj, typedarray_index_setter); 688 js_set_finalizer(obj, typedarray_finalize); 689 690 return obj; 691} 692 693ant_value_t create_typed_array( 694 ant_t *js, TypedArrayType type, ArrayBufferData *buffer, 695 size_t byte_offset, size_t length, const char *type_name 696) { 697 ant_value_t ab_obj = create_arraybuffer_obj(js, buffer); 698 ant_value_t result = create_typed_array_with_buffer(js, type, buffer, byte_offset, length, type_name, ab_obj); 699 free_array_buffer_data(buffer); return result; 700} 701 702ant_value_t create_dataview_with_buffer( 703 ant_t *js, ArrayBufferData *buffer, 704 size_t byte_offset, size_t byte_length, 705 ant_value_t arraybuffer_obj 706) { 707 DataViewData *dv_data = ta_meta_alloc(sizeof(DataViewData)); 708 if (!dv_data) return js_mkerr(js, "Failed to allocate DataView"); 709 710 dv_data->buffer = buffer; 711 dv_data->byte_offset = byte_offset; 712 dv_data->byte_length = byte_length; 713 buffer->ref_count++; 714 715 ant_value_t obj = js_mkobj(js); 716 ant_value_t proto = js_get_ctor_proto(js, "DataView", 8); 717 if (is_special_object(proto)) js_set_proto_init(obj, proto); 718 719 js_set_native(obj, dv_data, BUFFER_DATAVIEW_NATIVE_TAG); 720 js_set_slot(obj, SLOT_BRAND, js_mknum(BRAND_DATAVIEW)); 721 js_mkprop_fast(js, obj, "buffer", 6, arraybuffer_obj); 722 js_set_descriptor(js, obj, "buffer", 6, 0); 723 js_set(js, obj, "byteLength", js_mknum((double)byte_length)); 724 js_set(js, obj, "byteOffset", js_mknum((double)byte_offset)); 725 js_set_finalizer(obj, dataview_finalize); 726 727 return obj; 728} 729 730typedef struct { 731 ant_value_t *values; 732 size_t length; 733 size_t capacity; 734} iter_collect_ctx_t; 735 736static bool iter_collect_callback(ant_t *js, ant_value_t value, void *udata) { 737 iter_collect_ctx_t *ctx = (iter_collect_ctx_t *)udata; 738 if (ctx->length >= ctx->capacity) { 739 ctx->capacity *= 2; 740 ant_value_t *new_values = realloc(ctx->values, ctx->capacity * sizeof(ant_value_t)); 741 if (!new_values) return false; 742 ctx->values = new_values; 743 } 744 ctx->values[ctx->length++] = value; 745 return true; 746} 747 748static ant_value_t js_typedarray_constructor(ant_t *js, ant_value_t *args, int nargs, TypedArrayType type, const char *type_name) { 749 if (nargs == 0) { 750 ArrayBufferData *buffer = create_array_buffer_data(0); 751 return create_typed_array(js, type, buffer, 0, 0, type_name); 752 } 753 754 if (vtype(args[0]) == T_NUM) { 755 size_t length = (size_t)js_getnum(args[0]); 756 size_t element_size = get_element_size(type); 757 ArrayBufferData *buffer = create_array_buffer_data(length * element_size); 758 if (!buffer) return js_mkerr(js, "Failed to allocate buffer"); 759 return create_typed_array(js, type, buffer, 0, length, type_name); 760 } 761 762 ArrayBufferData *arraybuffer = buffer_get_arraybuffer_data(args[0]); 763 if (arraybuffer) { 764 ArrayBufferData *buffer = arraybuffer; 765 size_t byte_offset = 0; 766 size_t length = buffer->length; 767 768 if (nargs > 1 && vtype(args[1]) == T_NUM) { 769 byte_offset = (size_t)js_getnum(args[1]); 770 } 771 772 size_t element_size = get_element_size(type); 773 774 if (byte_offset > buffer->length) { 775 return js_mkerr(js, "Start offset is outside the bounds of the buffer"); 776 } 777 778 if (nargs > 2 && vtype(args[2]) == T_NUM) { 779 length = (size_t)js_getnum(args[2]); 780 size_t available = buffer->length - byte_offset; 781 if (length > available / element_size) { 782 return js_mkerr(js, "Invalid TypedArray length"); 783 } 784 } else length = (buffer->length - byte_offset) / element_size; 785 786 return create_typed_array_with_buffer(js, type, buffer, byte_offset, length, type_name, args[0]); 787 } 788 789 if (is_special_object(args[0])) { 790 ant_value_t len_val = js_get(js, args[0], "length"); 791 size_t length = 0; ant_value_t *values = NULL; 792 bool is_iterable = false; 793 794 if (vtype(len_val) == T_NUM) length = (size_t)js_getnum(len_val); else { 795 iter_collect_ctx_t ctx = { .values = NULL, .length = 0, .capacity = 16 }; 796 ctx.values = malloc(ctx.capacity * sizeof(ant_value_t)); 797 if (!ctx.values) return js_mkerr(js, "Failed to allocate memory"); 798 is_iterable = js_iter(js, args[0], iter_collect_callback, &ctx); 799 800 if (is_iterable) { 801 values = ctx.values; 802 length = ctx.length; 803 } else free(ctx.values); 804 } 805 806 if (length > 0 || is_iterable || vtype(len_val) == T_NUM) { 807 size_t element_size = get_element_size(type); 808 ArrayBufferData *buffer = create_array_buffer_data(length * element_size); 809 if (!buffer) { if (values) free(values); return js_mkerr(js, "Failed to allocate buffer"); } 810 811 ant_value_t result = create_typed_array(js, type, buffer, 0, length, type_name); 812 if (is_err(result)) { if (values) free(values); return result; } 813 TypedArrayData *result_ta = buffer_get_typedarray_data(result); 814 815 for (size_t i = 0; i < length; i++) { 816 ant_value_t elem; 817 if (values) elem = values[i]; else { 818 char idx_str[16]; 819 snprintf(idx_str, sizeof(idx_str), "%zu", i); 820 elem = js_get(js, args[0], idx_str); 821 } 822 ant_value_t write_result = typedarray_write_value(js, result_ta, i, elem); 823 if (is_err(write_result)) { 824 if (values) free(values); 825 return write_result; 826 } 827 } 828 if (values) free(values); 829 return result; 830 } 831 } 832 833 return js_mkerr(js, "Invalid TypedArray constructor arguments"); 834} 835 836// TypedArray.prototype.slice(begin, end) 837// TypedArray.prototype.at(index) 838static ant_value_t js_typedarray_at(ant_t *js, ant_value_t *args, int nargs) { 839 ant_value_t this_val = js_getthis(js); 840 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val); 841 if (!ta_data) return js_mkerr(js, "Invalid TypedArray"); 842 843 if (nargs == 0 || vtype(args[0]) != T_NUM) return js_mkundef(); 844 845 ssize_t len = (ssize_t)ta_data->length; 846 ssize_t idx = (ssize_t)js_getnum(args[0]); 847 if (idx < 0) idx += len; 848 if (idx < 0 || idx >= len) return js_mkundef(); 849 if (!ta_data->buffer || ta_data->buffer->is_detached) return js_mkundef(); 850 851 ant_value_t value; 852 if (!typedarray_read_value(js, ta_data, (size_t)idx, &value)) return js_mkundef(); 853 return value; 854} 855 856static ant_value_t js_typedarray_slice(ant_t *js, ant_value_t *args, int nargs) { 857 ant_value_t this_val = js_getthis(js); 858 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val); 859 if (!ta_data) return js_mkerr(js, "Invalid TypedArray"); 860 861 ssize_t len = (ssize_t)ta_data->length; 862 ssize_t begin = 0, end = len; 863 864 if (nargs > 0 && vtype(args[0]) == T_NUM) begin = (ssize_t)js_getnum(args[0]); 865 if (nargs > 1 && vtype(args[1]) == T_NUM) end = (ssize_t)js_getnum(args[1]); 866 867 begin = normalize_index(begin, len); 868 end = normalize_index(end, len); 869 if (end < begin) end = begin; 870 871 size_t new_length = (size_t)(end - begin); 872 size_t element_size = get_element_size(ta_data->type); 873 ArrayBufferData *new_buffer = create_array_buffer_data(new_length * element_size); 874 if (!new_buffer) return js_mkerr(js, "Failed to allocate new buffer"); 875 876 memcpy( 877 new_buffer->data, 878 ta_data->buffer->data + ta_data->byte_offset + (size_t)begin * element_size, 879 new_length * element_size 880 ); 881 882 ant_value_t out = create_typed_array_like( 883 js, this_val, ta_data->type, 884 new_buffer, 0, new_length 885 ); free_array_buffer_data(new_buffer); 886 887 return out; 888} 889 890// TypedArray.prototype.subarray(begin, end) 891static ant_value_t js_typedarray_subarray(ant_t *js, ant_value_t *args, int nargs) { 892 ant_value_t this_val = js_getthis(js); 893 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val); 894 if (!ta_data) return js_mkerr(js, "Invalid TypedArray"); 895 896 ssize_t len = (ssize_t)ta_data->length; 897 ssize_t begin = 0, end = len; 898 899 if (nargs > 0 && vtype(args[0]) == T_NUM) begin = (ssize_t)js_getnum(args[0]); 900 if (nargs > 1 && vtype(args[1]) == T_NUM) end = (ssize_t)js_getnum(args[1]); 901 902 begin = normalize_index(begin, len); 903 end = normalize_index(end, len); 904 if (end < begin) end = begin; 905 906 size_t new_length = (size_t)(end - begin); 907 size_t element_size = get_element_size(ta_data->type); 908 size_t new_offset = ta_data->byte_offset + (size_t)begin * element_size; 909 910 return create_typed_array_like( 911 js, this_val, ta_data->type, 912 ta_data->buffer, new_offset, new_length 913 ); 914} 915 916// TypedArray.prototype.fill(value, start, end) 917static ant_value_t js_typedarray_fill(ant_t *js, ant_value_t *args, int nargs) { 918 ant_value_t this_val = js_getthis(js); 919 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val); 920 if (!ta_data) return js_mkerr(js, "Invalid TypedArray"); 921 922 ant_value_t value = nargs > 0 ? args[0] : js_mknum(0); 923 924 ssize_t len = (ssize_t)ta_data->length; 925 ssize_t start = 0, end = len; 926 927 if (nargs > 1 && vtype(args[1]) == T_NUM) start = (ssize_t)js_getnum(args[1]); 928 if (nargs > 2 && vtype(args[2]) == T_NUM) end = (ssize_t)js_getnum(args[2]); 929 930 start = normalize_index(start, len); 931 end = normalize_index(end, len); 932 if (end < start) end = start; 933 934 if (ta_data->type == TYPED_ARRAY_BIGINT64 || ta_data->type == TYPED_ARRAY_BIGUINT64) { 935 for (ssize_t i = start; i < end; i++) { 936 ant_value_t write_result = typedarray_write_value(js, ta_data, (size_t)i, value); 937 if (is_err(write_result)) return write_result; 938 } 939 return this_val; 940 } 941 942 uint8_t *data = ta_data->buffer->data + ta_data->byte_offset; 943 944 static const void *dispatch[] = { 945 &&L_INT8, &&L_UINT8, &&L_UINT8, &&L_INT16, &&L_UINT16, 946 &&L_INT32, &&L_UINT32, &&L_FLOAT16, &&L_FLOAT32, &&L_FLOAT64, &&L_DONE, &&L_DONE 947 }; 948 949 if (ta_data->type > TYPED_ARRAY_BIGUINT64) goto L_DONE; 950 goto *dispatch[ta_data->type]; 951 952 L_INT8: 953 for (ssize_t i = start; i < end; i++) ((int8_t*)data)[i] = (int8_t)js_to_number(js, value); 954 goto L_DONE; 955 L_UINT8: 956 for (ssize_t i = start; i < end; i++) data[i] = (uint8_t)js_to_number(js, value); 957 goto L_DONE; 958 L_INT16: 959 for (ssize_t i = start; i < end; i++) ((int16_t*)data)[i] = (int16_t)js_to_number(js, value); 960 goto L_DONE; 961 L_UINT16: 962 for (ssize_t i = start; i < end; i++) ((uint16_t*)data)[i] = (uint16_t)js_to_number(js, value); 963 goto L_DONE; 964 L_INT32: 965 for (ssize_t i = start; i < end; i++) ((int32_t*)data)[i] = (int32_t)js_to_number(js, value); 966 goto L_DONE; 967 L_UINT32: 968 for (ssize_t i = start; i < end; i++) ((uint32_t*)data)[i] = (uint32_t)js_to_number(js, value); 969 goto L_DONE; 970 L_FLOAT16: 971 for (ssize_t i = start; i < end; i++) ((uint16_t*)data)[i] = double_to_half(js_to_number(js, value)); 972 goto L_DONE; 973 L_FLOAT32: 974 for (ssize_t i = start; i < end; i++) ((float*)data)[i] = (float)js_to_number(js, value); 975 goto L_DONE; 976 L_FLOAT64: 977 for (ssize_t i = start; i < end; i++) ((double*)data)[i] = js_to_number(js, value); 978 goto L_DONE; 979 L_DONE: 980 return this_val; 981} 982 983// TypedArray.prototype.set(source, offset = 0) 984static ant_value_t js_typedarray_set(ant_t *js, ant_value_t *args, int nargs) { 985 if (nargs < 1) return js_mkerr(js, "set requires source argument"); 986 987 ant_value_t this_val = js_getthis(js); 988 TypedArrayData *dst = buffer_get_typedarray_data(this_val); 989 if (!dst) return js_mkerr(js, "Invalid TypedArray"); 990 if (!dst->buffer || dst->buffer->is_detached) return js_mkerr(js, "Cannot operate on a detached TypedArray"); 991 992 ssize_t offset_i = 0; 993 if (nargs > 1 && vtype(args[1]) == T_NUM) offset_i = (ssize_t)js_getnum(args[1]); 994 if (offset_i < 0) return js_mkerr(js, "Offset out of bounds"); 995 size_t offset = (size_t)offset_i; 996 if (offset > dst->length) return js_mkerr(js, "Offset out of bounds"); 997 998 ant_value_t src_val = args[0]; 999 TypedArrayData *src_ta = buffer_get_typedarray_data(src_val); 1000 1001 if (src_ta && src_ta->buffer && !src_ta->buffer->is_detached) { 1002 size_t src_len = src_ta->length; 1003 if (offset + src_len > dst->length) return js_mkerr(js, "Source is too large"); 1004 1005 if (src_ta->type == dst->type) { 1006 size_t el = get_element_size(dst->type); 1007 uint8_t *dst_data = dst->buffer->data + dst->byte_offset + offset * el; 1008 uint8_t *src_data = src_ta->buffer->data + src_ta->byte_offset; 1009 memmove(dst_data, src_data, src_len * el); 1010 return js_mkundef(); 1011 } 1012 1013 for (size_t i = 0; i < src_len; i++) { 1014 ant_value_t value = js_mkundef(); 1015 if (!typedarray_read_value(js, src_ta, i, &value)) value = js_mknum(0); 1016 ant_value_t write_result = typedarray_write_value(js, dst, offset + i, value); 1017 if (is_err(write_result)) return write_result; 1018 } 1019 return js_mkundef(); 1020 } 1021 1022 if (!is_special_object(src_val) && vtype(src_val) != T_STR) { 1023 return js_mkerr(js, "set source must be array-like or TypedArray"); 1024 } 1025 1026 size_t src_len = 0; 1027 if (vtype(src_val) == T_STR) { 1028 src_len = (size_t)vstrlen(js, src_val); 1029 } else { 1030 ant_value_t len_val = js_get(js, src_val, "length"); 1031 src_len = vtype(len_val) == T_NUM ? (size_t)js_getnum(len_val) : 0; 1032 } 1033 1034 if (offset + src_len > dst->length) return js_mkerr(js, "Source is too large"); 1035 1036 for (size_t i = 0; i < src_len; i++) { 1037 if (vtype(src_val) == T_STR) { 1038 ant_offset_t slen = 0; 1039 ant_offset_t soff = vstr(js, src_val, &slen); 1040 const unsigned char *sptr = (const unsigned char *)(uintptr_t)soff; 1041 double value = 0; 1042 if (i < (size_t)slen) value = sptr[i]; 1043 ant_value_t write_result = typedarray_write_value(js, dst, offset + i, js_mknum(value)); 1044 if (is_err(write_result)) return write_result; 1045 } else { 1046 char idx[24]; 1047 size_t idx_len = uint_to_str(idx, sizeof(idx), (uint64_t)i); 1048 idx[idx_len] = '\0'; 1049 ant_value_t elem = js_get(js, src_val, idx); 1050 ant_value_t write_result = typedarray_write_value(js, dst, offset + i, elem); 1051 if (is_err(write_result)) return write_result; 1052 } 1053 } 1054 1055 return js_mkundef(); 1056} 1057 1058// TypedArray.prototype.copyWithin(target, start, end) 1059static ant_value_t js_typedarray_copyWithin(ant_t *js, ant_value_t *args, int nargs) { 1060 ant_value_t this_val = js_getthis(js); 1061 TypedArrayData *ta = buffer_get_typedarray_data(this_val); 1062 if (!ta) return js_mkerr(js, "Invalid TypedArray"); 1063 if (!ta->buffer || ta->buffer->is_detached) return js_mkerr(js, "Cannot operate on a detached TypedArray"); 1064 1065 ssize_t len = (ssize_t)ta->length; 1066 if (len <= 0) return this_val; 1067 1068 ssize_t target = 0, start = 0, end = len; 1069 if (nargs > 0 && vtype(args[0]) == T_NUM) target = (ssize_t)js_getnum(args[0]); 1070 if (nargs > 1 && vtype(args[1]) == T_NUM) start = (ssize_t)js_getnum(args[1]); 1071 if (nargs > 2 && vtype(args[2]) == T_NUM) end = (ssize_t)js_getnum(args[2]); 1072 1073 target = normalize_index(target, len); 1074 start = normalize_index(start, len); 1075 end = normalize_index(end, len); 1076 if (end < start) end = start; 1077 if (target >= len || start >= len || end <= start) return this_val; 1078 1079 size_t count = (size_t)(end - start); 1080 size_t max_to_end = (size_t)(len - target); 1081 if (count > max_to_end) count = max_to_end; 1082 if (count == 0) return this_val; 1083 1084 size_t el = get_element_size(ta->type); 1085 uint8_t *base = ta->buffer->data + ta->byte_offset; 1086 memmove(base + (size_t)target * el, base + (size_t)start * el, count * el); 1087 return this_val; 1088} 1089 1090// TypedArray.prototype.toReversed() 1091static ant_value_t js_typedarray_toReversed(ant_t *js, ant_value_t *args, int nargs) { 1092 (void)args; (void)nargs; 1093 ant_value_t this_val = js_getthis(js); 1094 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val); 1095 if (!ta_data) return js_mkerr(js, "Invalid TypedArray"); 1096 1097 size_t length = ta_data->length; 1098 size_t element_size = get_element_size(ta_data->type); 1099 ArrayBufferData *new_buffer = create_array_buffer_data(length * element_size); 1100 if (!new_buffer) return js_mkerr(js, "Failed to allocate new buffer"); 1101 1102 uint8_t *src = ta_data->buffer->data + ta_data->byte_offset; 1103 uint8_t *dst = new_buffer->data; 1104 1105 for (size_t i = 0; i < length; i++) { 1106 memcpy(dst + i * element_size, src + (length - 1 - i) * element_size, element_size); 1107 } 1108 1109 ant_value_t out = create_typed_array_like( 1110 js, this_val, ta_data->type, 1111 new_buffer, 0, length 1112 ); free_array_buffer_data(new_buffer); 1113 1114 return out; 1115} 1116 1117// TypedArray.prototype.toSorted(comparefn) 1118static ant_value_t js_typedarray_toSorted(ant_t *js, ant_value_t *args, int nargs) { 1119 ant_value_t this_val = js_getthis(js); 1120 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val); 1121 if (!ta_data) return js_mkerr(js, "Invalid TypedArray"); 1122 1123 size_t length = ta_data->length; 1124 size_t element_size = get_element_size(ta_data->type); 1125 ArrayBufferData *new_buffer = create_array_buffer_data(length * element_size); 1126 if (!new_buffer) return js_mkerr(js, "Failed to allocate new buffer"); 1127 1128 memcpy(new_buffer->data, ta_data->buffer->data + ta_data->byte_offset, length * element_size); 1129 ant_value_t result = create_typed_array_like(js, this_val, ta_data->type, new_buffer, 0, length); 1130 1131 free_array_buffer_data(new_buffer); 1132 if (is_err(result)) return result; 1133 1134 TypedArrayData *result_ta = buffer_get_typedarray_data(result); 1135 uint8_t *data = result_ta->buffer->data; 1136 1137 ant_value_t comparefn = (nargs > 0 && vtype(args[0]) == T_FUNC) ? args[0] : js_mkundef(); 1138 bool has_comparefn = vtype(comparefn) == T_FUNC; 1139 1140 for (size_t i = 1; i < length; i++) { 1141 for (size_t j = i; j > 0; j--) { 1142 double a_val, b_val; 1143 int cmp; 1144 1145 static const void *read_dispatch[] = { 1146 &&R_INT8, &&R_UINT8, &&R_UINT8, &&R_INT16, &&R_UINT16, 1147 &&R_INT32, &&R_UINT32, &&R_FLOAT16, &&R_FLOAT32, &&R_FLOAT64, &&R_DONE, &&R_DONE 1148 }; 1149 1150 if (ta_data->type > TYPED_ARRAY_BIGUINT64) goto R_DONE; 1151 goto *read_dispatch[ta_data->type]; 1152 1153 R_INT8: a_val = (double)((int8_t*)data)[j-1]; b_val = (double)((int8_t*)data)[j]; goto R_COMPARE; 1154 R_UINT8: a_val = (double)data[j-1]; b_val = (double)data[j]; goto R_COMPARE; 1155 R_INT16: a_val = (double)((int16_t*)data)[j-1]; b_val = (double)((int16_t*)data)[j]; goto R_COMPARE; 1156 R_UINT16: a_val = (double)((uint16_t*)data)[j-1]; b_val = (double)((uint16_t*)data)[j]; goto R_COMPARE; 1157 R_INT32: a_val = (double)((int32_t*)data)[j-1]; b_val = (double)((int32_t*)data)[j]; goto R_COMPARE; 1158 R_UINT32: a_val = (double)((uint32_t*)data)[j-1]; b_val = (double)((uint32_t*)data)[j]; goto R_COMPARE; 1159 R_FLOAT16: a_val = half_to_double(((uint16_t*)data)[j-1]); b_val = half_to_double(((uint16_t*)data)[j]); goto R_COMPARE; 1160 R_FLOAT32: a_val = (double)((float*)data)[j-1]; b_val = (double)((float*)data)[j]; goto R_COMPARE; 1161 R_FLOAT64: a_val = ((double*)data)[j-1]; b_val = ((double*)data)[j]; goto R_COMPARE; 1162 R_DONE: goto SORT_DONE; 1163 1164 R_COMPARE: 1165 if (has_comparefn) { 1166 ant_value_t cmp_args[2] = { js_mknum(a_val), js_mknum(b_val) }; 1167 ant_value_t cmp_result = sv_vm_call(js->vm, js, comparefn, js_mkundef(), cmp_args, 2, NULL, false); 1168 cmp = (int)js_getnum(cmp_result); 1169 } else { 1170 cmp = (a_val > b_val) ? 1 : ((a_val < b_val) ? -1 : 0); 1171 } 1172 1173 if (cmp <= 0) break; 1174 1175 static const void *swap_dispatch[] = { 1176 &&S_INT8, &&S_UINT8, &&S_UINT8, &&S_INT16, &&S_UINT16, 1177 &&S_INT32, &&S_UINT32, &&S_FLOAT16, &&S_FLOAT32, &&S_FLOAT64, &&S_DONE, &&S_DONE 1178 }; 1179 1180 if (ta_data->type > TYPED_ARRAY_BIGUINT64) goto S_DONE; 1181 goto *swap_dispatch[ta_data->type]; 1182 1183 S_INT8: { int8_t tmp = ((int8_t*)data)[j-1]; ((int8_t*)data)[j-1] = ((int8_t*)data)[j]; ((int8_t*)data)[j] = tmp; goto S_DONE; } 1184 S_UINT8: { uint8_t tmp = data[j-1]; data[j-1] = data[j]; data[j] = tmp; goto S_DONE; } 1185 S_INT16: { int16_t tmp = ((int16_t*)data)[j-1]; ((int16_t*)data)[j-1] = ((int16_t*)data)[j]; ((int16_t*)data)[j] = tmp; goto S_DONE; } 1186 S_UINT16: { uint16_t tmp = ((uint16_t*)data)[j-1]; ((uint16_t*)data)[j-1] = ((uint16_t*)data)[j]; ((uint16_t*)data)[j] = tmp; goto S_DONE; } 1187 S_INT32: { int32_t tmp = ((int32_t*)data)[j-1]; ((int32_t*)data)[j-1] = ((int32_t*)data)[j]; ((int32_t*)data)[j] = tmp; goto S_DONE; } 1188 S_UINT32: { uint32_t tmp = ((uint32_t*)data)[j-1]; ((uint32_t*)data)[j-1] = ((uint32_t*)data)[j]; ((uint32_t*)data)[j] = tmp; goto S_DONE; } 1189 S_FLOAT16: { uint16_t tmp = ((uint16_t*)data)[j-1]; ((uint16_t*)data)[j-1] = ((uint16_t*)data)[j]; ((uint16_t*)data)[j] = tmp; goto S_DONE; } 1190 S_FLOAT32: { float tmp = ((float*)data)[j-1]; ((float*)data)[j-1] = ((float*)data)[j]; ((float*)data)[j] = tmp; goto S_DONE; } 1191 S_FLOAT64: { double tmp = ((double*)data)[j-1]; ((double*)data)[j-1] = ((double*)data)[j]; ((double*)data)[j] = tmp; goto S_DONE; } 1192 S_DONE:; 1193 } 1194 } 1195 1196 SORT_DONE: 1197 return result; 1198} 1199 1200// TypedArray.prototype.with(index, value) 1201static ant_value_t js_typedarray_with(ant_t *js, ant_value_t *args, int nargs) { 1202 if (nargs < 2) return js_mkerr(js, "with requires index and value"); 1203 1204 ant_value_t this_val = js_getthis(js); 1205 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val); 1206 if (!ta_data) return js_mkerr(js, "Invalid TypedArray"); 1207 1208 ssize_t index = (ssize_t)js_getnum(args[0]); 1209 size_t length = ta_data->length; 1210 1211 if (index < 0) index = (ssize_t)length + index; 1212 if (index < 0 || (size_t)index >= length) { 1213 return js_mkerr(js, "Index out of bounds"); 1214 } 1215 1216 size_t element_size = get_element_size(ta_data->type); 1217 ArrayBufferData *new_buffer = create_array_buffer_data(length * element_size); 1218 if (!new_buffer) return js_mkerr(js, "Failed to allocate new buffer"); 1219 1220 memcpy(new_buffer->data, ta_data->buffer->data + ta_data->byte_offset, length * element_size); 1221 1222 ant_value_t out = create_typed_array_like( 1223 js, this_val, ta_data->type, 1224 new_buffer, 0, length 1225 ); free_array_buffer_data(new_buffer); 1226 if (is_err(out)) return out; 1227 1228 TypedArrayData *out_ta = buffer_get_typedarray_data(out); 1229 ant_value_t write_result = typedarray_write_value(js, out_ta, (size_t)index, args[1]); 1230 if (is_err(write_result)) return write_result; 1231 1232 return out; 1233} 1234 1235#define DEFINE_TYPEDARRAY_CONSTRUCTOR(name, type) \ 1236 static ant_value_t js_##name##_constructor(ant_t *js, ant_value_t *args, int nargs) { \ 1237 if (vtype(js->new_target) == T_UNDEF) return js_mkerr_typed(js, JS_ERR_TYPE, #name " constructor requires 'new'"); \ 1238 return js_typedarray_constructor(js, args, nargs, type, #name); \ 1239 } 1240 1241DEFINE_TYPEDARRAY_CONSTRUCTOR(Int8Array, TYPED_ARRAY_INT8) 1242DEFINE_TYPEDARRAY_CONSTRUCTOR(Uint8Array, TYPED_ARRAY_UINT8) 1243DEFINE_TYPEDARRAY_CONSTRUCTOR(Uint8ClampedArray, TYPED_ARRAY_UINT8_CLAMPED) 1244DEFINE_TYPEDARRAY_CONSTRUCTOR(Int16Array, TYPED_ARRAY_INT16) 1245DEFINE_TYPEDARRAY_CONSTRUCTOR(Uint16Array, TYPED_ARRAY_UINT16) 1246DEFINE_TYPEDARRAY_CONSTRUCTOR(Int32Array, TYPED_ARRAY_INT32) 1247DEFINE_TYPEDARRAY_CONSTRUCTOR(Uint32Array, TYPED_ARRAY_UINT32) 1248DEFINE_TYPEDARRAY_CONSTRUCTOR(Float16Array, TYPED_ARRAY_FLOAT16) 1249DEFINE_TYPEDARRAY_CONSTRUCTOR(Float32Array, TYPED_ARRAY_FLOAT32) 1250DEFINE_TYPEDARRAY_CONSTRUCTOR(Float64Array, TYPED_ARRAY_FLOAT64) 1251DEFINE_TYPEDARRAY_CONSTRUCTOR(BigInt64Array, TYPED_ARRAY_BIGINT64) 1252DEFINE_TYPEDARRAY_CONSTRUCTOR(BigUint64Array, TYPED_ARRAY_BIGUINT64) 1253 1254static ant_value_t js_typedarray_from(ant_t *js, ant_value_t *args, int nargs, TypedArrayType type, const char *type_name) { 1255 if (nargs < 1) return js_mkerr_typed(js, JS_ERR_TYPE, "%s.from requires at least 1 argument", type_name); 1256 1257 ant_value_t source = args[0]; 1258 bool has_map = nargs >= 2 && vtype(args[1]) != T_UNDEF; 1259 1260 ant_value_t map_fn = js_mkundef(); 1261 ant_value_t this_arg = nargs >= 3 ? args[2] : js_mkundef(); 1262 ant_value_t result = js_mkundef(); 1263 ant_value_t *collected = NULL; 1264 1265 gc_temp_root_scope_t temp_roots = {0}; 1266 bool temp_roots_active = false; 1267 1268 if (has_map) { 1269 if (!is_callable(args[1])) return js_mkerr_typed( 1270 js, JS_ERR_TYPE, "%s.from: mapFn is not a function", type_name 1271 ); 1272 map_fn = args[1]; 1273 } 1274 1275 gc_temp_root_scope_begin(js, &temp_roots); 1276 temp_roots_active = true; 1277 1278 if (!gc_temp_root_handle_valid(gc_temp_root_add(&temp_roots, source))) goto oom; 1279 if (!gc_temp_root_handle_valid(gc_temp_root_add(&temp_roots, map_fn))) goto oom; 1280 if (!gc_temp_root_handle_valid(gc_temp_root_add(&temp_roots, this_arg))) goto oom; 1281 1282 size_t count = 0, cap = 16; 1283 collected = malloc(cap * sizeof(ant_value_t)); 1284 if (!collected) goto oom; 1285 1286 js_iter_t it; 1287 if (js_iter_open(js, source, &it)) { 1288 ant_value_t item; 1289 while (js_iter_next(js, &it, &item)) { 1290 if (count >= cap) { 1291 cap *= 2; 1292 ant_value_t *tmp = realloc(collected, cap * sizeof(ant_value_t)); 1293 if (!tmp) goto oom; 1294 collected = tmp; 1295 } 1296 if (has_map) { 1297 ant_value_t map_args[2] = { item, js_mknum((double)count) }; 1298 item = sv_vm_call(js->vm, js, map_fn, this_arg, map_args, 2, NULL, false); 1299 if (is_err(item)) { 1300 result = item; 1301 goto done; 1302 } 1303 } 1304 collected[count++] = item; 1305 if (!gc_temp_root_handle_valid(gc_temp_root_add(&temp_roots, item))) goto oom; 1306 } 1307 js_iter_close(js, &it); 1308 } else { 1309 ant_value_t len_val = js_get(js, source, "length"); 1310 size_t len = vtype(len_val) == T_NUM ? (size_t)js_getnum(len_val) : 0; 1311 for (size_t i = 0; i < len; i++) { 1312 char idx[16]; 1313 snprintf(idx, sizeof(idx), "%zu", i); 1314 ant_value_t item = js_get(js, source, idx); 1315 if (count >= cap) { 1316 cap *= 2; 1317 ant_value_t *tmp = realloc(collected, cap * sizeof(ant_value_t)); 1318 if (!tmp) goto oom; 1319 collected = tmp; 1320 } 1321 if (has_map) { 1322 ant_value_t map_args[2] = { item, js_mknum((double)i) }; 1323 item = sv_vm_call(js->vm, js, map_fn, this_arg, map_args, 2, NULL, false); 1324 if (is_err(item)) { 1325 result = item; 1326 goto done; 1327 } 1328 } 1329 collected[count++] = item; 1330 if (!gc_temp_root_handle_valid(gc_temp_root_add(&temp_roots, item))) goto oom; 1331 } 1332 } 1333 1334 size_t elem_size = get_element_size(type); 1335 ArrayBufferData *buffer = create_array_buffer_data(count * elem_size); 1336 if (!buffer) goto oom; 1337 1338 result = create_typed_array(js, type, buffer, 0, count, type_name); 1339 if (is_err(result)) goto done; 1340 if (!gc_temp_root_handle_valid(gc_temp_root_add(&temp_roots, result))) goto oom; 1341 TypedArrayData *result_ta = buffer_get_typedarray_data(result); 1342 1343 for (size_t i = 0; i < count; i++) { 1344 ant_value_t write_result = typedarray_write_value(js, result_ta, i, collected[i]); 1345 if (is_err(write_result)) { 1346 result = write_result; 1347 goto done; 1348 } 1349 } 1350 1351done: 1352 if (temp_roots_active) gc_temp_root_scope_end(&temp_roots); 1353 free(collected); 1354 return result; 1355 1356oom: 1357 result = js_mkerr(js, "oom"); 1358 goto done; 1359} 1360 1361#define DEFINE_TYPEDARRAY_FROM(name, type) \ 1362 static ant_value_t js_##name##_from(ant_t *js, ant_value_t *args, int nargs) { \ 1363 return js_typedarray_from(js, args, nargs, type, #name); \ 1364 } 1365 1366DEFINE_TYPEDARRAY_FROM(Int8Array, TYPED_ARRAY_INT8) 1367DEFINE_TYPEDARRAY_FROM(Uint8Array, TYPED_ARRAY_UINT8) 1368DEFINE_TYPEDARRAY_FROM(Uint8ClampedArray, TYPED_ARRAY_UINT8_CLAMPED) 1369DEFINE_TYPEDARRAY_FROM(Int16Array, TYPED_ARRAY_INT16) 1370DEFINE_TYPEDARRAY_FROM(Uint16Array, TYPED_ARRAY_UINT16) 1371DEFINE_TYPEDARRAY_FROM(Int32Array, TYPED_ARRAY_INT32) 1372DEFINE_TYPEDARRAY_FROM(Uint32Array, TYPED_ARRAY_UINT32) 1373DEFINE_TYPEDARRAY_FROM(Float16Array, TYPED_ARRAY_FLOAT16) 1374DEFINE_TYPEDARRAY_FROM(Float32Array, TYPED_ARRAY_FLOAT32) 1375DEFINE_TYPEDARRAY_FROM(Float64Array, TYPED_ARRAY_FLOAT64) 1376DEFINE_TYPEDARRAY_FROM(BigInt64Array, TYPED_ARRAY_BIGINT64) 1377DEFINE_TYPEDARRAY_FROM(BigUint64Array, TYPED_ARRAY_BIGUINT64) 1378 1379static ant_value_t js_dataview_constructor(ant_t *js, ant_value_t *args, int nargs) { 1380 if (vtype(js->new_target) == T_UNDEF) { 1381 return js_mkerr_typed(js, JS_ERR_TYPE, "DataView constructor requires 'new'"); 1382 } 1383 if (nargs < 1) { 1384 return js_mkerr(js, "DataView requires an ArrayBuffer"); 1385 } 1386 1387 ArrayBufferData *buffer = buffer_get_arraybuffer_data(args[0]); 1388 if (!buffer) { 1389 return js_mkerr(js, "First argument must be an ArrayBuffer"); 1390 } 1391 size_t byte_offset = 0; 1392 size_t byte_length = buffer->length; 1393 1394 if (nargs > 1 && vtype(args[1]) == T_NUM) { 1395 byte_offset = (size_t)js_getnum(args[1]); 1396 } 1397 1398 if (byte_offset > buffer->length) { 1399 return js_mkerr(js, "Start offset is outside the bounds of the buffer"); 1400 } 1401 1402 if (nargs > 2 && vtype(args[2]) == T_NUM) { 1403 byte_length = (size_t)js_getnum(args[2]); 1404 if (byte_length > buffer->length - byte_offset) { 1405 return js_mkerr(js, "Invalid DataView length"); 1406 } 1407 } else byte_length = buffer->length - byte_offset; 1408 1409 DataViewData *dv_data = ta_meta_alloc(sizeof(DataViewData)); 1410 if (!dv_data) return js_mkerr(js, "Failed to allocate DataView"); 1411 1412 dv_data->buffer = buffer; 1413 dv_data->byte_offset = byte_offset; 1414 dv_data->byte_length = byte_length; 1415 buffer->ref_count++; 1416 1417 ant_value_t obj = js_mkobj(js); 1418 ant_value_t proto = js_get_ctor_proto(js, "DataView", 8); 1419 if (is_special_object(proto)) js_set_proto_init(obj, proto); 1420 1421 js_set_native(obj, dv_data, BUFFER_DATAVIEW_NATIVE_TAG); 1422 js_set_slot(obj, SLOT_BRAND, js_mknum(BRAND_DATAVIEW)); 1423 js_mkprop_fast(js, obj, "buffer", 6, args[0]); 1424 js_set_descriptor(js, obj, "buffer", 6, 0); 1425 1426 js_set(js, obj, "byteLength", js_mknum((double)byte_length)); 1427 js_set(js, obj, "byteOffset", js_mknum((double)byte_offset)); 1428 js_set_finalizer(obj, dataview_finalize); 1429 1430 return obj; 1431} 1432 1433// DataView.prototype.getUint8(byteOffset) 1434static ant_value_t js_dataview_getInt8(ant_t *js, ant_value_t *args, int nargs) { 1435 if (nargs < 1) return js_mkerr(js, "getInt8 requires byteOffset"); 1436 1437 ant_value_t this_val = js_getthis(js); 1438 DataViewData *dv = buffer_get_dataview_data(this_val); 1439 if (!dv) return js_mkerr(js, "Not a DataView"); 1440 size_t offset = (size_t)js_getnum(args[0]); 1441 1442 if (offset >= dv->byte_length) { 1443 return js_mkerr(js, "Offset out of bounds"); 1444 } 1445 1446 int8_t value = (int8_t)dv->buffer->data[dv->byte_offset + offset]; 1447 return js_mknum((double)value); 1448} 1449 1450// DataView.prototype.setInt8(byteOffset, value) 1451static ant_value_t js_dataview_setInt8(ant_t *js, ant_value_t *args, int nargs) { 1452 if (nargs < 2) return js_mkerr(js, "setInt8 requires byteOffset and value"); 1453 1454 ant_value_t this_val = js_getthis(js); 1455 DataViewData *dv = buffer_get_dataview_data(this_val); 1456 if (!dv) return js_mkerr(js, "Not a DataView"); 1457 size_t offset = (size_t)js_getnum(args[0]); 1458 int8_t value = (int8_t)js_to_int32(js_getnum(args[1])); 1459 1460 if (offset >= dv->byte_length) { 1461 return js_mkerr(js, "Offset out of bounds"); 1462 } 1463 1464 dv->buffer->data[dv->byte_offset + offset] = (uint8_t)value; 1465 return js_mkundef(); 1466} 1467 1468// DataView.prototype.getUint8(byteOffset) 1469static ant_value_t js_dataview_getUint8(ant_t *js, ant_value_t *args, int nargs) { 1470 if (nargs < 1) return js_mkerr(js, "getUint8 requires byteOffset"); 1471 1472 ant_value_t this_val = js_getthis(js); 1473 DataViewData *dv = buffer_get_dataview_data(this_val); 1474 if (!dv) return js_mkerr(js, "Not a DataView"); 1475 size_t offset = (size_t)js_getnum(args[0]); 1476 1477 if (offset >= dv->byte_length) { 1478 return js_mkerr(js, "Offset out of bounds"); 1479 } 1480 1481 uint8_t value = dv->buffer->data[dv->byte_offset + offset]; 1482 return js_mknum((double)value); 1483} 1484 1485// DataView.prototype.setUint8(byteOffset, value) 1486static ant_value_t js_dataview_setUint8(ant_t *js, ant_value_t *args, int nargs) { 1487 if (nargs < 2) return js_mkerr(js, "setUint8 requires byteOffset and value"); 1488 1489 ant_value_t this_val = js_getthis(js); 1490 DataViewData *dv = buffer_get_dataview_data(this_val); 1491 if (!dv) return js_mkerr(js, "Not a DataView"); 1492 size_t offset = (size_t)js_getnum(args[0]); 1493 uint8_t value = (uint8_t)js_to_uint32(js_getnum(args[1])); 1494 1495 if (offset >= dv->byte_length) { 1496 return js_mkerr(js, "Offset out of bounds"); 1497 } 1498 1499 dv->buffer->data[dv->byte_offset + offset] = value; 1500 return js_mkundef(); 1501} 1502 1503// DataView.prototype.getInt16(byteOffset, littleEndian) 1504static ant_value_t js_dataview_getInt16(ant_t *js, ant_value_t *args, int nargs) { 1505 if (nargs < 1) return js_mkerr(js, "getInt16 requires byteOffset"); 1506 1507 ant_value_t this_val = js_getthis(js); 1508 DataViewData *dv = buffer_get_dataview_data(this_val); 1509 if (!dv) return js_mkerr(js, "Not a DataView"); 1510 size_t offset = (size_t)js_getnum(args[0]); 1511 bool little_endian = (nargs > 1 && js_truthy(js, args[1])); 1512 1513 if (offset + 2 > dv->byte_length) { 1514 return js_mkerr(js, "Offset out of bounds"); 1515 } 1516 1517 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset; 1518 int16_t value; 1519 1520 if (little_endian) { 1521 value = (int16_t)(ptr[0] | (ptr[1] << 8)); 1522 } else { 1523 value = (int16_t)((ptr[0] << 8) | ptr[1]); 1524 } 1525 1526 return js_mknum((double)value); 1527} 1528 1529// DataView.prototype.getUint16(byteOffset, littleEndian) 1530static ant_value_t js_dataview_getUint16(ant_t *js, ant_value_t *args, int nargs) { 1531 if (nargs < 1) return js_mkerr(js, "getUint16 requires byteOffset"); 1532 1533 ant_value_t this_val = js_getthis(js); 1534 DataViewData *dv = buffer_get_dataview_data(this_val); 1535 if (!dv) return js_mkerr(js, "Not a DataView"); 1536 size_t offset = (size_t)js_getnum(args[0]); 1537 bool little_endian = (nargs > 1 && js_truthy(js, args[1])); 1538 1539 if (offset + 2 > dv->byte_length) { 1540 return js_mkerr(js, "Offset out of bounds"); 1541 } 1542 1543 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset; 1544 uint16_t value; 1545 1546 if (little_endian) value = (uint16_t)(ptr[0] | (ptr[1] << 8)); 1547 else value = (uint16_t)((ptr[0] << 8) | ptr[1]); 1548 1549 return js_mknum((double)value); 1550} 1551 1552// DataView.prototype.setUint16(byteOffset, value, littleEndian) 1553static ant_value_t js_dataview_setUint16(ant_t *js, ant_value_t *args, int nargs) { 1554 if (nargs < 2) return js_mkerr(js, "setUint16 requires byteOffset and value"); 1555 1556 ant_value_t this_val = js_getthis(js); 1557 DataViewData *dv = buffer_get_dataview_data(this_val); 1558 if (!dv) return js_mkerr(js, "Not a DataView"); 1559 size_t offset = (size_t)js_getnum(args[0]); 1560 uint16_t value = (uint16_t)js_to_uint32(js_getnum(args[1])); 1561 bool little_endian = (nargs > 2 && js_truthy(js, args[2])); 1562 1563 if (offset + 2 > dv->byte_length) { 1564 return js_mkerr(js, "Offset out of bounds"); 1565 } 1566 1567 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset; 1568 1569 if (little_endian) { 1570 ptr[0] = (uint8_t)(value & 0xFF); 1571 ptr[1] = (uint8_t)((value >> 8) & 0xFF); 1572 } else { 1573 ptr[0] = (uint8_t)((value >> 8) & 0xFF); 1574 ptr[1] = (uint8_t)(value & 0xFF); 1575 } 1576 1577 return js_mkundef(); 1578} 1579 1580// DataView.prototype.getInt32(byteOffset, littleEndian) 1581static ant_value_t js_dataview_getInt32(ant_t *js, ant_value_t *args, int nargs) { 1582 if (nargs < 1) return js_mkerr(js, "getInt32 requires byteOffset"); 1583 1584 ant_value_t this_val = js_getthis(js); 1585 DataViewData *dv = buffer_get_dataview_data(this_val); 1586 if (!dv) return js_mkerr(js, "Not a DataView"); 1587 size_t offset = (size_t)js_getnum(args[0]); 1588 bool little_endian = (nargs > 1 && js_truthy(js, args[1])); 1589 1590 if (offset + 4 > dv->byte_length) { 1591 return js_mkerr(js, "Offset out of bounds"); 1592 } 1593 1594 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset; 1595 int32_t value; 1596 1597 if (little_endian) { 1598 value = (int32_t)(ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24)); 1599 } else { 1600 value = (int32_t)((ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3]); 1601 } 1602 1603 return js_mknum((double)value); 1604} 1605 1606// DataView.prototype.getFloat32(byteOffset, littleEndian) 1607static ant_value_t js_dataview_getFloat32(ant_t *js, ant_value_t *args, int nargs) { 1608 if (nargs < 1) return js_mkerr(js, "getFloat32 requires byteOffset"); 1609 1610 ant_value_t this_val = js_getthis(js); 1611 DataViewData *dv = buffer_get_dataview_data(this_val); 1612 if (!dv) return js_mkerr(js, "Not a DataView"); 1613 size_t offset = (size_t)js_getnum(args[0]); 1614 bool little_endian = (nargs > 1 && js_truthy(js, args[1])); 1615 1616 if (offset + 4 > dv->byte_length) { 1617 return js_mkerr(js, "Offset out of bounds"); 1618 } 1619 1620 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset; 1621 uint32_t bits; 1622 1623 if (little_endian) { 1624 bits = ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); 1625 } else { 1626 bits = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3]; 1627 } 1628 1629 float value; 1630 memcpy(&value, &bits, 4); 1631 return js_mknum((double)value); 1632} 1633 1634// DataView.prototype.setInt16(byteOffset, value, littleEndian) 1635static ant_value_t js_dataview_setInt16(ant_t *js, ant_value_t *args, int nargs) { 1636 if (nargs < 2) return js_mkerr(js, "setInt16 requires byteOffset and value"); 1637 1638 ant_value_t this_val = js_getthis(js); 1639 DataViewData *dv = buffer_get_dataview_data(this_val); 1640 if (!dv) return js_mkerr(js, "Not a DataView"); 1641 size_t offset = (size_t)js_getnum(args[0]); 1642 int16_t value = (int16_t)js_to_int32(js_getnum(args[1])); 1643 bool little_endian = (nargs > 2 && js_truthy(js, args[2])); 1644 1645 if (offset + 2 > dv->byte_length) { 1646 return js_mkerr(js, "Offset out of bounds"); 1647 } 1648 1649 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset; 1650 1651 if (little_endian) { 1652 ptr[0] = (uint8_t)(value & 0xFF); 1653 ptr[1] = (uint8_t)((value >> 8) & 0xFF); 1654 } else { 1655 ptr[0] = (uint8_t)((value >> 8) & 0xFF); 1656 ptr[1] = (uint8_t)(value & 0xFF); 1657 } 1658 1659 return js_mkundef(); 1660} 1661 1662// DataView.prototype.setInt32(byteOffset, value, littleEndian) 1663static ant_value_t js_dataview_setInt32(ant_t *js, ant_value_t *args, int nargs) { 1664 if (nargs < 2) return js_mkerr(js, "setInt32 requires byteOffset and value"); 1665 1666 ant_value_t this_val = js_getthis(js); 1667 DataViewData *dv = buffer_get_dataview_data(this_val); 1668 if (!dv) return js_mkerr(js, "Not a DataView"); 1669 size_t offset = (size_t)js_getnum(args[0]); 1670 int32_t value = js_to_int32(js_getnum(args[1])); 1671 bool little_endian = (nargs > 2 && js_truthy(js, args[2])); 1672 1673 if (offset + 4 > dv->byte_length) { 1674 return js_mkerr(js, "Offset out of bounds"); 1675 } 1676 1677 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset; 1678 1679 if (little_endian) { 1680 ptr[0] = (uint8_t)(value & 0xFF); 1681 ptr[1] = (uint8_t)((value >> 8) & 0xFF); 1682 ptr[2] = (uint8_t)((value >> 16) & 0xFF); 1683 ptr[3] = (uint8_t)((value >> 24) & 0xFF); 1684 } else { 1685 ptr[0] = (uint8_t)((value >> 24) & 0xFF); 1686 ptr[1] = (uint8_t)((value >> 16) & 0xFF); 1687 ptr[2] = (uint8_t)((value >> 8) & 0xFF); 1688 ptr[3] = (uint8_t)(value & 0xFF); 1689 } 1690 1691 return js_mkundef(); 1692} 1693 1694// DataView.prototype.getUint32(byteOffset, littleEndian) 1695static ant_value_t js_dataview_getUint32(ant_t *js, ant_value_t *args, int nargs) { 1696 if (nargs < 1) return js_mkerr(js, "getUint32 requires byteOffset"); 1697 1698 ant_value_t this_val = js_getthis(js); 1699 DataViewData *dv = buffer_get_dataview_data(this_val); 1700 if (!dv) return js_mkerr(js, "Not a DataView"); 1701 size_t offset = (size_t)js_getnum(args[0]); 1702 bool little_endian = (nargs > 1 && js_truthy(js, args[1])); 1703 1704 if (offset + 4 > dv->byte_length) { 1705 return js_mkerr(js, "Offset out of bounds"); 1706 } 1707 1708 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset; 1709 uint32_t value; 1710 1711 if (little_endian) value = (uint32_t)(ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24)); 1712 else value = (uint32_t)((ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3]); 1713 1714 return js_mknum((double)value); 1715} 1716 1717// DataView.prototype.setUint32(byteOffset, value, littleEndian) 1718static ant_value_t js_dataview_setUint32(ant_t *js, ant_value_t *args, int nargs) { 1719 if (nargs < 2) return js_mkerr(js, "setUint32 requires byteOffset and value"); 1720 1721 ant_value_t this_val = js_getthis(js); 1722 DataViewData *dv = buffer_get_dataview_data(this_val); 1723 if (!dv) return js_mkerr(js, "Not a DataView"); 1724 size_t offset = (size_t)js_getnum(args[0]); 1725 1726 uint32_t value = js_to_uint32(js_getnum(args[1])); 1727 bool little_endian = (nargs > 2 && js_truthy(js, args[2])); 1728 1729 if (offset + 4 > dv->byte_length) return js_mkerr(js, "Offset out of bounds"); 1730 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset; 1731 1732 if (little_endian) { 1733 ptr[0] = (uint8_t)(value & 0xFF); 1734 ptr[1] = (uint8_t)((value >> 8) & 0xFF); 1735 ptr[2] = (uint8_t)((value >> 16) & 0xFF); 1736 ptr[3] = (uint8_t)((value >> 24) & 0xFF); 1737 } else { 1738 ptr[0] = (uint8_t)((value >> 24) & 0xFF); 1739 ptr[1] = (uint8_t)((value >> 16) & 0xFF); 1740 ptr[2] = (uint8_t)((value >> 8) & 0xFF); 1741 ptr[3] = (uint8_t)(value & 0xFF); 1742 } 1743 1744 return js_mkundef(); 1745} 1746 1747// DataView.prototype.setFloat32(byteOffset, value, littleEndian) 1748static ant_value_t js_dataview_setFloat32(ant_t *js, ant_value_t *args, int nargs) { 1749 if (nargs < 2) return js_mkerr(js, "setFloat32 requires byteOffset and value"); 1750 1751 ant_value_t this_val = js_getthis(js); 1752 DataViewData *dv = buffer_get_dataview_data(this_val); 1753 if (!dv) return js_mkerr(js, "Not a DataView"); 1754 size_t offset = (size_t)js_getnum(args[0]); 1755 float value = (float)js_getnum(args[1]); 1756 bool little_endian = (nargs > 2 && js_truthy(js, args[2])); 1757 1758 if (offset + 4 > dv->byte_length) { 1759 return js_mkerr(js, "Offset out of bounds"); 1760 } 1761 1762 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset; 1763 uint32_t bits; 1764 memcpy(&bits, &value, 4); 1765 1766 if (little_endian) { 1767 ptr[0] = (uint8_t)(bits & 0xFF); 1768 ptr[1] = (uint8_t)((bits >> 8) & 0xFF); 1769 ptr[2] = (uint8_t)((bits >> 16) & 0xFF); 1770 ptr[3] = (uint8_t)((bits >> 24) & 0xFF); 1771 } else { 1772 ptr[0] = (uint8_t)((bits >> 24) & 0xFF); 1773 ptr[1] = (uint8_t)((bits >> 16) & 0xFF); 1774 ptr[2] = (uint8_t)((bits >> 8) & 0xFF); 1775 ptr[3] = (uint8_t)(bits & 0xFF); 1776 } 1777 1778 return js_mkundef(); 1779} 1780 1781// DataView.prototype.getFloat64(byteOffset, littleEndian) 1782static ant_value_t js_dataview_getFloat64(ant_t *js, ant_value_t *args, int nargs) { 1783 if (nargs < 1) return js_mkerr(js, "getFloat64 requires byteOffset"); 1784 1785 ant_value_t this_val = js_getthis(js); 1786 DataViewData *dv = buffer_get_dataview_data(this_val); 1787 if (!dv) return js_mkerr(js, "Not a DataView"); 1788 size_t offset = (size_t)js_getnum(args[0]); 1789 bool little_endian = (nargs > 1 && js_truthy(js, args[1])); 1790 1791 if (offset + 8 > dv->byte_length) { 1792 return js_mkerr(js, "Offset out of bounds"); 1793 } 1794 1795 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset; 1796 uint64_t bits; 1797 1798 if (little_endian) { 1799 bits = (uint64_t)ptr[0] | ((uint64_t)ptr[1] << 8) | ((uint64_t)ptr[2] << 16) | ((uint64_t)ptr[3] << 24) | 1800 ((uint64_t)ptr[4] << 32) | ((uint64_t)ptr[5] << 40) | ((uint64_t)ptr[6] << 48) | ((uint64_t)ptr[7] << 56); 1801 } else { 1802 bits = ((uint64_t)ptr[0] << 56) | ((uint64_t)ptr[1] << 48) | ((uint64_t)ptr[2] << 40) | ((uint64_t)ptr[3] << 32) | 1803 ((uint64_t)ptr[4] << 24) | ((uint64_t)ptr[5] << 16) | ((uint64_t)ptr[6] << 8) | (uint64_t)ptr[7]; 1804 } 1805 1806 double value; 1807 memcpy(&value, &bits, 8); 1808 return js_mknum(value); 1809} 1810 1811// DataView.prototype.setFloat64(byteOffset, value, littleEndian) 1812static ant_value_t js_dataview_setFloat64(ant_t *js, ant_value_t *args, int nargs) { 1813 if (nargs < 2) return js_mkerr(js, "setFloat64 requires byteOffset and value"); 1814 1815 ant_value_t this_val = js_getthis(js); 1816 DataViewData *dv = buffer_get_dataview_data(this_val); 1817 if (!dv) return js_mkerr(js, "Not a DataView"); 1818 size_t offset = (size_t)js_getnum(args[0]); 1819 double value = js_getnum(args[1]); 1820 bool little_endian = (nargs > 2 && js_truthy(js, args[2])); 1821 1822 if (offset + 8 > dv->byte_length) { 1823 return js_mkerr(js, "Offset out of bounds"); 1824 } 1825 1826 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset; 1827 uint64_t bits; 1828 memcpy(&bits, &value, 8); 1829 1830 if (little_endian) { 1831 ptr[0] = (uint8_t)(bits & 0xFF); 1832 ptr[1] = (uint8_t)((bits >> 8) & 0xFF); 1833 ptr[2] = (uint8_t)((bits >> 16) & 0xFF); 1834 ptr[3] = (uint8_t)((bits >> 24) & 0xFF); 1835 ptr[4] = (uint8_t)((bits >> 32) & 0xFF); 1836 ptr[5] = (uint8_t)((bits >> 40) & 0xFF); 1837 ptr[6] = (uint8_t)((bits >> 48) & 0xFF); 1838 ptr[7] = (uint8_t)((bits >> 56) & 0xFF); 1839 } else { 1840 ptr[0] = (uint8_t)((bits >> 56) & 0xFF); 1841 ptr[1] = (uint8_t)((bits >> 48) & 0xFF); 1842 ptr[2] = (uint8_t)((bits >> 40) & 0xFF); 1843 ptr[3] = (uint8_t)((bits >> 32) & 0xFF); 1844 ptr[4] = (uint8_t)((bits >> 24) & 0xFF); 1845 ptr[5] = (uint8_t)((bits >> 16) & 0xFF); 1846 ptr[6] = (uint8_t)((bits >> 8) & 0xFF); 1847 ptr[7] = (uint8_t)(bits & 0xFF); 1848 } 1849 1850 return js_mkundef(); 1851} 1852 1853static ant_value_t js_dataview_getBigInt64(ant_t *js, ant_value_t *args, int nargs) { 1854 if (nargs < 1) return js_mkerr(js, "getBigInt64 requires byteOffset"); 1855 1856 ant_value_t this_val = js_getthis(js); 1857 DataViewData *dv = buffer_get_dataview_data(this_val); 1858 if (!dv) return js_mkerr(js, "Not a DataView"); 1859 size_t offset = (size_t)js_getnum(args[0]); 1860 bool little_endian = (nargs > 1 && js_truthy(js, args[1])); 1861 1862 if (offset + 8 > dv->byte_length) return js_mkerr(js, "Offset out of bounds"); 1863 1864 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset; 1865 uint64_t bits; 1866 if (little_endian) { 1867 bits = (uint64_t)ptr[0] | ((uint64_t)ptr[1] << 8) | ((uint64_t)ptr[2] << 16) | ((uint64_t)ptr[3] << 24) | 1868 ((uint64_t)ptr[4] << 32) | ((uint64_t)ptr[5] << 40) | ((uint64_t)ptr[6] << 48) | ((uint64_t)ptr[7] << 56); 1869 } else { 1870 bits = ((uint64_t)ptr[0] << 56) | ((uint64_t)ptr[1] << 48) | ((uint64_t)ptr[2] << 40) | ((uint64_t)ptr[3] << 32) | 1871 ((uint64_t)ptr[4] << 24) | ((uint64_t)ptr[5] << 16) | ((uint64_t)ptr[6] << 8) | (uint64_t)ptr[7]; 1872 } 1873 1874 return bigint_from_int64(js, (int64_t)bits); 1875} 1876 1877static ant_value_t js_dataview_setBigInt64(ant_t *js, ant_value_t *args, int nargs) { 1878 if (nargs < 2) return js_mkerr(js, "setBigInt64 requires byteOffset and value"); 1879 1880 ant_value_t this_val = js_getthis(js); 1881 DataViewData *dv = buffer_get_dataview_data(this_val); 1882 if (!dv) return js_mkerr(js, "Not a DataView"); 1883 size_t offset = (size_t)js_getnum(args[0]); 1884 ant_value_t bigint = buffer_require_bigint_value(js, args[1]); 1885 bool little_endian = (nargs > 2 && js_truthy(js, args[2])); 1886 int64_t wrapped = 0; 1887 1888 if (is_err(bigint)) return bigint; 1889 if (offset + 8 > dv->byte_length) return js_mkerr(js, "Offset out of bounds"); 1890 if (!bigint_to_int64_wrapping(js, bigint, &wrapped)) { 1891 return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot convert to BigInt"); 1892 } 1893 1894 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset; 1895 uint64_t bits = (uint64_t)wrapped; 1896 if (little_endian) { 1897 ptr[0] = (uint8_t)(bits & 0xFF); 1898 ptr[1] = (uint8_t)((bits >> 8) & 0xFF); 1899 ptr[2] = (uint8_t)((bits >> 16) & 0xFF); 1900 ptr[3] = (uint8_t)((bits >> 24) & 0xFF); 1901 ptr[4] = (uint8_t)((bits >> 32) & 0xFF); 1902 ptr[5] = (uint8_t)((bits >> 40) & 0xFF); 1903 ptr[6] = (uint8_t)((bits >> 48) & 0xFF); 1904 ptr[7] = (uint8_t)((bits >> 56) & 0xFF); 1905 } else { 1906 ptr[0] = (uint8_t)((bits >> 56) & 0xFF); 1907 ptr[1] = (uint8_t)((bits >> 48) & 0xFF); 1908 ptr[2] = (uint8_t)((bits >> 40) & 0xFF); 1909 ptr[3] = (uint8_t)((bits >> 32) & 0xFF); 1910 ptr[4] = (uint8_t)((bits >> 24) & 0xFF); 1911 ptr[5] = (uint8_t)((bits >> 16) & 0xFF); 1912 ptr[6] = (uint8_t)((bits >> 8) & 0xFF); 1913 ptr[7] = (uint8_t)(bits & 0xFF); 1914 } 1915 1916 return js_mkundef(); 1917} 1918 1919static ant_value_t js_dataview_getBigUint64(ant_t *js, ant_value_t *args, int nargs) { 1920 if (nargs < 1) return js_mkerr(js, "getBigUint64 requires byteOffset"); 1921 1922 ant_value_t this_val = js_getthis(js); 1923 DataViewData *dv = buffer_get_dataview_data(this_val); 1924 if (!dv) return js_mkerr(js, "Not a DataView"); 1925 size_t offset = (size_t)js_getnum(args[0]); 1926 bool little_endian = (nargs > 1 && js_truthy(js, args[1])); 1927 1928 if (offset + 8 > dv->byte_length) return js_mkerr(js, "Offset out of bounds"); 1929 1930 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset; 1931 uint64_t bits; 1932 if (little_endian) { 1933 bits = (uint64_t)ptr[0] | ((uint64_t)ptr[1] << 8) | ((uint64_t)ptr[2] << 16) | ((uint64_t)ptr[3] << 24) | 1934 ((uint64_t)ptr[4] << 32) | ((uint64_t)ptr[5] << 40) | ((uint64_t)ptr[6] << 48) | ((uint64_t)ptr[7] << 56); 1935 } else { 1936 bits = ((uint64_t)ptr[0] << 56) | ((uint64_t)ptr[1] << 48) | ((uint64_t)ptr[2] << 40) | ((uint64_t)ptr[3] << 32) | 1937 ((uint64_t)ptr[4] << 24) | ((uint64_t)ptr[5] << 16) | ((uint64_t)ptr[6] << 8) | (uint64_t)ptr[7]; 1938 } 1939 1940 return bigint_from_uint64(js, bits); 1941} 1942 1943static ant_value_t js_dataview_setBigUint64(ant_t *js, ant_value_t *args, int nargs) { 1944 if (nargs < 2) return js_mkerr(js, "setBigUint64 requires byteOffset and value"); 1945 1946 ant_value_t this_val = js_getthis(js); 1947 DataViewData *dv = buffer_get_dataview_data(this_val); 1948 if (!dv) return js_mkerr(js, "Not a DataView"); 1949 size_t offset = (size_t)js_getnum(args[0]); 1950 ant_value_t bigint = buffer_require_bigint_value(js, args[1]); 1951 bool little_endian = (nargs > 2 && js_truthy(js, args[2])); 1952 uint64_t wrapped = 0; 1953 1954 if (is_err(bigint)) return bigint; 1955 if (offset + 8 > dv->byte_length) return js_mkerr(js, "Offset out of bounds"); 1956 if (!bigint_to_uint64_wrapping(js, bigint, &wrapped)) { 1957 return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot convert to BigInt"); 1958 } 1959 1960 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset; 1961 if (little_endian) { 1962 ptr[0] = (uint8_t)(wrapped & 0xFF); 1963 ptr[1] = (uint8_t)((wrapped >> 8) & 0xFF); 1964 ptr[2] = (uint8_t)((wrapped >> 16) & 0xFF); 1965 ptr[3] = (uint8_t)((wrapped >> 24) & 0xFF); 1966 ptr[4] = (uint8_t)((wrapped >> 32) & 0xFF); 1967 ptr[5] = (uint8_t)((wrapped >> 40) & 0xFF); 1968 ptr[6] = (uint8_t)((wrapped >> 48) & 0xFF); 1969 ptr[7] = (uint8_t)((wrapped >> 56) & 0xFF); 1970 } else { 1971 ptr[0] = (uint8_t)((wrapped >> 56) & 0xFF); 1972 ptr[1] = (uint8_t)((wrapped >> 48) & 0xFF); 1973 ptr[2] = (uint8_t)((wrapped >> 40) & 0xFF); 1974 ptr[3] = (uint8_t)((wrapped >> 32) & 0xFF); 1975 ptr[4] = (uint8_t)((wrapped >> 24) & 0xFF); 1976 ptr[5] = (uint8_t)((wrapped >> 16) & 0xFF); 1977 ptr[6] = (uint8_t)((wrapped >> 8) & 0xFF); 1978 ptr[7] = (uint8_t)(wrapped & 0xFF); 1979 } 1980 1981 return js_mkundef(); 1982} 1983 1984static uint8_t *hex_decode(const char *data, size_t len, size_t *out_len) { 1985 if (len % 2 != 0) return NULL; 1986 1987 size_t decoded_len = len / 2; 1988 size_t alloc_len = decoded_len; 1989 1990 if (alloc_len == 0) alloc_len = 1; 1991 uint8_t *decoded = malloc(alloc_len); 1992 if (!decoded) return NULL; 1993 1994 for (size_t i = 0; i < decoded_len; i++) { 1995 unsigned char hi_ch = (unsigned char)data[i * 2]; 1996 unsigned char lo_ch = (unsigned char)data[i * 2 + 1]; 1997 int hi; int lo; 1998 1999 if (hi_ch >= '0' && hi_ch <= '9') { hi = hi_ch - '0'; goto have_hi; } 2000 if (hi_ch >= 'a' && hi_ch <= 'f') { hi = hi_ch - 'a' + 10; goto have_hi; } 2001 if (hi_ch >= 'A' && hi_ch <= 'F') { hi = hi_ch - 'A' + 10; goto have_hi; } 2002 goto fail; 2003 2004 have_hi: 2005 if (lo_ch >= '0' && lo_ch <= '9') { lo = lo_ch - '0'; goto have_lo; } 2006 if (lo_ch >= 'a' && lo_ch <= 'f') { lo = lo_ch - 'a' + 10; goto have_lo; } 2007 if (lo_ch >= 'A' && lo_ch <= 'F') { lo = lo_ch - 'A' + 10; goto have_lo; } 2008 goto fail; 2009 2010 have_lo: 2011 decoded[i] = (uint8_t)((hi << 4) | lo); 2012 } 2013 2014 *out_len = decoded_len; 2015 return decoded; 2016 2017fail: 2018 free(decoded); 2019 return NULL; 2020} 2021 2022static ant_value_t uint8array_from_bytes(ant_t *js, const uint8_t *bytes, size_t len) { 2023 ArrayBufferData *buffer = create_array_buffer_data(len); 2024 if (!buffer) return js_mkerr(js, "Failed to allocate buffer"); 2025 if (len > 0) memcpy(buffer->data, bytes, len); 2026 return create_typed_array(js, TYPED_ARRAY_UINT8, buffer, 0, len, "Uint8Array"); 2027} 2028 2029static ant_value_t js_uint8array_fromHex(ant_t *js, ant_value_t *args, int nargs) { 2030 ant_value_t source = nargs > 0 ? js_tostring_val(js, args[0]) : js_mkstr(js, "", 0); 2031 if (is_err(source)) return source; 2032 2033 size_t len = 0; 2034 char *str = js_getstr(js, source, &len); 2035 2036 size_t decoded_len = 0; 2037 uint8_t *decoded = hex_decode(str, len, &decoded_len); 2038 if (!decoded) return js_mkerr_typed(js, JS_ERR_SYNTAX, "Invalid hex string"); 2039 2040 ant_value_t result = uint8array_from_bytes(js, decoded, decoded_len); 2041 free(decoded); 2042 2043 return result; 2044} 2045 2046static ant_value_t js_uint8array_fromBase64(ant_t *js, ant_value_t *args, int nargs) { 2047 ant_value_t source = nargs > 0 ? js_tostring_val(js, args[0]) : js_mkstr(js, "", 0); 2048 if (is_err(source)) return source; 2049 2050 size_t len = 0; 2051 char *str = js_getstr(js, source, &len); 2052 2053 size_t decoded_len = 0; 2054 uint8_t *decoded = ant_base64_decode(str, len, &decoded_len); 2055 if (!decoded) return js_mkerr_typed(js, JS_ERR_SYNTAX, "Invalid base64 string"); 2056 2057 ant_value_t result = uint8array_from_bytes(js, decoded, decoded_len); 2058 free(decoded); 2059 2060 return result; 2061} 2062 2063static ant_value_t js_uint8array_toHex(ant_t *js, ant_value_t *args, int nargs) { 2064 ant_value_t this_val = js_getthis(js); 2065 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val); 2066 2067 if (!ta_data || ta_data->type != TYPED_ARRAY_UINT8) 2068 return js_mkerr(js, "Uint8Array.prototype.toHex called on incompatible receiver"); 2069 if (!ta_data->buffer || ta_data->buffer->is_detached) 2070 return js_mkerr(js, "Cannot read from detached Uint8Array"); 2071 2072 uint8_t *data = ta_data->buffer->data + ta_data->byte_offset; 2073 size_t len = ta_data->byte_length; 2074 char *hex = malloc(len * 2 + 1); 2075 2076 if (!hex) return js_mkerr(js, "Failed to allocate hex string"); 2077 for (size_t i = 0; i < len; i++) snprintf(hex + i * 2, 3, "%02x", data[i]); 2078 2079 ant_value_t result = js_mkstr(js, hex, len * 2); 2080 free(hex); 2081 2082 return result; 2083} 2084 2085static ant_value_t js_uint8array_toBase64(ant_t *js, ant_value_t *args, int nargs) { 2086 ant_value_t this_val = js_getthis(js); 2087 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val); 2088 2089 if (!ta_data || ta_data->type != TYPED_ARRAY_UINT8) 2090 return js_mkerr(js, "Uint8Array.prototype.toBase64 called on incompatible receiver"); 2091 if (!ta_data->buffer || ta_data->buffer->is_detached) 2092 return js_mkerr(js, "Cannot read from detached Uint8Array"); 2093 2094 size_t out_len = 0; 2095 char *encoded = ant_base64_encode( 2096 ta_data->buffer->data + ta_data->byte_offset, 2097 ta_data->byte_length, &out_len 2098 ); 2099 2100 if (!encoded) return js_mkerr(js, "Failed to encode base64"); 2101 ant_value_t result = js_mkstr(js, encoded, out_len); 2102 free(encoded); 2103 2104 return result; 2105} 2106 2107static ant_value_t uint8array_set_result(ant_t *js, size_t read, size_t written) { 2108 ant_value_t result = js_mkobj(js); 2109 js_set(js, result, "read", js_mknum((double)read)); 2110 js_set(js, result, "written", js_mknum((double)written)); 2111 return result; 2112} 2113 2114static ant_value_t uint8array_set_bytes(ant_t *js, const uint8_t *bytes, size_t byte_len, size_t read) { 2115 ant_value_t this_val = js_getthis(js); 2116 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val); 2117 2118 if (!ta_data || ta_data->type != TYPED_ARRAY_UINT8) 2119 return js_mkerr(js, "Uint8Array setFrom called on incompatible receiver"); 2120 if (!ta_data->buffer || ta_data->buffer->is_detached) 2121 return js_mkerr(js, "Cannot write to detached Uint8Array"); 2122 if (byte_len > ta_data->byte_length) 2123 return js_mkerr_typed(js, JS_ERR_RANGE, "Decoded data does not fit in Uint8Array"); 2124 2125 if (byte_len > 0) memcpy(ta_data->buffer->data + ta_data->byte_offset, bytes, byte_len); 2126 return uint8array_set_result(js, read, byte_len); 2127} 2128 2129static ant_value_t js_uint8array_setFromHex(ant_t *js, ant_value_t *args, int nargs) { 2130 ant_value_t source = nargs > 0 ? js_tostring_val(js, args[0]) : js_mkstr(js, "", 0); 2131 if (is_err(source)) return source; 2132 2133 size_t len = 0; 2134 char *str = js_getstr(js, source, &len); 2135 size_t decoded_len = 0; 2136 2137 uint8_t *decoded = hex_decode(str, len, &decoded_len); 2138 if (!decoded) return js_mkerr_typed(js, JS_ERR_SYNTAX, "Invalid hex string"); 2139 2140 ant_value_t result = uint8array_set_bytes(js, decoded, decoded_len, len); 2141 free(decoded); 2142 2143 return result; 2144} 2145 2146static ant_value_t js_uint8array_setFromBase64(ant_t *js, ant_value_t *args, int nargs) { 2147 ant_value_t source = nargs > 0 ? js_tostring_val(js, args[0]) : js_mkstr(js, "", 0); 2148 if (is_err(source)) return source; 2149 2150 size_t len = 0; 2151 char *str = js_getstr(js, source, &len); 2152 size_t decoded_len = 0; 2153 2154 uint8_t *decoded = ant_base64_decode(str, len, &decoded_len); 2155 if (!decoded) return js_mkerr_typed(js, JS_ERR_SYNTAX, "Invalid base64 string"); 2156 2157 ant_value_t result = uint8array_set_bytes(js, decoded, decoded_len, len); 2158 free(decoded); 2159 2160 return result; 2161} 2162 2163typedef enum { 2164 ENC_UTF8, 2165 ENC_HEX, 2166 ENC_BASE64, 2167 ENC_ASCII, 2168 ENC_LATIN1, 2169 ENC_UCS2, 2170 ENC_UNKNOWN 2171} BufferEncoding; 2172 2173static BufferEncoding parse_encoding(const char *enc, size_t len) { 2174 if (len == 3 && strncasecmp(enc, "hex", 3) == 0) return ENC_HEX; 2175 if (len == 5 && strncasecmp(enc, "ascii", 5) == 0) return ENC_ASCII; 2176 if (len == 6 && strncasecmp(enc, "base64", 6) == 0) return ENC_BASE64; 2177 if ((len == 4 && strncasecmp(enc, "utf8", 4) == 0) || (len == 5 && strncasecmp(enc, "utf-8", 5) == 0)) return ENC_UTF8; 2178 if ((len == 6 && strncasecmp(enc, "latin1", 6) == 0) || (len == 6 && strncasecmp(enc, "binary", 6) == 0)) return ENC_LATIN1; 2179 2180 if ( 2181 (len == 4 && strncasecmp(enc, "ucs2", 4) == 0) || 2182 (len == 5 && strncasecmp(enc, "ucs-2", 5) == 0) || 2183 (len == 7 && strncasecmp(enc, "utf16le", 7) == 0) || 2184 (len == 8 && strncasecmp(enc, "utf-16le", 8) == 0) 2185 ) return ENC_UCS2; 2186 2187 return ENC_UNKNOWN; 2188} 2189 2190// Buffer.from(array/string/buffer, encoding) 2191static ant_value_t js_buffer_from(ant_t *js, ant_value_t *args, int nargs) { 2192 if (nargs < 1) return js_mkerr(js, "Buffer.from requires at least one argument"); 2193 2194 if (vtype(args[0]) == T_STR) { 2195 size_t len; 2196 char *str = js_getstr(js, args[0], &len); 2197 2198 BufferEncoding encoding = ENC_UTF8; 2199 if (nargs >= 2 && vtype(args[1]) == T_STR) { 2200 size_t enc_len; 2201 char *enc_str = js_getstr(js, args[1], &enc_len); 2202 encoding = parse_encoding(enc_str, enc_len); 2203 if (encoding == ENC_UNKNOWN) encoding = ENC_UTF8; 2204 } 2205 2206 if (encoding == ENC_BASE64) { 2207 size_t decoded_len; 2208 uint8_t *decoded = ant_base64_decode(str, len, &decoded_len); 2209 if (!decoded) return js_mkerr(js, "Failed to decode base64"); 2210 2211 ArrayBufferData *buffer = create_array_buffer_data(decoded_len); 2212 if (!buffer) { free(decoded); return js_mkerr(js, "Failed to allocate buffer"); } 2213 2214 memcpy(buffer->data, decoded, decoded_len); 2215 free(decoded); 2216 return create_typed_array(js, TYPED_ARRAY_UINT8, buffer, 0, decoded_len, "Buffer"); 2217 } else if (encoding == ENC_HEX) { 2218 size_t decoded_len; 2219 uint8_t *decoded = hex_decode(str, len, &decoded_len); 2220 if (!decoded) return js_mkerr(js, "Failed to decode hex"); 2221 2222 ArrayBufferData *buffer = create_array_buffer_data(decoded_len); 2223 if (!buffer) { free(decoded); return js_mkerr(js, "Failed to allocate buffer"); } 2224 2225 memcpy(buffer->data, decoded, decoded_len); 2226 free(decoded); 2227 return create_typed_array(js, TYPED_ARRAY_UINT8, buffer, 0, decoded_len, "Buffer"); 2228 } else if (encoding == ENC_UCS2) { 2229 size_t decoded_len = len * 2; 2230 ArrayBufferData *buffer = create_array_buffer_data(decoded_len); 2231 if (!buffer) return js_mkerr(js, "Failed to allocate buffer"); 2232 2233 for (size_t i = 0; i < len; i++) { 2234 buffer->data[i * 2] = (uint8_t)str[i]; 2235 buffer->data[i * 2 + 1] = 0; 2236 } 2237 return create_typed_array(js, TYPED_ARRAY_UINT8, buffer, 0, decoded_len, "Buffer"); 2238 } else { 2239 ArrayBufferData *buffer = create_array_buffer_data(len); 2240 if (!buffer) return js_mkerr(js, "Failed to allocate buffer"); 2241 2242 memcpy(buffer->data, str, len); 2243 return create_typed_array(js, TYPED_ARRAY_UINT8, buffer, 0, len, "Buffer"); 2244 } 2245 } 2246 2247 ant_value_t length_val = js_get(js, args[0], "length"); 2248 if (vtype(length_val) == T_NUM) { 2249 size_t len = (size_t)js_getnum(length_val); 2250 ArrayBufferData *buffer = create_array_buffer_data(len); 2251 if (!buffer) return js_mkerr(js, "Failed to allocate buffer"); 2252 2253 for (size_t i = 0; i < len; i++) { 2254 char idx_str[32]; 2255 snprintf(idx_str, sizeof(idx_str), "%zu", i); 2256 ant_value_t elem = js_get(js, args[0], idx_str); 2257 if (vtype(elem) == T_NUM) { 2258 buffer->data[i] = (uint8_t)js_getnum(elem); 2259 } 2260 } 2261 2262 return create_typed_array(js, TYPED_ARRAY_UINT8, buffer, 0, len, "Buffer"); 2263 } 2264 2265 return js_mkerr(js, "Invalid argument to Buffer.from"); 2266} 2267 2268// Buffer.alloc(size) 2269static ant_value_t js_buffer_alloc(ant_t *js, ant_value_t *args, int nargs) { 2270 if (nargs < 1) { 2271 return js_mkerr(js, "Buffer.alloc requires a size argument"); 2272 } 2273 2274 size_t size = (size_t)js_getnum(args[0]); 2275 ArrayBufferData *buffer = create_array_buffer_data(size); 2276 if (!buffer) return js_mkerr(js, "Failed to allocate buffer"); 2277 2278 memset(buffer->data, 0, size); 2279 return create_typed_array(js, TYPED_ARRAY_UINT8, buffer, 0, size, "Buffer"); 2280} 2281 2282// Buffer.allocUnsafe(size) 2283static ant_value_t js_buffer_allocUnsafe(ant_t *js, ant_value_t *args, int nargs) { 2284 if (nargs < 1) { 2285 return js_mkerr(js, "Buffer.allocUnsafe requires a size argument"); 2286 } 2287 2288 size_t size = (size_t)js_getnum(args[0]); 2289 ArrayBufferData *buffer = create_array_buffer_data(size); 2290 if (!buffer) return js_mkerr(js, "Failed to allocate buffer"); 2291 return create_typed_array(js, TYPED_ARRAY_UINT8, buffer, 0, size, "Buffer"); 2292} 2293 2294static ant_value_t typedarray_join_with(ant_t *js, ant_value_t this_val, const char *sep, size_t sep_len) { 2295 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val); 2296 if (!ta_data) return js_mkstr(js, "", 0); 2297 if (!ta_data->buffer || ta_data->buffer->is_detached || ta_data->length == 0) 2298 return js_mkstr(js, "", 0); 2299 2300 uint8_t *data = ta_data->buffer->data + ta_data->byte_offset; 2301 size_t len = ta_data->length; 2302 2303 size_t cap = len * 12; 2304 char *buf = malloc(cap); 2305 if (!buf) return js_mkerr(js, "Out of memory"); 2306 size_t pos = 0; 2307 2308 for (size_t i = 0; i < len; i++) { 2309 if (i > 0) { 2310 if (pos + sep_len + 32 > cap) { 2311 cap *= 2; 2312 char *tmp = realloc(buf, cap); 2313 if (!tmp) { free(buf); return js_mkerr(js, "Out of memory"); } 2314 buf = tmp; 2315 } 2316 memcpy(buf + pos, sep, sep_len); 2317 pos += sep_len; 2318 } 2319 2320 if (pos + 32 > cap) { 2321 cap *= 2; 2322 char *tmp = realloc(buf, cap); 2323 if (!tmp) { free(buf); return js_mkerr(js, "Out of memory"); } 2324 buf = tmp; 2325 } 2326 2327 int written = 0; 2328 switch (ta_data->type) { 2329 case TYPED_ARRAY_INT8: written = snprintf(buf + pos, cap - pos, "%d", ((int8_t*)data)[i]); break; 2330 case TYPED_ARRAY_UINT8: 2331 case TYPED_ARRAY_UINT8_CLAMPED: written = snprintf(buf + pos, cap - pos, "%u", data[i]); break; 2332 case TYPED_ARRAY_INT16: written = snprintf(buf + pos, cap - pos, "%d", ((int16_t*)data)[i]); break; 2333 case TYPED_ARRAY_UINT16: written = snprintf(buf + pos, cap - pos, "%u", ((uint16_t*)data)[i]); break; 2334 case TYPED_ARRAY_INT32: written = snprintf(buf + pos, cap - pos, "%d", ((int32_t*)data)[i]); break; 2335 case TYPED_ARRAY_UINT32: written = snprintf(buf + pos, cap - pos, "%u", ((uint32_t*)data)[i]); break; 2336 case TYPED_ARRAY_FLOAT16: written = snprintf(buf + pos, cap - pos, "%g", half_to_double(((uint16_t*)data)[i])); break; 2337 case TYPED_ARRAY_FLOAT32: written = snprintf(buf + pos, cap - pos, "%g", (double)((float*)data)[i]); break; 2338 case TYPED_ARRAY_FLOAT64: written = snprintf(buf + pos, cap - pos, "%g", ((double*)data)[i]); break; 2339 case TYPED_ARRAY_BIGINT64: written = snprintf(buf + pos, cap - pos, "%lld", ((long long*)data)[i]); break; 2340 case TYPED_ARRAY_BIGUINT64: written = snprintf(buf + pos, cap - pos, "%llu", ((unsigned long long*)data)[i]); break; 2341 default: break; 2342 } 2343 if (written > 0) pos += (size_t)written; 2344 } 2345 2346 ant_value_t ret = js_mkstr(js, buf, pos); 2347 free(buf); 2348 return ret; 2349} 2350 2351// TypedArray.prototype.toString() 2352static ant_value_t js_typedarray_toString(ant_t *js, ant_value_t *args, int nargs) { 2353 return typedarray_join_with(js, js_getthis(js), ",", 1); 2354} 2355 2356// TypedArray.prototype.join(separator) 2357static ant_value_t js_typedarray_join(ant_t *js, ant_value_t *args, int nargs) { 2358 const char *sep = ","; 2359 size_t sep_len = 1; 2360 if (nargs > 0 && vtype(args[0]) == T_STR) 2361 sep = js_getstr(js, args[0], &sep_len); 2362 return typedarray_join_with(js, js_getthis(js), sep, sep_len); 2363} 2364 2365static ant_value_t js_typedarray_indexOf(ant_t *js, ant_value_t *args, int nargs) { 2366 ant_value_t this_val = js_getthis(js); 2367 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val); 2368 if (!ta_data || !ta_data->buffer || ta_data->buffer->is_detached) return js_mknum(-1); 2369 2370 size_t len = ta_data->length; 2371 if (len == 0 || nargs < 1) return js_mknum(-1); 2372 2373 int64_t from_index = 0; 2374 if (nargs > 1 && vtype(args[1]) != T_UNDEF) { 2375 from_index = (int64_t)js_to_number(js, args[1]); 2376 if (from_index < 0) { 2377 from_index += (int64_t)len; 2378 if (from_index < 0) from_index = 0; 2379 }} 2380 2381 if ((size_t)from_index >= len) return js_mknum(-1); 2382 uint8_t *data = ta_data->buffer->data + ta_data->byte_offset; 2383 double needle_num = js_to_number(js, args[0]); 2384 2385 for (size_t i = (size_t)from_index; i < len; i++) { 2386 bool match = false; 2387 switch (ta_data->type) { 2388 case TYPED_ARRAY_INT8: match = ((int8_t *)data)[i] == (int8_t)needle_num; break; 2389 case TYPED_ARRAY_UINT8: 2390 case TYPED_ARRAY_UINT8_CLAMPED: match = data[i] == (uint8_t)needle_num; break; 2391 case TYPED_ARRAY_INT16: match = ((int16_t *)data)[i] == (int16_t)needle_num; break; 2392 case TYPED_ARRAY_UINT16: match = ((uint16_t *)data)[i] == (uint16_t)needle_num; break; 2393 case TYPED_ARRAY_INT32: match = ((int32_t *)data)[i] == (int32_t)needle_num; break; 2394 case TYPED_ARRAY_UINT32: match = ((uint32_t *)data)[i] == (uint32_t)needle_num; break; 2395 case TYPED_ARRAY_FLOAT16: match = half_to_double(((uint16_t *)data)[i]) == needle_num; break; 2396 case TYPED_ARRAY_FLOAT32: match = ((float *)data)[i] == (float)needle_num; break; 2397 case TYPED_ARRAY_FLOAT64: match = ((double *)data)[i] == needle_num; break; 2398 case TYPED_ARRAY_BIGINT64: match = ((int64_t *)data)[i] == (int64_t)needle_num; break; 2399 case TYPED_ARRAY_BIGUINT64: match = ((uint64_t *)data)[i] == (uint64_t)needle_num; break; 2400 default: break; 2401 } 2402 if (match) return js_mknum((double)i); 2403 } 2404 2405 return js_mknum(-1); 2406} 2407 2408static ant_value_t js_typedarray_includes(ant_t *js, ant_value_t *args, int nargs) { 2409 ant_value_t this_val = js_getthis(js); 2410 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val); 2411 2412 if (!ta_data || !ta_data->buffer || ta_data->buffer->is_detached) { 2413 return js_mkerr(js, "Invalid TypedArray"); 2414 } 2415 2416 size_t len = ta_data->length; 2417 ant_value_t search = (nargs > 0) ? args[0] : js_mkundef(); 2418 2419 if (len == 0) return js_false; 2420 int64_t from_index = 0; 2421 2422 if (nargs > 1 && vtype(args[1]) != T_UNDEF) { 2423 double from_index_num = js_to_number(js, args[1]); 2424 if (!isnan(from_index_num)) from_index = (int64_t)from_index_num; 2425 if (from_index < 0) { 2426 from_index += (int64_t)len; 2427 if (from_index < 0) from_index = 0; 2428 }} 2429 2430 if ((size_t)from_index >= len) return js_false; 2431 2432 if (ta_data->type == TYPED_ARRAY_BIGINT64) { 2433 int64_t needle = 0; 2434 if (vtype(search) == T_BIGINT) { 2435 if (!bigint_to_int64_wrapping(js, search, &needle)) return js_false; 2436 } else needle = (int64_t)js_to_number(js, search); 2437 2438 int64_t *data = (int64_t *)(ta_data->buffer->data + ta_data->byte_offset); 2439 for (size_t i = (size_t)from_index; i < len; i++) { 2440 if (data[i] == needle) return js_true; 2441 } 2442 2443 return js_false; 2444 } 2445 2446 if (ta_data->type == TYPED_ARRAY_BIGUINT64) { 2447 uint64_t needle = 0; 2448 if (vtype(search) == T_BIGINT) { 2449 if (!bigint_to_uint64_wrapping(js, search, &needle)) return js_false; 2450 } else needle = (uint64_t)js_to_number(js, search); 2451 2452 uint64_t *data = (uint64_t *)(ta_data->buffer->data + ta_data->byte_offset); 2453 for (size_t i = (size_t)from_index; i < len; i++) { 2454 if (data[i] == needle) return js_true; 2455 } 2456 2457 return js_false; 2458 } 2459 2460 double needle = js_to_number(js, search); 2461 for (size_t i = (size_t)from_index; i < len; i++) { 2462 double value = 0; 2463 if (!typedarray_read_number(ta_data, i, &value)) return js_false; 2464 if (isnan(value) && isnan(needle)) return js_true; 2465 if (value == needle) return js_true; 2466 } 2467 2468 return js_false; 2469} 2470 2471// Buffer.prototype.toString(encoding) 2472static ant_value_t js_buffer_slice(ant_t *js, ant_value_t *args, int nargs) { 2473 return js_typedarray_subarray(js, args, nargs); 2474} 2475 2476// Buffer.prototype.toString(encoding) 2477static ant_value_t js_buffer_toString(ant_t *js, ant_value_t *args, int nargs) { 2478 ant_value_t this_val = js_getthis(js); 2479 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val); 2480 if (!ta_data) return js_mkerr(js, "Invalid Buffer"); 2481 2482 BufferEncoding encoding = ENC_UTF8; 2483 if (nargs > 0 && vtype(args[0]) == T_STR) { 2484 size_t enc_len; 2485 char *enc_str = js_getstr(js, args[0], &enc_len); 2486 encoding = parse_encoding(enc_str, enc_len); 2487 if (encoding == ENC_UNKNOWN) encoding = ENC_UTF8; 2488 } 2489 2490 if (!ta_data->buffer || ta_data->buffer->is_detached) { 2491 return js_mkerr(js, "Cannot read from detached buffer"); 2492 } 2493 2494 uint8_t *data = ta_data->buffer->data + ta_data->byte_offset; 2495 size_t len = ta_data->byte_length; 2496 2497 if (encoding == ENC_BASE64) { 2498 size_t out_len; 2499 char *encoded = ant_base64_encode(data, len, &out_len); 2500 if (!encoded) return js_mkerr(js, "Failed to encode base64"); 2501 2502 ant_value_t result = js_mkstr(js, encoded, out_len); 2503 free(encoded); 2504 return result; 2505 } else if (encoding == ENC_HEX) { 2506 char *hex = malloc(len * 2 + 1); 2507 if (!hex) return js_mkerr(js, "Failed to allocate hex string"); 2508 2509 for (size_t i = 0; i < len; i++) { 2510 snprintf(hex + i * 2, 3, "%02x", data[i]); 2511 } 2512 2513 ant_value_t result = js_mkstr(js, hex, len * 2); 2514 free(hex); 2515 return result; 2516 } else if (encoding == ENC_UCS2) { 2517 size_t char_count = len / 2; 2518 char *str = malloc(char_count + 1); 2519 if (!str) return js_mkerr(js, "Failed to allocate string"); 2520 2521 for (size_t i = 0; i < char_count; i++) str[i] = (char)data[i * 2]; 2522 str[char_count] = '\0'; 2523 2524 ant_value_t result = js_mkstr(js, str, char_count); 2525 free(str); 2526 return result; 2527 } else { 2528 size_t out_cap = len * 3 + 1; 2529 char *out = malloc(out_cap); 2530 if (!out) return js_mkerr(js, "Failed to allocate string"); 2531 2532 utf8_dec_t dec = { .bom_seen = true, .ignore_bom = true }; 2533 utf8proc_ssize_t out_len = utf8_whatwg_decode(&dec, data, len, out, false, false); 2534 2535 if (out_len < 0) { 2536 free(out); 2537 return js_mkerr(js, "Failed to decode buffer as UTF-8"); 2538 } 2539 2540 ant_value_t result = js_mkstr(js, out, (size_t)out_len); 2541 free(out); 2542 2543 return result; 2544 } 2545} 2546 2547// Buffer.prototype.toBase64() 2548static ant_value_t js_buffer_toBase64(ant_t *js, ant_value_t *args, int nargs) { 2549 (void)args; (void)nargs; 2550 ant_value_t encoding_arg = js_mkstr(js, "base64", 6); 2551 ant_value_t new_args[1] = {encoding_arg}; 2552 return js_buffer_toString(js, new_args, 1); 2553} 2554 2555// Buffer.prototype.write(string, offset, length, encoding) 2556static ant_value_t js_buffer_write(ant_t *js, ant_value_t *args, int nargs) { 2557 if (nargs < 1) return js_mkerr(js, "write requires a string"); 2558 2559 ant_value_t this_val = js_getthis(js); 2560 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val); 2561 if (!ta_data) return js_mkerr(js, "Invalid Buffer"); 2562 2563 size_t str_len; 2564 char *str = js_getstr(js, args[0], &str_len); 2565 size_t offset = 0; 2566 size_t length = ta_data->byte_length; 2567 2568 if (nargs > 1 && vtype(args[1]) == T_NUM) { 2569 offset = (size_t)js_getnum(args[1]); 2570 } 2571 2572 if (nargs > 2 && vtype(args[2]) == T_NUM) { 2573 length = (size_t)js_getnum(args[2]); 2574 } 2575 2576 if (offset >= ta_data->byte_length) { 2577 return js_mknum(0); 2578 } 2579 2580 size_t available = ta_data->byte_length - offset; 2581 size_t to_write = (str_len < length) ? str_len : length; 2582 to_write = (to_write < available) ? to_write : available; 2583 2584 memcpy(ta_data->buffer->data + ta_data->byte_offset + offset, str, to_write); 2585 return js_mknum((double)to_write); 2586} 2587 2588static ant_value_t js_buffer_copy(ant_t *js, ant_value_t *args, int nargs) { 2589 if (nargs < 1) return js_mkerr(js, "copy requires a target buffer"); 2590 2591 TypedArrayData *src = buffer_get_typedarray_data(js_getthis(js)); 2592 TypedArrayData *dst = buffer_get_typedarray_data(args[0]); 2593 if (!src || !dst) return js_mkerr(js, "copy requires Buffer arguments"); 2594 2595 size_t target_start = (nargs > 1 && vtype(args[1]) == T_NUM) ? (size_t)js_getnum(args[1]) : 0; 2596 size_t source_start = (nargs > 2 && vtype(args[2]) == T_NUM) ? (size_t)js_getnum(args[2]) : 0; 2597 size_t source_end = (nargs > 3 && vtype(args[3]) == T_NUM) ? (size_t)js_getnum(args[3]) : src->byte_length; 2598 2599 if (target_start > dst->byte_length) target_start = dst->byte_length; 2600 if (source_start > src->byte_length) source_start = src->byte_length; 2601 if (source_end > src->byte_length) source_end = src->byte_length; 2602 if (source_end < source_start) source_end = source_start; 2603 2604 size_t src_len = source_end - source_start; 2605 size_t dst_len = dst->byte_length - target_start; 2606 size_t copy_len = src_len < dst_len ? src_len : dst_len; 2607 if (copy_len == 0) return js_mknum(0); 2608 2609 uint8_t *src_ptr = src->buffer->data + src->byte_offset + source_start; 2610 uint8_t *dst_ptr = dst->buffer->data + dst->byte_offset + target_start; 2611 memmove(dst_ptr, src_ptr, copy_len); 2612 2613 return js_mknum((double)copy_len); 2614} 2615 2616static ant_value_t js_buffer_writeInt16BE(ant_t *js, ant_value_t *args, int nargs) { 2617 if (nargs < 1) return js_mkerr(js, "writeInt16BE requires a value"); 2618 2619 TypedArrayData *ta = buffer_get_typedarray_data(js_getthis(js)); 2620 if (!ta) return js_mkerr(js, "Invalid Buffer"); 2621 2622 int16_t value = (int16_t)js_to_int32(js_getnum(args[0])); 2623 size_t offset = (nargs > 1 && vtype(args[1]) == T_NUM) ? (size_t)js_getnum(args[1]) : 0; 2624 if (offset + 2 > ta->byte_length) return js_mkerr(js, "Offset out of bounds"); 2625 2626 uint8_t *ptr = ta->buffer->data + ta->byte_offset + offset; 2627 ptr[0] = (uint8_t)((value >> 8) & 0xff); 2628 ptr[1] = (uint8_t)(value & 0xff); 2629 2630 return js_mknum((double)(offset + 2)); 2631} 2632 2633static ant_value_t js_buffer_writeInt32BE(ant_t *js, ant_value_t *args, int nargs) { 2634 if (nargs < 1) return js_mkerr(js, "writeInt32BE requires a value"); 2635 2636 TypedArrayData *ta = buffer_get_typedarray_data(js_getthis(js)); 2637 if (!ta) return js_mkerr(js, "Invalid Buffer"); 2638 2639 int32_t value = js_to_int32(js_getnum(args[0])); 2640 size_t offset = (nargs > 1 && vtype(args[1]) == T_NUM) ? (size_t)js_getnum(args[1]) : 0; 2641 if (offset + 4 > ta->byte_length) return js_mkerr(js, "Offset out of bounds"); 2642 2643 uint8_t *ptr = ta->buffer->data + ta->byte_offset + offset; 2644 ptr[0] = (uint8_t)((value >> 24) & 0xff); 2645 ptr[1] = (uint8_t)((value >> 16) & 0xff); 2646 ptr[2] = (uint8_t)((value >> 8) & 0xff); 2647 ptr[3] = (uint8_t)(value & 0xff); 2648 2649 return js_mknum((double)(offset + 4)); 2650} 2651 2652static ant_value_t js_buffer_writeUInt32BE(ant_t *js, ant_value_t *args, int nargs) { 2653 if (nargs < 1) return js_mkerr(js, "writeUInt32BE requires a value"); 2654 2655 TypedArrayData *ta = buffer_get_typedarray_data(js_getthis(js)); 2656 if (!ta) return js_mkerr(js, "Invalid Buffer"); 2657 2658 uint32_t value = js_to_uint32(js_getnum(args[0])); 2659 size_t offset = (nargs > 1 && vtype(args[1]) == T_NUM) ? (size_t)js_getnum(args[1]) : 0; 2660 if (offset + 4 > ta->byte_length) return js_mkerr(js, "Offset out of bounds"); 2661 2662 uint8_t *ptr = ta->buffer->data + ta->byte_offset + offset; 2663 ptr[0] = (uint8_t)((value >> 24) & 0xff); 2664 ptr[1] = (uint8_t)((value >> 16) & 0xff); 2665 ptr[2] = (uint8_t)((value >> 8) & 0xff); 2666 ptr[3] = (uint8_t)(value & 0xff); 2667 2668 return js_mknum((double)(offset + 4)); 2669} 2670 2671static ant_value_t js_buffer_readInt16BE(ant_t *js, ant_value_t *args, int nargs) { 2672 TypedArrayData *ta = buffer_get_typedarray_data(js_getthis(js)); 2673 if (!ta) return js_mkerr(js, "Invalid Buffer"); 2674 2675 size_t offset = (nargs > 0 && vtype(args[0]) == T_NUM) ? (size_t)js_getnum(args[0]) : 0; 2676 if (offset + 2 > ta->byte_length) return js_mkerr(js, "Offset out of bounds"); 2677 2678 uint8_t *ptr = ta->buffer->data + ta->byte_offset + offset; 2679 int16_t value = (int16_t)((ptr[0] << 8) | ptr[1]); 2680 2681 return js_mknum((double)value); 2682} 2683 2684static ant_value_t js_buffer_readInt32BE(ant_t *js, ant_value_t *args, int nargs) { 2685 TypedArrayData *ta = buffer_get_typedarray_data(js_getthis(js)); 2686 if (!ta) return js_mkerr(js, "Invalid Buffer"); 2687 2688 size_t offset = (nargs > 0 && vtype(args[0]) == T_NUM) ? (size_t)js_getnum(args[0]) : 0; 2689 if (offset + 4 > ta->byte_length) return js_mkerr(js, "Offset out of bounds"); 2690 2691 uint8_t *ptr = ta->buffer->data + ta->byte_offset + offset; 2692 int32_t value = (int32_t)(((uint32_t)ptr[0] << 24) | ((uint32_t)ptr[1] << 16) | 2693 ((uint32_t)ptr[2] << 8) | (uint32_t)ptr[3]); 2694 2695 return js_mknum((double)value); 2696} 2697 2698static ant_value_t js_buffer_readUInt32BE(ant_t *js, ant_value_t *args, int nargs) { 2699 TypedArrayData *ta = buffer_get_typedarray_data(js_getthis(js)); 2700 if (!ta) return js_mkerr(js, "Invalid Buffer"); 2701 2702 size_t offset = (nargs > 0 && vtype(args[0]) == T_NUM) ? (size_t)js_getnum(args[0]) : 0; 2703 if (offset + 4 > ta->byte_length) return js_mkerr(js, "Offset out of bounds"); 2704 2705 uint8_t *ptr = ta->buffer->data + ta->byte_offset + offset; 2706 uint32_t value = ((uint32_t)ptr[0] << 24) | ((uint32_t)ptr[1] << 16) | 2707 ((uint32_t)ptr[2] << 8) | (uint32_t)ptr[3]; 2708 2709 return js_mknum((double)value); 2710} 2711 2712// Buffer.isBuffer(obj) 2713static ant_value_t js_buffer_isBuffer(ant_t *js, ant_value_t *args, int nargs) { 2714 if (nargs < 1) return js_false; 2715 if (!is_special_object(args[0])) return js_false; 2716 2717 ant_value_t proto = js_get_proto(js, args[0]); 2718 ant_value_t buffer_proto = js_get_ctor_proto(js, "Buffer", 6); 2719 2720 return js_bool(proto == buffer_proto); 2721} 2722 2723// Buffer.isEncoding(encoding) 2724static ant_value_t js_buffer_isEncoding(ant_t *js, ant_value_t *args, int nargs) { 2725 if (nargs < 1 || vtype(args[0]) != T_STR) return js_false; 2726 2727 size_t len; 2728 char *enc = js_getstr(js, args[0], &len); 2729 2730 if ((len == 4 && strncasecmp(enc, "utf8", 4) == 0) || 2731 (len == 5 && strncasecmp(enc, "utf-8", 5) == 0) || 2732 (len == 3 && strncasecmp(enc, "hex", 3) == 0) || 2733 (len == 6 && strncasecmp(enc, "base64", 6) == 0) || 2734 (len == 5 && strncasecmp(enc, "ascii", 5) == 0) || 2735 (len == 6 && strncasecmp(enc, "latin1", 6) == 0) || 2736 (len == 6 && strncasecmp(enc, "binary", 6) == 0) || 2737 (len == 4 && strncasecmp(enc, "ucs2", 4) == 0) || 2738 (len == 5 && strncasecmp(enc, "ucs-2", 5) == 0) || 2739 (len == 7 && strncasecmp(enc, "utf16le", 7) == 0) || 2740 (len == 8 && strncasecmp(enc, "utf-16le", 8) == 0)) { 2741 return js_true; 2742 } 2743 2744 return js_false; 2745} 2746 2747// Buffer.byteLength(string, encoding) 2748static ant_value_t js_buffer_byteLength(ant_t *js, ant_value_t *args, int nargs) { 2749 if (nargs < 1) return js_mknum(0); 2750 2751 ant_value_t arg = args[0]; 2752 2753 if (is_special_object(arg)) { 2754 ant_value_t bytelen = js_get(js, arg, "byteLength"); 2755 if (vtype(bytelen) == T_NUM) return bytelen; 2756 2757 ant_value_t len = js_get(js, arg, "length"); 2758 if (vtype(len) == T_NUM) return len; 2759 } 2760 2761 if (vtype(arg) == T_STR) { 2762 size_t len; 2763 js_getstr(js, arg, &len); 2764 return js_mknum((double)len); 2765 } 2766 2767 return js_mknum(0); 2768} 2769 2770// Buffer.concat(list, totalLength) 2771static ant_value_t js_buffer_concat(ant_t *js, ant_value_t *args, int nargs) { 2772 if (nargs < 1 || !is_special_object(args[0])) { 2773 return js_mkerr(js, "First argument must be an array"); 2774 } 2775 2776 ant_value_t list = args[0]; 2777 ant_value_t len_val = js_get(js, list, "length"); 2778 if (vtype(len_val) != T_NUM) { 2779 return js_mkerr(js, "First argument must be an array"); 2780 } 2781 2782 size_t list_len = (size_t)js_getnum(len_val); 2783 size_t total_length = 0; 2784 2785 if (nargs > 1 && vtype(args[1]) == T_NUM) { 2786 total_length = (size_t)js_getnum(args[1]); 2787 } else { 2788 for (size_t i = 0; i < list_len; i++) { 2789 char idx[16]; 2790 snprintf(idx, sizeof(idx), "%zu", i); 2791 ant_value_t buf = js_get(js, list, idx); 2792 ant_value_t buf_len = js_get(js, buf, "length"); 2793 if (vtype(buf_len) == T_NUM) total_length += (size_t)js_getnum(buf_len); 2794 } 2795 } 2796 2797 ArrayBufferData *buffer = create_array_buffer_data(total_length); 2798 if (!buffer) return js_mkerr(js, "Failed to allocate buffer"); 2799 2800 size_t offset = 0; 2801 for (size_t i = 0; i < list_len && offset < total_length; i++) { 2802 char idx[16]; 2803 snprintf(idx, sizeof(idx), "%zu", i); 2804 ant_value_t buf = js_get(js, list, idx); 2805 2806 TypedArrayData *ta = buffer_get_typedarray_data(buf); 2807 if (!ta || !ta->buffer) continue; 2808 2809 size_t copy_len = ta->byte_length; 2810 if (offset + copy_len > total_length) { 2811 copy_len = total_length - offset; 2812 } 2813 2814 memcpy(buffer->data + offset, ta->buffer->data + ta->byte_offset, copy_len); 2815 offset += copy_len; 2816 } 2817 2818 return create_typed_array(js, TYPED_ARRAY_UINT8, buffer, 0, total_length, "Buffer"); 2819} 2820 2821// Buffer.compare(buf1, buf2) 2822static ant_value_t js_buffer_compare(ant_t *js, ant_value_t *args, int nargs) { 2823 if (nargs < 2) return js_mkerr(js, "Buffer.compare requires two arguments"); 2824 2825 TypedArrayData *ta1 = buffer_get_typedarray_data(args[0]); 2826 TypedArrayData *ta2 = buffer_get_typedarray_data(args[1]); 2827 2828 if (!ta1 || !ta2) { 2829 return js_mkerr(js, "Arguments must be Buffers"); 2830 } 2831 2832 if (!ta1 || !ta1->buffer || !ta2 || !ta2->buffer) { 2833 return js_mkerr(js, "Invalid buffer"); 2834 } 2835 2836 size_t len = ta1->byte_length < ta2->byte_length ? ta1->byte_length : ta2->byte_length; 2837 int cmp = memcmp(ta1->buffer->data + ta1->byte_offset, ta2->buffer->data + ta2->byte_offset, len); 2838 2839 if (cmp == 0) { 2840 if (ta1->byte_length < ta2->byte_length) cmp = -1; 2841 else if (ta1->byte_length > ta2->byte_length) cmp = 1; 2842 } else cmp = cmp < 0 ? -1 : 1; 2843 2844 return js_mknum((double)cmp); 2845} 2846 2847static ant_value_t js_sharedarraybuffer_constructor(ant_t *js, ant_value_t *args, int nargs) { 2848 if (vtype(js->new_target) == T_UNDEF) { 2849 return js_mkerr_typed(js, JS_ERR_TYPE, "SharedArrayBuffer constructor requires 'new'"); 2850 } 2851 size_t length = 0; 2852 if (nargs > 0 && vtype(args[0]) == T_NUM) { 2853 length = (size_t)js_getnum(args[0]); 2854 } 2855 2856 ArrayBufferData *data = create_shared_array_buffer_data(length); 2857 if (!data) { 2858 return js_mkerr(js, "Failed to allocate SharedArrayBuffer"); 2859 } 2860 2861 ant_value_t obj = js_mkobj(js); 2862 ant_value_t proto = js_get_ctor_proto(js, "SharedArrayBuffer", 17); 2863 2864 if (is_special_object(proto)) js_set_proto_init(obj, proto); 2865 js_set_native(obj, data, BUFFER_ARRAYBUFFER_NATIVE_TAG); 2866 js_set(js, obj, "byteLength", js_mknum((double)length)); 2867 js_set_finalizer(obj, arraybuffer_finalize); 2868 2869 return obj; 2870} 2871 2872static ant_value_t buffer_make_constants(ant_t *js) { 2873 ant_value_t constants = js_newobj(js); 2874 js_set(js, constants, "MAX_LENGTH", js_mknum(BUFFER_COMPAT_MAX_LENGTH)); 2875 js_set(js, constants, "MAX_STRING_LENGTH", js_mknum(BUFFER_COMPAT_MAX_STRING_LENGTH)); 2876 return constants; 2877} 2878 2879ant_value_t buffer_library(ant_t *js) { 2880 ant_value_t glob = js_glob(js); 2881 ant_value_t lib = js_newobj(js); 2882 2883 js_set(js, lib, "Buffer", js_get(js, glob, "Buffer")); 2884 js_set(js, lib, "Blob", js_get(js, glob, "Blob")); 2885 js_set(js, lib, "File", js_get(js, glob, "File")); 2886 js_set(js, lib, "atob", js_get(js, glob, "atob")); 2887 js_set(js, lib, "btoa", js_get(js, glob, "btoa")); 2888 js_set(js, lib, "constants", buffer_make_constants(js)); 2889 js_set(js, lib, "kMaxLength", js_mknum(BUFFER_COMPAT_MAX_LENGTH)); 2890 js_set(js, lib, "kStringMaxLength", js_mknum(BUFFER_COMPAT_MAX_STRING_LENGTH)); 2891 js_set(js, lib, "INSPECT_MAX_BYTES", js_mknum(BUFFER_COMPAT_INSPECT_MAX_BYTES)); 2892 2893 return lib; 2894} 2895 2896void init_buffer_module() { 2897 ant_t *js = rt->js; 2898 2899 ant_value_t glob = js->global; 2900 ant_value_t object_proto = js->sym.object_proto; 2901 2902 ant_value_t arraybuffer_ctor_obj = js_mkobj(js); 2903 ant_value_t arraybuffer_proto = js_mkobj(js); 2904 js_set_proto_init(arraybuffer_proto, object_proto); 2905 2906 js_set(js, arraybuffer_proto, "slice", js_mkfun(js_arraybuffer_slice)); 2907 js_set(js, arraybuffer_proto, "transfer", js_mkfun(js_arraybuffer_transfer)); 2908 js_set(js, arraybuffer_proto, "transferToFixedLength", js_mkfun(js_arraybuffer_transferToFixedLength)); 2909 js_set_getter_desc(js, arraybuffer_proto, "detached", 8, js_mkfun(js_arraybuffer_detached_getter), JS_DESC_E); 2910 js_set_getter_desc(js, arraybuffer_proto, "byteLength", 10, js_mkfun(js_arraybuffer_byteLength_getter), JS_DESC_C); 2911 js_set_sym(js, arraybuffer_proto, get_toStringTag_sym(), js_mkstr(js, "ArrayBuffer", 11)); 2912 2913 js_set_slot(arraybuffer_ctor_obj, SLOT_CFUNC, js_mkfun(js_arraybuffer_constructor)); 2914 js_mkprop_fast(js, arraybuffer_ctor_obj, "prototype", 9, arraybuffer_proto); 2915 js_mkprop_fast(js, arraybuffer_ctor_obj, "name", 4, ANT_STRING("ArrayBuffer")); 2916 js_set_descriptor(js, arraybuffer_ctor_obj, "name", 4, 0); 2917 js_set(js, arraybuffer_ctor_obj, "isView", js_mkfun(js_arraybuffer_isView)); 2918 js_define_species_getter(js, arraybuffer_ctor_obj); 2919 ant_value_t arraybuffer_ctor = js_obj_to_func(arraybuffer_ctor_obj); 2920 js_set(js, arraybuffer_proto, "constructor", arraybuffer_ctor); 2921 js_set_descriptor(js, arraybuffer_proto, "constructor", 11, JS_DESC_W | JS_DESC_C); 2922 js_set(js, glob, "ArrayBuffer", arraybuffer_ctor); 2923 2924 ant_value_t typedarray_proto = js_mkobj(js); 2925 js_set_proto_init(typedarray_proto, object_proto); 2926 2927 js_set(js, typedarray_proto, "at", js_mkfun(js_typedarray_at)); 2928 js_set(js, typedarray_proto, "set", js_mkfun(js_typedarray_set)); 2929 js_set(js, typedarray_proto, "copyWithin", js_mkfun(js_typedarray_copyWithin)); 2930 js_set(js, typedarray_proto, "slice", js_mkfun(js_typedarray_slice)); 2931 js_set(js, typedarray_proto, "subarray", js_mkfun(js_typedarray_subarray)); 2932 js_set(js, typedarray_proto, "fill", js_mkfun(js_typedarray_fill)); 2933 js_set(js, typedarray_proto, "toReversed", js_mkfun(js_typedarray_toReversed)); 2934 js_set(js, typedarray_proto, "toSorted", js_mkfun(js_typedarray_toSorted)); 2935 js_set(js, typedarray_proto, "with", js_mkfun(js_typedarray_with)); 2936 js_set(js, typedarray_proto, "toString", js_mkfun(js_typedarray_toString)); 2937 js_set(js, typedarray_proto, "join", js_mkfun(js_typedarray_join)); 2938 js_set(js, typedarray_proto, "indexOf", js_mkfun(js_typedarray_indexOf)); 2939 js_set(js, typedarray_proto, "includes", js_mkfun(js_typedarray_includes)); 2940 js_set(js, typedarray_proto, "every", js_mkfun(js_typedarray_every)); 2941 js_set_sym(js, typedarray_proto, get_toStringTag_sym(), js_mkstr(js, "TypedArray", 10)); 2942 2943 g_typedarray_iter_proto = js_mkobj(js); 2944 js_set_proto_init(g_typedarray_iter_proto, js->sym.iterator_proto); 2945 js_set(js, g_typedarray_iter_proto, "next", js_mkfun(ta_iter_next)); 2946 js_iter_register_advance(g_typedarray_iter_proto, advance_typedarray); 2947 2948 js_set(js, typedarray_proto, "values", js_mkfun(ta_values)); 2949 js_set(js, typedarray_proto, "keys", js_mkfun(ta_keys)); 2950 js_set(js, typedarray_proto, "entries", js_mkfun(ta_entries)); 2951 js_set_sym(js, typedarray_proto, get_iterator_sym(), js_get(js, typedarray_proto, "values")); 2952 2953 // TODO: find a better way of doing this, macro is code smell 2954 #define SETUP_TYPEDARRAY(name) \ 2955 do { \ 2956 ant_value_t name##_ctor_obj = js_mkobj(js); \ 2957 ant_value_t name##_proto = js_mkobj(js); \ 2958 js_set_proto_init(name##_proto, typedarray_proto); \ 2959 js_set_sym(js, name##_proto, get_toStringTag_sym(), js_mkstr(js, #name, sizeof(#name) - 1)); \ 2960 js_set_slot(name##_ctor_obj, SLOT_CFUNC, js_mkfun(js_##name##_constructor)); \ 2961 js_setprop(js, name##_ctor_obj, js_mkstr(js, "prototype", 9), name##_proto); \ 2962 js_mkprop_fast(js, name##_ctor_obj, "name", 4, ANT_STRING(#name)); \ 2963 js_set_descriptor(js, name##_ctor_obj, "name", 4, 0); \ 2964 js_define_species_getter(js, name##_ctor_obj); \ 2965 js_set(js, name##_ctor_obj, "from", js_mkfun(js_##name##_from)); \ 2966 ant_value_t name##_ctor = js_obj_to_func(name##_ctor_obj); \ 2967 js_setprop(js, name##_proto, ANT_STRING("constructor"), name##_ctor); \ 2968 js_set_descriptor(js, name##_proto, "constructor", 11, JS_DESC_W | JS_DESC_C); \ 2969 js_set(js, glob, #name, name##_ctor); \ 2970 } while(0) 2971 2972 SETUP_TYPEDARRAY(Int8Array); 2973 SETUP_TYPEDARRAY(Uint8Array); 2974 SETUP_TYPEDARRAY(Uint8ClampedArray); 2975 SETUP_TYPEDARRAY(Int16Array); 2976 SETUP_TYPEDARRAY(Uint16Array); 2977 SETUP_TYPEDARRAY(Int32Array); 2978 SETUP_TYPEDARRAY(Uint32Array); 2979 SETUP_TYPEDARRAY(Float16Array); 2980 SETUP_TYPEDARRAY(Float32Array); 2981 SETUP_TYPEDARRAY(Float64Array); 2982 SETUP_TYPEDARRAY(BigInt64Array); 2983 SETUP_TYPEDARRAY(BigUint64Array); 2984 2985 ant_value_t uint8array_codec_ctor = js_get(js, glob, "Uint8Array"); 2986 ant_value_t uint8array_codec_proto = js_get(js, uint8array_codec_ctor, "prototype"); 2987 js_set(js, uint8array_codec_ctor, "fromHex", js_mkfun(js_uint8array_fromHex)); 2988 js_set(js, uint8array_codec_ctor, "fromBase64", js_mkfun(js_uint8array_fromBase64)); 2989 js_set(js, uint8array_codec_proto, "toHex", js_mkfun(js_uint8array_toHex)); 2990 js_set(js, uint8array_codec_proto, "toBase64", js_mkfun(js_uint8array_toBase64)); 2991 js_set(js, uint8array_codec_proto, "setFromHex", js_mkfun(js_uint8array_setFromHex)); 2992 js_set(js, uint8array_codec_proto, "setFromBase64", js_mkfun(js_uint8array_setFromBase64)); 2993 2994 ant_value_t dataview_ctor_obj = js_mkobj(js); 2995 ant_value_t dataview_proto = js_mkobj(js); 2996 js_set_proto_init(dataview_proto, object_proto); 2997 2998 js_set(js, dataview_proto, "getInt8", js_mkfun(js_dataview_getInt8)); 2999 js_set(js, dataview_proto, "setInt8", js_mkfun(js_dataview_setInt8)); 3000 js_set(js, dataview_proto, "getUint8", js_mkfun(js_dataview_getUint8)); 3001 js_set(js, dataview_proto, "setUint8", js_mkfun(js_dataview_setUint8)); 3002 js_set(js, dataview_proto, "getInt16", js_mkfun(js_dataview_getInt16)); 3003 js_set(js, dataview_proto, "setInt16", js_mkfun(js_dataview_setInt16)); 3004 js_set(js, dataview_proto, "getUint16", js_mkfun(js_dataview_getUint16)); 3005 js_set(js, dataview_proto, "setUint16", js_mkfun(js_dataview_setUint16)); 3006 js_set(js, dataview_proto, "getInt32", js_mkfun(js_dataview_getInt32)); 3007 js_set(js, dataview_proto, "setInt32", js_mkfun(js_dataview_setInt32)); 3008 js_set(js, dataview_proto, "getUint32", js_mkfun(js_dataview_getUint32)); 3009 js_set(js, dataview_proto, "setUint32", js_mkfun(js_dataview_setUint32)); 3010 js_set(js, dataview_proto, "getFloat32", js_mkfun(js_dataview_getFloat32)); 3011 js_set(js, dataview_proto, "setFloat32", js_mkfun(js_dataview_setFloat32)); 3012 js_set(js, dataview_proto, "getFloat64", js_mkfun(js_dataview_getFloat64)); 3013 js_set(js, dataview_proto, "setFloat64", js_mkfun(js_dataview_setFloat64)); 3014 js_set(js, dataview_proto, "getBigInt64", js_mkfun(js_dataview_getBigInt64)); 3015 js_set(js, dataview_proto, "setBigInt64", js_mkfun(js_dataview_setBigInt64)); 3016 js_set(js, dataview_proto, "getBigUint64", js_mkfun(js_dataview_getBigUint64)); 3017 js_set(js, dataview_proto, "setBigUint64", js_mkfun(js_dataview_setBigUint64)); 3018 js_set_sym(js, dataview_proto, get_toStringTag_sym(), js_mkstr(js, "DataView", 8)); 3019 3020 js_set_slot(dataview_ctor_obj, SLOT_CFUNC, js_mkfun(js_dataview_constructor)); 3021 js_mkprop_fast(js, dataview_ctor_obj, "prototype", 9, dataview_proto); 3022 js_mkprop_fast(js, dataview_ctor_obj, "name", 4, ANT_STRING("DataView")); 3023 js_set_descriptor(js, dataview_ctor_obj, "name", 4, 0); 3024 3025 ant_value_t dataview_ctor = js_obj_to_func(dataview_ctor_obj); 3026 js_set(js, dataview_proto, "constructor", dataview_ctor); 3027 js_set_descriptor(js, dataview_proto, "constructor", 11, JS_DESC_W | JS_DESC_C); 3028 js_set(js, glob, "DataView", dataview_ctor); 3029 3030 ant_value_t sharedarraybuffer_ctor_obj = js_mkobj(js); 3031 ant_value_t sharedarraybuffer_proto = js_mkobj(js); 3032 js_set_proto_init(sharedarraybuffer_proto, object_proto); 3033 3034 js_set(js, sharedarraybuffer_proto, "slice", js_mkfun(js_arraybuffer_slice)); 3035 js_set_getter_desc(js, sharedarraybuffer_proto, "byteLength", 10, js_mkfun(js_arraybuffer_byteLength_getter), JS_DESC_C); 3036 js_set_sym(js, sharedarraybuffer_proto, get_toStringTag_sym(), js_mkstr(js, "SharedArrayBuffer", 17)); 3037 3038 js_set_slot(sharedarraybuffer_ctor_obj, SLOT_CFUNC, js_mkfun(js_sharedarraybuffer_constructor)); 3039 js_mkprop_fast(js, sharedarraybuffer_ctor_obj, "prototype", 9, sharedarraybuffer_proto); 3040 js_mkprop_fast(js, sharedarraybuffer_ctor_obj, "name", 4, ANT_STRING("SharedArrayBuffer")); 3041 js_set_descriptor(js, sharedarraybuffer_ctor_obj, "name", 4, 0); 3042 js_define_species_getter(js, sharedarraybuffer_ctor_obj); 3043 3044 ant_value_t sharedarraybuffer_ctor = js_obj_to_func(sharedarraybuffer_ctor_obj); 3045 js_set(js, sharedarraybuffer_proto, "constructor", sharedarraybuffer_ctor); 3046 js_set_descriptor(js, sharedarraybuffer_proto, "constructor", 11, JS_DESC_W | JS_DESC_C); 3047 js_set(js, glob, "SharedArrayBuffer", sharedarraybuffer_ctor); 3048 3049 ant_value_t buffer_ctor_obj = js_mkobj(js); 3050 ant_value_t buffer_proto = js_mkobj(js); 3051 3052 ant_value_t uint8array_ctor = js_get(js, glob, "Uint8Array"); 3053 ant_value_t uint8array_proto = js_get(js, uint8array_ctor, "prototype"); 3054 3055 if (is_special_object(uint8array_proto)) js_set_proto_init(buffer_proto, uint8array_proto); 3056 else js_set_proto_init(buffer_proto, typedarray_proto); 3057 3058 js_set(js, buffer_proto, "slice", js_mkfun(js_buffer_slice)); 3059 js_set(js, buffer_proto, "toString", js_mkfun(js_buffer_toString)); 3060 js_set(js, buffer_proto, "toBase64", js_mkfun(js_buffer_toBase64)); 3061 js_set(js, buffer_proto, "write", js_mkfun(js_buffer_write)); 3062 js_set(js, buffer_proto, "copy", js_mkfun(js_buffer_copy)); 3063 js_set(js, buffer_proto, "writeInt16BE", js_mkfun(js_buffer_writeInt16BE)); 3064 js_set(js, buffer_proto, "writeInt32BE", js_mkfun(js_buffer_writeInt32BE)); 3065 js_set(js, buffer_proto, "writeUInt32BE", js_mkfun(js_buffer_writeUInt32BE)); 3066 js_set(js, buffer_proto, "readInt16BE", js_mkfun(js_buffer_readInt16BE)); 3067 js_set(js, buffer_proto, "readInt32BE", js_mkfun(js_buffer_readInt32BE)); 3068 js_set(js, buffer_proto, "readUInt32BE", js_mkfun(js_buffer_readUInt32BE)); 3069 3070 js_set_sym(js, buffer_proto, get_toStringTag_sym(), js_mkstr(js, "Buffer", 6)); 3071 js_set(js, buffer_proto, "values", js_get(js, typedarray_proto, "values")); 3072 js_set_sym(js, buffer_proto, get_iterator_sym(), js_get(js, buffer_proto, "values")); 3073 3074 js_set(js, buffer_ctor_obj, "from", js_mkfun(js_buffer_from)); 3075 js_set(js, buffer_ctor_obj, "alloc", js_mkfun(js_buffer_alloc)); 3076 js_set(js, buffer_ctor_obj, "allocUnsafe", js_mkfun(js_buffer_allocUnsafe)); 3077 js_set(js, buffer_ctor_obj, "isBuffer", js_mkfun(js_buffer_isBuffer)); 3078 js_set(js, buffer_ctor_obj, "isEncoding", js_mkfun(js_buffer_isEncoding)); 3079 js_set(js, buffer_ctor_obj, "byteLength", js_mkfun(js_buffer_byteLength)); 3080 js_set(js, buffer_ctor_obj, "concat", js_mkfun(js_buffer_concat)); 3081 js_set(js, buffer_ctor_obj, "compare", js_mkfun(js_buffer_compare)); 3082 3083 js_set_slot(buffer_ctor_obj, SLOT_CFUNC, js_mkfun(js_buffer_from)); 3084 js_mkprop_fast(js, buffer_ctor_obj, "prototype", 9, buffer_proto); 3085 js_mkprop_fast(js, buffer_ctor_obj, "name", 4, ANT_STRING("Buffer")); 3086 js_set_descriptor(js, buffer_ctor_obj, "name", 4, 0); 3087 3088 ant_value_t buffer_ctor = js_obj_to_func(buffer_ctor_obj); 3089 js_set(js, buffer_proto, "constructor", buffer_ctor); 3090 js_set_descriptor(js, buffer_proto, "constructor", 11, JS_DESC_W | JS_DESC_C); 3091 js_set(js, glob, "Buffer", buffer_ctor); 3092} 3093 3094void cleanup_buffer_module(void) { 3095 if (buffer_registry) { 3096 for (size_t i = 0; i < buffer_registry_count; i++) { 3097 if (buffer_registry[i]) free(buffer_registry[i]); 3098 } 3099 free(buffer_registry); 3100 buffer_registry = NULL; 3101 buffer_registry_count = 0; 3102 buffer_registry_cap = 0; 3103 } 3104 3105 ta_metadata_bytes = 0; 3106} 3107 3108size_t buffer_get_external_memory(void) { 3109 size_t total = ta_metadata_bytes; 3110 3111 for (size_t i = 0; i < buffer_registry_count; i++) { 3112 if (buffer_registry[i]) 3113 total += sizeof(ArrayBufferData) + buffer_registry[i]->capacity; 3114 } 3115 total += buffer_registry_cap * sizeof(ArrayBufferData *); 3116 3117 return total; 3118}