Module: wine Branch: master Commit: 35a65559293e6ef57f0423ab488d489939074204 URL: https://gitlab.winehq.org/wine/wine/-/commit/35a65559293e6ef57f0423ab488d489...
Author: Gabriel Ivăncescu gabrielopcode@gmail.com Date: Fri Oct 14 22:14:43 2022 +0300
jscript: Implement Function.prototype.bind's `thisArg` properly.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com
---
dlls/jscript/function.c | 40 +++++++++++++++++++++------------------- dlls/mshtml/tests/es5.js | 17 +++++++++++++++++ 2 files changed, 38 insertions(+), 19 deletions(-)
diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index bf152e22868..8009f3a5d8b 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -57,7 +57,7 @@ typedef struct { typedef struct { FunctionInstance function; FunctionInstance *target; - IDispatch *this; + jsval_t this; unsigned argc; jsval_t args[1]; } BindFunction; @@ -70,7 +70,7 @@ typedef struct { unsigned argc; } ArgumentsInstance;
-static HRESULT create_bind_function(script_ctx_t*,FunctionInstance*,IDispatch*,unsigned,jsval_t*,jsdisp_t**r); +static HRESULT create_bind_function(script_ctx_t*,FunctionInstance*,jsval_t,unsigned,jsval_t*,jsdisp_t**r);
static inline FunctionInstance *function_from_jsdisp(jsdisp_t *jsdisp) { @@ -448,7 +448,7 @@ static HRESULT Function_call(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsig static HRESULT Function_bind(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - IDispatch *bound_this = NULL; + jsval_t bound_this = jsval_undefined(); FunctionInstance *function; jsdisp_t *new_function; HRESULT hres; @@ -459,18 +459,19 @@ static HRESULT Function_bind(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsig return JS_E_FUNCTION_EXPECTED;
if(argc < 1) { - FIXME("no this argument\n"); - return E_NOTIMPL; - } - - if(is_object_instance(argv[0])) { - bound_this = get_object(argv[0]); - }else if(!is_null(argv[0])) { - FIXME("%s is not an object instance\n", debugstr_jsval(argv[0])); - return E_NOTIMPL; + argc = 1; + }else if(is_null(argv[0])) { + bound_this = argv[0]; + }else if(!is_undefined(argv[0])) { + IDispatch *obj; + hres = to_object(ctx, argv[0], &obj); + if(FAILED(hres)) + return hres; + bound_this = jsval_disp(obj); }
hres = create_bind_function(ctx, function, bound_this, argc - 1, argv + 1, &new_function); + jsval_release(bound_this); if(FAILED(hres)) return hres;
@@ -849,8 +850,7 @@ static HRESULT BindFunction_call(script_ctx_t *ctx, FunctionInstance *func, jsva memcpy(call_args + function->argc, argv, argc * sizeof(*call_args)); }
- hres = function->target->vtbl->call(ctx, function->target, function->this ? jsval_disp(function->this) : jsval_null(), - flags, call_argc, call_args, r); + hres = function->target->vtbl->call(ctx, function->target, function->this, flags, call_argc, call_args, r);
heap_free(call_args); return hres; @@ -877,8 +877,7 @@ static void BindFunction_destructor(FunctionInstance *func) for(i = 0; i < function->argc; i++) jsval_release(function->args[i]); jsdisp_release(&function->target->dispex); - if(function->this) - IDispatch_Release(function->this); + jsval_release(function->this); }
static const function_vtbl_t BindFunctionVtbl = { @@ -888,7 +887,7 @@ static const function_vtbl_t BindFunctionVtbl = { BindFunction_destructor };
-static HRESULT create_bind_function(script_ctx_t *ctx, FunctionInstance *target, IDispatch *bound_this, unsigned argc, +static HRESULT create_bind_function(script_ctx_t *ctx, FunctionInstance *target, jsval_t bound_this, unsigned argc, jsval_t *argv, jsdisp_t **ret) { BindFunction *function; @@ -902,8 +901,11 @@ static HRESULT create_bind_function(script_ctx_t *ctx, FunctionInstance *target, jsdisp_addref(&target->dispex); function->target = target;
- if(bound_this) - IDispatch_AddRef(function->this = bound_this); + hres = jsval_copy(bound_this, &function->this); + if(FAILED(hres)) { + jsdisp_release(&function->function.dispex); + return hres; + }
for(function->argc = 0; function->argc < argc; function->argc++) { hres = jsval_copy(argv[function->argc], function->args + function->argc); diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index bfaacd1bd5b..e22f610e197 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -1188,6 +1188,23 @@ sync_test("bind", function() { ok(t != a, "t == a");
ok(Function.prototype.bind.length === 1, "Function.prototype.bind.length = " + Function.prototype.bind.length); + + ((function() { ok(this === window, "bind() this = " + this); }).bind())(); + ((function() { ok(this === window, "bind(undefined) = " + this); }).bind(undefined))(); + ((function() { ok(this === window, "bind(nullDisp) = " + this); }).bind(external.nullDisp))(); + ((function() { + ok(typeof(this) === "object", "bind(42) typeof(this) = " + typeof(this)); + ok(this.valueOf() === 42, "bind(42) this = " + this); + }).bind(42))(); + + r = (Object.prototype.toString.bind())(); + ok(r === "[object Undefined]", "toString.bind() returned " + r); + r = (Object.prototype.toString.bind(undefined))(); + ok(r === "[object Undefined]", "toString.bind(undefined) returned " + r); + r = (Object.prototype.toString.bind(null))(); + ok(r === "[object Null]", "toString.bind(null) returned " + r); + r = (Object.prototype.toString.bind(external.nullDisp))(); + ok(r === "[object Null]", "toString.bind(nullDisp) returned " + r); });
sync_test("keys", function() {