[PATCH v3 1/9] vbscript: Use arrays for global variable and function lists.

Gabriel Ivăncescu gabrielopcode at gmail.com
Fri Nov 1 10:00:58 CDT 2019


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

Supersedes 172426 to 172433.

DISPID_FUNCTION_MASK has been chosen to be the same bit used in TypeLibs
to separate functions from variables in MEMBERIDs.

 dlls/vbscript/compile.c  |  31 +++++-----
 dlls/vbscript/interp.c   |  56 ++++++++++++-----
 dlls/vbscript/vbdisp.c   | 127 ++++++++++++---------------------------
 dlls/vbscript/vbscript.c |  10 ++-
 dlls/vbscript/vbscript.h |  52 +++++++++++++---
 5 files changed, 149 insertions(+), 127 deletions(-)

diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c
index 0727979..f7bceeb 100644
--- a/dlls/vbscript/compile.c
+++ b/dlls/vbscript/compile.c
@@ -1780,17 +1780,18 @@ static HRESULT compile_class(compile_ctx_t *ctx, class_decl_t *class_decl)
 
 static BOOL lookup_script_identifier(script_ctx_t *script, const WCHAR *identifier)
 {
+    dynamic_var_t **vars = script->global_vars;
+    function_t **funcs = script->global_funcs;
     class_desc_t *class;
-    dynamic_var_t *var;
-    function_t *func;
+    UINT i;
 
-    for(var = script->global_vars; var; var = var->next) {
-        if(!wcsicmp(var->name, identifier))
+    for(i = 0; i < script->global_vars_num; i++) {
+        if(!wcsicmp(vars[i]->name, identifier))
             return TRUE;
     }
 
-    for(func = script->global_funcs; func; func = func->next) {
-        if(!wcsicmp(func->name, identifier))
+    for(i = 0; i < script->global_funcs_num; i++) {
+        if(!wcsicmp(funcs[i]->name, identifier))
             return TRUE;
     }
 
@@ -1956,17 +1957,19 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *deli
     if(ctx.global_vars) {
         dynamic_var_t *var;
 
-        for(var = ctx.global_vars; var->next; var = var->next);
-
-        var->next = script->global_vars;
-        script->global_vars = ctx.global_vars;
+        for (var = ctx.global_vars; var; var = var->next)
+            if (!add_global_var(script, var)) {
+                release_compiler(&ctx);
+                return compile_error(script, E_OUTOFMEMORY);
+            }
     }
 
     if(ctx.funcs) {
-        for(new_func = ctx.funcs; new_func->next; new_func = new_func->next);
-
-        new_func->next = script->global_funcs;
-        script->global_funcs = ctx.funcs;
+        for (new_func = ctx.funcs; new_func; new_func = new_func->next)
+            if (!add_global_func(script, new_func)) {
+                release_compiler(&ctx);
+                return compile_error(script, E_OUTOFMEMORY);
+            }
     }
 
     if(ctx.classes) {
diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c
index ad6454a..acd524f 100644
--- a/dlls/vbscript/interp.c
+++ b/dlls/vbscript/interp.c
@@ -95,10 +95,41 @@ static BOOL lookup_dynamic_vars(dynamic_var_t *var, const WCHAR *name, ref_t *re
     return FALSE;
 }
 
+static BOOL lookup_global_vars(script_ctx_t *script, const WCHAR *name, ref_t *ref)
+{
+    dynamic_var_t **vars = script->global_vars;
+    UINT i, num = script->global_vars_num;
+
+    for (i = 0; i < num; i++) {
+        if (!wcsicmp(vars[i]->name, name)) {
+            ref->type = vars[i]->is_const ? REF_CONST : REF_VAR;
+            ref->u.v = &vars[i]->v;
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+static BOOL lookup_global_funcs(script_ctx_t *script, const WCHAR *name, ref_t *ref)
+{
+    function_t **funcs = script->global_funcs;
+    UINT i, num = script->global_funcs_num;
+
+    for (i = 0; i < num; i++) {
+        if (!wcsicmp(funcs[i]->name, name)) {
+            ref->type = REF_FUNC;
+            ref->u.f = funcs[i];
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
 static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_t invoke_type, ref_t *ref)
 {
     named_item_t *item;
-    function_t *func;
     IDispatch *disp;
     unsigned i;
     DISPID id;
@@ -128,10 +159,13 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_
         }
     }
 
-    if(lookup_dynamic_vars(ctx->func->type == FUNC_GLOBAL ? ctx->script->global_vars : ctx->dynamic_vars, name, ref))
-        return S_OK;
+    if(ctx->func->type == FUNC_GLOBAL) {
+        if(lookup_global_vars(ctx->script, name, ref))
+            return S_OK;
+    }else {
+        if(lookup_dynamic_vars(ctx->dynamic_vars, name, ref))
+            return S_OK;
 
-    if(ctx->func->type != FUNC_GLOBAL) {
         if(ctx->vbthis) {
             /* FIXME: Bind such identifier while generating bytecode. */
             for(i=0; i < ctx->vbthis->desc->prop_cnt; i++) {
@@ -162,16 +196,11 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_
         }
     }
 
-    if(ctx->func->type != FUNC_GLOBAL && lookup_dynamic_vars(ctx->script->global_vars, name, ref))
+    if(ctx->func->type != FUNC_GLOBAL && lookup_global_vars(ctx->script, name, ref))
         return S_OK;
 
-    for(func = ctx->script->global_funcs; func; func = func->next) {
-        if(!wcsicmp(func->name, name)) {
-            ref->type = REF_FUNC;
-            ref->u.f = func;
-            return S_OK;
-        }
-    }
+    if(lookup_global_funcs(ctx->script, name, ref))
+        return S_OK;
 
     hres = get_builtin_id(ctx->script->global_obj, name, &id);
     if(SUCCEEDED(hres)) {
@@ -228,8 +257,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->next = ctx->script->global_vars;
-        ctx->script->global_vars = new_var;
+        add_global_var(ctx->script, new_var);
     }else {
         new_var->next = ctx->dynamic_vars;
         ctx->dynamic_vars = new_var;
diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c
index 25a80fc..7b5e28f 100644
--- a/dlls/vbscript/vbdisp.c
+++ b/dlls/vbscript/vbdisp.c
@@ -24,6 +24,7 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
 
+#define DISPID_FUNCTION_MASK 0x20000000
 #define FDEX_VERSION_MASK 0xf0000000
 
 static inline BOOL is_func_id(vbdisp_t *This, DISPID id)
@@ -526,49 +527,6 @@ HRESULT create_vbdisp(const class_desc_t *desc, vbdisp_t **ret)
     return S_OK;
 }
 
-struct _ident_map_t {
-    const WCHAR *name;
-    BOOL is_var;
-    union {
-        dynamic_var_t *var;
-        function_t *func;
-    } u;
-};
-
-static inline DISPID ident_to_id(ScriptDisp *This, ident_map_t *ident)
-{
-    return (ident-This->ident_map)+1;
-}
-
-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;
-}
-
-static ident_map_t *add_ident(ScriptDisp *This, const WCHAR *name)
-{
-    ident_map_t *ret;
-
-    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;
-
-        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;
-    }
-
-    ret = This->ident_map + This->ident_map_cnt++;
-    ret->name = name;
-    return ret;
-}
-
 static inline ScriptDisp *ScriptDisp_from_IDispatchEx(IDispatchEx *iface)
 {
     return CONTAINING_RECORD(iface, ScriptDisp, IDispatchEx_iface);
@@ -616,7 +574,6 @@ static ULONG WINAPI ScriptDisp_Release(IDispatchEx *iface)
 
     if(!ref) {
         assert(!This->ctx);
-        heap_free(This->ident_map);
         heap_free(This);
     }
 
@@ -675,44 +632,29 @@ static HRESULT WINAPI ScriptDisp_Invoke(IDispatchEx *iface, DISPID dispIdMember,
 static HRESULT WINAPI ScriptDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
 {
     ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
-    dynamic_var_t *var;
-    ident_map_t *ident;
-    function_t *func;
+    dynamic_var_t **vars;
+    function_t **funcs;
+    UINT i, num;
 
     TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid);
 
     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);
+    vars = This->ctx->global_vars;
+    num = This->ctx->global_vars_num;
+    for(i = 0; i < num; i++) {
+        if(!wcsicmp(vars[i]->name, bstrName)) {
+            *pid = i + 1;
             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);
-            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);
+    funcs = This->ctx->global_funcs;
+    num = This->ctx->global_funcs_num;
+    for(i = 0; i < num; i++) {
+        if(!wcsicmp(funcs[i]->name, bstrName)) {
+            *pid = i + 1 + DISPID_FUNCTION_MASK;
             return S_OK;
         }
     }
@@ -725,35 +667,40 @@ static HRESULT WINAPI ScriptDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc
         VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
 {
     ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
-    ident_map_t *ident;
     HRESULT hres;
 
     TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
 
-    ident = id_to_ident(This, id);
-    if(!ident)
-        return DISP_E_MEMBERNOTFOUND;
+    if (id & DISPID_FUNCTION_MASK)
+    {
+        id &= ~DISPID_FUNCTION_MASK;
+        if (id > This->ctx->global_funcs_num)
+            return DISP_E_MEMBERNOTFOUND;
 
-    if(ident->is_var) {
-        if(ident->u.var->is_const) {
-            FIXME("const not supported\n");
-            return E_NOTIMPL;
+        switch (wFlags)
+        {
+        case DISPATCH_METHOD:
+        case DISPATCH_METHOD | DISPATCH_PROPERTYGET:
+            hres = exec_script(This->ctx, TRUE, This->ctx->global_funcs[id - 1], NULL, pdp, pvarRes);
+            break;
+        default:
+            FIXME("Unsupported flags %x\n", wFlags);
+            hres = E_NOTIMPL;
         }
 
-        return invoke_variant_prop(This->ctx, &ident->u.var->v, wFlags, pdp, pvarRes);
+        return hres;
     }
 
-    switch(wFlags) {
-    case DISPATCH_METHOD:
-    case DISPATCH_METHOD|DISPATCH_PROPERTYGET:
-        hres = exec_script(This->ctx, TRUE, ident->u.func, NULL, pdp, pvarRes);
-        break;
-    default:
-        FIXME("Unsupported flags %x\n", wFlags);
-        hres = E_NOTIMPL;
+    if (id > This->ctx->global_vars_num)
+        return DISP_E_MEMBERNOTFOUND;
+
+    if (This->ctx->global_vars[id - 1]->is_const)
+    {
+        FIXME("const not supported\n");
+        return E_NOTIMPL;
     }
 
-    return hres;
+    return invoke_variant_prop(This->ctx, &This->ctx->global_vars[id - 1]->v, wFlags, pdp, pvarRes);
 }
 
 static HRESULT WINAPI ScriptDisp_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c
index 56c53b4..1f8c48e 100644
--- a/dlls/vbscript/vbscript.c
+++ b/dlls/vbscript/vbscript.c
@@ -131,12 +131,20 @@ IDispatch *lookup_named_item(script_ctx_t *ctx, const WCHAR *name, unsigned flag
 static void release_script(script_ctx_t *ctx)
 {
     class_desc_t *class_desc;
+    UINT i;
 
     collect_objects(ctx);
     clear_ei(&ctx->ei);
 
-    release_dynamic_vars(ctx->global_vars);
+    for(i = 0; i < ctx->global_vars_num; i++)
+        VariantClear(&ctx->global_vars[i]->v);
+
+    heap_free(ctx->global_vars);
+    heap_free(ctx->global_funcs);
     ctx->global_vars = NULL;
+    ctx->global_funcs = NULL;
+    ctx->global_vars_num = 0;
+    ctx->global_funcs_num = 0;
 
     while(!list_empty(&ctx->named_items)) {
         named_item_t *iter = LIST_ENTRY(list_head(&ctx->named_items), named_item_t, entry);
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h
index fefed63..38fb874 100644
--- a/dlls/vbscript/vbscript.h
+++ b/dlls/vbscript/vbscript.h
@@ -34,6 +34,11 @@
 #include "wine/heap.h"
 #include "wine/list.h"
 
+static inline BOOL is_power_of_2(unsigned x)
+{
+    return !(x & (x - 1));
+}
+
 typedef struct {
     void **blocks;
     DWORD block_cnt;
@@ -120,16 +125,10 @@ struct _vbdisp_t {
     VARIANT props[1];
 };
 
-typedef struct _ident_map_t ident_map_t;
-
 typedef struct {
     IDispatchEx IDispatchEx_iface;
     LONG ref;
 
-    ident_map_t *ident_map;
-    unsigned ident_map_cnt;
-    unsigned ident_map_size;
-
     script_ctx_t *ctx;
 } ScriptDisp;
 
@@ -187,8 +186,11 @@ struct _script_ctx_t {
 
     EXCEPINFO ei;
 
-    dynamic_var_t *global_vars;
-    function_t *global_funcs;
+    UINT global_vars_num;
+    UINT global_funcs_num;
+
+    dynamic_var_t **global_vars;
+    function_t **global_funcs;
     class_desc_t *classes;
     class_desc_t *procs;
 
@@ -350,6 +352,40 @@ struct _vbscode_t {
     struct list entry;
 };
 
+static inline BOOL add_global_var(script_ctx_t *obj, dynamic_var_t *var)
+{
+    dynamic_var_t **vars;
+
+    if (is_power_of_2(obj->global_vars_num))
+    {
+        UINT num = max(16, obj->global_vars_num * 2);
+
+        vars = heap_realloc(obj->global_vars, num * sizeof(*obj->global_vars));
+        if (!vars) return FALSE;
+        obj->global_vars = vars;
+    }
+    obj->global_vars[obj->global_vars_num++] = var;
+
+    return TRUE;
+}
+
+static inline BOOL add_global_func(script_ctx_t *obj, function_t *func)
+{
+    function_t **funcs;
+
+    if (is_power_of_2(obj->global_funcs_num))
+    {
+        UINT num = max(16, obj->global_funcs_num * 2);
+
+        funcs = heap_realloc(obj->global_funcs, num * sizeof(*obj->global_funcs));
+        if (!funcs) return FALSE;
+        obj->global_funcs = funcs;
+    }
+    obj->global_funcs[obj->global_funcs_num++] = func;
+
+    return TRUE;
+}
+
 void release_vbscode(vbscode_t*) DECLSPEC_HIDDEN;
 HRESULT compile_script(script_ctx_t*,const WCHAR*,const WCHAR*,DWORD,vbscode_t**) DECLSPEC_HIDDEN;
 HRESULT compile_procedure(script_ctx_t*,const WCHAR*,const WCHAR*,DWORD,class_desc_t**) DECLSPEC_HIDDEN;
-- 
2.21.0




More information about the wine-devel mailing list