From: Francis De Brabandere <francisdb@gmail.com> When a For-Each loop iterates over a SAFEARRAY, bypass the IEnumVARIANT COM vtable dispatch and copy elements directly from the array data. This eliminates the COM call overhead and one intermediate VariantCopy per iteration. Non-SAFEARRAY iterators (e.g. IDispatch collections) continue to use the standard IEnumVARIANT_Next path. For-Each over a 10M-element array: 160ms -> 109ms (1.5x faster). --- dlls/vbscript/interp.c | 27 ++++++++++++++++----------- dlls/vbscript/utils.c | 31 +++++++++++++++++++++++++++++++ dlls/vbscript/vbscript.h | 1 + 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 8377ac33bc8..12eadea86d8 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -1884,7 +1884,6 @@ static HRESULT interp_enumnext_local(exec_ctx_t *ctx) { const unsigned loop_end = ctx->instr->arg1.uint; const int ref = ctx->instr->arg2.lng; - VARIANT v; IEnumVARIANT *iter; VARIANT *local_var; BOOL do_continue; @@ -1899,21 +1898,27 @@ static HRESULT interp_enumnext_local(exec_ctx_t *ctx) assert(V_VT(stack_top(ctx, 0)) == VT_UNKNOWN); iter = (IEnumVARIANT*)V_UNKNOWN(stack_top(ctx, 0)); - V_VT(&v) = VT_EMPTY; - hres = IEnumVARIANT_Next(iter, 1, &v, NULL); - if(FAILED(hres)) - return hres; - - do_continue = hres == S_OK; - local_var = get_local_var(ctx, ref); if(V_VT(local_var) == (VT_VARIANT|VT_BYREF)) local_var = V_VARIANTREF(local_var); - hres = assign_value(ctx, local_var, &v, DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF); - VariantClear(&v); - if(FAILED(hres)) + hres = safearray_iter_next(iter, local_var, &do_continue); + if(hres == E_UNEXPECTED) { + VARIANT v; + + V_VT(&v) = VT_EMPTY; + hres = IEnumVARIANT_Next(iter, 1, &v, NULL); + if(FAILED(hres)) + return hres; + + do_continue = hres == S_OK; + hres = assign_value(ctx, local_var, &v, DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF); + VariantClear(&v); + if(FAILED(hres)) + return hres; + }else if(FAILED(hres)) { return hres; + } if(do_continue) { ctx->instr++; diff --git a/dlls/vbscript/utils.c b/dlls/vbscript/utils.c index 4bfc2c65a0a..a824849e370 100644 --- a/dlls/vbscript/utils.c +++ b/dlls/vbscript/utils.c @@ -196,3 +196,34 @@ HRESULT create_safearray_iter(SAFEARRAY *sa, BOOL owned, IEnumVARIANT **ev) *ev = &iter->IEnumVARIANT_iface; return S_OK; } + +HRESULT safearray_iter_next(IEnumVARIANT *iface, VARIANT *dst, BOOL *fetched) +{ + safearray_iter *iter; + VARIANT *src, value; + HRESULT hres; + + if(iface->lpVtbl != &safearray_iter_EnumVARIANTVtbl) + return E_UNEXPECTED; + + iter = impl_from_IEnumVARIANT(iface); + + if(iter->i >= iter->size) { + VariantClear(dst); + *fetched = FALSE; + return S_OK; + } + + src = (VARIANT*)(((BYTE*)iter->sa->pvData) + iter->i * iter->sa->cbElements); + V_VT(&value) = VT_EMPTY; + hres = VariantCopyInd(&value, src); + if(FAILED(hres)) + return hres; + + VariantClear(dst); + *dst = value; + iter->i++; + *fetched = TRUE; + return S_OK; +} + diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index 1312ccde740..8cba81fc205 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -440,6 +440,7 @@ BSTR string_replace(BSTR,BSTR,BSTR,int,int,int); void map_vbs_exception(EXCEPINFO *); HRESULT create_safearray_iter(SAFEARRAY *sa, BOOL owned, IEnumVARIANT **ev); +HRESULT safearray_iter_next(IEnumVARIANT *iface, VARIANT *dst, BOOL *fetched); #define FACILITY_VBS 0xa #define MAKE_VBSERROR(code) MAKE_HRESULT(SEVERITY_ERROR, FACILITY_VBS, code) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10515