jscript: Use host global object as default 'this' if available and global object...
authorJacek Caban <jacek@codeweavers.com>
Sun, 27 Sep 2009 18:59:28 +0000 (20:59 +0200)
committerAlexandre Julliard <julliard@winehq.org>
Mon, 28 Sep 2009 10:38:00 +0000 (12:38 +0200)
dlls/jscript/engine.c
dlls/jscript/engine.h
dlls/jscript/function.c
dlls/jscript/jscript.c
dlls/jscript/jscript.h
dlls/jscript/tests/jscript.c
dlls/jscript/tests/run.c

index a3007fc3941649d16eef2002c685eb59fa6e565a..cecfd62b60622f691dd6e6d1eb72e95e2086427f 100644 (file)
@@ -178,7 +178,8 @@ void scope_release(scope_chain_t *scope)
     heap_free(scope);
 }
 
-HRESULT create_exec_ctx(IDispatch *this_obj, DispatchEx *var_disp, scope_chain_t *scope, exec_ctx_t **ret)
+HRESULT create_exec_ctx(script_ctx_t *script_ctx, IDispatch *this_obj, DispatchEx *var_disp,
+        scope_chain_t *scope, exec_ctx_t **ret)
 {
     exec_ctx_t *ctx;
 
@@ -188,8 +189,13 @@ HRESULT create_exec_ctx(IDispatch *this_obj, DispatchEx *var_disp, scope_chain_t
 
     ctx->ref = 1;
 
-    IDispatch_AddRef(this_obj);
-    ctx->this_obj = this_obj;
+    if(this_obj)
+        ctx->this_obj = this_obj;
+    else if(script_ctx->host_global)
+        ctx->this_obj = script_ctx->host_global;
+    else
+        ctx->this_obj = (IDispatch*)_IDispatchEx_(script_ctx->global);
+    IDispatch_AddRef(ctx->this_obj);
 
     IDispatchEx_AddRef(_IDispatchEx_(var_disp));
     ctx->var_disp = var_disp;
@@ -537,21 +543,15 @@ static HRESULT identifier_eval(exec_ctx_t *ctx, BSTR identifier, DWORD flags, js
         }
     }
 
-    hres = jsdisp_get_id(ctx->parser->script->script_disp, identifier, 0, &id);
-    if(SUCCEEDED(hres)) {
-        exprval_set_idref(ret, (IDispatch*)_IDispatchEx_(ctx->parser->script->script_disp), id);
-        return S_OK;
-    }
-
     if(lookup_global_members(ctx->parser->script, identifier, ret))
         return S_OK;
 
     if(flags & EXPR_NEWREF) {
-        hres = jsdisp_get_id(ctx->parser->script->script_disp, identifier, fdexNameEnsure, &id);
+        hres = jsdisp_get_id(ctx->parser->script->global, identifier, fdexNameEnsure, &id);
         if(FAILED(hres))
             return hres;
 
-        exprval_set_idref(ret, (IDispatch*)_IDispatchEx_(ctx->parser->script->script_disp), id);
+        exprval_set_idref(ret, (IDispatch*)_IDispatchEx_(ctx->parser->script->global), id);
         return S_OK;
     }
 
index 09394cefa1279a5015b5bac377d9c14da1a747bf..386f38b51fd74d88e5a8935f8382eb5534587aa9 100644 (file)
@@ -116,7 +116,7 @@ static inline void exec_addref(exec_ctx_t *ctx)
 }
 
 void exec_release(exec_ctx_t*);
-HRESULT create_exec_ctx(IDispatch*,DispatchEx*,scope_chain_t*,exec_ctx_t**);
+HRESULT create_exec_ctx(script_ctx_t*,IDispatch*,DispatchEx*,scope_chain_t*,exec_ctx_t**);
 HRESULT exec_source(exec_ctx_t*,parser_ctx_t*,source_elements_t*,jsexcept_t*,VARIANT*);
 
 typedef struct _statement_t statement_t;
