Module: wine Branch: master Commit: 426f4bb3eadcf15378f7d4682a8ea904d5143408 URL: https://gitlab.winehq.org/wine/wine/-/commit/426f4bb3eadcf15378f7d4682a8ea90...
Author: Gabriel Ivăncescu gabrielopcode@gmail.com Date: Thu Jun 22 16:19:01 2023 +0300
jscript: Implement `caller` for function instances and prototype.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com
---
dlls/jscript/function.c | 49 ++++++++++++++++++++++++++++++++++++++- dlls/jscript/tests/api.js | 1 + dlls/mshtml/tests/documentmode.js | 21 +++++++++++++++++ dlls/mshtml/tests/es5.js | 12 ++++++++++ 4 files changed, 82 insertions(+), 1 deletion(-)
diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 83dbfed6054..abd6638cab8 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -270,6 +270,26 @@ HRESULT Function_invoke(jsdisp_t *func_this, jsval_t vthis, WORD flags, unsigned return function->vtbl->call(function->dispex.ctx, function, vthis, flags, argc, argv, r); }
+static HRESULT Function_get_caller(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) +{ + FunctionInstance *function = function_from_jsdisp(jsthis); + call_frame_t *frame; + + TRACE("%p\n", jsthis); + + for(frame = ctx->call_ctx; frame; frame = frame->prev_frame) { + if(frame->function_instance == &function->dispex) { + if(!frame->prev_frame || !frame->prev_frame->function_instance) + break; + *r = jsval_obj(jsdisp_addref(frame->prev_frame->function_instance)); + return S_OK; + } + } + + *r = jsval_null(); + return S_OK; +} + static HRESULT Function_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) { TRACE("%p\n", jsthis); @@ -565,6 +585,7 @@ static const builtin_prop_t Function_props[] = { {L"arguments", NULL, 0, Function_get_arguments}, {L"bind", Function_bind, PROPF_METHOD|PROPF_ES5|1}, {L"call", Function_call, PROPF_METHOD|1}, + {L"caller", NULL, PROPF_HTML, Function_get_caller}, {L"length", NULL, 0, Function_get_length}, {L"toString", Function_toString, PROPF_METHOD} }; @@ -584,6 +605,7 @@ static const builtin_info_t Function_info = {
static const builtin_prop_t FunctionInst_props[] = { {L"arguments", NULL, 0, Function_get_arguments}, + {L"caller", NULL, PROPF_HTML, Function_get_caller}, {L"length", NULL, 0, Function_get_length} };
@@ -769,6 +791,7 @@ static HRESULT InterpretedFunction_set_prototype(script_ctx_t *ctx, jsdisp_t *js
static const builtin_prop_t InterpretedFunction_props[] = { {L"arguments", NULL, 0, Function_get_arguments}, + {L"caller", NULL, PROPF_HTML, Function_get_caller}, {L"length", NULL, 0, Function_get_length}, {L"prototype", NULL, 0, InterpretedFunction_get_prototype, InterpretedFunction_set_prototype} }; @@ -889,6 +912,30 @@ HRESULT create_source_function(script_ctx_t *ctx, bytecode_t *code, function_cod return S_OK; }
+static HRESULT BindFunction_get_caller(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) +{ + return JS_E_INVALID_ACTION; +} + +static const builtin_prop_t BindFunction_props[] = { + {L"arguments", NULL, 0, Function_get_arguments}, + {L"caller", NULL, 0, BindFunction_get_caller}, + {L"length", NULL, 0, Function_get_length} +}; + +static const builtin_info_t BindFunction_info = { + JSCLASS_FUNCTION, + Function_value, + ARRAY_SIZE(BindFunction_props), + BindFunction_props, + Function_destructor, + NULL, + NULL, + NULL, + NULL, + Function_gc_traverse +}; + static HRESULT BindFunction_call(script_ctx_t *ctx, FunctionInstance *func, jsval_t vthis, unsigned flags, unsigned argc, jsval_t *argv, jsval_t *r) { @@ -975,7 +1022,7 @@ static HRESULT create_bind_function(script_ctx_t *ctx, FunctionInstance *target, BindFunction *function; HRESULT hres;
- hres = create_function(ctx, NULL, &BindFunctionVtbl, FIELD_OFFSET(BindFunction, args[argc]), PROPF_METHOD, + hres = create_function(ctx, &BindFunction_info, &BindFunctionVtbl, FIELD_OFFSET(BindFunction, args[argc]), PROPF_METHOD, FALSE, NULL, (void**)&function); if(FAILED(hres)) return hres; diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js index 481e0612be5..a7a6f5a0ac2 100644 --- a/dlls/jscript/tests/api.js +++ b/dlls/jscript/tests/api.js @@ -286,6 +286,7 @@ ok(unescape(escape(tmp)) === tmp, "unescape(escape('" + tmp + "')) = " + unescap ok(Object.prototype.hasOwnProperty('toString'), "Object.prototype.hasOwnProperty('toString') is false"); ok(Object.prototype.hasOwnProperty('isPrototypeOf'), "Object.prototype.hasOwnProperty('isPrototypeOf') is false"); ok(Function.prototype.hasOwnProperty('call'), "Function.prototype.hasOwnProperty('call') is false"); +ok(!Function.prototype.hasOwnProperty('caller'), "Function.prototype.hasOwnProperty('caller') is true");
Object(); new Object(); diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 9007d451bdb..dd67a117e64 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -840,6 +840,27 @@ sync_test("for..in", function() { ok(found === 1, "ondragstart enumerated " + found + " times in document after set to empty string"); });
+sync_test("function caller", function() { + ok(Function.prototype.hasOwnProperty("caller"), "caller not prop of Function.prototype"); + + function test_caller(expected_caller, stop) { + ok(test_caller.caller === expected_caller, "caller = " + test_caller.caller); + if(stop) return; + function nested() { + ok(nested.caller === test_caller, "nested caller = " + nested.caller); + test_caller(nested, true); + ok(test_caller.caller === expected_caller, "caller within nested = " + test_caller.caller); + } + nested(); + ok(test_caller.caller === expected_caller, "caller after nested = " + test_caller.caller); + } + ok(test_caller.hasOwnProperty("caller"), "caller not prop of test_caller"); + ok(test_caller.caller === null, "test_caller.caller = " + test_caller.caller); + + function f1() { test_caller(f1); } f1(); + function f2() { test_caller(f2); } f2(); +}); + sync_test("elem_by_id", function() { document.body.innerHTML = '<form id="testid" name="testname"></form>'; var v = document.documentMode, found, i; diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 1ed3a64bcba..43723a68d00 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -18,6 +18,7 @@
var E_INVALIDARG = 0x80070057; var JS_E_PROP_DESC_MISMATCH = 0x800a01bd; +var JS_E_INVALID_ACTION = 0x800a01bd; var JS_E_NUMBER_EXPECTED = 0x800a1389; var JS_E_FUNCTION_EXPECTED = 0x800a138a; var JS_E_DATE_EXPECTED = 0x800a138e; @@ -525,11 +526,14 @@ sync_test("getOwnPropertyDescriptor", function() { (function() { test_own_data_prop_desc(arguments, "length", true, false, true); test_own_data_prop_desc(arguments, "callee", true, false, true); + ok(!("caller" in arguments), "caller in arguments"); })();
test_own_data_prop_desc(String, "prototype", false, false, false); test_own_data_prop_desc(function(){}, "prototype", true, false, false); + test_own_data_prop_desc(function(){}, "caller", false, false, false); test_own_data_prop_desc(Function, "prototype", false, false, false); + test_own_data_prop_desc(Function.prototype, "caller", false, false, false); test_own_data_prop_desc(String.prototype, "constructor", true, false, true);
try { @@ -1136,6 +1140,14 @@ sync_test("bind", function() { r = f.call(o2); ok(r === 1, "r = " + r);
+ try { + f.caller; + ok(false, "expected exception getting f.caller"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_INVALID_ACTION, "f.caller threw " + n); + } + f = (function() { ok(this === o, "this != o"); ok(arguments.length === 1, "arguments.length = " + arguments.length);