[PATCH v2 1/4] vbscript: Store the DISPID for functions and variables when they are created.

Gabriel Ivăncescu gabrielopcode at gmail.com
Mon Oct 21 06:40:27 CDT 2019


Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---

Sending only first bit of patches now, the rest will come after.

The ident map is still needed for accessing it directly by DISPID (and by
MEMBERIDs when the TypeInfo is implemented), but now it is simply re-created
when the DISPID count changes (after the script has stuff added to it).

Note that the map can have NULL entries in very rare cases, because of
dynamic vars. The code lists which have their DISPIDs stored when the
functions/variables are compiled will remain even if the script is released
(by decreasing its state) but not destroyed. Meanwhile, dynamic variables
created during the interpreting phase will be gone, and those slots in
future ident maps will not be filled.

The scenario is rare enough that I think it is not worthwhile to keep track
of available DISPIDs in this case, which would be more complicated, so we
just never re-use the DISPIDs at all.

 dlls/vbscript/compile.c  |  7 ++++
 dlls/vbscript/interp.c   |  1 +
 dlls/vbscript/vbdisp.c   | 69 ++++++++++++++++------------------------
 dlls/vbscript/vbscript.h |  5 ++-
 4 files changed, 40 insertions(+), 42 deletions(-)

diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c
index c129f36..a9bf96e 100644
--- a/dlls/vbscript/compile.c
+++ b/dlls/vbscript/compile.c
@@ -53,6 +53,8 @@ typedef struct {
     unsigned func_end_label;
     unsigned prop_end_label;
 
+    DISPID cur_dispid;
+
     dim_decl_t *dim_decls;
     dim_decl_t *dim_decls_tail;
     dynamic_var_t *global_vars;
@@ -1424,6 +1426,7 @@ static HRESULT compile_func(compile_ctx_t *ctx, statement_t *stat, function_t *f
 
                 V_VT(&new_var->v) = VT_EMPTY;
                 new_var->is_const = FALSE;
+                new_var->dispid   = ++ctx->cur_dispid;
 
                 new_var->next = ctx->global_vars;
                 ctx->global_vars = new_var;
@@ -1503,6 +1506,7 @@ static HRESULT create_function(compile_ctx_t *ctx, function_decl_t *decl, functi
     func->code_ctx = ctx->code;
     func->type = decl->type;
     func->is_public = decl->is_public;
+    func->dispid = ++ctx->cur_dispid;
 
     func->arg_cnt = 0;
     if(decl->args) {
@@ -1852,6 +1856,7 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *deli
     ctx.global_consts = NULL;
     ctx.stat_ctx = NULL;
     ctx.labels_cnt = ctx.labels_size = 0;
+    ctx.cur_dispid = script->cur_dispid;
 
     hres = compile_func(&ctx, ctx.parser.stats, &ctx.code->main_code);
     if(FAILED(hres)) {
@@ -1919,6 +1924,8 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *deli
     if(TRACE_ON(vbscript_disas))
         dump_code(&ctx);
 
+    script->cur_dispid = ctx.cur_dispid;
+
     ctx.code = NULL;
     release_compiler(&ctx);
 
diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c
index 80ecc41..80588b5 100644
--- a/dlls/vbscript/interp.c
+++ b/dlls/vbscript/interp.c
@@ -228,6 +228,7 @@ static HRESULT add_dynamic_var(exec_ctx_t *ctx, const WCHAR *name,
     V_VT(&new_var->v) = VT_EMPTY;
 
     if(ctx->func->type == FUNC_GLOBAL) {
+        new_var->dispid = ++ctx->script->cur_dispid;
         new_var->next = ctx->script->global_vars;
         ctx->script->global_vars = new_var;
     }else {
diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c
index 1dd6d4e..fd51935 100644
--- a/dlls/vbscript/vbdisp.c
+++ b/dlls/vbscript/vbdisp.c
@@ -527,7 +527,6 @@ HRESULT create_vbdisp(const class_desc_t *desc, vbdisp_t **ret)
 }
 
 struct _ident_map_t {
-    const WCHAR *name;
     BOOL is_var;
     union {
         dynamic_var_t *var;
@@ -542,31 +541,36 @@ static inline DISPID ident_to_id(ScriptDisp *This, ident_map_t *ident)
 
 static inline ident_map_t *id_to_ident(ScriptDisp *This, DISPID id)
 {
-    return 0 < id && id <= This->ident_map_cnt ? This->ident_map+id-1 : NULL;
+    return 0 < id && id <= This->ident_map_cnt && This->ident_map[id - 1].u.var
+           ? This->ident_map + id - 1 : NULL;
 }
 
-static ident_map_t *add_ident(ScriptDisp *This, const WCHAR *name)
+static BOOL update_ident_map(ScriptDisp *This)
 {
-    ident_map_t *ret;
+    dynamic_var_t *var;
+    function_t *func;
+    ident_map_t *map;
+
+    if (This->ident_map_cnt == This->ctx->cur_dispid)
+        return TRUE;
 
-    if(!This->ident_map_size) {
-        This->ident_map = heap_alloc(4 * sizeof(*This->ident_map));
-        if(!This->ident_map)
-            return NULL;
-        This->ident_map_size = 4;
-    }else if(This->ident_map_cnt == This->ident_map_size) {
-        ident_map_t *new_map;
+    map = heap_alloc_zero(This->ctx->cur_dispid * sizeof(*map));
+    if (!map) return FALSE;
 
-        new_map = heap_realloc(This->ident_map, 2*This->ident_map_size*sizeof(*new_map));
-        if(!new_map)
-            return NULL;
-        This->ident_map = new_map;
-        This->ident_map_size *= 2;
+    heap_free(This->ident_map);
+    This->ident_map_cnt = This->ctx->cur_dispid;
+    This->ident_map = map;
+
+    for (var = This->ctx->global_vars; var; var = var->next)
+    {
+        map[var->dispid - 1].is_var = TRUE;
+        map[var->dispid - 1].u.var = var;
     }
 
-    ret = This->ident_map + This->ident_map_cnt++;
-    ret->name = name;
-    return ret;
+    for (func = This->ctx->global_funcs; func; func = func->next)
+        map[func->dispid - 1].u.func = func;
+
+    return TRUE;
 }
 
 static inline ScriptDisp *ScriptDisp_from_IDispatchEx(IDispatchEx *iface)
@@ -676,7 +680,6 @@ static HRESULT WINAPI ScriptDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, DW
 {
     ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
     dynamic_var_t *var;
-    ident_map_t *ident;
     function_t *func;
 
     TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid);
@@ -684,35 +687,16 @@ static HRESULT WINAPI ScriptDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, DW
     if(!This->ctx)
         return E_UNEXPECTED;
 
-    for(ident = This->ident_map; ident < This->ident_map+This->ident_map_cnt; ident++) {
-        if(!wcsicmp(ident->name, bstrName)) {
-            *pid = ident_to_id(This, ident);
-            return S_OK;
-        }
-    }
-
     for(var = This->ctx->global_vars; var; var = var->next) {
         if(!wcsicmp(var->name, bstrName)) {
-            ident = add_ident(This, var->name);
-            if(!ident)
-                return E_OUTOFMEMORY;
-
-            ident->is_var = TRUE;
-            ident->u.var = var;
-            *pid = ident_to_id(This, ident);
+            *pid = var->dispid;
             return S_OK;
         }
     }
 
     for(func = This->ctx->global_funcs; func; func = func->next) {
         if(!wcsicmp(func->name, bstrName)) {
-            ident = add_ident(This, func->name);
-            if(!ident)
-                return E_OUTOFMEMORY;
-
-            ident->is_var = FALSE;
-            ident->u.func = func;
-            *pid =  ident_to_id(This, ident);
+            *pid = func->dispid;
             return S_OK;
         }
     }
@@ -730,6 +714,9 @@ static HRESULT WINAPI ScriptDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc
 
     TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
 
+    if(!update_ident_map(This))
+        return E_OUTOFMEMORY;
+
     ident = id_to_ident(This, id);
     if(!ident)
         return DISP_E_MEMBERNOTFOUND;
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h
index 71f42aa..9d41632 100644
--- a/dlls/vbscript/vbscript.h
+++ b/dlls/vbscript/vbscript.h
@@ -128,7 +128,6 @@ typedef struct {
 
     ident_map_t *ident_map;
     unsigned ident_map_cnt;
-    unsigned ident_map_size;
 
     script_ctx_t *ctx;
 } ScriptDisp;
@@ -169,6 +168,7 @@ typedef struct _dynamic_var_t {
     VARIANT v;
     const WCHAR *name;
     BOOL is_const;
+    DISPID dispid;
 } dynamic_var_t;
 
 struct _script_ctx_t {
@@ -178,6 +178,8 @@ struct _script_ctx_t {
     IInternetHostSecurityManager *secmgr;
     DWORD safeopt;
 
+    DISPID cur_dispid;
+
     IDispatch *host_global;
 
     ScriptDisp *script_obj;
@@ -314,6 +316,7 @@ typedef struct {
 } var_desc_t;
 
 struct _function_t {
+    DISPID dispid;
     function_type_t type;
     const WCHAR *name;
     BOOL is_public;
-- 
2.21.0




More information about the wine-devel mailing list