index cbdc08b953ea594c1f545bb8fcf3711a79c07bb4..b0fb79d711d4e8b69b7dfd709d6a92ba9e6b6331 100644 (file)
@@ -210,7 +210,7 @@ static HRESULT invoke_source(script_ctx_t *ctx, FunctionInstance *function, IDis
 
     hres = scope_push(function->scope_chain, var_disp, &scope);
     if(SUCCEEDED(hres)) {
-        hres = create_exec_ctx(this_obj, var_disp, scope, &exec_ctx);
+        hres = create_exec_ctx(ctx, this_obj, var_disp, scope, &exec_ctx);
         scope_release(scope);
     }
     if(FAILED(hres))
@@ -222,17 +222,6 @@ static HRESULT invoke_source(script_ctx_t *ctx, FunctionInstance *function, IDis
     return hres;
 }
 
-static HRESULT invoke_function(script_ctx_t *ctx, FunctionInstance *function, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
-{
-    IDispatch *this_obj;
-
-    if(!(this_obj = get_this(dp)))
-        this_obj = (IDispatch*)_IDispatchEx_(ctx->script_disp);
-
-    return invoke_source(ctx, function, this_obj, dp, retv, ei, caller);
-}
-
 static HRESULT invoke_constructor(script_ctx_t *ctx, FunctionInstance *function, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
@@ -254,18 +243,18 @@ static HRESULT invoke_constructor(script_ctx_t *ctx, FunctionInstance *function,
     return S_OK;
 }
 
-static HRESULT invoke_value_proc(script_ctx_t *ctx, FunctionInstance *function, WORD flags, DISPPARAMS *dp,
+static HRESULT invoke_value_proc(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_disp, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
-    IDispatch *this_disp;
     vdisp_t vthis;
     HRESULT hres;
 
-    this_disp = get_this(dp);
     if(this_disp)
         set_disp(&vthis, this_disp);
+    else if(ctx->host_global)
+        set_disp(&vthis, ctx->host_global);
     else
-        set_jsdisp(&vthis, ctx->script_disp);
+        set_jsdisp(&vthis, ctx->global);
 
     hres = function->value_proc(ctx, &vthis, flags, dp, retv, ei, caller);
 
@@ -276,24 +265,10 @@ static HRESULT invoke_value_proc(script_ctx_t *ctx, FunctionInstance *function,
 static HRESULT call_function(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_obj, DISPPARAMS *args,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
-    HRESULT hres;
+    if(function->value_proc)
+        return invoke_value_proc(ctx, function, this_obj, DISPATCH_METHOD, args, retv, ei, caller);
 
-    if(function->value_proc) {
-        vdisp_t vthis;
-
-        if(this_obj)
-            set_disp(&vthis, this_obj);
-        else
-            set_jsdisp(&vthis, ctx->script_disp);
-
-        hres = function->value_proc(ctx, &vthis, DISPATCH_METHOD, args, retv, ei, caller);
-        vdisp_release(&vthis);
-    }else {
-        hres = invoke_source(ctx, function, this_obj ? this_obj : (IDispatch*)_IDispatchEx_(ctx->script_disp),
-                args, retv, ei, caller);
-    }
-
-    return hres;
+    return invoke_source(ctx, function, this_obj, args, retv, ei, caller);
 }
 
 static HRESULT function_to_string(FunctionInstance *function, BSTR *ret)
@@ -506,9 +481,9 @@ HRESULT Function_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAM
     switch(flags) {
     case DISPATCH_METHOD:
         if(function->value_proc)
-            return invoke_value_proc(ctx, function, flags, dp, retv, ei, caller);
+            return invoke_value_proc(ctx, function, get_this(dp), flags, dp, retv, ei, caller);
 
-        return invoke_function(ctx, function, dp, retv, ei, caller);
+        return invoke_source(ctx, function, get_this(dp), dp, retv, ei, caller);
 
     case DISPATCH_PROPERTYGET: {
         HRESULT hres;
@@ -525,7 +500,7 @@ HRESULT Function_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAM
 
     case DISPATCH_CONSTRUCT:
         if(function->value_proc)
-            return invoke_value_proc(ctx, function, flags, dp, retv, ei, caller);
+            return invoke_value_proc(ctx, function, get_this(dp), flags, dp, retv, ei, caller);
 
         return invoke_constructor(ctx, function, dp, retv, ei, caller);
 
index 0771e9badb789132980b599f1363653e217b0446..1efe8e13d0fdddbf9034458022a6cf1d533b3ef8 100644 (file)
@@ -96,7 +96,7 @@ static HRESULT exec_global_code(JScript *This, parser_ctx_t *parser_ctx)
     VARIANT var;
     HRESULT hres;
 
-    hres = create_exec_ctx((IDispatch*)_IDispatchEx_(This->ctx->script_disp), This->ctx->script_disp, NULL, &exec_ctx);
+    hres = create_exec_ctx(This->ctx, NULL, This->ctx->global, NULL, &exec_ctx);
     if(FAILED(hres))
         return hres;
 
@@ -148,12 +148,6 @@ static HRESULT set_ctx_site(JScript *This)
 
     This->ctx->lcid = This->lcid;
 
-    if(!This->ctx->script_disp) {
-        hres = create_dispex(This->ctx, NULL, NULL, &This->ctx->script_disp);
-        if(FAILED(hres))
-            return hres;
-    }
-
     hres = init_global(This->ctx);
     if(FAILED(hres))
         return hres;
@@ -335,6 +329,11 @@ static HRESULT WINAPI JScript_Close(IActiveScript *iface)
         if(This->ctx->state == SCRIPTSTATE_DISCONNECTED)
             change_state(This, SCRIPTSTATE_INITIALIZED);
 
+        if(This->ctx->host_global) {
+            IDispatch_Release(This->ctx->host_global);
+            This->ctx->host_global = NULL;
+        }
+
         if(This->ctx->named_items) {
             named_item_t *iter, *iter2;
 
@@ -360,11 +359,6 @@ static HRESULT WINAPI JScript_Close(IActiveScript *iface)
         if (This->site)
             change_state(This, SCRIPTSTATE_CLOSED);
 
-        if(This->ctx->script_disp) {
-            jsdisp_release(This->ctx->script_disp);
-            This->ctx->script_disp = NULL;
-        }
-
         if(This->ctx->global) {
             jsdisp_release(This->ctx->global);
             This->ctx->global = NULL;
@@ -407,6 +401,11 @@ static HRESULT WINAPI JScript_AddNamedItem(IActiveScript *iface,
             WARN("object does not implement IDispatch\n");
             return hres;
         }
+
+        if(This->ctx->host_global)
+            IDispatch_Release(This->ctx->host_global);
+        IDispatch_AddRef(disp);
+        This->ctx->host_global = disp;
     }
 
     item = heap_alloc(sizeof(*item));
@@ -449,12 +448,12 @@ static HRESULT WINAPI JScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR
     if(!ppdisp)
         return E_POINTER;
 
-    if(This->thread_id != GetCurrentThreadId() || !This->ctx->script_disp) {
+    if(This->thread_id != GetCurrentThreadId() || !This->ctx->global) {
         *ppdisp = NULL;
         return E_UNEXPECTED;
     }
 
-    *ppdisp = (IDispatch*)_IDispatchEx_(This->ctx->script_disp);
+    *ppdisp = (IDispatch*)_IDispatchEx_(This->ctx->global);
     IDispatch_AddRef(*ppdisp);
     return S_OK;
 }
index 8f9873cb9a6a6e679097f6de3f4aef6953c44e04..bbf929dd631d386b47bc92d3ef5641f2f78becdb 100644 (file)
@@ -264,7 +264,8 @@ struct _script_ctx_t {
 
     jsheap_t tmp_heap;
 
-    DispatchEx *script_disp;
+    IDispatch *host_global;
+
     DispatchEx *global;
     DispatchEx *function_constr;
     DispatchEx *array_constr;
index 9d9681c299bda2d07788629f459b594a50deca8d..e53fc2dcfd29ede9c09bbd1370aca208acd43246 100644 (file)
@@ -68,6 +68,18 @@ DEFINE_EXPECT(OnStateChange_INITIALIZED);
 DEFINE_EXPECT(OnEnterScript);
 DEFINE_EXPECT(OnLeaveScript);
 
+static BSTR a2bstr(const char *str)
+{
+    BSTR ret;
+    int len;
+
+    len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
+    ret = SysAllocStringLen(NULL, len-1);
+    MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
+
+    return ret;
+}
+
 #define test_state(s,ss) _test_state(__LINE__,s,ss)
 static void _test_state(unsigned line, IActiveScript *script, SCRIPTSTATE exstate)
 {
@@ -195,6 +207,8 @@ static void test_script_dispatch(IActiveScript *script, BOOL initialized)
 {
     IDispatchEx *dispex;
     IDispatch *disp;
+    BSTR str;
+    DISPID id;
     HRESULT hres;
 
     disp = (void*)0xdeadbeef;
@@ -214,6 +228,11 @@ static void test_script_dispatch(IActiveScript *script, BOOL initialized)
     IDispatch_Release(disp);
     ok(hres == S_OK, "Could not get IDispatchEx interface: %08x\n", hres);
 
+    str = a2bstr("ActiveXObject");
+    hres = IDispatchEx_GetDispID(dispex, str, fdexNameCaseSensitive, &id);
+    SysFreeString(str);
+    ok(hres == S_OK, "GetDispID failed: %08x\n", hres);
+
     IDispatchEx_Release(dispex);
 }
 
index 1cfee4f26b0dff171d1038c27589bc2231d3776d..cf34b2f1abd2bb83cf5e660570b0ecfd883fb4ec 100644 (file)
@@ -79,6 +79,8 @@ DEFINE_EXPECT(GetItemInfo_testVal);
 #define DISPID_GLOBAL_TESTOBJ       0x1006
 #define DISPID_GLOBAL_NULL_BSTR     0x1007
 #define DISPID_GLOBAL_NULL_DISP     0x1008
+#define DISPID_GLOBAL_TESTTHIS      0x1009
+#define DISPID_GLOBAL_TESTTHIS2     0x100a
 
 #define DISPID_TESTOBJ_PROP         0x2000
 
@@ -89,6 +91,7 @@ static const CHAR test_valA[] = "testVal";
 
 static BOOL strict_dispid_check;
 static const char *test_name = "(null)";
+static IDispatch *script_disp;
 
 static BSTR a2bstr(const char *str)
 {
@@ -325,6 +328,18 @@ static HRESULT WINAPI Global_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD
         return DISP_E_UNKNOWNNAME;
     }
 
+    if(!strcmp_wa(bstrName, "testThis")) {
+        ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex);
+        *pid = DISPID_GLOBAL_TESTTHIS;
+        return S_OK;
+    }
+
+    if(!strcmp_wa(bstrName, "testThis2")) {
+        ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex);
+        *pid = DISPID_GLOBAL_TESTTHIS2;
+        return S_OK;
+    }
+
     if(strict_dispid_check)
         ok(0, "unexpected call %s\n", wine_dbgstr_w(bstrName));
     return DISP_E_UNKNOWNNAME;
@@ -492,6 +507,35 @@ static HRESULT WINAPI Global_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid,
         V_VT(pvarRes) = VT_DISPATCH;
         V_DISPATCH(pvarRes) = NULL;
         return S_OK;
+
+    case DISPID_GLOBAL_TESTTHIS:
+        ok(pdp != NULL, "pdp == NULL\n");
+        ok(pdp->rgvarg != NULL, "rgvarg == NULL\n");
+        ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n");
+        ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs);
+        ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
+        ok(pvarRes == NULL, "pvarRes != NULL\n");
+        ok(pei != NULL, "pei == NULL\n");
+
+        ok(V_VT(pdp->rgvarg) == VT_DISPATCH, "V_VT(arg) = %d\n", V_VT(pdp->rgvarg));
+        ok(V_DISPATCH(pdp->rgvarg) == (IDispatch*)iface, "disp != iface\n");
+
+        return S_OK;
+
+    case DISPID_GLOBAL_TESTTHIS2:
+        ok(pdp != NULL, "pdp == NULL\n");
+        ok(pdp->rgvarg != NULL, "rgvarg == NULL\n");
+        ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n");
+        ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs);
+        ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
+        ok(pvarRes == NULL, "pvarRes != NULL\n");
+        ok(pei != NULL, "pei == NULL\n");
+
+        ok(V_VT(pdp->rgvarg) == VT_DISPATCH, "V_VT(arg) = %d\n", V_VT(pdp->rgvarg));
+        ok(V_DISPATCH(pdp->rgvarg) != (IDispatch*)iface, "disp == iface\n");
+        ok(V_DISPATCH(pdp->rgvarg) == script_disp, "disp != script_disp\n");
+
+        return S_OK;
     }
 
     ok(0, "unexpected call %x\n", id);
@@ -625,7 +669,7 @@ static IActiveScript *create_script(void)
     return script;
 }
 
-static void parse_script(BSTR script_str)
+static void parse_script(DWORD flags, BSTR script_str)
 {
     IActiveScriptParse *parser;
     IActiveScript *engine;
@@ -650,15 +694,21 @@ static void parse_script(BSTR script_str)
     ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres);
 
     hres = IActiveScript_AddNamedItem(engine, testW,
-            SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS);
+            SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|flags);
     ok(hres == S_OK, "AddNamedItem failed: %08x\n", hres);
 
     hres = IActiveScript_SetScriptState(engine, SCRIPTSTATE_STARTED);
     ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_STARTED) failed: %08x\n", hres);
 
+    hres = IActiveScript_GetScriptDispatch(engine, NULL, &script_disp);
+    ok(hres == S_OK, "GetScriptDispatch failed: %08x\n", hres);
+    ok(script_disp != NULL, "script_disp == NULL\n");
+    ok(script_disp != (IDispatch*)&Global, "script_disp == Global\n");
+
     hres = IActiveScriptParse64_ParseScriptText(parser, script_str, NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
     ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
 
+    IDispatch_Release(script_disp);
     IActiveScript_Release(engine);
     IUnknown_Release(parser);
 }
@@ -704,13 +754,18 @@ static HRESULT parse_htmlscript(BSTR script_str)
     return hres;
 }
 
-static void parse_script_a(const char *src)
+static void parse_script_af(DWORD flags, const char *src)
 {
     BSTR tmp = a2bstr(src);
-    parse_script(tmp);
+    parse_script(flags, tmp);
     SysFreeString(tmp);
 }
 
+static void parse_script_a(const char *src)
+{
+    parse_script_af(SCRIPTITEM_GLOBALMEMBERS, src);
+}
+
 static HRESULT parse_htmlscript_a(const char *src)
 {
     HRESULT hres;
@@ -766,7 +821,7 @@ static void run_from_file(const char *filename)
     strict_dispid_check = FALSE;
 
     if(script_str)
-        parse_script(script_str);
+        parse_script(SCRIPTITEM_GLOBALMEMBERS, script_str);
 
     SysFreeString(script_str);
 }
@@ -793,7 +848,7 @@ static void run_from_res(const char *name)
 
     SET_EXPECT(global_success_d);
     SET_EXPECT(global_success_i);
-    parse_script(str);
+    parse_script(SCRIPTITEM_GLOBALMEMBERS, str);
     CHECK_CALLED(global_success_d);
     CHECK_CALLED(global_success_i);
 
@@ -916,6 +971,21 @@ static void run_tests(void)
     parse_script_a("ok(String.prototype.concat.call(testObj, ' OK') === '1 OK', 'wrong concat result');");
     CHECK_CALLED(testobj_value);
 
+    SET_EXPECT(global_propget_d);
+    SET_EXPECT(global_propget_i);
+    parse_script_a("this.testPropGet;");
+    CHECK_CALLED(global_propget_d);
+    CHECK_CALLED(global_propget_i);
+
+    SET_EXPECT(global_propget_d);
+    SET_EXPECT(global_propget_i);
+    parse_script_a("(function () { this.testPropGet; })();");
+    CHECK_CALLED(global_propget_d);
+    CHECK_CALLED(global_propget_i);
+
+    parse_script_a("testThis(this);");
+    parse_script_a("(function () { testThis(this); })();");
+
     run_from_res("lang.js");
     run_from_res("api.js");
     run_from_res("regexp.js");
@@ -923,6 +993,9 @@ static void run_tests(void)
     test_isvisible(FALSE);
     test_isvisible(TRUE);
 
+    parse_script_af(0, "test.testThis2(this);");
+    parse_script_af(0, "(function () { test.testThis2(this); })();");
+
     hres = parse_htmlscript_a("<!--");
     ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
     hres = parse_htmlscript_a("-->");