From: Francis De Brabandere <francisdb@gmail.com> Resolve Dim variables and function arguments to direct indices during compilation, emitting OP_local instead of OP_ident. This eliminates runtime wcsicmp scans in lookup_identifier() for the most common case. This mirrors jscript's OP_local optimization (dlls/jscript/compile.c: bind_local / emit_identifier). --- dlls/vbscript/compile.c | 41 +++++++++++++++++++++++++++++++++++----- dlls/vbscript/interp.c | 21 ++++++++++++++++++++ dlls/vbscript/vbscript.h | 1 + 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index 54314372a13..713834ee5e6 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -456,6 +456,34 @@ static BOOL lookup_dim_decls(compile_ctx_t *ctx, const WCHAR *name) return FALSE; } +/* Resolve an identifier to a local variable or argument index at compile time. + * Returns TRUE if bound, with *ret set to: non-negative = dim var index, negative = arg index (-1 = arg 0, etc.). + * This mirrors jscript's bind_local() / local_off() convention. */ +static BOOL bind_local(compile_ctx_t *ctx, const WCHAR *name, int *ret) +{ + dim_decl_t *dim_decl; + unsigned i; + + if(ctx->func->type == FUNC_GLOBAL) + return FALSE; + + for(dim_decl = ctx->dim_decls, i = 0; dim_decl; dim_decl = dim_decl->next, i++) { + if(!vbs_wcsicmp(dim_decl->name, name)) { + *ret = i; + return TRUE; + } + } + + for(i = 0; i < ctx->func->arg_cnt; i++) { + if(!vbs_wcsicmp(ctx->func->args[i].name, name)) { + *ret = -(int)i - 1; + return TRUE; + } + } + + return FALSE; +} + static HRESULT compile_args(compile_ctx_t *ctx, expression_t *args, unsigned *ret) { unsigned arg_cnt = 0; @@ -506,15 +534,18 @@ static HRESULT compile_member_call_expression(compile_ctx_t *ctx, member_express static HRESULT compile_member_expression(compile_ctx_t *ctx, member_expression_t *expr) { expression_t *const_expr; + int local_ref; if (expr->obj_expr) /* FIXME: we should probably have a dedicated opcode as well */ return compile_member_call_expression(ctx, expr, 0, TRUE); - if (!lookup_dim_decls(ctx, expr->identifier) && !lookup_args_name(ctx, expr->identifier)) { - const_expr = lookup_const_decls(ctx, expr->identifier, TRUE); - if(const_expr) - return compile_expression(ctx, const_expr); - } + if(bind_local(ctx, expr->identifier, &local_ref)) + return push_instr_int(ctx, OP_local, local_ref); + + const_expr = lookup_const_decls(ctx, expr->identifier, TRUE); + if(const_expr) + return compile_expression(ctx, const_expr); + return push_instr_bstr(ctx, OP_ident, expr->identifier); } diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 994da407169..2bc7c40dee3 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -873,6 +873,27 @@ static HRESULT interp_mcallv(exec_ctx_t *ctx) return do_mcall(ctx, NULL); } +static HRESULT interp_local(exec_ctx_t *ctx) +{ + const int arg = ctx->instr->arg1.lng; + VARIANT *v; + VARIANT r; + + if(arg < 0) + v = ctx->args - arg - 1; + else + v = ctx->vars + arg; + + TRACE("%s\n", debugstr_variant(v)); + + if(V_VT(v) == (VT_BYREF|VT_VARIANT)) + v = V_VARIANTREF(v); + + V_VT(&r) = VT_BYREF|VT_VARIANT; + V_BYREF(&r) = v; + return stack_push(ctx, &r); +} + static HRESULT interp_ident(exec_ctx_t *ctx) { BSTR identifier = ctx->instr->arg1.bstr; diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index 19c9260a342..353aab3a9e3 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -270,6 +270,7 @@ typedef enum { X(incc, 1, ARG_BSTR, 0) \ X(int, 1, ARG_INT, 0) \ X(is, 1, 0, 0) \ + X(local, 1, ARG_INT, 0) \ X(jmp, 0, ARG_ADDR, 0) \ X(jmp_false, 0, ARG_ADDR, 0) \ X(jmp_true, 0, ARG_ADDR, 0) \ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10515