From: Francis De Brabandere <francisdb@gmail.com> Emit OP_assign_local and OP_set_local instead of OP_assign_ident and OP_set_ident when the assignment target is a known local variable or function argument. This eliminates runtime lookup_identifier() calls for the most common assignment pattern. This mirrors jscript's OP_local optimization for identifier writes. --- dlls/vbscript/compile.c | 28 ++++++++++++ dlls/vbscript/interp.c | 92 ++++++++++++++++++++++++++++++++++++++++ dlls/vbscript/vbscript.h | 2 + 3 files changed, 122 insertions(+) diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index 713834ee5e6..890d024a276 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -192,6 +192,19 @@ static HRESULT push_instr_uint(compile_ctx_t *ctx, vbsop_t op, unsigned arg) return S_OK; } +static HRESULT push_instr_int_uint(compile_ctx_t *ctx, vbsop_t op, LONG arg1, unsigned arg2) +{ + unsigned ret; + + ret = push_instr(ctx, op); + if(!ret) + return E_OUTOFMEMORY; + + instr_ptr(ctx, ret)->arg1.lng = arg1; + instr_ptr(ctx, ret)->arg2.uint = arg2; + return S_OK; +} + static HRESULT push_instr_addr(compile_ctx_t *ctx, vbsop_t op, unsigned arg) { unsigned ret; @@ -1199,6 +1212,21 @@ static HRESULT compile_assignment(compile_ctx_t *ctx, expression_t *left, expres return hres; } + if(!member_expr->obj_expr) { + int local_ref; + if(bind_local(ctx, member_expr->identifier, &local_ref)) { + hres = push_instr_int_uint(ctx, is_set ? OP_set_local : OP_assign_local, + local_ref, args_cnt); + if(FAILED(hres)) + return hres; + + if(!emit_catch(ctx, 0)) + return E_OUTOFMEMORY; + + return S_OK; + } + } + hres = push_instr_bstr_uint(ctx, op, member_expr->identifier, args_cnt); if(FAILED(hres)) return hres; diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 2bc7c40dee3..703eb174d5e 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -1068,6 +1068,98 @@ static HRESULT interp_set_ident(exec_ctx_t *ctx) return S_OK; } +static HRESULT assign_local_var(exec_ctx_t *ctx, VARIANT *v, WORD flags, DISPPARAMS *dp) +{ + HRESULT hres; + + if(V_VT(v) == (VT_VARIANT|VT_BYREF)) + v = V_VARIANTREF(v); + + if(arg_cnt(dp)) { + SAFEARRAY *array; + + if(V_VT(v) == VT_DISPATCH) { + hres = disp_propput(ctx->script, V_DISPATCH(v), DISPID_VALUE, flags, dp); + return hres; + } + + if(!(V_VT(v) & VT_ARRAY)) + return DISP_E_TYPEMISMATCH; + + switch(V_VT(v)) { + case VT_ARRAY|VT_BYREF|VT_VARIANT: + array = *V_ARRAYREF(v); + break; + case VT_ARRAY|VT_VARIANT: + array = V_ARRAY(v); + break; + default: + FIXME("Unsupported array type %x\n", V_VT(v)); + return E_NOTIMPL; + } + + if(!array) { + WARN("null array\n"); + return MAKE_VBSERROR(VBSE_OUT_OF_BOUNDS); + } + + hres = array_access(array, dp, &v); + if(FAILED(hres)) + return hres; + }else if(V_VT(v) == (VT_ARRAY|VT_BYREF|VT_VARIANT)) { + FIXME("non-array assign\n"); + return E_NOTIMPL; + } + + return assign_value(ctx, v, dp->rgvarg, flags); +} + +static HRESULT interp_assign_local(exec_ctx_t *ctx) +{ + const int ref = ctx->instr->arg1.lng; + const unsigned arg_cnt = ctx->instr->arg2.uint; + VARIANT *v; + DISPPARAMS dp; + HRESULT hres; + + v = ref < 0 ? ctx->args - ref - 1 : ctx->vars + ref; + + TRACE("%d\n", ref); + + vbstack_to_dp(ctx, arg_cnt, TRUE, &dp); + hres = assign_local_var(ctx, v, DISPATCH_PROPERTYPUT, &dp); + if(FAILED(hres)) + return hres; + + stack_popn(ctx, arg_cnt+1); + return S_OK; +} + +static HRESULT interp_set_local(exec_ctx_t *ctx) +{ + const int ref = ctx->instr->arg1.lng; + const unsigned arg_cnt = ctx->instr->arg2.uint; + VARIANT *v; + DISPPARAMS dp; + HRESULT hres; + + v = ref < 0 ? ctx->args - ref - 1 : ctx->vars + ref; + + TRACE("%d %u\n", ref, arg_cnt); + + hres = stack_assume_disp(ctx, arg_cnt, NULL); + if(FAILED(hres)) + return hres; + + vbstack_to_dp(ctx, arg_cnt, TRUE, &dp); + hres = assign_local_var(ctx, v, DISPATCH_PROPERTYPUTREF, &dp); + if(FAILED(hres)) + return hres; + + stack_popn(ctx, arg_cnt + 1); + return S_OK; +} + static HRESULT interp_assign_member(exec_ctx_t *ctx) { BSTR identifier = ctx->instr->arg1.bstr; diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index 353aab3a9e3..53fcb3bb518 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -241,6 +241,7 @@ typedef enum { X(add, 1, 0, 0) \ X(and, 1, 0, 0) \ X(assign_ident, 1, ARG_BSTR, ARG_UINT) \ + X(assign_local, 1, ARG_INT, ARG_UINT) \ X(assign_member, 1, ARG_BSTR, ARG_UINT) \ X(bool, 1, ARG_INT, 0) \ X(catch, 1, ARG_ADDR, ARG_UINT) \ @@ -296,6 +297,7 @@ typedef enum { X(ret, 0, 0, 0) \ X(retval, 1, 0, 0) \ X(set_ident, 1, ARG_BSTR, ARG_UINT) \ + X(set_local, 1, ARG_INT, ARG_UINT) \ X(set_member, 1, ARG_BSTR, ARG_UINT) \ X(stack, 1, ARG_UINT, 0) \ X(step, 0, ARG_ADDR, ARG_BSTR) \ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10515