From: Francis De Brabandere <francisdb@gmail.com> For-loop counters and conditional comparisons hit VarAdd/VarCmp every iteration with trivial I2/I4 operands, but the full VARIANT conversion pipeline (VariantChangeType, locale grab/free in ucrtbase) dominates the cost. Short-circuit at the call site in interp.c when both operands are pure VT_I2/VT_I4: compare directly, or add via LONGLONG with native promotion (I2+I2 -> I4 on overflow, I4+I4 -> R8 on overflow). Keeps the optimisation scoped to vbscript callers rather than adding branches to oleaut32 generic VarAdd/VarCmp. --- dlls/vbscript/interp.c | 44 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index ac2bbc64ce6..37c7aefd83b 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -2285,6 +2285,22 @@ static HRESULT var_cmp(exec_ctx_t *ctx, VARIANT *l, VARIANT *r, unsigned flags) if(is_unsupported_script_vt(lvt) || is_unsupported_script_vt(rvt)) return MAKE_VBSERROR(VBSE_INVALID_TYPELIB_VARIABLE); + /* Fast path: pure-integer comparisons (the dominant case in For-loops and + * If-conditions) skip VarCmp's VariantChangeType pipeline. */ + if(V_VT(l) == VT_I2 && V_VT(r) == VT_I2) { + if(V_I2(l) < V_I2(r)) return VARCMP_LT; + if(V_I2(l) > V_I2(r)) return VARCMP_GT; + return VARCMP_EQ; + } + if((V_VT(l) == VT_I2 || V_VT(l) == VT_I4) && + (V_VT(r) == VT_I2 || V_VT(r) == VT_I4)) { + LONG lv = V_VT(l) == VT_I2 ? V_I2(l) : V_I4(l); + LONG rv = V_VT(r) == VT_I2 ? V_I2(r) : V_I4(r); + if(lv < rv) return VARCMP_LT; + if(lv > rv) return VARCMP_GT; + return VARCMP_EQ; + } + /* BSTR vs numeric LITERAL: coerce BSTR to a number, parse failure raises * type-mismatch (error 13). */ if((lvt == VT_BSTR && is_numeric_vt(rvt) && r_lit) || @@ -2600,7 +2616,33 @@ static HRESULT interp_add(exec_ctx_t *ctx) hres = stack_pop_val(ctx, &l); if(SUCCEEDED(hres)) { - hres = VarAdd(l.v, r.v, &v); + /* Fast path: pure-integer addition skips VarAdd's VariantChangeType + * pipeline. Covers the dominant For-loop counter increment case. + * Overflow promotes per native: I2+I2 -> I4, I4+I4 -> R8. */ + if((V_VT(l.v) == VT_I2 || V_VT(l.v) == VT_I4) && + (V_VT(r.v) == VT_I2 || V_VT(r.v) == VT_I4)) { + LONGLONG lv = V_VT(l.v) == VT_I2 ? V_I2(l.v) : V_I4(l.v); + LONGLONG rv = V_VT(r.v) == VT_I2 ? V_I2(r.v) : V_I4(r.v); + LONGLONG sum = lv + rv; + + if(V_VT(l.v) == VT_I2 && V_VT(r.v) == VT_I2) { + if(sum >= SHRT_MIN && sum <= SHRT_MAX) { + V_VT(&v) = VT_I2; + V_I2(&v) = sum; + }else { + V_VT(&v) = VT_I4; + V_I4(&v) = sum; + } + }else if(sum >= LONG_MIN && sum <= LONG_MAX) { + V_VT(&v) = VT_I4; + V_I4(&v) = sum; + }else { + V_VT(&v) = VT_R8; + V_R8(&v) = sum; + } + }else { + hres = VarAdd(l.v, r.v, &v); + } release_val(&l); } release_val(&r); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10921