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;
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
This is needed for the next patch to work properly.
dlls/vbscript/vbscript.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index 1f8c48e..3174151 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -419,6 +419,9 @@ static HRESULT WINAPI VBScript_SetScriptSite(IActiveScript *iface, IActiveScript if(InterlockedCompareExchange(&This->thread_id, GetCurrentThreadId(), 0)) return E_UNEXPECTED;
+ if(!This->ctx->global_obj && FAILED(hres = init_global(This->ctx))) + return hres; + hres = create_script_disp(This->ctx, &This->ctx->script_obj); if(FAILED(hres)) return hres;
Persistent code has to be re-executed if the script is uninitialized and then reinitialized and restarted.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
v3: Turns out it's slightly more complicated than I initially expected, to handle all corner cases. This patch uses a flag as suggested, to keep the ordering proper, since it is required. However, a separate list will also be needed later to tie its lifetime to the script dispatch object.
I wasn't sure if I should have made all the BOOLs in vbscode_t struct bit fields with this patch (like it is done in the winex11.drv for example) since we have 3 BOOLs already, so I didn't.
dlls/vbscript/compile.c | 6 +++++- dlls/vbscript/vbscript.c | 12 ++++++++++++ dlls/vbscript/vbscript.h | 3 +++ 3 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index f7bceeb..42aaf92 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -1984,6 +1984,7 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *deli
class->next = script->classes; script->classes = ctx.classes; + code->last_class = class; }
if(TRACE_ON(vbscript_disas)) @@ -1992,6 +1993,9 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *deli ctx.code = NULL; release_compiler(&ctx);
+ if(flags & SCRIPTTEXT_ISPERSISTENT) + code->is_persistent = TRUE; + list_add_tail(&script->code_list, &code->entry); *ret = code; return S_OK; @@ -2003,7 +2007,7 @@ HRESULT compile_procedure(script_ctx_t *script, const WCHAR *src, const WCHAR *d vbscode_t *code; HRESULT hres;
- hres = compile_script(script, src, delimiter, flags, &code); + hres = compile_script(script, src, delimiter, flags & ~SCRIPTTEXT_ISPERSISTENT, &code); if(FAILED(hres)) return hres;
diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index 3174151..2ffd6fd 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -130,6 +130,7 @@ IDispatch *lookup_named_item(script_ctx_t *ctx, const WCHAR *name, unsigned flag
static void release_script(script_ctx_t *ctx) { + vbscode_t *code, *code_next; class_desc_t *class_desc; UINT i;
@@ -146,6 +147,17 @@ static void release_script(script_ctx_t *ctx) ctx->global_vars_num = 0; ctx->global_funcs_num = 0;
+ LIST_FOR_EACH_ENTRY_SAFE(code, code_next, &ctx->code_list, vbscode_t, entry) + { + if(code->is_persistent) + { + code->pending_exec = TRUE; + if(code->last_class) code->last_class->next = NULL; + } + else + release_vbscode(code); + } + 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 38fb874..74fef1a 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -341,6 +341,7 @@ struct _vbscode_t { BOOL option_explicit;
BOOL pending_exec; + BOOL is_persistent; function_t main_code; IDispatch *context;
@@ -349,6 +350,8 @@ struct _vbscode_t { unsigned bstr_cnt; heap_pool_t heap;
+ class_desc_t *last_class; + struct list entry; };
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/vbscript/compile.c | 60 +++++++++++++++++----------------------- dlls/vbscript/vbscript.c | 35 +++++++++++++++++++++++ dlls/vbscript/vbscript.h | 3 ++ 3 files changed, 64 insertions(+), 34 deletions(-)
diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index 42aaf92..be4b37d 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -1780,9 +1780,10 @@ 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; + dynamic_var_t *var, **vars = script->global_vars; + function_t *func, **funcs = script->global_funcs; class_desc_t *class; + vbscode_t *code; UINT i;
for(i = 0; i < script->global_vars_num; i++) { @@ -1800,6 +1801,26 @@ static BOOL lookup_script_identifier(script_ctx_t *script, const WCHAR *identifi return TRUE; }
+ LIST_FOR_EACH_ENTRY(code, &script->code_list, vbscode_t, entry) { + if(!code->pending_exec) + continue; + + for(var = code->global_vars; var; var = var->next) { + if(!wcsicmp(var->name, identifier)) + return TRUE; + } + + for(func = code->funcs; func; func = func->next) { + if(!wcsicmp(func->name, identifier)) + return TRUE; + } + + for(class = code->classes; class; class = class->next) { + if(!wcsicmp(class->name, identifier)) + return TRUE; + } + } + return FALSE; }
@@ -1954,38 +1975,9 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *deli return compile_error(script, hres); }
- if(ctx.global_vars) { - dynamic_var_t *var; - - 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; new_func = new_func->next) - if (!add_global_func(script, new_func)) { - release_compiler(&ctx); - return compile_error(script, E_OUTOFMEMORY); - } - } - - if(ctx.classes) { - class_desc_t *class = ctx.classes; - - while(1) { - class->ctx = script; - if(!class->next) - break; - class = class->next; - } - - class->next = script->classes; - script->classes = ctx.classes; - code->last_class = class; - } + code->global_vars = ctx.global_vars; + code->funcs = ctx.funcs; + code->classes = ctx.classes;
if(TRACE_ON(vbscript_disas)) dump_code(&ctx); diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index 2ffd6fd..9165759 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -82,6 +82,41 @@ static inline BOOL is_started(VBScript *This)
static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res) { + if (code->global_vars) + { + dynamic_var_t *var; + + for (var = code->global_vars; var; var = var->next) + if (!add_global_var(ctx, var)) + return E_OUTOFMEMORY; + } + + if (code->funcs) + { + function_t *func; + + for (func = code->funcs; func; func = func->next) + if (!add_global_func(ctx, func)) + return E_OUTOFMEMORY; + } + + if (code->classes) + { + class_desc_t *class = code->classes; + + while (1) + { + class->ctx = ctx; + if (!class->next) + break; + class = class->next; + } + + class->next = ctx->classes; + ctx->classes = code->classes; + code->last_class = class; + } + code->pending_exec = FALSE; return exec_script(ctx, TRUE, &code->main_code, NULL, NULL, res); } diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index 74fef1a..24ff84d 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -350,6 +350,9 @@ struct _vbscode_t { unsigned bstr_cnt; heap_pool_t heap;
+ dynamic_var_t *global_vars; + function_t *funcs; + class_desc_t *classes; class_desc_t *last_class;
struct list entry;
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
Note that we have to move the non-persistent vbscode from the context's list, so it can be freed by the dispatch object only when it is released. Not doing so will cause a crash even with Wine's own existing tests, since the script dispatch will be held and released later when the code list no longer exists.
At the same time, the original approach wasn't quite correct either (using the dispatch's code list when compiling the code), because of ordering issues.
dlls/vbscript/compile.c | 15 ++++++++------- dlls/vbscript/interp.c | 20 ++++++++++++-------- dlls/vbscript/vbdisp.c | 39 ++++++++++++++++++++++++++++++--------- dlls/vbscript/vbscript.c | 38 +++++++++++--------------------------- dlls/vbscript/vbscript.h | 40 +++++++++++++++++++++------------------- 5 files changed, 82 insertions(+), 70 deletions(-)
diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index be4b37d..c57d569 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -1780,23 +1780,24 @@ 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 *var, **vars = script->global_vars; - function_t *func, **funcs = script->global_funcs; + ScriptDisp *obj = script->script_obj; + dynamic_var_t *var, **vars = obj->global_vars; + function_t *func, **funcs = obj->global_funcs; class_desc_t *class; vbscode_t *code; UINT i;
- for(i = 0; i < script->global_vars_num; i++) { + for(i = 0; i < obj->global_vars_num; i++) { if(!wcsicmp(vars[i]->name, identifier)) return TRUE; }
- for(i = 0; i < script->global_funcs_num; i++) { + for(i = 0; i < obj->global_funcs_num; i++) { if(!wcsicmp(funcs[i]->name, identifier)) return TRUE; }
- for(class = script->classes; class; class = class->next) { + for(class = obj->classes; class; class = class->next) { if(!wcsicmp(class->name, identifier)) return TRUE; } @@ -2012,8 +2013,8 @@ HRESULT compile_procedure(script_ctx_t *script, const WCHAR *src, const WCHAR *d desc->func_cnt = 1; desc->funcs->entries[VBDISP_CALLGET] = &code->main_code;
- desc->next = script->procs; - script->procs = desc; + desc->next = script->script_obj->procs; + script->script_obj->procs = desc;
*ret = desc; return S_OK; diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index acd524f..77c4a0a 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -95,7 +95,7 @@ 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) +static BOOL lookup_global_vars(ScriptDisp *script, const WCHAR *name, ref_t *ref) { dynamic_var_t **vars = script->global_vars; UINT i, num = script->global_vars_num; @@ -111,7 +111,7 @@ static BOOL lookup_global_vars(script_ctx_t *script, const WCHAR *name, ref_t *r return FALSE; }
-static BOOL lookup_global_funcs(script_ctx_t *script, const WCHAR *name, ref_t *ref) +static BOOL lookup_global_funcs(ScriptDisp *script, const WCHAR *name, ref_t *ref) { function_t **funcs = script->global_funcs; UINT i, num = script->global_funcs_num; @@ -129,6 +129,7 @@ static BOOL lookup_global_funcs(script_ctx_t *script, const WCHAR *name, ref_t *
static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_t invoke_type, ref_t *ref) { + ScriptDisp *script_obj = ctx->script->script_obj; named_item_t *item; IDispatch *disp; unsigned i; @@ -160,7 +161,7 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ }
if(ctx->func->type == FUNC_GLOBAL) { - if(lookup_global_vars(ctx->script, name, ref)) + if(lookup_global_vars(script_obj, name, ref)) return S_OK; }else { if(lookup_dynamic_vars(ctx->dynamic_vars, name, ref)) @@ -196,10 +197,10 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ } }
- if(ctx->func->type != FUNC_GLOBAL && lookup_global_vars(ctx->script, name, ref)) + if(ctx->func->type != FUNC_GLOBAL && lookup_global_vars(script_obj, name, ref)) return S_OK;
- if(lookup_global_funcs(ctx->script, name, ref)) + if(lookup_global_funcs(script_obj, name, ref)) return S_OK;
hres = get_builtin_id(ctx->script->global_obj, name, &id); @@ -236,12 +237,13 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ static HRESULT add_dynamic_var(exec_ctx_t *ctx, const WCHAR *name, BOOL is_const, VARIANT **out_var) { + ScriptDisp *script_obj = ctx->script->script_obj; dynamic_var_t *new_var; heap_pool_t *heap; WCHAR *str; unsigned size;
- heap = ctx->func->type == FUNC_GLOBAL ? &ctx->script->heap : &ctx->heap; + heap = ctx->func->type == FUNC_GLOBAL ? &script_obj->heap : &ctx->heap;
new_var = heap_pool_alloc(heap, sizeof(*new_var)); if(!new_var) @@ -257,7 +259,9 @@ 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) { - add_global_var(ctx->script, new_var); + add_global_var(script_obj, new_var); + new_var->next = script_obj->dynamic_vars; + script_obj->dynamic_vars = new_var; }else { new_var->next = ctx->dynamic_vars; ctx->dynamic_vars = new_var; @@ -1115,7 +1119,7 @@ static HRESULT interp_new(exec_ctx_t *ctx) return stack_push(ctx, &v); }
- for(class_desc = ctx->script->classes; class_desc; class_desc = class_desc->next) { + for(class_desc = ctx->script->script_obj->classes; class_desc; class_desc = class_desc->next) { if(!wcsicmp(class_desc->name, arg)) break; } diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c index 7b5e28f..05426aa 100644 --- a/dlls/vbscript/vbdisp.c +++ b/dlls/vbscript/vbdisp.c @@ -569,11 +569,30 @@ static ULONG WINAPI ScriptDisp_Release(IDispatchEx *iface) { ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface); LONG ref = InterlockedDecrement(&This->ref); + vbscode_t *code, *code_next;
TRACE("(%p) ref=%d\n", This, ref);
if(!ref) { assert(!This->ctx); + + while (This->procs) + { + class_desc_t *class_desc = This->procs; + This->procs = class_desc->next; + heap_free(class_desc); + } + + LIST_FOR_EACH_ENTRY_SAFE(code, code_next, &This->code_list, vbscode_t, entry) + { + release_dynamic_vars(code->global_vars); + release_vbscode(code); + } + release_dynamic_vars(This->dynamic_vars); + + heap_pool_free(&This->heap); + heap_free(This->global_vars); + heap_free(This->global_funcs); heap_free(This); }
@@ -641,8 +660,8 @@ static HRESULT WINAPI ScriptDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, DW if(!This->ctx) return E_UNEXPECTED;
- vars = This->ctx->global_vars; - num = This->ctx->global_vars_num; + vars = This->global_vars; + num = This->global_vars_num; for(i = 0; i < num; i++) { if(!wcsicmp(vars[i]->name, bstrName)) { *pid = i + 1; @@ -650,8 +669,8 @@ static HRESULT WINAPI ScriptDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, DW } }
- funcs = This->ctx->global_funcs; - num = This->ctx->global_funcs_num; + funcs = This->global_funcs; + num = This->global_funcs_num; for(i = 0; i < num; i++) { if(!wcsicmp(funcs[i]->name, bstrName)) { *pid = i + 1 + DISPID_FUNCTION_MASK; @@ -674,14 +693,14 @@ static HRESULT WINAPI ScriptDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc if (id & DISPID_FUNCTION_MASK) { id &= ~DISPID_FUNCTION_MASK; - if (id > This->ctx->global_funcs_num) + if (id > This->global_funcs_num) return DISP_E_MEMBERNOTFOUND;
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); + hres = exec_script(This->ctx, TRUE, This->global_funcs[id - 1], NULL, pdp, pvarRes); break; default: FIXME("Unsupported flags %x\n", wFlags); @@ -691,16 +710,16 @@ static HRESULT WINAPI ScriptDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc return hres; }
- if (id > This->ctx->global_vars_num) + if (id > This->global_vars_num) return DISP_E_MEMBERNOTFOUND;
- if (This->ctx->global_vars[id - 1]->is_const) + if (This->global_vars[id - 1]->is_const) { FIXME("const not supported\n"); return E_NOTIMPL; }
- return invoke_variant_prop(This->ctx, &This->ctx->global_vars[id - 1]->v, wFlags, pdp, pvarRes); + return invoke_variant_prop(This->ctx, &This->global_vars[id - 1]->v, wFlags, pdp, pvarRes); }
static HRESULT WINAPI ScriptDisp_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex) @@ -774,6 +793,8 @@ HRESULT create_script_disp(script_ctx_t *ctx, ScriptDisp **ret) script_disp->IDispatchEx_iface.lpVtbl = &ScriptDispVtbl; script_disp->ref = 1; script_disp->ctx = ctx; + heap_pool_init(&script_disp->heap); + list_init(&script_disp->code_list);
*ret = script_disp; return S_OK; diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index 9165759..224e030 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -82,12 +82,14 @@ static inline BOOL is_started(VBScript *This)
static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res) { + ScriptDisp *obj = ctx->script_obj; + if (code->global_vars) { dynamic_var_t *var;
for (var = code->global_vars; var; var = var->next) - if (!add_global_var(ctx, var)) + if (!add_global_var(obj, var)) return E_OUTOFMEMORY; }
@@ -96,7 +98,7 @@ static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res function_t *func;
for (func = code->funcs; func; func = func->next) - if (!add_global_func(ctx, func)) + if (!add_global_func(obj, func)) return E_OUTOFMEMORY; }
@@ -112,8 +114,8 @@ static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res class = class->next; }
- class->next = ctx->classes; - ctx->classes = code->classes; + class->next = obj->classes; + obj->classes = code->classes; code->last_class = class; }
@@ -166,31 +168,23 @@ IDispatch *lookup_named_item(script_ctx_t *ctx, const WCHAR *name, unsigned flag static void release_script(script_ctx_t *ctx) { vbscode_t *code, *code_next; - class_desc_t *class_desc; - UINT i;
collect_objects(ctx); clear_ei(&ctx->ei);
- 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; - LIST_FOR_EACH_ENTRY_SAFE(code, code_next, &ctx->code_list, vbscode_t, entry) { if(code->is_persistent) { code->pending_exec = TRUE; if(code->last_class) code->last_class->next = NULL; + release_dynamic_vars(code->global_vars); } else - release_vbscode(code); + { + list_remove(&code->entry); + list_add_tail(&ctx->script_obj->code_list, &code->entry); + } }
while(!list_empty(&ctx->named_items)) { @@ -203,13 +197,6 @@ static void release_script(script_ctx_t *ctx) heap_free(iter); }
- while(ctx->procs) { - class_desc = ctx->procs; - ctx->procs = class_desc->next; - - heap_free(class_desc); - } - if(ctx->host_global) { IDispatch_Release(ctx->host_global); ctx->host_global = NULL; @@ -234,8 +221,6 @@ static void release_script(script_ctx_t *ctx) }
detach_global_objects(ctx); - heap_pool_free(&ctx->heap); - heap_pool_init(&ctx->heap); }
static void destroy_script(script_ctx_t *ctx) @@ -1013,7 +998,6 @@ HRESULT WINAPI VBScriptFactory_CreateInstance(IClassFactory *iface, IUnknown *pU }
ctx->safeopt = INTERFACE_USES_DISPEX; - heap_pool_init(&ctx->heap); list_init(&ctx->objects); list_init(&ctx->code_list); list_init(&ctx->named_items); diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index 24ff84d..fa7d4a1 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -125,11 +125,30 @@ struct _vbdisp_t { VARIANT props[1]; };
+typedef struct _dynamic_var_t { + struct _dynamic_var_t *next; + VARIANT v; + const WCHAR *name; + BOOL is_const; +} dynamic_var_t; + typedef struct { IDispatchEx IDispatchEx_iface; LONG ref;
+ UINT global_vars_num; + UINT global_funcs_num; + + dynamic_var_t *dynamic_vars; + dynamic_var_t **global_vars; + function_t **global_funcs; + class_desc_t *classes; + class_desc_t *procs; + script_ctx_t *ctx; + heap_pool_t heap; + + struct list code_list; } ScriptDisp;
typedef struct _builtin_prop_t builtin_prop_t; @@ -163,13 +182,6 @@ static inline VARIANT *get_arg(DISPPARAMS *dp, DWORD i) return dp->rgvarg + dp->cArgs-i-1; }
-typedef struct _dynamic_var_t { - struct _dynamic_var_t *next; - VARIANT v; - const WCHAR *name; - BOOL is_const; -} dynamic_var_t; - struct _script_ctx_t { IActiveScriptSite *site; LCID lcid; @@ -186,16 +198,6 @@ struct _script_ctx_t {
EXCEPINFO ei;
- 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; - - heap_pool_t heap; - struct list objects; struct list code_list; struct list named_items; @@ -358,7 +360,7 @@ struct _vbscode_t { struct list entry; };
-static inline BOOL add_global_var(script_ctx_t *obj, dynamic_var_t *var) +static inline BOOL add_global_var(ScriptDisp *obj, dynamic_var_t *var) { dynamic_var_t **vars;
@@ -375,7 +377,7 @@ static inline BOOL add_global_var(script_ctx_t *obj, dynamic_var_t *var) return TRUE; }
-static inline BOOL add_global_func(script_ctx_t *obj, function_t *func) +static inline BOOL add_global_func(ScriptDisp *obj, function_t *func) { function_t **funcs;
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/vbscript/vbscript.c | 42 ++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-)
diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index 224e030..16759ea 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -73,6 +73,32 @@ static void change_state(VBScript *This, SCRIPTSTATE state) IActiveScriptSite_OnStateChange(This->ctx->site, state); }
+static HRESULT init_ctx(VBScript *vbscript) +{ + script_ctx_t *ctx; + HRESULT hr; + + if (vbscript->ctx) return S_OK; + + ctx = heap_alloc_zero(sizeof(*ctx)); + if (!ctx) return E_OUTOFMEMORY; + + ctx->safeopt = INTERFACE_USES_DISPEX; + list_init(&ctx->objects); + list_init(&ctx->code_list); + list_init(&ctx->named_items); + + hr = init_global(ctx); + if (FAILED(hr)) + { + heap_free(ctx); + return hr; + } + + vbscript->ctx = ctx; + return S_OK; +} + static inline BOOL is_started(VBScript *This) { return This->state == SCRIPTSTATE_STARTED @@ -972,7 +998,6 @@ static const IObjectSafetyVtbl VBScriptSafetyVtbl = {
HRESULT WINAPI VBScriptFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, REFIID riid, void **ppv) { - script_ctx_t *ctx; VBScript *ret; HRESULT hres;
@@ -991,20 +1016,9 @@ HRESULT WINAPI VBScriptFactory_CreateInstance(IClassFactory *iface, IUnknown *pU ret->ref = 1; ret->state = SCRIPTSTATE_UNINITIALIZED;
- ctx = ret->ctx = heap_alloc_zero(sizeof(*ctx)); - if(!ctx) { + if(FAILED(hres = init_ctx(ret))) + { heap_free(ret); - return E_OUTOFMEMORY; - } - - ctx->safeopt = INTERFACE_USES_DISPEX; - list_init(&ctx->objects); - list_init(&ctx->code_list); - list_init(&ctx->named_items); - - hres = init_global(ctx); - if(FAILED(hres)) { - IActiveScript_Release(&ret->IActiveScript_iface); return hres; }
When the engine is closed, even the persistent code is removed.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
Removing the context altogether is necessary when the script context will be ref counted, since we can't re-use the existing one.
This is needed because re-initializng a new context when the old one is closed can potentially fail, and decrease_state shouldn't be able to fail.
So instead it is re-initialized on demand, when necessary.
dlls/vbscript/vbscript.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index 16759ea..920743f 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -254,7 +254,6 @@ static void destroy_script(script_ctx_t *ctx) while(!list_empty(&ctx->code_list)) release_vbscode(LIST_ENTRY(list_head(&ctx->code_list), vbscode_t, entry));
- release_script(ctx); heap_free(ctx); }
@@ -278,6 +277,11 @@ static void decrease_state(VBScript *This, SCRIPTSTATE state) change_state(This, state); release_script(This->ctx); This->thread_id = 0; + if(state == SCRIPTSTATE_CLOSED) + { + destroy_script(This->ctx); + This->ctx = NULL; + } break; case SCRIPTSTATE_CLOSED: break; @@ -453,7 +457,6 @@ static ULONG WINAPI VBScript_Release(IActiveScript *iface)
if(!ref) { decrease_state(This, SCRIPTSTATE_CLOSED); - destroy_script(This->ctx); heap_free(This); }
@@ -471,6 +474,9 @@ static HRESULT WINAPI VBScript_SetScriptSite(IActiveScript *iface, IActiveScript if(!pass) return E_POINTER;
+ if(FAILED(hres = init_ctx(This))) + return hres; + if(This->ctx->site) return E_UNEXPECTED;
@@ -800,9 +806,13 @@ static ULONG WINAPI VBScriptParse_Release(IActiveScriptParse *iface) static HRESULT WINAPI VBScriptParse_InitNew(IActiveScriptParse *iface) { VBScript *This = impl_from_IActiveScriptParse(iface); + HRESULT hr;
TRACE("(%p)\n", This);
+ if(FAILED(hr = init_ctx(This))) + return hr; + if(This->is_initialized) return E_UNEXPECTED; This->is_initialized = TRUE; @@ -963,12 +973,16 @@ static HRESULT WINAPI VBScriptSafety_GetInterfaceSafetyOptions(IObjectSafety *if DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions) { VBScript *This = impl_from_IObjectSafety(iface); + HRESULT hr;
TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), pdwSupportedOptions, pdwEnabledOptions);
if(!pdwSupportedOptions || !pdwEnabledOptions) return E_POINTER;
+ if(FAILED(hr = init_ctx(This))) + return hr; + *pdwSupportedOptions = SUPPORTED_OPTIONS; *pdwEnabledOptions = This->ctx->safeopt; return S_OK; @@ -978,12 +992,16 @@ static HRESULT WINAPI VBScriptSafety_SetInterfaceSafetyOptions(IObjectSafety *if DWORD dwOptionSetMask, DWORD dwEnabledOptions) { VBScript *This = impl_from_IObjectSafety(iface); + HRESULT hr;
TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), dwOptionSetMask, dwEnabledOptions);
if(dwOptionSetMask & ~SUPPORTED_OPTIONS) return E_FAIL;
+ if(FAILED(hr = init_ctx(This))) + return hr; + This->ctx->safeopt = (dwEnabledOptions & dwOptionSetMask) | (This->ctx->safeopt & ~dwOptionSetMask) | INTERFACE_USES_DISPEX; return S_OK; }
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
This will be needed for next patch, since we'll need to record two such calls at one point.
dlls/vbscript/tests/vbscript.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/dlls/vbscript/tests/vbscript.c b/dlls/vbscript/tests/vbscript.c index fdbfc44..2020738 100644 --- a/dlls/vbscript/tests/vbscript.c +++ b/dlls/vbscript/tests/vbscript.c @@ -53,27 +53,27 @@ DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
#define DEFINE_EXPECT(func) \ - static BOOL expect_ ## func = FALSE, called_ ## func = FALSE + static int expect_ ## func = 0, called_ ## func = 0
#define SET_EXPECT(func) \ - expect_ ## func = TRUE + expect_ ## func = 1
#define CHECK_EXPECT2(func) \ do { \ ok(expect_ ##func, "unexpected call " #func "\n"); \ - called_ ## func = TRUE; \ + called_ ## func++; \ }while(0)
#define CHECK_EXPECT(func) \ do { \ CHECK_EXPECT2(func); \ - expect_ ## func = FALSE; \ + expect_ ## func--; \ }while(0)
#define CHECK_CALLED(func) \ do { \ ok(called_ ## func, "expected " #func "\n"); \ - expect_ ## func = called_ ## func = FALSE; \ + expect_ ## func = called_ ## func = 0; \ }while(0)
DEFINE_EXPECT(GetLCID);
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/vbscript/tests/vbscript.c | 252 +++++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+)
diff --git a/dlls/vbscript/tests/vbscript.c b/dlls/vbscript/tests/vbscript.c index 2020738..10f4da4 100644 --- a/dlls/vbscript/tests/vbscript.c +++ b/dlls/vbscript/tests/vbscript.c @@ -58,6 +58,9 @@ DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); #define SET_EXPECT(func) \ expect_ ## func = 1
+#define SET_EXPECT_MULTI(func, num) \ + expect_ ## func = num + #define CHECK_EXPECT2(func) \ do { \ ok(expect_ ##func, "unexpected call " #func "\n"); \ @@ -76,6 +79,12 @@ DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); expect_ ## func = called_ ## func = 0; \ }while(0)
+#define CHECK_CALLED_MULTI(func, num) \ + do { \ + ok(called_ ## func == num, "expected " #func " %d times (got %d)\n", num, called_ ## func); \ + expect_ ## func = called_ ## func = 0; \ + }while(0) + DEFINE_EXPECT(GetLCID); DEFINE_EXPECT(OnStateChange_UNINITIALIZED); DEFINE_EXPECT(OnStateChange_STARTED); @@ -624,6 +633,248 @@ static void test_scriptdisp(void) ok(!ref, "ref = %d\n", ref); }
+static void test_code_persistence(void) +{ + IActiveScriptParse *parser; + IDispatchEx *script_disp; + IActiveScript *vbscript; + VARIANT var; + HRESULT hr; + DISPID id; + ULONG ref; + BSTR str; + + vbscript = create_vbscript(); + + hr = IActiveScript_QueryInterface(vbscript, &IID_IActiveScriptParse, (void**)&parser); + ok(hr == S_OK, "Could not get IActiveScriptParse iface: %08x\n", hr); + test_state(vbscript, SCRIPTSTATE_UNINITIALIZED); + test_safety(vbscript); + + SET_EXPECT(GetLCID); + hr = IActiveScript_SetScriptSite(vbscript, &ActiveScriptSite); + ok(hr == S_OK, "SetScriptSite failed: %08x\n", hr); + CHECK_CALLED(GetLCID); + + SET_EXPECT(OnStateChange_INITIALIZED); + hr = IActiveScriptParse_InitNew(parser); + ok(hr == S_OK, "InitNew failed: %08x\n", hr); + CHECK_CALLED(OnStateChange_INITIALIZED); + test_state(vbscript, SCRIPTSTATE_INITIALIZED); + + str = a2bstr( + "x = 1\n" + "dim y\ny = 2\n"); + hr = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, 0, NULL, NULL); + ok(hr == S_OK, "ParseScriptText failed: %08x\n", hr); + SysFreeString(str); + + str = a2bstr( + "dim z\nz = 3\n" + "y = 42\n" + "var = 10\n"); + hr = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISPERSISTENT, NULL, NULL); + ok(hr == S_OK, "ParseScriptText failed: %08x\n", hr); + SysFreeString(str); + + /* Pending code does not add identifiers to the global scope */ + script_disp = get_script_dispatch(vbscript); + id = 0; + get_disp_id(script_disp, "x", DISP_E_UNKNOWNNAME, &id); + ok(id == -1, "id = %d, expected -1\n", id); + id = 0; + get_disp_id(script_disp, "y", DISP_E_UNKNOWNNAME, &id); + ok(id == -1, "id = %d, expected -1\n", id); + id = 0; + get_disp_id(script_disp, "z", DISP_E_UNKNOWNNAME, &id); + ok(id == -1, "id = %d, expected -1\n", id); + IDispatchEx_Release(script_disp); + + /* Uninitialized state removes code without SCRIPTTEXT_ISPERSISTENT */ + SET_EXPECT(OnStateChange_UNINITIALIZED); + hr = IActiveScript_SetScriptState(vbscript, SCRIPTSTATE_UNINITIALIZED); + ok(hr == S_OK, "SetScriptState(SCRIPTSTATE_UNINITIALIZED) failed: %08x\n", hr); + CHECK_CALLED(OnStateChange_UNINITIALIZED); + test_no_script_dispatch(vbscript); + + SET_EXPECT(GetLCID); + SET_EXPECT(OnStateChange_INITIALIZED); + hr = IActiveScript_SetScriptSite(vbscript, &ActiveScriptSite); + ok(hr == S_OK, "SetScriptSite failed: %08x\n", hr); + CHECK_CALLED(GetLCID); + CHECK_CALLED(OnStateChange_INITIALIZED); + + str = a2bstr("var = 20\n"); + hr = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, 0, NULL, NULL); + ok(hr == S_OK, "ParseScriptText failed: %08x\n", hr); + SysFreeString(str); + + SET_EXPECT(OnStateChange_CONNECTED); + SET_EXPECT_MULTI(OnEnterScript, 2); + SET_EXPECT_MULTI(OnLeaveScript, 2); + hr = IActiveScript_SetScriptState(vbscript, SCRIPTSTATE_CONNECTED); + ok(hr == S_OK, "SetScriptState(SCRIPTSTATE_CONNECTED) failed: %08x\n", hr); + CHECK_CALLED(OnStateChange_CONNECTED); + CHECK_CALLED_MULTI(OnEnterScript, 2); + CHECK_CALLED_MULTI(OnLeaveScript, 2); + test_state(vbscript, SCRIPTSTATE_CONNECTED); + + script_disp = get_script_dispatch(vbscript); + id = 0; + get_disp_id(script_disp, "x", DISP_E_UNKNOWNNAME, &id); + ok(id == -1, "id = %d, expected -1\n", id); + id = 0; + get_disp_id(script_disp, "y", S_OK, &id); + ok(id != -1, "id = -1\n"); + id = 0; + get_disp_id(script_disp, "z", S_OK, &id); + ok(id != -1, "id = -1\n"); + IDispatchEx_Release(script_disp); + + str = a2bstr("y"); + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + hr = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL); + ok(hr == S_OK, "ParseScriptText failed: %08x\n", hr); + ok(V_VT(&var) == VT_I2 && V_I2(&var) == 42, "V_VT(y) = %d, V_I2(y) = %d\n", V_VT(&var), V_I2(&var)); + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(OnLeaveScript); + SysFreeString(str); + + str = a2bstr("var"); + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + hr = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL); + ok(hr == S_OK, "ParseScriptText failed: %08x\n", hr); + ok(V_VT(&var) == VT_I2 && V_I2(&var) == 20, "V_VT(var) = %d, V_I2(var) = %d\n", V_VT(&var), V_I2(&var)); + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(OnLeaveScript); + SysFreeString(str); + + /* Uninitialized state does not remove persistent code, even if it was executed */ + SET_EXPECT(OnStateChange_DISCONNECTED); + SET_EXPECT(OnStateChange_INITIALIZED); + SET_EXPECT(OnStateChange_UNINITIALIZED); + hr = IActiveScript_SetScriptState(vbscript, SCRIPTSTATE_UNINITIALIZED); + ok(hr == S_OK, "SetScriptState(SCRIPTSTATE_UNINITIALIZED) failed: %08x\n", hr); + CHECK_CALLED(OnStateChange_DISCONNECTED); + CHECK_CALLED(OnStateChange_INITIALIZED); + CHECK_CALLED(OnStateChange_UNINITIALIZED); + test_no_script_dispatch(vbscript); + + SET_EXPECT(GetLCID); + SET_EXPECT(OnStateChange_INITIALIZED); + hr = IActiveScript_SetScriptSite(vbscript, &ActiveScriptSite); + ok(hr == S_OK, "SetScriptSite failed: %08x\n", hr); + CHECK_CALLED(GetLCID); + CHECK_CALLED(OnStateChange_INITIALIZED); + + script_disp = get_script_dispatch(vbscript); + id = 0; + get_disp_id(script_disp, "z", DISP_E_UNKNOWNNAME, &id); + ok(id == -1, "id = %d, expected -1\n", id); + IDispatchEx_Release(script_disp); + + SET_EXPECT(OnStateChange_CONNECTED); + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + hr = IActiveScript_SetScriptState(vbscript, SCRIPTSTATE_CONNECTED); + ok(hr == S_OK, "SetScriptState(SCRIPTSTATE_CONNECTED) failed: %08x\n", hr); + CHECK_CALLED(OnStateChange_CONNECTED); + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(OnLeaveScript); + test_state(vbscript, SCRIPTSTATE_CONNECTED); + + script_disp = get_script_dispatch(vbscript); + id = 0; + get_disp_id(script_disp, "z", S_OK, &id); + ok(id != -1, "id = -1\n"); + IDispatchEx_Release(script_disp); + + str = a2bstr("y"); + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + hr = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL); + ok(hr == S_OK, "ParseScriptText failed: %08x\n", hr); + ok(V_VT(&var) == VT_I2 && V_I2(&var) == 42, "V_VT(y) = %d, V_I2(y) = %d\n", V_VT(&var), V_I2(&var)); + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(OnLeaveScript); + SysFreeString(str); + + str = a2bstr("var"); + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + hr = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL); + ok(hr == S_OK, "ParseScriptText failed: %08x\n", hr); + ok(V_VT(&var) == VT_I2 && V_I2(&var) == 10, "V_VT(var) = %d, V_I2(var) = %d\n", V_VT(&var), V_I2(&var)); + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(OnLeaveScript); + SysFreeString(str); + + SET_EXPECT(OnStateChange_DISCONNECTED); + SET_EXPECT(OnStateChange_INITIALIZED); + SET_EXPECT(OnStateChange_UNINITIALIZED); + hr = IActiveScript_SetScriptState(vbscript, SCRIPTSTATE_UNINITIALIZED); + ok(hr == S_OK, "SetScriptState(SCRIPTSTATE_UNINITIALIZED) failed: %08x\n", hr); + CHECK_CALLED(OnStateChange_DISCONNECTED); + CHECK_CALLED(OnStateChange_INITIALIZED); + CHECK_CALLED(OnStateChange_UNINITIALIZED); + + SET_EXPECT(GetLCID); + SET_EXPECT(OnStateChange_INITIALIZED); + hr = IActiveScript_SetScriptSite(vbscript, &ActiveScriptSite); + ok(hr == S_OK, "SetScriptSite failed: %08x\n", hr); + CHECK_CALLED(GetLCID); + CHECK_CALLED(OnStateChange_INITIALIZED); + + str = a2bstr("dim y\ny = 2\n"); + hr = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISPERSISTENT, NULL, NULL); + ok(hr == S_OK, "ParseScriptText failed: %08x\n", hr); + SysFreeString(str); + + /* Closing the script engine removes all code (even if it's pending and persistent) */ + SET_EXPECT(OnStateChange_CLOSED); + hr = IActiveScript_Close(vbscript); + ok(hr == S_OK, "Close failed: %08x\n", hr); + CHECK_CALLED(OnStateChange_CLOSED); + test_state(vbscript, SCRIPTSTATE_CLOSED); + test_no_script_dispatch(vbscript); + + SET_EXPECT(OnStateChange_INITIALIZED); + SET_EXPECT(GetLCID); + hr = IActiveScript_SetScriptSite(vbscript, &ActiveScriptSite); + ok(hr == S_OK, "SetScriptSite failed: %08x\n", hr); + CHECK_CALLED(OnStateChange_INITIALIZED); + CHECK_CALLED(GetLCID); + test_state(vbscript, SCRIPTSTATE_INITIALIZED); + + SET_EXPECT(OnStateChange_CONNECTED); + hr = IActiveScript_SetScriptState(vbscript, SCRIPTSTATE_CONNECTED); + ok(hr == S_OK, "SetScriptState(SCRIPTSTATE_CONNECTED) failed: %08x\n", hr); + CHECK_CALLED(OnStateChange_CONNECTED); + test_state(vbscript, SCRIPTSTATE_CONNECTED); + + script_disp = get_script_dispatch(vbscript); + id = 0; + get_disp_id(script_disp, "y", DISP_E_UNKNOWNNAME, &id); + ok(id == -1, "id = %d, expected -1\n", id); + id = 0; + get_disp_id(script_disp, "z", DISP_E_UNKNOWNNAME, &id); + ok(id == -1, "id = %d, expected -1\n", id); + IDispatchEx_Release(script_disp); + + IActiveScriptParse_Release(parser); + + SET_EXPECT(OnStateChange_DISCONNECTED); + SET_EXPECT(OnStateChange_INITIALIZED); + SET_EXPECT(OnStateChange_CLOSED); + ref = IActiveScript_Release(vbscript); + ok(!ref, "ref = %d\n", ref); + CHECK_CALLED(OnStateChange_DISCONNECTED); + CHECK_CALLED(OnStateChange_INITIALIZED); + CHECK_CALLED(OnStateChange_CLOSED); +} + static void test_vbscript(void) { IActiveScriptParseProcedure2 *parse_proc; @@ -1215,6 +1466,7 @@ START_TEST(vbscript) test_vbscript_initializing(); test_named_items(); test_scriptdisp(); + test_code_persistence(); test_RegExp(); test_RegExp_Replace(); }else {
Hi Gabriel,
On 11/1/19 4:00 PM, Gabriel Ivăncescu wrote:
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(-)
This could really use a split to at least three patches: one for variables, one for functions and one to get rid of ident_map_t. I needed to touch functions for the project I'm working on, so I submitted functions part based on your patch already.
+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;
+}
I'd rather not use inline functions for those.
Thanks,
Jacek