MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
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}