Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/vbscript/compile.c | 29 +++++++++++++++++++---------- dlls/vbscript/interp.c | 33 ++++++++++++++++++++++++++++++--- dlls/vbscript/vbdisp.c | 4 ++-- dlls/vbscript/vbscript.c | 9 +++++++-- dlls/vbscript/vbscript.h | 5 ++++- 5 files changed, 62 insertions(+), 18 deletions(-)
diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index e52b081..3f700a4 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -1786,11 +1786,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) { class_desc_t *class; - dynamic_var_t *var; unsigned i;
- for(var = script->global_vars; var; var = var->next) { - if(!wcsicmp(var->name, identifier)) + for(i = 0; i < script->global_vars_cnt; i++) { + if(!wcsicmp(script->global_vars[i]->name, identifier)) return TRUE; }
@@ -1894,6 +1893,7 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *deli function_t *new_func, *func_iter; function_decl_t *func_decl; class_decl_t *class_decl; + dynamic_var_t *var_iter; compile_ctx_t ctx; vbscode_t *code; size_t cnt; @@ -1951,13 +1951,22 @@ 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->next; var = var->next); - - var->next = script->global_vars; - script->global_vars = ctx.global_vars; + cnt = script->global_vars_cnt; + for(var_iter = ctx.global_vars; var_iter; var_iter = var_iter->next) + cnt++; + if(cnt > script->global_vars_size) { + dynamic_var_t **new_vars; + if(script->global_vars) + new_vars = heap_realloc(script->global_vars, cnt * sizeof(*new_vars)); + else + new_vars = heap_alloc(cnt * sizeof(*new_vars)); + if(!new_vars) + return compile_error(script, E_OUTOFMEMORY); + script->global_vars = new_vars; + script->global_vars_size = cnt; + } + for(var_iter = ctx.global_vars; var_iter; var_iter = var_iter->next) { + script->global_vars[script->global_vars_cnt++] = var_iter; }
cnt = script->global_funcs_cnt; diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 89f9d35..7076d21 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -94,6 +94,22 @@ 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; + size_t i, cnt = script->global_vars_cnt; + + for(i = 0; i < cnt; 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 HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_t invoke_type, ref_t *ref) { named_item_t *item; @@ -159,7 +175,7 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ } }
- if(lookup_dynamic_vars(ctx->script->global_vars, name, ref)) + if(lookup_global_vars(ctx->script, name, ref)) return S_OK;
for(i = 0; i < ctx->script->global_funcs_cnt; i++) { @@ -226,8 +242,19 @@ 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; + size_t cnt = ctx->script->global_vars_cnt + 1; + if(cnt > ctx->script->global_vars_size) { + dynamic_var_t **new_vars; + if(ctx->script->global_vars) + new_vars = heap_realloc(ctx->script->global_vars, cnt * 2 * sizeof(*new_vars)); + else + new_vars = heap_alloc(cnt * 2 * sizeof(*new_vars)); + if(!new_vars) + return E_OUTOFMEMORY; + ctx->script->global_vars = new_vars; + ctx->script->global_vars_size = cnt * 2; + } + ctx->script->global_vars[ctx->script->global_vars_cnt++] = 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 a5ae40d..00e975e 100644 --- a/dlls/vbscript/vbdisp.c +++ b/dlls/vbscript/vbdisp.c @@ -675,7 +675,6 @@ 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; unsigned i;
@@ -691,7 +690,8 @@ static HRESULT WINAPI ScriptDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, DW } }
- for(var = This->ctx->global_vars; var; var = var->next) { + for(i = 0; i < This->ctx->global_vars_cnt; i++) { + dynamic_var_t *var = This->ctx->global_vars[i]; if(!wcsicmp(var->name, bstrName)) { ident = add_ident(This, var->name); if(!ident) diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index 886c9d0..6d2bb54 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -131,14 +131,19 @@ 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; + unsigned i;
collect_objects(ctx); clear_ei(&ctx->ei);
- release_dynamic_vars(ctx->global_vars); - ctx->global_vars = NULL; + for(i = 0; i < ctx->global_vars_cnt; i++) + VariantClear(&ctx->global_vars[i]->v);
+ heap_free(ctx->global_vars); heap_free(ctx->global_funcs); + ctx->global_vars = NULL; + ctx->global_vars_cnt = 0; + ctx->global_vars_size = 0; ctx->global_funcs = NULL; ctx->global_funcs_cnt = 0; ctx->global_funcs_size = 0; diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index 0bd1fce..1b20af8 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -187,11 +187,14 @@ struct _script_ctx_t {
EXCEPINFO ei;
+ dynamic_var_t **global_vars; + size_t global_vars_cnt; + size_t global_vars_size; + function_t **global_funcs; size_t global_funcs_cnt; size_t global_funcs_size;
- dynamic_var_t *global_vars; class_desc_t *classes; class_desc_t *procs;
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
DISPID_FUNCTION_MASK has been chosen to be the same bit used in TypeLibs to separate functions from variables in MEMBERIDs.
dlls/vbscript/vbdisp.c | 116 ++++++++++----------------------------- dlls/vbscript/vbscript.h | 6 -- 2 files changed, 28 insertions(+), 94 deletions(-)
diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c index 00e975e..12626e0 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,7 +632,6 @@ 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); - ident_map_t *ident; unsigned i;
TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid); @@ -683,37 +639,16 @@ static HRESULT WINAPI ScriptDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, DW if(!This->ctx) return E_UNEXPECTED;
- for(ident = This->ident_map; ident < This->ident_map+This->ident_map_cnt; ident++) { - if(!wcsicmp(ident->name, bstrName)) { - *pid = ident_to_id(This, ident); - return S_OK; - } - } - for(i = 0; i < This->ctx->global_vars_cnt; i++) { - dynamic_var_t *var = This->ctx->global_vars[i]; - 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); + if(!wcsicmp(This->ctx->global_vars[i]->name, bstrName)) { + *pid = i + 1; return S_OK; } }
for(i = 0; i < This->ctx->global_funcs_cnt; i++) { - function_t *func = This->ctx->global_funcs[i]; - 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); + if(!wcsicmp(This->ctx->global_funcs[i]->name, bstrName)) { + *pid = i + 1 + DISPID_FUNCTION_MASK; return S_OK; } } @@ -726,35 +661,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_cnt) + 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_cnt) + 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.h b/dlls/vbscript/vbscript.h index 1b20af8..71cf68b 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -120,16 +120,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;
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/vbscript/vbscript.c | 44 ++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 15 deletions(-)
diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index 6d2bb54..a90d6bb 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -73,6 +73,33 @@ 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; + heap_pool_init(&ctx->heap); + 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 @@ -938,7 +965,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;
@@ -957,21 +983,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; - heap_pool_init(&ctx->heap); - 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. It is also needed for script persistence to work properly.
This is required 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 a90d6bb..37fb5e5 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -225,7 +225,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); }
@@ -248,6 +247,11 @@ static void decrease_state(VBScript *This, SCRIPTSTATE state) break; release_script(This->ctx); This->thread_id = 0; + if(state == SCRIPTSTATE_CLOSED) + { + destroy_script(This->ctx); + This->ctx = NULL; + } break; case SCRIPTSTATE_CLOSED: break; @@ -423,7 +427,6 @@ static ULONG WINAPI VBScript_Release(IActiveScript *iface)
if(!ref) { decrease_state(This, SCRIPTSTATE_CLOSED); - destroy_script(This->ctx); heap_free(This); }
@@ -441,6 +444,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;
@@ -767,9 +773,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; @@ -930,12 +940,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; @@ -945,12 +959,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; }
Hi Gabriel,
On 11/6/19 12:53 PM, Gabriel Ivăncescu wrote:
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. It is also needed for script persistence to work properly.
This is required 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.
I think I already mentioned it, but it doesn't look right to me. When releasing the context you lose safety flags that are stored in the context. I'd be very surprised if that's what should happen. You're also missing handling of AddNamedItem.
Overall, I fail to see why why we need it. It seems to me that if you go from closed to initialized state, you shouldn't use decrease_state at all.
Thanks, Jacek
On 11/6/19 6:47 PM, Jacek Caban wrote:
Hi Gabriel,
On 11/6/19 12:53 PM, Gabriel Ivăncescu wrote:
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. It is also needed for script persistence to work properly.
This is required 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.
I think I already mentioned it, but it doesn't look right to me. When releasing the context you lose safety flags that are stored in the context. I'd be very surprised if that's what should happen. You're also missing handling of AddNamedItem.
Overall, I fail to see why why we need it. It seems to me that if you go from closed to initialized state, you shouldn't use decrease_state at all.
Thanks, Jacek
Hi Jacek,
It's needed for ref counting the context since we'll need the old persistent code_list referenced while the context can be new. And yeah it was mostly for the TypeInfo, but I have an alternative below.
That said, at the very least, this patch should release the code list (persistent code) without releasing the context in that case, otherwise it doesn't pass the tests at the end of the series.
An alternative is to ref count just the code lists, since really that's all we care about. I'll postpone this and do it that way when I'll send the TypeInfo patchset, see if it's any better. For now I'll just release the code list.
On 11/7/19 1:12 PM, Gabriel Ivăncescu wrote:
On 11/6/19 6:47 PM, Jacek Caban wrote:
Hi Gabriel,
On 11/6/19 12:53 PM, Gabriel Ivăncescu wrote:
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. It is also needed for script persistence to work properly.
This is required 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.
I think I already mentioned it, but it doesn't look right to me. When releasing the context you lose safety flags that are stored in the context. I'd be very surprised if that's what should happen. You're also missing handling of AddNamedItem.
Overall, I fail to see why why we need it. It seems to me that if you go from closed to initialized state, you shouldn't use decrease_state at all.
Thanks, Jacek
Hi Jacek,
It's needed for ref counting the context since we'll need the old persistent code_list referenced while the context can be new. And yeah it was mostly for the TypeInfo, but I have an alternative below.
That said, at the very least, this patch should release the code list (persistent code) without releasing the context in that case, otherwise it doesn't pass the tests at the end of the series.
Yes, I think this should work.
Thanks,
Jacek
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
This is needed for the next patch to work properly, else it will crash when script is re-initialized.
dlls/vbscript/vbscript.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index 37fb5e5..31f2d79 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -453,6 +453,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 ---
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.
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 3f700a4..48f9073 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -2008,6 +2008,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)) @@ -2016,6 +2017,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; @@ -2027,7 +2031,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 31f2d79..9477757 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -157,6 +157,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; unsigned i;
@@ -175,6 +176,17 @@ static void release_script(script_ctx_t *ctx) ctx->global_funcs_cnt = 0; ctx->global_funcs_size = 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 71cf68b..0cb0626 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -340,6 +340,7 @@ struct _vbscode_t { BOOL option_explicit;
BOOL pending_exec; + BOOL is_persistent; function_t main_code; IDispatch *context;
@@ -348,6 +349,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 | 90 +++++++++++++--------------------------- dlls/vbscript/vbscript.c | 67 ++++++++++++++++++++++++++++++ dlls/vbscript/vbscript.h | 3 ++ 3 files changed, 98 insertions(+), 62 deletions(-)
diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index 48f9073..097086b 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -1786,6 +1786,7 @@ 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) { class_desc_t *class; + vbscode_t *code; unsigned i;
for(i = 0; i < script->global_vars_cnt; i++) { @@ -1803,6 +1804,29 @@ 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) { + dynamic_var_t *var; + function_t *func; + + 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; }
@@ -1890,13 +1914,11 @@ static void release_compiler(compile_ctx_t *ctx)
HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *delimiter, DWORD flags, vbscode_t **ret) { - function_t *new_func, *func_iter; function_decl_t *func_decl; class_decl_t *class_decl; - dynamic_var_t *var_iter; + function_t *new_func; compile_ctx_t ctx; vbscode_t *code; - size_t cnt; HRESULT hres;
if (!src) src = L""; @@ -1951,65 +1973,9 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *deli return compile_error(script, hres); }
- cnt = script->global_vars_cnt; - for(var_iter = ctx.global_vars; var_iter; var_iter = var_iter->next) - cnt++; - if(cnt > script->global_vars_size) { - dynamic_var_t **new_vars; - if(script->global_vars) - new_vars = heap_realloc(script->global_vars, cnt * sizeof(*new_vars)); - else - new_vars = heap_alloc(cnt * sizeof(*new_vars)); - if(!new_vars) - return compile_error(script, E_OUTOFMEMORY); - script->global_vars = new_vars; - script->global_vars_size = cnt; - } - for(var_iter = ctx.global_vars; var_iter; var_iter = var_iter->next) { - script->global_vars[script->global_vars_cnt++] = var_iter; - } - - cnt = script->global_funcs_cnt; - for(func_iter = ctx.funcs; func_iter; func_iter = func_iter->next) - cnt++; - if(cnt > script->global_funcs_size) { - function_t **new_funcs; - if(script->global_funcs) - new_funcs = heap_realloc(script->global_funcs, cnt * sizeof(*new_funcs)); - else - new_funcs = heap_alloc(cnt * sizeof(*new_funcs)); - if(!new_funcs) - return compile_error(script, E_OUTOFMEMORY); - script->global_funcs = new_funcs; - script->global_funcs_size = cnt; - } - for(func_iter = ctx.funcs; func_iter; func_iter = func_iter->next) { - unsigned i; - for(i = 0; i < script->global_funcs_cnt; i++) { - if(!wcsicmp(script->global_funcs[i]->name, func_iter->name)) { - /* global function already exists, replace it */ - script->global_funcs[i] = func_iter; - break; - } - } - if(i == script->global_funcs_cnt) - script->global_funcs[script->global_funcs_cnt++] = func_iter; - } - - 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 9477757..865efd0 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -109,6 +109,73 @@ static inline BOOL is_started(VBScript *This)
static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res) { + dynamic_var_t *var_iter, **new_vars; + function_t *func_iter, **new_funcs; + size_t cnt, i; + + cnt = ctx->global_vars_cnt; + for (var_iter = code->global_vars; var_iter; var_iter = var_iter->next) + cnt++; + if (cnt > ctx->global_vars_size) + { + if (ctx->global_vars) + new_vars = heap_realloc(ctx->global_vars, cnt * sizeof(*new_vars)); + else + new_vars = heap_alloc(cnt * sizeof(*new_vars)); + if (!new_vars) + return E_OUTOFMEMORY; + ctx->global_vars = new_vars; + ctx->global_vars_size = cnt; + } + for (var_iter = code->global_vars; var_iter; var_iter = var_iter->next) + ctx->global_vars[ctx->global_vars_cnt++] = var_iter; + + cnt = ctx->global_funcs_cnt; + for (func_iter = code->funcs; func_iter; func_iter = func_iter->next) + cnt++; + if (cnt > ctx->global_funcs_size) + { + if (ctx->global_funcs) + new_funcs = heap_realloc(ctx->global_funcs, cnt * sizeof(*new_funcs)); + else + new_funcs = heap_alloc(cnt * sizeof(*new_funcs)); + if (!new_funcs) + return E_OUTOFMEMORY; + ctx->global_funcs = new_funcs; + ctx->global_funcs_size = cnt; + } + for (func_iter = code->funcs; func_iter; func_iter = func_iter->next) + { + for (i = 0; i < ctx->global_funcs_cnt; i++) + { + if (!wcsicmp(ctx->global_funcs[i]->name, func_iter->name)) + { + /* global function already exists, replace it */ + ctx->global_funcs[i] = func_iter; + break; + } + } + if (i == ctx->global_funcs_cnt) + ctx->global_funcs[ctx->global_funcs_cnt++] = func_iter; + } + + 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 0cb0626..a456180 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -349,6 +349,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. So we have to move the entry.
dlls/vbscript/compile.c | 15 +++++---- dlls/vbscript/interp.c | 30 +++++++++-------- dlls/vbscript/vbdisp.c | 39 +++++++++++++++++----- dlls/vbscript/vbscript.c | 71 +++++++++++++++------------------------- dlls/vbscript/vbscript.h | 42 +++++++++++++----------- 5 files changed, 103 insertions(+), 94 deletions(-)
diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index 097086b..a59af64 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -1785,21 +1785,22 @@ 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) { + ScriptDisp *obj = script->script_obj; class_desc_t *class; vbscode_t *code; unsigned i;
- for(i = 0; i < script->global_vars_cnt; i++) { - if(!wcsicmp(script->global_vars[i]->name, identifier)) + for(i = 0; i < obj->global_vars_cnt; i++) { + if(!wcsicmp(obj->global_vars[i]->name, identifier)) return TRUE; }
- for(i = 0; i < script->global_funcs_cnt; i++) { - if(!wcsicmp(script->global_funcs[i]->name, identifier)) + for(i = 0; i < obj->global_funcs_cnt; i++) { + if(!wcsicmp(obj->global_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; } @@ -2010,8 +2011,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 7076d21..432f292 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -94,7 +94,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; size_t i, cnt = script->global_vars_cnt; @@ -112,6 +112,7 @@ static BOOL lookup_global_vars(script_ctx_t *script, const WCHAR *name, ref_t *r
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; @@ -175,11 +176,11 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ } }
- if(lookup_global_vars(ctx->script, name, ref)) + if(lookup_global_vars(script_obj, name, ref)) return S_OK;
- for(i = 0; i < ctx->script->global_funcs_cnt; i++) { - function_t *func = ctx->script->global_funcs[i]; + for(i = 0; i < script_obj->global_funcs_cnt; i++) { + function_t *func = script_obj->global_funcs[i]; if(!wcsicmp(func->name, name)) { ref->type = REF_FUNC; ref->u.f = func; @@ -221,12 +222,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) @@ -242,19 +244,21 @@ 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) { - size_t cnt = ctx->script->global_vars_cnt + 1; - if(cnt > ctx->script->global_vars_size) { + size_t cnt = script_obj->global_vars_cnt + 1; + if(cnt > script_obj->global_vars_size) { dynamic_var_t **new_vars; - if(ctx->script->global_vars) - new_vars = heap_realloc(ctx->script->global_vars, cnt * 2 * sizeof(*new_vars)); + if(script_obj->global_vars) + new_vars = heap_realloc(script_obj->global_vars, cnt * 2 * sizeof(*new_vars)); else new_vars = heap_alloc(cnt * 2 * sizeof(*new_vars)); if(!new_vars) return E_OUTOFMEMORY; - ctx->script->global_vars = new_vars; - ctx->script->global_vars_size = cnt * 2; + script_obj->global_vars = new_vars; + script_obj->global_vars_size = cnt * 2; } - ctx->script->global_vars[ctx->script->global_vars_cnt++] = new_var; + script_obj->global_vars[script_obj->global_vars_cnt++] = 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; @@ -1112,7 +1116,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 12626e0..09bf4a8 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); }
@@ -639,15 +658,15 @@ static HRESULT WINAPI ScriptDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, DW if(!This->ctx) return E_UNEXPECTED;
- for(i = 0; i < This->ctx->global_vars_cnt; i++) { - if(!wcsicmp(This->ctx->global_vars[i]->name, bstrName)) { + for(i = 0; i < This->global_vars_cnt; i++) { + if(!wcsicmp(This->global_vars[i]->name, bstrName)) { *pid = i + 1; return S_OK; } }
- for(i = 0; i < This->ctx->global_funcs_cnt; i++) { - if(!wcsicmp(This->ctx->global_funcs[i]->name, bstrName)) { + for(i = 0; i < This->global_funcs_cnt; i++) { + if(!wcsicmp(This->global_funcs[i]->name, bstrName)) { *pid = i + 1 + DISPID_FUNCTION_MASK; return S_OK; } @@ -668,14 +687,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_cnt) + if (id > This->global_funcs_cnt) 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); @@ -685,16 +704,16 @@ static HRESULT WINAPI ScriptDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc return hres; }
- if (id > This->ctx->global_vars_cnt) + if (id > This->global_vars_cnt) 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) @@ -768,6 +787,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 865efd0..e05924a 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -84,7 +84,6 @@ static HRESULT init_ctx(VBScript *vbscript) if (!ctx) return E_OUTOFMEMORY;
ctx->safeopt = INTERFACE_USES_DISPEX; - heap_pool_init(&ctx->heap); list_init(&ctx->objects); list_init(&ctx->code_list); list_init(&ctx->named_items); @@ -111,52 +110,53 @@ static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res { dynamic_var_t *var_iter, **new_vars; function_t *func_iter, **new_funcs; + ScriptDisp *obj = ctx->script_obj; size_t cnt, i;
- cnt = ctx->global_vars_cnt; + cnt = obj->global_vars_cnt; for (var_iter = code->global_vars; var_iter; var_iter = var_iter->next) cnt++; - if (cnt > ctx->global_vars_size) + if (cnt > obj->global_vars_size) { - if (ctx->global_vars) - new_vars = heap_realloc(ctx->global_vars, cnt * sizeof(*new_vars)); + if (obj->global_vars) + new_vars = heap_realloc(obj->global_vars, cnt * sizeof(*new_vars)); else new_vars = heap_alloc(cnt * sizeof(*new_vars)); if (!new_vars) return E_OUTOFMEMORY; - ctx->global_vars = new_vars; - ctx->global_vars_size = cnt; + obj->global_vars = new_vars; + obj->global_vars_size = cnt; } for (var_iter = code->global_vars; var_iter; var_iter = var_iter->next) - ctx->global_vars[ctx->global_vars_cnt++] = var_iter; + obj->global_vars[obj->global_vars_cnt++] = var_iter;
- cnt = ctx->global_funcs_cnt; + cnt = obj->global_funcs_cnt; for (func_iter = code->funcs; func_iter; func_iter = func_iter->next) cnt++; - if (cnt > ctx->global_funcs_size) + if (cnt > obj->global_funcs_size) { - if (ctx->global_funcs) - new_funcs = heap_realloc(ctx->global_funcs, cnt * sizeof(*new_funcs)); + if (obj->global_funcs) + new_funcs = heap_realloc(obj->global_funcs, cnt * sizeof(*new_funcs)); else new_funcs = heap_alloc(cnt * sizeof(*new_funcs)); if (!new_funcs) return E_OUTOFMEMORY; - ctx->global_funcs = new_funcs; - ctx->global_funcs_size = cnt; + obj->global_funcs = new_funcs; + obj->global_funcs_size = cnt; } for (func_iter = code->funcs; func_iter; func_iter = func_iter->next) { - for (i = 0; i < ctx->global_funcs_cnt; i++) + for (i = 0; i < obj->global_funcs_cnt; i++) { - if (!wcsicmp(ctx->global_funcs[i]->name, func_iter->name)) + if (!wcsicmp(obj->global_funcs[i]->name, func_iter->name)) { /* global function already exists, replace it */ - ctx->global_funcs[i] = func_iter; + obj->global_funcs[i] = func_iter; break; } } - if (i == ctx->global_funcs_cnt) - ctx->global_funcs[ctx->global_funcs_cnt++] = func_iter; + if (i == obj->global_funcs_cnt) + obj->global_funcs[obj->global_funcs_cnt++] = func_iter; }
if (code->classes) @@ -171,8 +171,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; }
@@ -225,33 +225,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; - unsigned i;
collect_objects(ctx); clear_ei(&ctx->ei);
- for(i = 0; i < ctx->global_vars_cnt; i++) - VariantClear(&ctx->global_vars[i]->v); - - heap_free(ctx->global_vars); - heap_free(ctx->global_funcs); - ctx->global_vars = NULL; - ctx->global_vars_cnt = 0; - ctx->global_vars_size = 0; - ctx->global_funcs = NULL; - ctx->global_funcs_cnt = 0; - ctx->global_funcs_size = 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)) { @@ -264,13 +254,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; @@ -295,8 +278,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) diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index a456180..baad410 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -120,11 +120,33 @@ 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;
+ dynamic_var_t **global_vars; + size_t global_vars_cnt; + size_t global_vars_size; + + function_t **global_funcs; + size_t global_funcs_cnt; + size_t global_funcs_size; + + dynamic_var_t *dynamic_vars; + 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; @@ -158,13 +180,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; @@ -181,19 +196,6 @@ struct _script_ctx_t {
EXCEPINFO ei;
- dynamic_var_t **global_vars; - size_t global_vars_cnt; - size_t global_vars_size; - - function_t **global_funcs; - size_t global_funcs_cnt; - size_t global_funcs_size; - - class_desc_t *classes; - class_desc_t *procs; - - heap_pool_t heap; - struct list objects; struct list code_list; struct list named_items;
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 c0a582c..3fe73a9 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 3fe73a9..5cb50c5 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; @@ -1249,6 +1500,7 @@ START_TEST(vbscript) test_vbscript_initializing(); test_named_items(); test_scriptdisp(); + test_code_persistence(); test_RegExp(); test_RegExp_Replace(); }else {