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

Configure Feed

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

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