[PATCH 7/8] jscript: Implement separate script dispatch objects for each named item.

Gabriel Ivăncescu gabrielopcode at gmail.com
Wed Feb 19 10:38:09 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   |   3 +-
 dlls/jscript/engine.c   |  19 +++++-
 dlls/jscript/engine.h   |   5 +-
 dlls/jscript/function.c |   6 ++
 dlls/jscript/global.c   |   4 +-
 dlls/jscript/jscript.c  | 127 ++++++++++++++++++++++++++++++++++++----
 dlls/jscript/jscript.h  |   5 ++
 dlls/jscript/jsutils.c  |   4 +-
 9 files changed, 157 insertions(+), 18 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..6dd4a3a 100644
--- a/dlls/jscript/dispex.c
+++ b/dlls/jscript/dispex.c
@@ -1526,7 +1526,8 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc
         return DISP_E_MEMBERNOTFOUND;
     }
 
-    enter_script(This->ctx, &ei);
+    hres = enter_script(This->ctx, This->named_item, &ei);
+    if(FAILED(hres)) return hres;
 
     switch(wFlags) {
     case DISPATCH_METHOD|DISPATCH_PROPERTYGET:
diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c
index 4e28b63..79b0c57 100644
--- a/dlls/jscript/engine.c
+++ b/dlls/jscript/engine.c
@@ -656,6 +656,14 @@ static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *re
         }
     }
 
