msscript.ocx: Cache the procedures obtained from the ScriptProcedureCollection.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Gabriel Ivăncescu 2020-08-12 17:13:41 +03:00 committed by Alexandre Julliard
parent e8348bdbcc
commit 19ebaa85fc
2 changed files with 66 additions and 5 deletions

View File

@ -93,6 +93,9 @@ typedef struct {
IScriptProcedure IScriptProcedure_iface; IScriptProcedure IScriptProcedure_iface;
LONG ref; LONG ref;
ULONG hash;
struct list entry;
BSTR name; BSTR name;
} ScriptProcedure; } ScriptProcedure;
@ -102,6 +105,7 @@ struct ScriptProcedureCollection {
LONG count; LONG count;
ScriptModule *module; ScriptModule *module;
struct list hash_table[43];
}; };
struct ScriptHost { struct ScriptHost {
@ -800,6 +804,7 @@ static ULONG WINAPI ScriptProcedure_Release(IScriptProcedure *iface)
if (!ref) if (!ref)
{ {
list_remove(&This->entry);
SysFreeString(This->name); SysFreeString(This->name);
heap_free(This); heap_free(This);
} }
@ -908,9 +913,12 @@ static const IScriptProcedureVtbl ScriptProcedureVtbl = {
}; };
/* This function always releases the FUNCDESC passed in */ /* This function always releases the FUNCDESC passed in */
static HRESULT get_script_procedure(ITypeInfo *typeinfo, FUNCDESC *desc, IScriptProcedure **procedure) static HRESULT get_script_procedure(ScriptProcedureCollection *procedures, ITypeInfo *typeinfo,
FUNCDESC *desc, IScriptProcedure **procedure)
{ {
struct list *proc_list;
ScriptProcedure *proc; ScriptProcedure *proc;
ULONG hash;
HRESULT hr; HRESULT hr;
BSTR str; BSTR str;
UINT len; UINT len;
@ -918,6 +926,23 @@ static HRESULT get_script_procedure(ITypeInfo *typeinfo, FUNCDESC *desc, IScript
hr = ITypeInfo_GetNames(typeinfo, desc->memid, &str, 1, &len); hr = ITypeInfo_GetNames(typeinfo, desc->memid, &str, 1, &len);
if (FAILED(hr)) goto done; if (FAILED(hr)) goto done;
len = SysStringLen(str);
hash = LHashValOfNameSys(sizeof(void*) == 8 ? SYS_WIN64 : SYS_WIN32, LOCALE_USER_DEFAULT, str);
proc_list = &procedures->hash_table[hash % ARRAY_SIZE(procedures->hash_table)];
/* Try to find it in the hash table */
LIST_FOR_EACH_ENTRY(proc, proc_list, ScriptProcedure, entry)
{
if (proc->hash == hash && SysStringLen(proc->name) == len &&
!memcmp(proc->name, str, len * sizeof(*str)))
{
SysFreeString(str);
IScriptProcedure_AddRef(&proc->IScriptProcedure_iface);
*procedure = &proc->IScriptProcedure_iface;
goto done;
}
}
if (!(proc = heap_alloc(sizeof(*proc)))) if (!(proc = heap_alloc(sizeof(*proc))))
{ {
hr = E_OUTOFMEMORY; hr = E_OUTOFMEMORY;
@ -927,7 +952,9 @@ static HRESULT get_script_procedure(ITypeInfo *typeinfo, FUNCDESC *desc, IScript
proc->IScriptProcedure_iface.lpVtbl = &ScriptProcedureVtbl; proc->IScriptProcedure_iface.lpVtbl = &ScriptProcedureVtbl;
proc->ref = 1; proc->ref = 1;
proc->hash = hash;
proc->name = str; proc->name = str;
list_add_tail(proc_list, &proc->entry);
*procedure = &proc->IScriptProcedure_iface; *procedure = &proc->IScriptProcedure_iface;
@ -970,11 +997,16 @@ static ULONG WINAPI ScriptProcedureCollection_Release(IScriptProcedureCollection
{ {
ScriptProcedureCollection *This = impl_from_IScriptProcedureCollection(iface); ScriptProcedureCollection *This = impl_from_IScriptProcedureCollection(iface);
LONG ref = InterlockedDecrement(&This->ref); LONG ref = InterlockedDecrement(&This->ref);
UINT i;
TRACE("(%p) ref=%d\n", This, ref); TRACE("(%p) ref=%d\n", This, ref);
if (!ref) if (!ref)
{ {
/* Unlink any dangling items from the hash table */
for (i = 0; i < ARRAY_SIZE(This->hash_table); i++)
list_remove(&This->hash_table[i]);
This->module->procedures = NULL; This->module->procedures = NULL;
IScriptModule_Release(&This->module->IScriptModule_iface); IScriptModule_Release(&This->module->IScriptModule_iface);
heap_free(This); heap_free(This);
@ -1073,12 +1105,29 @@ static HRESULT WINAPI ScriptProcedureCollection_get_Item(IScriptProcedureCollect
if (V_VT(&index) == VT_BSTR) if (V_VT(&index) == VT_BSTR)
{ {
struct list *proc_list;
ScriptProcedure *proc;
ITypeComp *comp; ITypeComp *comp;
BINDPTR bindptr; BINDPTR bindptr;
DESCKIND kind; DESCKIND kind;
ULONG hash; ULONG hash;
UINT len;
len = SysStringLen(V_BSTR(&index));
hash = LHashValOfNameSys(sizeof(void*) == 8 ? SYS_WIN64 : SYS_WIN32, LOCALE_USER_DEFAULT, V_BSTR(&index)); hash = LHashValOfNameSys(sizeof(void*) == 8 ? SYS_WIN64 : SYS_WIN32, LOCALE_USER_DEFAULT, V_BSTR(&index));
proc_list = &This->hash_table[hash % ARRAY_SIZE(This->hash_table)];
/* Try to find it in the hash table */
LIST_FOR_EACH_ENTRY(proc, proc_list, ScriptProcedure, entry)
{
if (proc->hash == hash && SysStringLen(proc->name) == len &&
!memcmp(proc->name, V_BSTR(&index), len * sizeof(WCHAR)))
{
IScriptProcedure_AddRef(&proc->IScriptProcedure_iface);
*ppdispProcedure = &proc->IScriptProcedure_iface;
return S_OK;
}
}
hr = get_script_typecomp(This->module, typeinfo, &comp); hr = get_script_typecomp(This->module, typeinfo, &comp);
if (FAILED(hr)) return hr; if (FAILED(hr)) return hr;
@ -1089,7 +1138,7 @@ static HRESULT WINAPI ScriptProcedureCollection_get_Item(IScriptProcedureCollect
switch (kind) switch (kind)
{ {
case DESCKIND_FUNCDESC: case DESCKIND_FUNCDESC:
hr = get_script_procedure(typeinfo, bindptr.lpfuncdesc, ppdispProcedure); hr = get_script_procedure(This, typeinfo, bindptr.lpfuncdesc, ppdispProcedure);
ITypeInfo_Release(typeinfo); ITypeInfo_Release(typeinfo);
return hr; return hr;
case DESCKIND_IMPLICITAPPOBJ: case DESCKIND_IMPLICITAPPOBJ:
@ -1113,7 +1162,7 @@ static HRESULT WINAPI ScriptProcedureCollection_get_Item(IScriptProcedureCollect
hr = ITypeInfo_GetFuncDesc(typeinfo, V_INT(&index) - 1, &desc); hr = ITypeInfo_GetFuncDesc(typeinfo, V_INT(&index) - 1, &desc);
if (FAILED(hr)) return hr; if (FAILED(hr)) return hr;
return get_script_procedure(typeinfo, desc, ppdispProcedure); return get_script_procedure(This, typeinfo, desc, ppdispProcedure);
} }
static HRESULT WINAPI ScriptProcedureCollection_get_Count(IScriptProcedureCollection *iface, LONG *plCount) static HRESULT WINAPI ScriptProcedureCollection_get_Count(IScriptProcedureCollection *iface, LONG *plCount)
@ -1343,6 +1392,7 @@ static HRESULT WINAPI ScriptModule_get_Procedures(IScriptModule *iface, IScriptP
else else
{ {
ScriptProcedureCollection *procs; ScriptProcedureCollection *procs;
UINT i;
if (!(procs = heap_alloc(sizeof(*procs)))) if (!(procs = heap_alloc(sizeof(*procs))))
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
@ -1351,6 +1401,9 @@ static HRESULT WINAPI ScriptModule_get_Procedures(IScriptModule *iface, IScriptP
procs->ref = 1; procs->ref = 1;
procs->count = -1; procs->count = -1;
procs->module = This; procs->module = This;
for (i = 0; i < ARRAY_SIZE(procs->hash_table); i++)
list_init(&procs->hash_table[i]);
This->procedures = procs; This->procedures = procs;
IScriptModule_AddRef(&This->IScriptModule_iface); IScriptModule_AddRef(&This->IScriptModule_iface);
} }

View File

@ -3293,7 +3293,7 @@ static void test_IScriptControl_get_CodeObject(void)
static void test_IScriptControl_get_Procedures(void) static void test_IScriptControl_get_Procedures(void)
{ {
IScriptProcedureCollection *procs, *procs2; IScriptProcedureCollection *procs, *procs2;
IScriptProcedure *proc; IScriptProcedure *proc, *proc2;
IScriptControl *sc; IScriptControl *sc;
VARIANT var; VARIANT var;
LONG count; LONG count;
@ -3527,10 +3527,18 @@ static void test_IScriptControl_get_Procedures(void)
CHECK_CALLED(GetFuncDesc); CHECK_CALLED(GetFuncDesc);
CHECK_CALLED(GetNames); CHECK_CALLED(GetNames);
CHECK_CALLED(ReleaseFuncDesc); CHECK_CALLED(ReleaseFuncDesc);
IScriptProcedure_Release(proc);
/* The name is cached and not looked up with Bind anymore */
V_VT(&var) = VT_BSTR; V_VT(&var) = VT_BSTR;
V_BSTR(&var) = SysAllocString(custom_engine_funcs[i].name); V_BSTR(&var) = SysAllocString(custom_engine_funcs[i].name);
hr = IScriptProcedureCollection_get_Item(procs, var, &proc2);
ok(hr == S_OK, "get_Item for %s failed: 0x%08x.\n", wine_dbgstr_w(custom_engine_funcs[i].name), hr);
ok(proc == proc2, "proc and proc2 are not the same for %s and index %u.\n",
wine_dbgstr_w(custom_engine_funcs[i].name), i + 1);
IScriptProcedure_Release(proc);
IScriptProcedure_Release(proc2);
/* Since both were released, the cache entry is destroyed */
SET_EXPECT(Bind); SET_EXPECT(Bind);
SET_EXPECT(GetNames); SET_EXPECT(GetNames);
SET_EXPECT(ReleaseFuncDesc); SET_EXPECT(ReleaseFuncDesc);