fn proxy
This commit is contained in:
111
source/quickjs.c
111
source/quickjs.c
@@ -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 */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user