This commit is contained in:
2026-01-11 23:13:58 -06:00
parent ffe7b61ae2
commit b039b0c4ba
2 changed files with 280 additions and 9 deletions

View File

@@ -13534,6 +13534,8 @@ static JSValue JS_CallInternal_OLD(JSContext *caller_ctx, JSValueConst func_obj,
CASE(OP_call_method):
CASE(OP_tail_call_method):
{
BOOL is_proxy = FALSE;
call_argc = get_u16(pc);
pc += 2;
call_argv = sp - call_argc;
@@ -13542,8 +13544,49 @@ static JSValue JS_CallInternal_OLD(JSContext *caller_ctx, JSValueConst func_obj,
/* Record call site */
profile_record_call_site(rt, b, (uint32_t)(pc - b->byte_code_buf));
#endif
ret_val = JS_CallInternal_OLD(ctx, call_argv[-1], call_argv[-2],
JS_NULL, call_argc, call_argv, 0);
/* Proxy method-call: detect [bytecode_func, "name", ...args]
and rewrite as func("name", [args]) */
if (JS_VALUE_GET_TAG(call_argv[-2]) == JS_TAG_OBJECT) {
JSObject *fp = JS_VALUE_GET_OBJ(call_argv[-2]);
if (fp->class_id == JS_CLASS_BYTECODE_FUNCTION) {
if (!JS_IsFunction(ctx, call_argv[-1])) {
int t = JS_VALUE_GET_TAG(call_argv[-1]);
if (t == JS_TAG_STRING || t == JS_TAG_SYMBOL)
is_proxy = TRUE;
}
}
}
if (is_proxy) {
JSValue name = call_argv[-1];
JSValue args = JS_NewArray(ctx);
if (unlikely(JS_IsException(args)))
goto exception;
/* Move args into the array, then null out stack slots. */
for(i = 0; i < call_argc; i++) {
int r = JS_DefinePropertyValue(ctx, args, __JS_AtomFromUInt32(i), call_argv[i],
JS_PROP_C_W_E | JS_PROP_THROW);
call_argv[i] = JS_NULL;
if (unlikely(r < 0)) {
JS_FreeValue(ctx, args);
goto exception;
}
}
{
JSValue proxy_argv[2];
proxy_argv[0] = name; /* still owned by stack; freed by normal cleanup */
proxy_argv[1] = args;
ret_val = JS_CallInternal_OLD(ctx, call_argv[-2], JS_NULL,
JS_NULL, 2, proxy_argv, 0);
JS_FreeValue(ctx, args);
}
} else {
ret_val = JS_CallInternal_OLD(ctx, call_argv[-1], call_argv[-2],
JS_NULL, call_argc, call_argv, 0);
}
if (unlikely(JS_IsException(ret_val)))
goto exception;
if (opcode == OP_tail_call_method)
@@ -13581,11 +13624,35 @@ static JSValue JS_CallInternal_OLD(JSContext *caller_ctx, JSValueConst func_obj,
CASE(OP_apply):
{
int magic;
BOOL is_proxy = FALSE;
magic = get_u16(pc);
pc += 2;
sf->cur_pc = pc;
ret_val = js_function_apply(ctx, sp[-3], 2, (JSValueConst *)&sp[-2], magic);
/* Proxy method-call with spread: detect ["name", bytecode_func, args_array]
and rewrite as func("name", args_array) */
if (JS_VALUE_GET_TAG(sp[-2]) == JS_TAG_OBJECT) {
JSObject *fp = JS_VALUE_GET_OBJ(sp[-2]);
if (fp->class_id == JS_CLASS_BYTECODE_FUNCTION) {
if (!JS_IsFunction(ctx, sp[-3])) {
int t = JS_VALUE_GET_TAG(sp[-3]);
if (t == JS_TAG_STRING || t == JS_TAG_SYMBOL)
is_proxy = TRUE;
}
}
}
if (is_proxy) {
JSValue proxy_argv[2];
proxy_argv[0] = sp[-3]; /* name */
proxy_argv[1] = sp[-1]; /* args array already built by bytecode */
ret_val = JS_CallInternal_OLD(ctx, sp[-2], JS_NULL,
JS_NULL, 2, proxy_argv, 0);
} else {
ret_val = js_function_apply(ctx, sp[-3], 2, (JSValueConst *)&sp[-2], magic);
}
if (unlikely(JS_IsException(ret_val)))
goto exception;
JS_FreeValue(ctx, sp[-3]);
@@ -14468,12 +14535,16 @@ static JSValue JS_CallInternal_OLD(JSContext *caller_ctx, JSValueConst func_obj,
#endif
obj = sp[-1];
/* User-defined functions don't support property access in cell script */
/* Proxy method-call sugar: func.name(...) -> func("name", [args...])
OP_get_field2 is only emitted when a call immediately follows. */
if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
JSObject *fp = JS_VALUE_GET_OBJ(obj);
if (fp->class_id == JS_CLASS_BYTECODE_FUNCTION) {
JS_ThrowTypeError(ctx, "cannot get property of function");
goto exception;
val = JS_AtomToValue(ctx, atom); /* "name" */
if (unlikely(JS_IsException(val)))
goto exception;
*sp++ = val; /* stack becomes [func, "name"] */
goto get_field2_done;
}
}
@@ -14712,12 +14783,34 @@ static JSValue JS_CallInternal_OLD(JSContext *caller_ctx, JSValueConst func_obj,
{
JSValue val;
/* User-defined functions don't support property access in cell script */
/* Proxy method-call sugar for bracket calls: func[key](...) */
if (JS_VALUE_GET_TAG(sp[-2]) == JS_TAG_OBJECT) {
JSObject *fp = JS_VALUE_GET_OBJ(sp[-2]);
if (fp->class_id == JS_CLASS_BYTECODE_FUNCTION) {
JS_ThrowTypeError(ctx, "cannot get property of function");
goto exception;
/* Keep [func, key] and normalize key to property-key (string/symbol). */
switch (JS_VALUE_GET_TAG(sp[-1])) {
case JS_TAG_INT:
/* Convert integer to string */
sf->cur_pc = pc;
ret_val = JS_ToString(ctx, sp[-1]);
if (JS_IsException(ret_val))
goto exception;
JS_FreeValue(ctx, sp[-1]);
sp[-1] = ret_val;
break;
case JS_TAG_STRING:
case JS_TAG_SYMBOL:
break;
default:
sf->cur_pc = pc;
ret_val = JS_ToPropertyKey(ctx, sp[-1]);
if (JS_IsException(ret_val))
goto exception;
JS_FreeValue(ctx, sp[-1]);
sp[-1] = ret_val;
break;
}
BREAK; /* skip JS_GetPropertyValue, keep [func, key] on stack */
}
}