[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