[PATCH v2 2/3] jscript: Implement separate script dispatch objects for each named item.

Gabriel Ivăncescu gabrielopcode at gmail.com
Mon Feb 24 07:48:24 CST 2020


Each named item should have its own associated script dispatch
object. Identifiers are added to this object, but code does look into the
global script object as well.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---
 dlls/jscript/compile.c |  2 ++
 dlls/jscript/dispex.c  |  1 +
 dlls/jscript/engine.c  | 33 +++++++++++++++--
 dlls/jscript/engine.h  |  2 ++
 dlls/jscript/global.c  |  9 ++++-
 dlls/jscript/jscript.c | 82 ++++++++++++++++++++++++++++++++++++++++--
 dlls/jscript/jscript.h |  2 ++
 7 files changed, 125 insertions(+), 6 deletions(-)

diff --git a/dlls/jscript/compile.c b/dlls/jscript/compile.c
index 61db10c..07027c2 100644
--- a/dlls/jscript/compile.c
+++ b/dlls/jscript/compile.c
@@ -2250,6 +2250,8 @@ void release_bytecode(bytecode_t *code)
     for(i=0; i < code->str_cnt; i++)
         jsstr_release(code->str_pool[i]);
 
+    if(code->named_item)
+        release_named_item(code->named_item);
     heap_free(code->source);
     heap_pool_free(&code->heap);
     heap_free(code->bstr_pool);
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c
index e986de6..a0c8f38 100644
--- a/dlls/jscript/dispex.c
+++ b/dlls/jscript/dispex.c
@@ -1527,6 +1527,7 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc
     }
 
     enter_script(This->ctx, &ei);
+    ei.script_obj = This;
 
     switch(wFlags) {
     case DISPATCH_METHOD|DISPATCH_PROPERTYGET:
diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c
index 4e28b63..6b261e7 100644
--- a/dlls/jscript/engine.c
+++ b/dlls/jscript/engine.c
@@ -654,6 +654,15 @@ static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *re
                 return S_OK;
             }
         }
+
+        if(ctx->call_ctx->bytecode->named_item) {
+            jsdisp_t *script_obj = ctx->call_ctx->bytecode->named_item->script_obj;
+            hres = jsdisp_get_id(script_obj, identifier, 0, &id);
+            if(SUCCEEDED(hres)) {
+                exprval_set_disp_ref(ret, to_disp(script_obj), id);
+                return S_OK;
+            }
+        }
     }
 
     hres = jsdisp_get_id(ctx->global, identifier, 0, &id);
