Not just for interpreted functions. And set to undefined in ES5+ modes.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
Supersedes 234852-234853.
dlls/jscript/engine.c | 12 ++++-------- dlls/jscript/function.c | 30 ++++++++++++++++++++++++------ dlls/jscript/tests/api.js | 2 ++ dlls/jscript/tests/lang.js | 3 +++ dlls/mshtml/tests/es5.js | 15 +++++++++++++++ 5 files changed, 48 insertions(+), 14 deletions(-)
diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c index 73b9d86..83005eb 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -3300,16 +3300,12 @@ HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, functi } }
- /* ECMA-262 3rd Edition 11.2.3.7 */ + /* FIXME: Workaround for ES5 mode because we don't have the JS global == window yet */ if(this_obj) { - jsdisp_t *jsthis; + jsdisp_t *jsthis = to_jsdisp(this_obj);
- jsthis = iface_to_jsdisp(this_obj); - if(jsthis) { - if(jsthis->builtin_info->class == JSCLASS_GLOBAL || jsthis->builtin_info->class == JSCLASS_NONE) - this_obj = NULL; - jsdisp_release(jsthis); - } + if(jsthis && jsthis->builtin_info->class == JSCLASS_GLOBAL) + this_obj = NULL; }
if(ctx->call_ctx && (flags & EXEC_EVAL)) { diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 12511bb..942ec9d 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -247,6 +247,24 @@ void detach_arguments_object(jsdisp_t *args_disp) jsdisp_release(frame->arguments_obj); }
+/* ECMA-262 3rd Edition 11.2.3.7 + ECMA-262 5.1 Edition 11.2.3.6 */ +static inline HRESULT call(script_ctx_t *ctx, FunctionInstance *function, jsval_t vthis, unsigned flags, + unsigned argc, jsval_t *argv, jsval_t *r) +{ + jsdisp_t *jsthis; + + if(is_object_instance(vthis) && (jsthis = to_jsdisp(get_object(vthis)))) { + if(ctx->version < SCRIPTLANGUAGEVERSION_ES5) { + if(jsthis->builtin_info->class == JSCLASS_GLOBAL || jsthis->builtin_info->class == JSCLASS_NONE) + vthis = jsval_null(); + }else if(jsthis->builtin_info->class == JSCLASS_NONE) + vthis = jsval_undefined(); + } + + return function->vtbl->call(ctx, function, vthis, flags, argc, argv, r); +} + HRESULT Function_invoke(jsdisp_t *func_this, IDispatch *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { FunctionInstance *function; @@ -256,7 +274,7 @@ HRESULT Function_invoke(jsdisp_t *func_this, IDispatch *jsthis, WORD flags, unsi assert(is_class(func_this, JSCLASS_FUNCTION)); function = function_from_jsdisp(func_this);
- return function->vtbl->call(function->dispex.ctx, function, jsthis ? jsval_disp(jsthis) : jsval_null(), flags, argc, argv, r); + return call(function->dispex.ctx, function, jsthis ? jsval_disp(jsthis) : jsval_null(), flags, argc, argv, r); }
static HRESULT Function_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) @@ -378,7 +396,7 @@ static HRESULT Function_apply(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi
if(SUCCEEDED(hres)) { if(function) { - hres = function->vtbl->call(ctx, function, this_val, flags, cnt, args, r); + hres = call(ctx, function, this_val, flags, cnt, args, r); }else { jsval_t res; hres = disp_call_value(ctx, get_object(vthis), is_object_instance(this_val) ? get_object(this_val) : NULL, @@ -429,7 +447,7 @@ static HRESULT Function_call(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsig cnt = argc-1; }
- hres = function->vtbl->call(ctx, function, this_val, flags, cnt, argv + 1, r); + hres = call(ctx, function, this_val, flags, cnt, argv + 1, r);
jsval_release(this_val); return hres; @@ -483,7 +501,7 @@ HRESULT Function_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned ar return E_FAIL; }
- return function->vtbl->call(ctx, function, vthis, flags, argc, argv, r); + return call(ctx, function, vthis, flags, argc, argv, r); }
HRESULT Function_get_value(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) @@ -839,8 +857,8 @@ 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 = call(ctx, function->target, function->this ? jsval_disp(function->this) : jsval_null(), + flags, call_argc, call_args, r);
heap_free(call_args); return hres; diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js index e81bbea..1368f39 100644 --- a/dlls/jscript/tests/api.js +++ b/dlls/jscript/tests/api.js @@ -2634,6 +2634,8 @@ testException(function() {null.toString();}, "E_OBJECT_EXPECTED"); testException(function() {RegExp.prototype.toString.call(new Object());}, "E_REGEXP_EXPECTED"); testException(function() {/a/.lastIndex();}, "E_NOT_FUNC"); testException(function() {"a".length();}, "E_NOT_FUNC"); +testException(function() {((function() { var f = Number.prototype.toString; return (function() { return f(); }); })())();}, "E_NOT_NUM"); +testException(function() {((function() { var f = Object.prototype.hasOwnProperty; return (function() { return f("f"); }); })())();}, "E_OBJECT_EXPECTED");
testException(function() { return arguments.callee(); }, "E_STACK_OVERFLOW");
diff --git a/dlls/jscript/tests/lang.js b/dlls/jscript/tests/lang.js index cf08423..67e4576 100644 --- a/dlls/jscript/tests/lang.js +++ b/dlls/jscript/tests/lang.js @@ -310,6 +310,9 @@ argumentsTest(); ok(callAsExprTest.arguments === null, "callAsExprTest.arguments = " + callAsExprTest.arguments); })(1,2);
+tmp = ((function() { var f = function() {return this}; return (function() { return f(); }); })())(); +ok(tmp === this, "detached scope function call this != global this"); + tmp = (function() {1;})(); ok(tmp === undefined, "tmp = " + tmp); tmp = eval("1;"); diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 8238e5d..fb756ac 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -1784,6 +1784,21 @@ sync_test("let scope instances", function() { ok(f() == 2, "f() = " + f()); });
+sync_test("builtins detached scope this", function() { + try { + ((function() { var f = Number.prototype.toString; return (function() { return f(); }); })())(); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NUMBER_EXPECTED, "Number.toString threw " + n); + } + + var r = ((function() { var f = Object.prototype.toString; return (function() { return f(); }); })())(); + ok(r === "[object Undefined]", "Object.toString returned " + r); + + var r = ((function() { return (function() { return this; }); })())(); + ok(r === window, "detached scope this = " + r); +}); + sync_test("functions scope", function() { function f(){ return 1; } function f(){ return 2; }
Based on the spec (ECMA-262 5.1 Edition 11.2.3.7), whereas the ES3 spec says it gets replaced with null.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/function.c | 7 ++++++- dlls/mshtml/tests/es5.js | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 942ec9d..a18705b 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -268,13 +268,18 @@ static inline HRESULT call(script_ctx_t *ctx, FunctionInstance *function, jsval_ HRESULT Function_invoke(jsdisp_t *func_this, IDispatch *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { FunctionInstance *function; + jsval_t vthis;
TRACE("func %p this %p\n", func_this, jsthis);
assert(is_class(func_this, JSCLASS_FUNCTION)); function = function_from_jsdisp(func_this);
- return call(function->dispex.ctx, function, jsthis ? jsval_disp(jsthis) : jsval_null(), flags, argc, argv, r); + if(jsthis) + vthis = jsval_disp(jsthis); + else + vthis = function->dispex.ctx->version < SCRIPTLANGUAGEVERSION_ES5 ? jsval_null() : jsval_undefined(); + return call(function->dispex.ctx, function, vthis, flags, argc, argv, r); }
static HRESULT Function_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index fb756ac..b02f71c 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -1795,6 +1795,9 @@ sync_test("builtins detached scope this", function() { var r = ((function() { var f = Object.prototype.toString; return (function() { return f(); }); })())(); ok(r === "[object Undefined]", "Object.toString returned " + r);
+ var r = (function() { var f = Object.prototype.toString; return f(); })(); + ok(r === "[object Undefined]", "Object.toString returned " + r); + var r = ((function() { return (function() { return this; }); })())(); ok(r === window, "detached scope this = " + r); });
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=114324
Your paranoid android.
=== w10pro64 (32 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
=== w10pro64 (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=114323
Your paranoid android.
=== w8 (32 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS htmldoc.c:350: Test failed: expected Exec_SETTITLE htmldoc.c:2859: Test failed: unexpected call Exec_SETTITLE
=== w10pro64 (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
=== w7u_adm (32 bit report) ===
mshtml: script.c:644: Test failed: L"/index.html?es5.js:date_now: unexpected Date.now() result 1651849985748 expected 1651849985811"