Signed-off-by: Gabriel Ivăncescu gabrielopcode@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;