@@ -1236,13 +1245,17 @@ static HRESULT interp_identifier_ref(script_ctx_t *ctx, BSTR identifier, unsigne
         return hres;
 
     if(exprval.type == EXPRVAL_INVALID && (flags & fdexNameEnsure)) {
+        jsdisp_t *script_obj = ctx->global;
         DISPID id;
 
-        hres = jsdisp_get_id(ctx->global, identifier, fdexNameEnsure, &id);
+        if(ctx->call_ctx->bytecode->named_item)
+            script_obj = ctx->call_ctx->bytecode->named_item->script_obj;
+
+        hres = jsdisp_get_id(script_obj, identifier, fdexNameEnsure, &id);
         if(FAILED(hres))
             return hres;
 
-        exprval_set_disp_ref(&exprval, to_disp(ctx->global), id);
+        exprval_set_disp_ref(&exprval, to_disp(script_obj), id);
     }
 
     if(exprval.type == EXPRVAL_JSVAL || exprval.type == EXPRVAL_INVALID) {
@@ -2972,6 +2985,15 @@ HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, functi
     unsigned i;
     HRESULT hres;
 
+    if(bytecode->named_item) {
+        if(!bytecode->named_item->script_obj) {
+            hres = create_named_item_script_obj(ctx, bytecode->named_item);
+            if(FAILED(hres)) return hres;
+        }
+        if(variable_obj == ctx->global)
+            variable_obj = bytecode->named_item->script_obj;
+    }
+
     if(!ctx->ei->enter_notified) {
         ctx->ei->enter_notified = TRUE;
         IActiveScriptSite_OnEnterScript(ctx->site);
@@ -2994,6 +3016,8 @@ HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, functi
     }
 
     if(flags & (EXEC_GLOBAL | EXEC_EVAL)) {
+        BOOL lookup_globals = (flags & EXEC_GLOBAL) && !bytecode->named_item;
+
         for(i=0; i < function->var_cnt; i++) {
             TRACE("[%d] %s %d\n", i, debugstr_w(function->variables[i].name), function->variables[i].func_id);
             if(function->variables[i].func_id != -1) {
@@ -3005,7 +3029,7 @@ HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, functi
 
                 hres = jsdisp_propput_name(variable_obj, function->variables[i].name, jsval_obj(func_obj));
                 jsdisp_release(func_obj);
-            }else if(!(flags & EXEC_GLOBAL) || !lookup_global_members(ctx, function->variables[i].name, NULL)) {
+            }else if(!lookup_globals || !lookup_global_members(ctx, function->variables[i].name, NULL)) {
                 DISPID id = 0;
 
                 hres = jsdisp_get_id(variable_obj, function->variables[i].name, fdexNameEnsure, &id);
@@ -3057,6 +3081,9 @@ HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, functi
     frame->stack_base = ctx->stack_top;
     if(this_obj)
         frame->this_obj = this_obj;
+    else if(bytecode->named_item)
+        frame->this_obj = (bytecode->named_item->flags & SCRIPTITEM_CODEONLY)
+                          ? to_disp(bytecode->named_item->script_obj) : bytecode->named_item->disp;
     else if(ctx->host_global)
         frame->this_obj = ctx->host_global;
     else
diff --git a/dlls/jscript/engine.h b/dlls/jscript/engine.h
index cad46e1..06ef500 100644
--- a/dlls/jscript/engine.h
+++ b/dlls/jscript/engine.h
@@ -180,6 +180,7 @@ struct _bytecode_t {
     heap_pool_t heap;
 
     function_code_t global_code;
+    named_item_t *named_item;
 
     WCHAR *source;
     UINT64 source_context;
@@ -231,6 +232,7 @@ struct _jsexcept_t {
     jsstr_t *message;
     jsstr_t *line;
 
+    jsdisp_t *script_obj;
     bytecode_t *code;
     unsigned loc;
 
diff --git a/dlls/jscript/global.c b/dlls/jscript/global.c
index e2758bf..bb53709 100644
--- a/dlls/jscript/global.c
+++ b/dlls/jscript/global.c
@@ -181,6 +181,7 @@ HRESULT JSGlobal_eval(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned a
 {
     call_frame_t *frame = ctx->call_ctx;
     DWORD exec_flags = EXEC_EVAL;
+    jsdisp_t *context;
     bytecode_t *code;
     const WCHAR *src;
     HRESULT hres;
@@ -210,12 +211,18 @@ HRESULT JSGlobal_eval(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned a
         return hres;
     }
 
+    if(frame && frame->bytecode->named_item) {
+        code->named_item = frame->bytecode->named_item;
+        code->named_item->ref++;
+    }
+    context = frame ? frame->variable_obj : (ctx->ei->script_obj ? ctx->ei->script_obj : ctx->global);
+
     if(!frame || (frame->flags & EXEC_GLOBAL))
         exec_flags |= EXEC_GLOBAL;
     if(flags & DISPATCH_JSCRIPT_CALLEREXECSSOURCE)
         exec_flags |= EXEC_RETURN_TO_INTERP;
     hres = exec_source(ctx, exec_flags, code, &code->global_code, frame ? frame->scope : NULL,
-            frame ? frame->this_obj : NULL, NULL, frame ? frame->variable_obj : ctx->global, 0, NULL, r);
+            frame ? frame->this_obj : NULL, NULL, context, 0, NULL, r);
     release_bytecode(code);
     return hres;
 }
diff --git a/dlls/jscript/jscript.c b/dlls/jscript/jscript.c
index 5e9b153..ea7d031 100644
--- a/dlls/jscript/jscript.c
+++ b/dlls/jscript/jscript.c
@@ -108,6 +108,32 @@ static inline BOOL is_started(script_ctx_t *ctx)
         || ctx->state == SCRIPTSTATE_DISCONNECTED;
 }
 
+HRESULT create_named_item_script_obj(script_ctx_t *ctx, named_item_t *item)
+{
+    static const builtin_info_t disp_info = {
+        JSCLASS_GLOBAL,
+        {NULL, NULL, 0},
+        0, NULL,
+        NULL,
+        NULL
+    };
+
+    if(item->flags & SCRIPTITEM_GLOBALMEMBERS) {
+        item->script_obj = ctx->global;
+        IDispatchEx_AddRef(&item->script_obj->IDispatchEx_iface);
+        return S_OK;
+    }
+    return create_dispex(ctx, &disp_info, NULL, &item->script_obj);
+}
+
+static void release_named_item_script_obj(named_item_t *item)
+{
+    if(!item->script_obj) return;
+
+    jsdisp_release(item->script_obj);
+    item->script_obj = NULL;
+}
+
 named_item_t *lookup_named_item(script_ctx_t *ctx, const WCHAR *item_name, unsigned flags)
 {
     named_item_t *item;
@@ -115,6 +141,10 @@ named_item_t *lookup_named_item(script_ctx_t *ctx, const WCHAR *item_name, unsig
 
     for(item = ctx->named_items; item; item = item->next) {
         if((item->flags & flags) == flags && !wcscmp(item->name, item_name)) {
+            if(!item->script_obj) {
+                hr = create_named_item_script_obj(ctx, item);
+                if(FAILED(hr)) return NULL;
+            }
             if(!item->disp && (flags || !(item->flags & SCRIPTITEM_CODEONLY))) {
                 IUnknown *unk;
 
@@ -371,6 +401,15 @@ static void clear_persistent_code_list(JScript *This)
     }
 }
 
+static void release_persistent_script_objs(JScript *This)
+{
+    bytecode_t *iter;
+
+    LIST_FOR_EACH_ENTRY(iter, &This->persistent_code, bytecode_t, entry)
+        if(iter->named_item)
+            release_named_item_script_obj(iter->named_item);
+}
+
 static void exec_queued_code(JScript *This)
 {
     bytecode_t *iter;
@@ -408,6 +447,7 @@ static void decrease_state(JScript *This, SCRIPTSTATE state)
             /* FALLTHROUGH */
         case SCRIPTSTATE_INITIALIZED:
             clear_script_queue(This);
+            release_persistent_script_objs(This);
 
             if(This->ctx->host_global) {
                 IDispatch_Release(This->ctx->host_global);
@@ -423,6 +463,7 @@ static void decrease_state(JScript *This, SCRIPTSTATE state)
 
                     if(iter->disp)
                         IDispatch_Release(iter->disp);
+                    release_named_item_script_obj(iter);
                     release_named_item(iter);
                     iter = iter2;
                 }
@@ -843,6 +884,7 @@ static HRESULT WINAPI JScript_AddNamedItem(IActiveScript *iface,
     item->ref = 1;
     item->disp = disp;
     item->flags = dwFlags;
+    item->script_obj = NULL;
     item->name = heap_strdupW(pstrName);
     if(!item->name) {
         if(disp)
@@ -869,6 +911,7 @@ static HRESULT WINAPI JScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR
                                                 IDispatch **ppdisp)
 {
     JScript *This = impl_from_IActiveScript(iface);
+    jsdisp_t *script_obj;
 
     TRACE("(%p)->(%s %p)\n", This, debugstr_w(pstrItemName), ppdisp);
 
@@ -880,7 +923,15 @@ static HRESULT WINAPI JScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR
         return E_UNEXPECTED;
     }
 
-    *ppdisp = to_disp(This->ctx->global);
+    if(pstrItemName) {
+        named_item_t *item = lookup_named_item(This->ctx, pstrItemName, 0);
+        if(!item) return E_INVALIDARG;
+        script_obj = item->script_obj;
+    }
+    else
+        script_obj = This->ctx->global;
+
+    *ppdisp = to_disp(script_obj);
     IDispatch_AddRef(*ppdisp);
     return S_OK;
 }
@@ -1001,6 +1052,7 @@ static HRESULT WINAPI JScriptParse_ParseScriptText(IActiveScriptParse *iface,
         DWORD dwFlags, VARIANT *pvarResult, EXCEPINFO *pexcepinfo)
 {
     JScript *This = impl_from_IActiveScriptParse(iface);
+    named_item_t *item = NULL;
     bytecode_t *code;
     jsexcept_t ei;
     HRESULT hres;
@@ -1012,11 +1064,23 @@ static HRESULT WINAPI JScriptParse_ParseScriptText(IActiveScriptParse *iface,
     if(This->thread_id != GetCurrentThreadId() || This->ctx->state == SCRIPTSTATE_CLOSED)
         return E_UNEXPECTED;
 
+    if(pstrItemName) {
+        item = lookup_named_item(This->ctx, pstrItemName, 0);
+        if(!item) {
+            WARN("Unknown context %s\n", debugstr_w(pstrItemName));
+            return E_INVALIDARG;
+        }
+    }
+
     enter_script(This->ctx, &ei);
     hres = compile_script(This->ctx, pstrCode, dwSourceContextCookie, ulStartingLine, NULL, pstrDelimiter,
             (dwFlags & SCRIPTTEXT_ISEXPRESSION) != 0, This->is_encode, &code);
     if(FAILED(hres))
         return leave_script(This->ctx, hres);
+    if(item) {
+        code->named_item = item;
+        item->ref++;
+    }
 
     if(dwFlags & SCRIPTTEXT_ISEXPRESSION) {
         jsval_t r;
@@ -1093,6 +1157,7 @@ static HRESULT WINAPI JScriptParseProcedure_ParseProcedureText(IActiveScriptPars
         CTXARG_T dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags, IDispatch **ppdisp)
 {
     JScript *This = impl_from_IActiveScriptParseProcedure2(iface);
+    named_item_t *item = NULL;
     bytecode_t *code;
     jsdisp_t *dispex;
     jsexcept_t ei;
@@ -1105,11 +1170,24 @@ static HRESULT WINAPI JScriptParseProcedure_ParseProcedureText(IActiveScriptPars
     if(This->thread_id != GetCurrentThreadId() || This->ctx->state == SCRIPTSTATE_CLOSED)
         return E_UNEXPECTED;
 
+    if(pstrItemName) {
+        item = lookup_named_item(This->ctx, pstrItemName, 0);
+        if(!item) {
+            WARN("Unknown context %s\n", debugstr_w(pstrItemName));
+            return E_INVALIDARG;
+        }
+    }
+
     enter_script(This->ctx, &ei);
     hres = compile_script(This->ctx, pstrCode, dwSourceContextCookie, ulStartingLineNumber, pstrFormalParams,
                           pstrDelimiter, FALSE, This->is_encode, &code);
-    if(SUCCEEDED(hres))
+    if(SUCCEEDED(hres)) {
+        if(item) {
+            code->named_item = item;
+            item->ref++;
+        }
         hres = create_source_function(This->ctx, code, &code->global_code, NULL,  &dispex);
+    }
     release_bytecode(code);
     hres = leave_script(This->ctx, hres);
     if(FAILED(hres))
diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h
index efd5a54..bf7a179 100644
--- a/dlls/jscript/jscript.h
+++ b/dlls/jscript/jscript.h
@@ -205,6 +205,7 @@ typedef HRESULT (*builtin_setter_t)(script_ctx_t*,jsdisp_t*,jsval_t);
 HRESULT builtin_set_const(script_ctx_t*,jsdisp_t*,jsval_t) DECLSPEC_HIDDEN;
 
 typedef struct named_item_t {
+    jsdisp_t *script_obj;
     IDispatch *disp;
     unsigned ref;
     DWORD flags;
@@ -213,6 +214,7 @@ typedef struct named_item_t {
     struct named_item_t *next;
 } named_item_t;
 
+HRESULT create_named_item_script_obj(script_ctx_t*,named_item_t*) DECLSPEC_HIDDEN;
 named_item_t *lookup_named_item(script_ctx_t*,const WCHAR*,unsigned) DECLSPEC_HIDDEN;
 void release_named_item(named_item_t*) DECLSPEC_HIDDEN;
 
-- 
2.21.0




More information about the wine-devel mailing list