From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/function.c | 46 ++++++++++++++++++++++++++++++- dlls/jscript/tests/lang.js | 3 ++ dlls/mshtml/tests/documentmode.js | 15 ++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-)
diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 40ff015121b..ceaf50e8538 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -195,7 +195,51 @@ static HRESULT Arguments_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op return S_OK; }
+static HRESULT Arguments_get_caller(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) +{ + ArgumentsInstance *arguments = arguments_from_jsdisp(jsthis); + call_frame_t *frame; + HRESULT hres; + + TRACE("\n"); + + for(frame = ctx->call_ctx; frame; frame = frame->prev_frame) { + if(frame->arguments_obj == &arguments->jsdisp) { + frame = frame->prev_frame; + if(!frame || !frame->function_instance) + break; + if(!frame->arguments_obj) { + hres = setup_arguments_object(ctx, frame); + if(FAILED(hres)) + return hres; + } + *r = jsval_obj(jsdisp_addref(frame->arguments_obj)); + return S_OK; + } + } + + *r = jsval_null(); + return S_OK; +} + +static const builtin_prop_t Arguments_props[] = { + {L"caller", NULL, 0, Arguments_get_caller}, +}; + static const builtin_info_t Arguments_info = { + .class = JSCLASS_ARGUMENTS, + .call = Arguments_value, + .props_cnt = ARRAY_SIZE(Arguments_props), + .props = Arguments_props, + .destructor = Arguments_destructor, + .lookup_prop = Arguments_lookup_prop, + .next_prop = Arguments_next_prop, + .prop_get = Arguments_prop_get, + .prop_put = Arguments_prop_put, + .gc_traverse = Arguments_gc_traverse +}; + +static const builtin_info_t Arguments_ES5_info = { .class = JSCLASS_ARGUMENTS, .call = Arguments_value, .destructor = Arguments_destructor, @@ -215,7 +259,7 @@ HRESULT setup_arguments_object(script_ctx_t *ctx, call_frame_t *frame) if(!args) return E_OUTOFMEMORY;
- hres = init_dispex_from_constr(&args->jsdisp, ctx, &Arguments_info, ctx->object_constr); + hres = init_dispex_from_constr(&args->jsdisp, ctx, ctx->version < SCRIPTLANGUAGEVERSION_ES5 ? &Arguments_info : &Arguments_ES5_info, ctx->object_constr); if(FAILED(hres)) { free(args); return hres; diff --git a/dlls/jscript/tests/lang.js b/dlls/jscript/tests/lang.js index 2ddfc3a8341..89f52298fb3 100644 --- a/dlls/jscript/tests/lang.js +++ b/dlls/jscript/tests/lang.js @@ -447,6 +447,9 @@ obj1.func = function () { ok(arguments.length === 1, "arguments.length is not 1"); ok(arguments["0"] === true, "arguments[0] is not true"); ok(typeof(arguments.callee) === "function", "typeof(arguments.calee) = " + typeof(arguments.calee)); + ok(arguments.caller === null, "arguments.caller = " + arguments.caller); + function test_caller() { ok(arguments.caller === foobar.arguments, "nested arguments.caller = " + arguments.caller); } + function foobar() { test_caller(); } foobar();
return "test"; }; diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 95c033f46dd..c2f0a7ecb82 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -892,18 +892,33 @@ sync_test("for..in", function() { });
sync_test("function caller", function() { + var v = document.documentMode; + ok(Function.prototype.hasOwnProperty("caller"), "caller not prop of Function.prototype"); + if(v < 9) + ok(arguments.hasOwnProperty("caller"), "caller not prop of arguments"); + else + ok(!("caller" in arguments), "caller in arguments");
function test_caller(expected_caller, stop) { ok(test_caller.caller === expected_caller, "caller = " + test_caller.caller); + if(v < 9) + ok(arguments.caller === expected_caller.arguments, "arguments.caller = " + arguments.caller); + if(stop) return; function nested() { ok(nested.caller === test_caller, "nested caller = " + nested.caller); + if(v < 9) + ok(arguments.caller === test_caller.arguments, "nested arguments.caller = " + arguments.caller); test_caller(nested, true); ok(test_caller.caller === expected_caller, "caller within nested = " + test_caller.caller); + if(v < 9) + ok(test_caller.arguments.caller === expected_caller.arguments, "arguments.caller within nested = " + test_caller.arguments.caller); } nested(); ok(test_caller.caller === expected_caller, "caller after nested = " + test_caller.caller); + if(v < 9) + ok(arguments.caller === expected_caller.arguments, "arguments.caller after nested = " + arguments.caller); } ok(test_caller.hasOwnProperty("caller"), "caller not prop of test_caller"); ok(test_caller.caller === null, "test_caller.caller = " + test_caller.caller);
Jacek Caban (@jacek) commented about dlls/jscript/function.c:
+};
static const builtin_info_t Arguments_info = {
- .class = JSCLASS_ARGUMENTS,
- .call = Arguments_value,
- .props_cnt = ARRAY_SIZE(Arguments_props),
- .props = Arguments_props,
- .destructor = Arguments_destructor,
- .lookup_prop = Arguments_lookup_prop,
- .next_prop = Arguments_next_prop,
- .prop_get = Arguments_prop_get,
- .prop_put = Arguments_prop_put,
- .gc_traverse = Arguments_gc_traverse
+};
+static const builtin_info_t Arguments_ES5_info = {
Duplicating the descriptor like that just for one property is not great. Do you know if there are more cases like this? Maybe we should extend property descriptor to specify the maximal version? Given that it will be probably used only for ES3, maybe something like `PROPF_ES3` (with a meaning of max version rather than min)? Or maybe even move that out of flags?
On Fri Aug 2 15:51:22 2024 +0000, Jacek Caban wrote:
Duplicating the descriptor like that just for one property is not great. Do you know if there are more cases like this? Maybe we should extend property descriptor to specify the maximal version? Given that it will be probably used only for ES3, maybe something like `PROPF_ES3` (with a meaning of max version rather than min)? Or maybe even move that out of flags?
I think it's the only case, and I didn't want to add code handling a new flag just for this, seemed over-engineered. I could also use a macro to fill the info to avoid duplication, or is that a bad idea?
On Fri Aug 2 16:17:42 2024 +0000, Gabriel Ivăncescu wrote:
I think it's the only case, and I didn't want to add code handling a new flag just for this, seemed over-engineered. I could also use a macro to fill the info to avoid duplication, or is that a bad idea?
I don't think a macro would be any nicer, let's keep it duplicated for now.
This merge request was approved by Jacek Caban.