[PATCH 6/9] msscript.ocx: Cache the procedures obtained from the ScriptProcedureCollection.
Gabriel Ivăncescu
gabrielopcode at gmail.com
Mon Aug 10 09:58:01 CDT 2020
Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---
Since we're computing the hash anyway for ITypeComp::Bind, a simple fixed hash
table has been used to cache them much more efficiently than a linear lookup.
dlls/msscript.ocx/msscript.c | 59 ++++++++++++++++++++++++++++--
dlls/msscript.ocx/tests/msscript.c | 12 +++++-
2 files changed, 66 insertions(+), 5 deletions(-)
diff --git a/dlls/msscript.ocx/msscript.c b/dlls/msscript.ocx/msscript.c
index df173be..ccdbba4 100644
--- a/dlls/msscript.ocx/msscript.c
+++ b/dlls/msscript.ocx/msscript.c
@@ -93,6 +93,9 @@ typedef struct {
IScriptProcedure IScriptProcedure_iface;
LONG ref;
+ ULONG hash;
+ struct list entry;
+
BSTR name;
} ScriptProcedure;
@@ -102,6 +105,7 @@ struct ScriptProcedureCollection {
LONG count;
ScriptModule *module;
+ struct list hash_table[43];
};
struct ScriptHost {
@@ -800,6 +804,7 @@ static ULONG WINAPI ScriptProcedure_Release(IScriptProcedure *iface)
if (!ref)
{
+ list_remove(&This->entry);
SysFreeString(This->name);
heap_free(This);
}
@@ -908,9 +913,12 @@ static const IScriptProcedureVtbl ScriptProcedureVtbl = {
};
/* 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;
+ ULONG hash;
HRESULT hr;
BSTR str;
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);
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))))
{
hr = E_OUTOFMEMORY;
@@ -927,7 +952,9 @@ static HRESULT get_script_procedure(ITypeInfo *typeinfo, FUNCDESC *desc, IScript
proc->IScriptProcedure_iface.lpVtbl = &ScriptProcedureVtbl;
proc->ref = 1;
+ proc->hash = hash;
proc->name = str;
+ list_add_tail(proc_list, &proc->entry);
*procedure = &proc->IScriptProcedure_iface;
@@ -970,11 +997,16 @@ static ULONG WINAPI ScriptProcedureCollection_Release(IScriptProcedureCollection
{
ScriptProcedureCollection *This = impl_from_IScriptProcedureCollection(iface);
LONG ref = InterlockedDecrement(&This->ref);
+ UINT i;
TRACE("(%p) ref=%d\n", This, 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;
IScriptModule_Release(&This->module->IScriptModule_iface);
heap_free(This);
@@ -1073,12 +1105,29 @@ static HRESULT WINAPI ScriptProcedureCollection_get_Item(IScriptProcedureCollect
if (V_VT(&index) == VT_BSTR)
{
+ struct list *proc_list;
+ ScriptProcedure *proc;
ITypeComp *comp;
BINDPTR bindptr;
DESCKIND kind;
ULONG hash;
+ UINT len;
+ len = SysStringLen(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);
if (FAILED(hr)) return hr;
@@ -1089,7 +1138,7 @@ static HRESULT WINAPI ScriptProcedureCollection_get_Item(IScriptProcedureCollect
switch (kind)
{
case DESCKIND_FUNCDESC:
- hr = get_script_procedure(typeinfo, bindptr.lpfuncdesc, ppdispProcedure);
+ hr = get_script_procedure(This, typeinfo, bindptr.lpfuncdesc, ppdispProcedure);
ITypeInfo_Release(typeinfo);
return hr;
case DESCKIND_IMPLICITAPPOBJ:
@@ -1113,7 +1162,7 @@ static HRESULT WINAPI ScriptProcedureCollection_get_Item(IScriptProcedureCollect
hr = ITypeInfo_GetFuncDesc(typeinfo, V_INT(&index) - 1, &desc);
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)
@@ -1343,6 +1392,7 @@ static HRESULT WINAPI ScriptModule_get_Procedures(IScriptModule *iface, IScriptP
else
{
ScriptProcedureCollection *procs;
+ UINT i;
if (!(procs = heap_alloc(sizeof(*procs))))
return E_OUTOFMEMORY;
@@ -1351,6 +1401,9 @@ static HRESULT WINAPI ScriptModule_get_Procedures(IScriptModule *iface, IScriptP
procs->ref = 1;
procs->count = -1;
procs->module = This;
+ for (i = 0; i < ARRAY_SIZE(procs->hash_table); i++)
+ list_init(&procs->hash_table[i]);
+
This->procedures = procs;
IScriptModule_AddRef(&This->IScriptModule_iface);
}
diff --git a/dlls/msscript.ocx/tests/msscript.c b/dlls/msscript.ocx/tests/msscript.c
index ed4d0f8..c56e2d5 100644
--- a/dlls/msscript.ocx/tests/msscript.c
+++ b/dlls/msscript.ocx/tests/msscript.c
@@ -3293,7 +3293,7 @@ static void test_IScriptControl_get_CodeObject(void)
static void test_IScriptControl_get_Procedures(void)
{
IScriptProcedureCollection *procs, *procs2;
- IScriptProcedure *proc;
+ IScriptProcedure *proc, *proc2;
IScriptControl *sc;
VARIANT var;
LONG count;
@@ -3527,10 +3527,18 @@ static void test_IScriptControl_get_Procedures(void)
CHECK_CALLED(GetFuncDesc);
CHECK_CALLED(GetNames);
CHECK_CALLED(ReleaseFuncDesc);
- IScriptProcedure_Release(proc);
+ /* The name is cached and not looked up with Bind anymore */
V_VT(&var) = VT_BSTR;
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(GetNames);
SET_EXPECT(ReleaseFuncDesc);
--
2.21.0
More information about the wine-devel
mailing list