Resolve identifiers to direct indices during compilation instead of doing runtime `wcsicmp` string scans in `lookup_identifier()`. This adds new opcodes that access local variables, function arguments, class properties, and loop variables by index, eliminating the linear string comparison overhead for the most common cases. **New opcodes:** - `OP_local` / `OP_assign_local` / `OP_set_local` - read/write local vars and args by index - `OP_local_prop` / `OP_assign_local_prop` / `OP_set_local_prop` - read/write class properties by index - `OP_step_local` / `OP_incc_local` - For-loop step/increment with indexed counter - `OP_enumnext_local` - For-Each iteration with indexed loop variable This mirrors jscript's `OP_local` / `bind_local()` optimization (`dlls/jscript/compile.c`) and addresses the FIXME in `lookup_identifier()` noting that class property access should be bound at compile time. Names that cannot be resolved at compile time (globals in Execute/ExecuteGlobal code, dynamic vars, host objects) continue to use the existing string-based path. The last commit also adds a fast path for SAFEARRAY iteration that bypasses the `IEnumVARIANT` COM vtable dispatch and copies elements directly from the array data, eliminating one intermediate `VariantCopy` per iteration. ### Local variable / argument / class property access (1M iterations, 10 reads per iteration) | Benchmark | Windows (VM) | Wine master | Wine (7 commits) | **Speedup** | vs Windows | |-----------|-------------|-------------|-------------------|---------|------------| | Local vars | 156 ms | 10,134 ms | 960 ms | **10.6x** | 6.2x slower | | Arguments | 171 ms | 6,656 ms | 968 ms | **6.9x** | 5.7x slower | | Class props | 265 ms | 6,673 ms | 964 ms | **6.9x** | 3.6x slower | ### For-loop variants (10M iterations) | Benchmark | Windows (VM) | Wine master | Wine (7 commits) | **Speedup** | vs Windows | |-----------|-------------|-------------|-------------------|---------|------------| | Empty For | 117 ms | 6,222 ms | 1,531 ms | **4.1x** | 13x slower | | For + assign | 203 ms | 10,226 ms | 1,710 ms | **6.0x** | 8.4x slower | | Do-While manual | 437 ms | 8,773 ms | 1,820 ms | **4.8x** | 4.2x slower | | For Step 2 | 62 ms | 6,125 ms | 1,527 ms | **4.0x** | 25x slower | | Nested For | 125 ms | 7,742 ms | 1,546 ms | **5.0x** | 12x slower | | For local Sub | 109 ms | 3,062 ms | 1,531 ms | **2.0x** | 14x slower | | For R8 counter | 203 ms | 10,882 ms | 1,492 ms | **7.3x** | 7.4x slower | | For-Each array | 7 ms | 6,339 ms | 58 ms | **109x** | 8.3x slower | The remaining 4-13x gap vs Windows in For-loops is from `VarAdd`/`VarCmp` going through full `VariantChangeTypeEx` machinery (including locale alloc/free per call). A separate MR ([!10528](https://gitlab.winehq.org/wine/wine/-/merge_requests/10529)) adds I2/I4 fast paths in oleaut32 that bring integer loops within 1.2-1.9x of Windows when combined with this branch. -- v9: fixup! vbscript: Bind local variables and arguments at compile time. vbscript: Fast-path For-Each iteration over SAFEARRAY. vbscript: Bind For-Each loop variable at compile time. vbscript: Bind global-scope Dim variables at compile time. vbscript: Bind class properties at compile time. vbscript: Bind For-loop variables at compile time. vbscript: Bind local variable assignments at compile time. vbscript: Bind local variables and arguments at compile time. https://gitlab.winehq.org/wine/wine/-/merge_requests/10515