+    if(ctx->item_context) {
+        hres = jsdisp_get_id(ctx->item_context, identifier, 0, &id);
+        if(SUCCEEDED(hres)) {
+            exprval_set_disp_ref(ret, to_disp(ctx->item_context), id);
+            return S_OK;
+        }
+    }
+
     hres = jsdisp_get_id(ctx->global, identifier, 0, &id);
     if(SUCCEEDED(hres)) {
         exprval_set_disp_ref(ret, to_disp(ctx->global), id);
@@ -1236,13 +1244,14 @@ static HRESULT interp_identifier_ref(script_ctx_t *ctx, BSTR identifier, unsigne
         return hres;
 
     if(exprval.type == EXPRVAL_INVALID && (flags & fdexNameEnsure)) {
+        jsdisp_t *jsdisp = ctx->item_context ? ctx->item_context : ctx->global;
         DISPID id;
 
-        hres = jsdisp_get_id(ctx->global, identifier, fdexNameEnsure, &id);
+        hres = jsdisp_get_id(jsdisp, 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(jsdisp), id);
     }
 
     if(exprval.type == EXPRVAL_JSVAL || exprval.type == EXPRVAL_INVALID) {
@@ -2994,6 +3003,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) && !ctx->item_context;
+
         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 +3016,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 +3068,8 @@ 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(ctx->item_context)
+        frame->this_obj = to_disp(ctx->item_context);
     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..d50b0fa 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,8 @@ struct _jsexcept_t {
     jsstr_t *message;
     jsstr_t *line;
 
+    jsdisp_t *item_context;
+
     bytecode_t *code;
     unsigned loc;
 
@@ -238,7 +241,7 @@ struct _jsexcept_t {
     jsexcept_t *prev;
 };
 
-void enter_script(script_ctx_t*,jsexcept_t*) DECLSPEC_HIDDEN;
+HRESULT enter_script(script_ctx_t*,named_item_t*,jsexcept_t*) DECLSPEC_HIDDEN;
 HRESULT leave_script(script_ctx_t*,HRESULT) DECLSPEC_HIDDEN;
 void reset_ei(jsexcept_t*) DECLSPEC_HIDDEN;
 void set_error_location(jsexcept_t*,bytecode_t*,unsigned,unsigned,jsstr_t*) DECLSPEC_HIDDEN;
diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c
index baa5eb1..f34745d 100644
--- a/dlls/jscript/function.c
+++ b/dlls/jscript/function.c
@@ -612,6 +612,8 @@ static HRESULT NativeFunction_call(script_ctx_t *ctx, FunctionInstance *func, ID
 
     if(this_disp)
         set_disp(&vthis, this_disp);
+    else if(ctx->item_context)
+        set_jsdisp(&vthis, ctx->item_context);
     else if(ctx->host_global)
         set_disp(&vthis, ctx->host_global);
     else
@@ -820,6 +822,10 @@ HRESULT create_source_function(script_ctx_t *ctx, bytecode_t *code, function_cod
     }
 
     bytecode_addref(code);
+    if(!code->named_item && ctx->item_context) {
+        code->named_item = ctx->item_context->named_item;
+        code->named_item->ref++;
+    }
     function->code = code;
     function->func_code = func_code;
     function->function.length = function->func_code->param_cnt;
diff --git a/dlls/jscript/global.c b/dlls/jscript/global.c
index e2758bf..3bf06de 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,13 @@ HRESULT JSGlobal_eval(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned a
         return hres;
     }
 
+    context = frame ? frame->variable_obj : (ctx->item_context ? ctx->item_context : 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 3ec259f..e562f2d 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;
 }
 
+static 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
+    };
+    HRESULT hr = create_dispex(ctx, &disp_info, NULL, &item->script_obj);
+
+    if(FAILED(hr))
+        return hr;
+    item->script_obj->named_item = item;
+    return S_OK;
+}
+
+static void release_named_item_script_obj(named_item_t *item)
+{
+    if(!item->script_obj) return;
+
+    item->script_obj->named_item = NULL;
+    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;
 
@@ -143,6 +173,14 @@ named_item_t *lookup_named_item(script_ctx_t *ctx, const WCHAR *item_name, unsig
     return NULL;
 }
 
+void release_named_item(named_item_t *item)
+{
+    if(--item->ref) return;
+
+    heap_free(item->name);
+    heap_free(item);
+}
+
 static inline JScriptError *impl_from_IActiveScriptError(IActiveScriptError *iface)
 {
     return CONTAINING_RECORD(iface, JScriptError, IActiveScriptError_iface);
@@ -295,12 +333,24 @@ void reset_ei(jsexcept_t *ei)
     }
 }
 
-void enter_script(script_ctx_t *ctx, jsexcept_t *ei)
+HRESULT enter_script(script_ctx_t *ctx, named_item_t *item, jsexcept_t *ei)
 {
+    HRESULT hres;
+
     memset(ei, 0, sizeof(*ei));
+    if(item) {
+        if(!item->script_obj) {
+            hres = create_named_item_script_obj(ctx, item);
+            if(FAILED(hres)) return hres;
+        }
+        ei->item_context = item->script_obj;
+    }
+    ctx->item_context = ei->item_context;
+
     ei->prev = ctx->ei;
     ctx->ei = ei;
     TRACE("ctx %p ei %p prev %p\n", ctx, ei, ei->prev);
+    return S_OK;
 }
 
 HRESULT leave_script(script_ctx_t *ctx, HRESULT result)
@@ -311,6 +361,7 @@ HRESULT leave_script(script_ctx_t *ctx, HRESULT result)
     TRACE("ctx %p ei %p prev %p\n", ctx, ei, ei->prev);
 
     ctx->ei = ei->prev;
+    ctx->item_context = ctx->ei ? ctx->ei->item_context : NULL;
     if(result == DISP_E_EXCEPTION) {
         result = ei->error;
     }else {
@@ -364,6 +415,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;
@@ -371,8 +431,11 @@ static void exec_queued_code(JScript *This)
     HRESULT hres = S_OK;
 
     LIST_FOR_EACH_ENTRY(iter, &This->queued_code, bytecode_t, entry) {
-        enter_script(This->ctx, &ei);
-        hres = exec_source(This->ctx, EXEC_GLOBAL, iter, &iter->global_code, NULL, NULL, NULL, This->ctx->global, 0, NULL, NULL);
+        hres = enter_script(This->ctx, iter->named_item, &ei);
+        if(FAILED(hres))
+            break;
+        hres = exec_source(This->ctx, EXEC_GLOBAL, iter, &iter->global_code, NULL, NULL, NULL,
+                           This->ctx->item_context ? This->ctx->item_context : This->ctx->global, 0, NULL, NULL);
         leave_script(This->ctx, hres);
         if(FAILED(hres))
             break;
@@ -401,6 +464,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);
@@ -416,8 +480,8 @@ static void decrease_state(JScript *This, SCRIPTSTATE state)
 
                     if(iter->disp)
                         IDispatch_Release(iter->disp);
-                    heap_free(iter->name);
-                    heap_free(iter);
+                    release_named_item_script_obj(iter);
+                    release_named_item(iter);
                     iter = iter2;
                 }
 
@@ -834,8 +898,10 @@ static HRESULT WINAPI JScript_AddNamedItem(IActiveScript *iface,
         return E_OUTOFMEMORY;
     }
 
+    item->ref = 1;
     item->disp = disp;
     item->flags = dwFlags;
+    item->script_obj = NULL;
     item->name = heap_strdupW(pstrName);
     if(!item->name) {
         if(disp)
@@ -862,6 +928,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);
 
@@ -873,7 +940,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;
 }
@@ -994,6 +1069,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;
@@ -1005,16 +1081,31 @@ static HRESULT WINAPI JScriptParse_ParseScriptText(IActiveScriptParse *iface,
     if(This->thread_id != GetCurrentThreadId() || This->ctx->state == SCRIPTSTATE_CLOSED)
         return E_UNEXPECTED;
 
-    enter_script(This->ctx, &ei);
+    if(pstrItemName) {
+        item = lookup_named_item(This->ctx, pstrItemName, 0);
+        if(!item) {
+            WARN("Unknown context %s\n", debugstr_w(pstrItemName));
+            return E_INVALIDARG;
+        }
+    }
+
+    hres = enter_script(This->ctx, item, &ei);
+    if(FAILED(hres))
+        return hres;
     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;
 
-        hres = exec_source(This->ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, This->ctx->global, 0, NULL, &r);
+        hres = exec_source(This->ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL,
+                           This->ctx->item_context ? This->ctx->item_context : This->ctx->global, 0, NULL, &r);
         if(SUCCEEDED(hres)) {
             if(pvarResult)
                 hres = jsval_to_variant(r, pvarResult);
@@ -1033,7 +1124,8 @@ static HRESULT WINAPI JScriptParse_ParseScriptText(IActiveScriptParse *iface,
     if(!pvarResult && !is_started(This->ctx)) {
         list_add_tail(&This->queued_code, &code->entry);
     }else {
-        hres = exec_source(This->ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, This->ctx->global, 0, NULL, NULL);
+        hres = exec_source(This->ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL,
+                           This->ctx->item_context ? This->ctx->item_context : This->ctx->global, 0, NULL, NULL);
         if(code->is_persistent)
             list_add_tail(&This->persistent_code, &code->entry);
         else
@@ -1086,6 +1178,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;
@@ -1098,7 +1191,17 @@ static HRESULT WINAPI JScriptParseProcedure_ParseProcedureText(IActiveScriptPars
     if(This->thread_id != GetCurrentThreadId() || This->ctx->state == SCRIPTSTATE_CLOSED)
         return E_UNEXPECTED;
 
-    enter_script(This->ctx, &ei);
+    if(pstrItemName) {
+        item = lookup_named_item(This->ctx, pstrItemName, 0);
+        if(!item) {
+            WARN("Unknown context %s\n", debugstr_w(pstrItemName));
+            return E_INVALIDARG;
+        }
+    }
+
+    hres = enter_script(This->ctx, item, &ei);
+    if(FAILED(hres))
+        return hres;
     hres = compile_script(This->ctx, pstrCode, dwSourceContextCookie, ulStartingLineNumber, pstrFormalParams,
                           pstrDelimiter, FALSE, This->is_encode, &code);
     if(SUCCEEDED(hres))
@@ -1287,7 +1390,9 @@ static HRESULT WINAPI VariantChangeType_ChangeType(IVariantChangeType *iface, VA
         return E_UNEXPECTED;
     }
 
-    enter_script(This->ctx, &ei);
+    hres = enter_script(This->ctx, NULL, &ei);
+    if(FAILED(hres))
+        return hres;
     hres = variant_change_type(This->ctx, &res, src, vt);
     hres = leave_script(This->ctx, hres);
     if(FAILED(hres))
diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h
index 8297838..9492f3f 100644
--- a/dlls/jscript/jscript.h
+++ b/dlls/jscript/jscript.h
@@ -205,7 +205,9 @@ 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;
     LPWSTR name;
 
@@ -213,6 +215,7 @@ typedef struct named_item_t {
 } named_item_t;
 
 named_item_t *lookup_named_item(script_ctx_t*,const WCHAR*,unsigned) DECLSPEC_HIDDEN;
+void release_named_item(named_item_t*) DECLSPEC_HIDDEN;
 
 typedef struct {
     const WCHAR *name;
@@ -243,6 +246,7 @@ struct jsdisp_t {
     DWORD prop_cnt;
     dispex_prop_t *props;
     script_ctx_t *ctx;
+    named_item_t *named_item;
 
     jsdisp_t *prototype;
 
@@ -433,6 +437,7 @@ struct _script_ctx_t {
     DWORD last_match_length;
 
     jsdisp_t *global;
+    jsdisp_t *item_context;
     jsdisp_t *function_constr;
     jsdisp_t *array_constr;
     jsdisp_t *bool_constr;
diff --git a/dlls/jscript/jsutils.c b/dlls/jscript/jsutils.c
index 421116f..351255b 100644
--- a/dlls/jscript/jsutils.c
+++ b/dlls/jscript/jsutils.c
@@ -881,7 +881,9 @@ HRESULT variant_change_type(script_ctx_t *ctx, VARIANT *dst, VARIANT *src, VARTY
     if(FAILED(hres))
         return hres;
 
-    enter_script(ctx, &ei);
+    hres = enter_script(ctx, NULL, &ei);
+    if(FAILED(hres))
+        return hres;
 
     switch(vt) {
     case VT_I2:
-- 
2.21.0




More information about the wine-devel mailing list