This commit is contained in:
2026-02-19 01:37:54 -06:00
parent 85ef711229
commit ab43ab0d2c
5 changed files with 148 additions and 103 deletions

View File

@@ -4736,6 +4736,11 @@ JSValue JS_CallInternal (JSContext *ctx, JSValue func_obj, JSValue this_obj,
if (!JS_IsFunction (func_obj))
return JS_RaiseDisrupt (ctx, "not a function");
JSFunction *f = JS_VALUE_GET_FUNCTION (func_obj);
if (unlikely (f->length >= 0 && argc > f->length)) {
char buf[KEY_GET_STR_BUF_SIZE];
return JS_RaiseDisrupt (ctx, "too many arguments for %s: expected %d, got %d",
JS_KeyGetStr (ctx, buf, KEY_GET_STR_BUF_SIZE, f->name), f->length, argc);
}
switch (f->kind) {
case JS_FUNC_KIND_C:
case JS_FUNC_KIND_C_DATA:
@@ -4750,6 +4755,16 @@ JSValue JS_CallInternal (JSContext *ctx, JSValue func_obj, JSValue this_obj,
}
}
/* Call helper used by runtime callback intrinsics.
Caps argc to function arity so helper callbacks never rely on over-arity calls. */
static inline JSValue js_call_internal_capped (JSContext *ctx, JSValue func_obj, JSValue this_obj,
int argc, JSValue *argv) {
JSFunction *f = JS_VALUE_GET_FUNCTION (func_obj);
if (f->length >= 0 && argc > f->length)
argc = f->length;
return JS_CallInternal (ctx, func_obj, this_obj, argc, argc > 0 ? argv : NULL, 0);
}
JSValue JS_Call (JSContext *ctx, JSValue func_obj, JSValue this_obj, int argc, JSValue *argv) {
if (js_poll_interrupts (ctx)) return JS_EXCEPTION;
if (unlikely (!JS_IsFunction (func_obj)))
@@ -8245,7 +8260,7 @@ static JSValue js_cell_array (JSContext *ctx, JSValue this_val, int argc, JSValu
MAP_STORE (val);
}
}
} else {
} else if (arity == 1) {
if (reverse) {
for (int i = len - 1; i >= 0; i--) {
arr = JS_VALUE_GET_ARRAY (arg0_ref.val);
@@ -8267,6 +8282,26 @@ static JSValue js_cell_array (JSContext *ctx, JSValue this_val, int argc, JSValu
MAP_STORE (val);
}
}
} else {
if (reverse) {
for (int i = len - 1; i >= 0; i--) {
arr = JS_VALUE_GET_ARRAY (arg0_ref.val);
if (i >= (int)arr->len) continue;
JSValue val = JS_CallInternal (ctx, arg1_ref.val, JS_NULL, 0, NULL, 0);
if (JS_IsException (val)) { MAP_ERR (); }
if (!JS_IsNull (exit_val) && js_strict_eq (ctx, val, exit_val)) break;
MAP_STORE (val);
}
} else {
for (int i = 0; i < len; i++) {
arr = JS_VALUE_GET_ARRAY (arg0_ref.val);
if (i >= (int)arr->len) break;
JSValue val = JS_CallInternal (ctx, arg1_ref.val, JS_NULL, 0, NULL, 0);
if (JS_IsException (val)) { MAP_ERR (); }
if (!JS_IsNull (exit_val) && js_strict_eq (ctx, val, exit_val)) break;
MAP_STORE (val);
}
}
}
#undef MAP_STORE
#undef MAP_ERR
@@ -8626,6 +8661,7 @@ static JSValue js_cell_array_reduce (JSContext *ctx, JSValue this_val, int argc,
JSArray *arr = JS_VALUE_GET_ARRAY (argv[0]);
word_t len = arr->len;
JSValue fn = argv[1];
int reverse = argc > 3 && JS_ToBool (ctx, argv[3]);
JSGCRef acc_ref;
@@ -8642,7 +8678,7 @@ static JSValue js_cell_array_reduce (JSContext *ctx, JSValue this_val, int argc,
if (i - 1 >= arr->len) continue;
JSValue args[2] = { acc, arr->values[i - 1] };
JS_PUSH_VALUE (ctx, acc);
JSValue new_acc = JS_CallInternal (ctx, argv[1], JS_NULL, 2, args, 0);
JSValue new_acc = js_call_internal_capped (ctx, fn, JS_NULL, 2, args);
JS_POP_VALUE (ctx, acc);
if (JS_IsException (new_acc)) return JS_EXCEPTION;
acc = new_acc;
@@ -8654,7 +8690,7 @@ static JSValue js_cell_array_reduce (JSContext *ctx, JSValue this_val, int argc,
if (i >= arr->len) break;
JSValue args[2] = { acc, arr->values[i] };
JS_PUSH_VALUE (ctx, acc);
JSValue new_acc = JS_CallInternal (ctx, argv[1], JS_NULL, 2, args, 0);
JSValue new_acc = js_call_internal_capped (ctx, fn, JS_NULL, 2, args);
JS_POP_VALUE (ctx, acc);
if (JS_IsException (new_acc)) return JS_EXCEPTION;
acc = new_acc;
@@ -8670,7 +8706,7 @@ static JSValue js_cell_array_reduce (JSContext *ctx, JSValue this_val, int argc,
if (i - 1 >= arr->len) continue;
JSValue args[2] = { acc, arr->values[i - 1] };
JS_PUSH_VALUE (ctx, acc);
JSValue new_acc = JS_CallInternal (ctx, argv[1], JS_NULL, 2, args, 0);
JSValue new_acc = js_call_internal_capped (ctx, fn, JS_NULL, 2, args);
JS_POP_VALUE (ctx, acc);
if (JS_IsException (new_acc)) return JS_EXCEPTION;
acc = new_acc;
@@ -8681,7 +8717,7 @@ static JSValue js_cell_array_reduce (JSContext *ctx, JSValue this_val, int argc,
if (i >= arr->len) break;
JSValue args[2] = { acc, arr->values[i] };
JS_PUSH_VALUE (ctx, acc);
JSValue new_acc = JS_CallInternal (ctx, argv[1], JS_NULL, 2, args, 0);
JSValue new_acc = js_call_internal_capped (ctx, fn, JS_NULL, 2, args);
JS_POP_VALUE (ctx, acc);
if (JS_IsException (new_acc)) return JS_EXCEPTION;
acc = new_acc;
@@ -8706,23 +8742,14 @@ static JSValue js_cell_array_for (JSContext *ctx, JSValue this_val, int argc, JS
int reverse = argc > 2 && JS_ToBool (ctx, argv[2]);
JSValue exit_val = argc > 3 ? argv[3] : JS_NULL;
/* Determine function arity */
int arity = ((JSFunction *)JS_VALUE_GET_FUNCTION (argv[1]))->length;
if (reverse) {
for (word_t i = len; i > 0; i--) {
arr = JS_VALUE_GET_ARRAY (argv[0]);
if (i - 1 >= arr->len) continue;
JSValue result;
if (arity == 1) {
JSValue item = arr->values[i - 1];
result = JS_CallInternal (ctx, argv[1], JS_NULL, 1, &item, 0);
} else {
JSValue args[2];
args[0] = arr->values[i - 1];
args[1] = JS_NewInt32 (ctx, (int32_t)(i - 1));
result = JS_CallInternal (ctx, argv[1], JS_NULL, 2, args, 0);
}
JSValue args[2];
args[0] = arr->values[i - 1];
args[1] = JS_NewInt32 (ctx, (int32_t)(i - 1));
JSValue result = js_call_internal_capped (ctx, argv[1], JS_NULL, 2, args);
if (JS_IsException (result)) return JS_EXCEPTION;
if (!JS_IsNull (exit_val) && js_strict_eq (ctx, result, exit_val))
return result;
@@ -8731,16 +8758,10 @@ static JSValue js_cell_array_for (JSContext *ctx, JSValue this_val, int argc, JS
for (word_t i = 0; i < len; i++) {
arr = JS_VALUE_GET_ARRAY (argv[0]);
if (i >= arr->len) break;
JSValue result;
if (arity == 1) {
JSValue item = arr->values[i];
result = JS_CallInternal (ctx, argv[1], JS_NULL, 1, &item, 0);
} else {
JSValue args[2];
args[0] = arr->values[i];
args[1] = JS_NewInt32 (ctx, (int32_t)i);
result = JS_CallInternal (ctx, argv[1], JS_NULL, 2, args, 0);
}
JSValue args[2];
args[0] = arr->values[i];
args[1] = JS_NewInt32 (ctx, (int32_t)i);
JSValue result = js_call_internal_capped (ctx, argv[1], JS_NULL, 2, args);
if (JS_IsException (result)) return JS_EXCEPTION;
if (!JS_IsNull (exit_val) && js_strict_eq (ctx, result, exit_val))
return result;
@@ -8787,47 +8808,23 @@ static JSValue js_cell_array_find (JSContext *ctx, JSValue this_val, int argc, J
}
/* Use function predicate — re-chase after each call */
int arity = ((JSFunction *)JS_VALUE_GET_FUNCTION (argv[1]))->length;
if (arity == 2) {
if (reverse) {
for (int32_t i = from; i >= 0; i--) {
arr = JS_VALUE_GET_ARRAY (argv[0]);
if ((word_t)i >= arr->len) continue;
JSValue args[2] = { arr->values[i], JS_NewInt32 (ctx, i) };
JSValue result = JS_CallInternal (ctx, argv[1], JS_NULL, 2, args, 0);
if (JS_IsException (result)) return JS_EXCEPTION;
if (JS_ToBool (ctx, result)) return JS_NewInt32 (ctx, i);
}
} else {
for (word_t i = (word_t)from; i < len; i++) {
arr = JS_VALUE_GET_ARRAY (argv[0]);
if (i >= arr->len) break;
JSValue args[2] = { arr->values[i], JS_NewInt32 (ctx, (int32_t)i) };
JSValue result = JS_CallInternal (ctx, argv[1], JS_NULL, 2, args, 0);
if (JS_IsException (result)) return JS_EXCEPTION;
if (JS_ToBool (ctx, result)) return JS_NewInt32 (ctx, (int32_t)i);
}
if (reverse) {
for (int32_t i = from; i >= 0; i--) {
arr = JS_VALUE_GET_ARRAY (argv[0]);
if ((word_t)i >= arr->len) continue;
JSValue args[2] = { arr->values[i], JS_NewInt32 (ctx, i) };
JSValue result = js_call_internal_capped (ctx, argv[1], JS_NULL, 2, args);
if (JS_IsException (result)) return JS_EXCEPTION;
if (JS_ToBool (ctx, result)) return JS_NewInt32 (ctx, i);
}
} else {
if (reverse) {
for (int32_t i = from; i >= 0; i--) {
arr = JS_VALUE_GET_ARRAY (argv[0]);
if ((word_t)i >= arr->len) continue;
JSValue item = arr->values[i];
JSValue result = JS_CallInternal (ctx, argv[1], JS_NULL, 1, &item, 0);
if (JS_IsException (result)) return JS_EXCEPTION;
if (JS_ToBool (ctx, result)) return JS_NewInt32 (ctx, i);
}
} else {
for (word_t i = (word_t)from; i < len; i++) {
arr = JS_VALUE_GET_ARRAY (argv[0]);
if (i >= arr->len) break;
JSValue item = arr->values[i];
JSValue result = JS_CallInternal (ctx, argv[1], JS_NULL, 1, &item, 0);
if (JS_IsException (result)) return JS_EXCEPTION;
if (JS_ToBool (ctx, result)) return JS_NewInt32 (ctx, (int32_t)i);
}
for (word_t i = (word_t)from; i < len; i++) {
arr = JS_VALUE_GET_ARRAY (argv[0]);
if (i >= arr->len) break;
JSValue args[2] = { arr->values[i], JS_NewInt32 (ctx, (int32_t)i) };
JSValue result = js_call_internal_capped (ctx, argv[1], JS_NULL, 2, args);
if (JS_IsException (result)) return JS_EXCEPTION;
if (JS_ToBool (ctx, result)) return JS_NewInt32 (ctx, (int32_t)i);
}
}
@@ -9264,7 +9261,7 @@ static JSValue js_cell_object (JSContext *ctx, JSValue this_val, int argc, JSVal
val = JS_TRUE;
} else if (is_func) {
JSValue arg_key = key;
val = JS_CallInternal (ctx, func_ref.val, JS_NULL, 1, &arg_key, 0);
val = js_call_internal_capped (ctx, func_ref.val, JS_NULL, 1, &arg_key);
if (JS_IsException (val)) {
JS_PopGCRef (ctx, &result_ref);
JS_PopGCRef (ctx, &func_ref);
@@ -11317,7 +11314,7 @@ static JSValue js_cell_every (JSContext *ctx, JSValue this_val, int argc, JSValu
JSArray *arr = JS_VALUE_GET_ARRAY (argv[0]);
for (int i = 0; i < arr->len; i++) {
JSValue elem = arr->values[i];
JSValue r = JS_CallInternal (ctx, argv[1], JS_NULL, 1, &elem, 0);
JSValue r = js_call_internal_capped (ctx, argv[1], JS_NULL, 1, &elem);
arr = JS_VALUE_GET_ARRAY (argv[0]);
if (JS_IsException (r)) return r;
if (!JS_ToBool (ctx, r)) return JS_FALSE;