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