Commit 598709f8 authored by Gabriel Ivăncescu's avatar Gabriel Ivăncescu Committed by Alexandre Julliard

jscript: Pass jsval "this" to function calls instead of a dispatch.

parent 22ce4d7e
...@@ -35,7 +35,7 @@ typedef struct { ...@@ -35,7 +35,7 @@ typedef struct {
} FunctionInstance; } FunctionInstance;
struct _function_vtbl_t { struct _function_vtbl_t {
HRESULT (*call)(script_ctx_t*,FunctionInstance*,IDispatch*,unsigned,unsigned,jsval_t*,jsval_t*); HRESULT (*call)(script_ctx_t*,FunctionInstance*,jsval_t,unsigned,unsigned,jsval_t*,jsval_t*);
HRESULT (*toString)(FunctionInstance*,jsstr_t**); HRESULT (*toString)(FunctionInstance*,jsstr_t**);
function_code_t* (*get_code)(FunctionInstance*); function_code_t* (*get_code)(FunctionInstance*);
void (*destructor)(FunctionInstance*); void (*destructor)(FunctionInstance*);
...@@ -256,7 +256,7 @@ HRESULT Function_invoke(jsdisp_t *func_this, IDispatch *jsthis, WORD flags, unsi ...@@ -256,7 +256,7 @@ HRESULT Function_invoke(jsdisp_t *func_this, IDispatch *jsthis, WORD flags, unsi
assert(is_class(func_this, JSCLASS_FUNCTION)); assert(is_class(func_this, JSCLASS_FUNCTION));
function = function_from_jsdisp(func_this); function = function_from_jsdisp(func_this);
return function->vtbl->call(function->dispex.ctx, function, jsthis, flags, argc, argv, r); return function->vtbl->call(function->dispex.ctx, function, jsval_disp(jsthis), flags, argc, argv, r);
} }
static HRESULT Function_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) static HRESULT Function_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
...@@ -328,10 +328,10 @@ static HRESULT array_to_args(script_ctx_t *ctx, jsdisp_t *arg_array, unsigned *a ...@@ -328,10 +328,10 @@ static HRESULT array_to_args(script_ctx_t *ctx, jsdisp_t *arg_array, unsigned *a
static HRESULT Function_apply(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) static HRESULT Function_apply(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
{ {
jsval_t this_val = jsval_undefined();
FunctionInstance *function; FunctionInstance *function;
jsval_t *args = NULL; jsval_t *args = NULL;
unsigned i, cnt = 0; unsigned i, cnt = 0;
IDispatch *this_obj = NULL;
HRESULT hres = S_OK; HRESULT hres = S_OK;
TRACE("\n"); TRACE("\n");
...@@ -340,10 +340,16 @@ static HRESULT Function_apply(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi ...@@ -340,10 +340,16 @@ static HRESULT Function_apply(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi
return JS_E_FUNCTION_EXPECTED; return JS_E_FUNCTION_EXPECTED;
if(argc) { if(argc) {
if(!is_undefined(argv[0]) && !is_null(argv[0])) { if(ctx->version < SCRIPTLANGUAGEVERSION_ES5 && !is_undefined(argv[0]) && !is_null(argv[0])) {
IDispatch *this_obj;
hres = to_object(ctx, argv[0], &this_obj); hres = to_object(ctx, argv[0], &this_obj);
if(FAILED(hres)) if(FAILED(hres))
return hres; return hres;
this_val = jsval_disp(this_obj);
}else {
hres = jsval_copy(argv[0], &this_val);
if(FAILED(hres))
return hres;
} }
} }
...@@ -370,10 +376,11 @@ static HRESULT Function_apply(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi ...@@ -370,10 +376,11 @@ static HRESULT Function_apply(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi
if(SUCCEEDED(hres)) { if(SUCCEEDED(hres)) {
if(function) { if(function) {
hres = function->vtbl->call(ctx, function, this_obj, flags, cnt, args, r); hres = function->vtbl->call(ctx, function, this_val, flags, cnt, args, r);
}else { }else {
jsval_t res; jsval_t res;
hres = disp_call_value(ctx, get_object(vthis), this_obj, DISPATCH_METHOD, cnt, args, &res); hres = disp_call_value(ctx, get_object(vthis), is_object_instance(this_val) ? get_object(this_val) : NULL,
DISPATCH_METHOD, cnt, args, &res);
if(SUCCEEDED(hres)) { if(SUCCEEDED(hres)) {
if(r) if(r)
*r = res; *r = res;
...@@ -383,8 +390,7 @@ static HRESULT Function_apply(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi ...@@ -383,8 +390,7 @@ static HRESULT Function_apply(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi
} }
} }
if(this_obj) jsval_release(this_val);
IDispatch_Release(this_obj);
for(i=0; i < cnt; i++) for(i=0; i < cnt; i++)
jsval_release(args[i]); jsval_release(args[i]);
heap_free(args); heap_free(args);
...@@ -394,8 +400,8 @@ static HRESULT Function_apply(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi ...@@ -394,8 +400,8 @@ static HRESULT Function_apply(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi
static HRESULT Function_call(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, static HRESULT Function_call(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r) jsval_t *r)
{ {
jsval_t this_val = jsval_undefined();
FunctionInstance *function; FunctionInstance *function;
IDispatch *this_obj = NULL;
unsigned cnt = 0; unsigned cnt = 0;
HRESULT hres; HRESULT hres;
...@@ -405,19 +411,23 @@ static HRESULT Function_call(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsig ...@@ -405,19 +411,23 @@ static HRESULT Function_call(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsig
return JS_E_FUNCTION_EXPECTED; return JS_E_FUNCTION_EXPECTED;
if(argc) { if(argc) {
if(!is_undefined(argv[0]) && !is_null(argv[0])) { if(ctx->version < SCRIPTLANGUAGEVERSION_ES5 && !is_undefined(argv[0]) && !is_null(argv[0])) {
IDispatch *this_obj;
hres = to_object(ctx, argv[0], &this_obj); hres = to_object(ctx, argv[0], &this_obj);
if(FAILED(hres)) if(FAILED(hres))
return hres; return hres;
this_val = jsval_disp(this_obj);
}else {
hres = jsval_copy(argv[0], &this_val);
if(FAILED(hres))
return hres;
} }
cnt = argc-1; cnt = argc-1;
} }
hres = function->vtbl->call(ctx, function, this_obj, flags, cnt, argv + 1, r); hres = function->vtbl->call(ctx, function, this_val, flags, cnt, argv + 1, r);
if(this_obj) jsval_release(this_val);
IDispatch_Release(this_obj);
return hres; return hres;
} }
...@@ -469,7 +479,7 @@ HRESULT Function_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned ar ...@@ -469,7 +479,7 @@ HRESULT Function_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned ar
return E_FAIL; return E_FAIL;
} }
return function->vtbl->call(ctx, function, NULL, flags, argc, argv, r); return function->vtbl->call(ctx, function, vthis, flags, argc, argv, r);
} }
HRESULT Function_get_value(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) HRESULT Function_get_value(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
...@@ -590,16 +600,10 @@ static HRESULT create_function(script_ctx_t *ctx, const builtin_info_t *builtin_ ...@@ -590,16 +600,10 @@ static HRESULT create_function(script_ctx_t *ctx, const builtin_info_t *builtin_
return S_OK; return S_OK;
} }
static HRESULT NativeFunction_call(script_ctx_t *ctx, FunctionInstance *func, IDispatch *this_disp, unsigned flags, static HRESULT NativeFunction_call(script_ctx_t *ctx, FunctionInstance *func, jsval_t vthis, unsigned flags,
unsigned argc, jsval_t *argv, jsval_t *r) unsigned argc, jsval_t *argv, jsval_t *r)
{ {
NativeFunction *function = (NativeFunction*)func; NativeFunction *function = (NativeFunction*)func;
jsval_t vthis;
if(this_disp)
vthis = jsval_disp(this_disp);
else
vthis = jsval_null();
return function->proc(ctx, vthis, flags & ~DISPATCH_JSCRIPT_INTERNAL_MASK, argc, argv, r); return function->proc(ctx, vthis, flags & ~DISPATCH_JSCRIPT_INTERNAL_MASK, argc, argv, r);
} }
...@@ -698,12 +702,13 @@ HRESULT create_builtin_constructor(script_ctx_t *ctx, builtin_invoke_t value_pro ...@@ -698,12 +702,13 @@ HRESULT create_builtin_constructor(script_ctx_t *ctx, builtin_invoke_t value_pro
return S_OK; return S_OK;
} }
static HRESULT InterpretedFunction_call(script_ctx_t *ctx, FunctionInstance *func, IDispatch *this_obj, unsigned flags, static HRESULT InterpretedFunction_call(script_ctx_t *ctx, FunctionInstance *func, jsval_t vthis, unsigned flags,
unsigned argc, jsval_t *argv, jsval_t *r) unsigned argc, jsval_t *argv, jsval_t *r)
{ {
InterpretedFunction *function = (InterpretedFunction*)func; InterpretedFunction *function = (InterpretedFunction*)func;
jsdisp_t *new_obj = NULL; IDispatch *this_obj = NULL;
DWORD exec_flags = 0; DWORD exec_flags = 0;
jsdisp_t *new_obj;
HRESULT hres; HRESULT hres;
TRACE("%p\n", function); TRACE("%p\n", function);
...@@ -718,6 +723,14 @@ static HRESULT InterpretedFunction_call(script_ctx_t *ctx, FunctionInstance *fun ...@@ -718,6 +723,14 @@ static HRESULT InterpretedFunction_call(script_ctx_t *ctx, FunctionInstance *fun
if(FAILED(hres)) if(FAILED(hres))
return hres; return hres;
this_obj = to_disp(new_obj); this_obj = to_disp(new_obj);
}else if(is_object_instance(vthis)) {
this_obj = get_object(vthis);
if(this_obj)
IDispatch_AddRef(this_obj);
}else if(ctx->version >= SCRIPTLANGUAGEVERSION_ES5 && !is_undefined(vthis) && !is_null(vthis)) {
hres = to_object(ctx, vthis, &this_obj);
if(FAILED(hres))
return hres;
} }
if(flags & DISPATCH_JSCRIPT_CALLEREXECSSOURCE) if(flags & DISPATCH_JSCRIPT_CALLEREXECSSOURCE)
...@@ -726,8 +739,8 @@ static HRESULT InterpretedFunction_call(script_ctx_t *ctx, FunctionInstance *fun ...@@ -726,8 +739,8 @@ static HRESULT InterpretedFunction_call(script_ctx_t *ctx, FunctionInstance *fun
exec_flags |= EXEC_CONSTRUCTOR; exec_flags |= EXEC_CONSTRUCTOR;
hres = exec_source(ctx, exec_flags, function->code, function->func_code, function->scope_chain, this_obj, hres = exec_source(ctx, exec_flags, function->code, function->func_code, function->scope_chain, this_obj,
&function->function.dispex, argc, argv, r); &function->function.dispex, argc, argv, r);
if(new_obj) if(this_obj)
jsdisp_release(new_obj); IDispatch_Release(this_obj);
return hres; return hres;
} }
...@@ -801,7 +814,7 @@ HRESULT create_source_function(script_ctx_t *ctx, bytecode_t *code, function_cod ...@@ -801,7 +814,7 @@ HRESULT create_source_function(script_ctx_t *ctx, bytecode_t *code, function_cod
return S_OK; return S_OK;
} }
static HRESULT BindFunction_call(script_ctx_t *ctx, FunctionInstance *func, IDispatch *this_obj, unsigned flags, static HRESULT BindFunction_call(script_ctx_t *ctx, FunctionInstance *func, jsval_t vthis, unsigned flags,
unsigned argc, jsval_t *argv, jsval_t *r) unsigned argc, jsval_t *argv, jsval_t *r)
{ {
BindFunction *function = (BindFunction*)func; BindFunction *function = (BindFunction*)func;
...@@ -823,7 +836,8 @@ static HRESULT BindFunction_call(script_ctx_t *ctx, FunctionInstance *func, IDis ...@@ -823,7 +836,8 @@ static HRESULT BindFunction_call(script_ctx_t *ctx, FunctionInstance *func, IDis
memcpy(call_args + function->argc, argv, argc * sizeof(*call_args)); memcpy(call_args + function->argc, argv, argc * sizeof(*call_args));
} }
hres = function->target->vtbl->call(ctx, function->target, function->this, flags, call_argc, call_args, r); hres = function->target->vtbl->call(ctx, function->target, jsval_disp(function->this),
flags, call_argc, call_args, r);
heap_free(call_args); heap_free(call_args);
return hres; return hres;
......
...@@ -3104,6 +3104,14 @@ ok(String.length == 1, "String.length = " + String.length); ...@@ -3104,6 +3104,14 @@ ok(String.length == 1, "String.length = " + String.length);
ok(r === "[object Error]", "Error.toString with undefined context returned " + r); ok(r === "[object Error]", "Error.toString with undefined context returned " + r);
r = String.prototype.slice.call(null, 1, 3); r = String.prototype.slice.call(null, 1, 3);
ok(r === "ul", "String.slice with null context returned " + r); ok(r === "ul", "String.slice with null context returned " + r);
r = String.prototype.slice.call(undefined, 2, 5);
ok(r === "def", "String.slice with undefined context returned " + r);
r = (function() { return this; }).call(null);
ok(r === test, "wrong 'this' of function with null context");
r = (function() { return this; }).call(undefined);
ok(r === test, "wrong 'this' of function with undefined context");
r = (function() { return this; }).call(42);
ok(r.valueOf() === 42, "'this' of function with 42 context = " + r);
})(); })();
var tmp = createArray(); var tmp = createArray();
......
...@@ -1272,6 +1272,10 @@ sync_test("builtin_context", function() { ...@@ -1272,6 +1272,10 @@ sync_test("builtin_context", function() {
var obj = (function() { return this; }).call(null); var obj = (function() { return this; }).call(null);
ok(obj === window, "obj = " + obj); ok(obj === window, "obj = " + obj);
var obj = (function() { return this; }).call(undefined);
ok(obj === window, "obj = " + obj);
obj = (function() { return this; }).call(42);
ok(obj.valueOf() === 42, "obj = " + obj);
}); });
sync_test("head_setter", function() { sync_test("head_setter", function() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment