From 6bec7635df75e9826e909dad1c52c672b641a6ee Mon Sep 17 00:00:00 2001 From: jiang1997 Date: Mon, 11 May 2026 01:15:34 +0800 Subject: [PATCH 1/2] Fix find_var_htab to skip entries with scope_level != 0 When a `var` shadows a block-scoped `let` of the same name, find_var_htab returned the block-scoped entry. find_var rejected it (scope_level != 0) and fell through to an O(n) linear scan. Add scope_level == 0 check to the htab probe loop so non-scope-0 entries are skipped. This lets find_var treat htab miss as definitive. --- quickjs.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/quickjs.c b/quickjs.c index 0a3abac68..e7d92b70d 100644 --- a/quickjs.c +++ b/quickjs.c @@ -23378,7 +23378,8 @@ static int find_var_htab(JSFunctionDef *fd, JSAtom var_name) p = &fd->vars_htab[i & m]; if (*p == UINT32_MAX) return -1; - if (fd->vars[*p].var_name == var_name) + if (fd->vars[*p].var_name == var_name && + fd->vars[*p].scope_level == 0) return *p; i += j; j += 1; // quadratic probing @@ -23405,11 +23406,9 @@ static int find_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name) if (fd->vars_htab) { i = find_var_htab(fd, name); - if (i == -1) - goto not_found; - vd = &fd->vars[i]; - if (vd->scope_level == 0) + if (i >= 0) return i; + goto not_found; } for(i = fd->var_count; i-- > 0;) { vd = &fd->vars[i]; From bf52efb14bbbafbf4a208cc9e5389cae13fddc27 Mon Sep 17 00:00:00 2001 From: jiang1997 Date: Sun, 17 May 2026 07:09:09 +0800 Subject: [PATCH 2/2] Add test for find_var_htab scope_level regression --- tests/test_find_var_htab.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/test_find_var_htab.js diff --git a/tests/test_find_var_htab.js b/tests/test_find_var_htab.js new file mode 100644 index 000000000..996954307 --- /dev/null +++ b/tests/test_find_var_htab.js @@ -0,0 +1,20 @@ +import { assert } from "./assert.js"; + +// Regression test for find_var_htab: when a var shadows a block-scoped +// let of the same name, the htab probe must skip entries with +// scope_level != 0. 27 vars are needed to trigger the htab path. +function test_find_var_htab() { + { let x = "let"; } + var v0, v1, v2, v3, v4, v5, v6, v7, v8, v9; + var v10, v11, v12, v13, v14, v15, v16, v17; + var v18, v19, v20, v21, v22, v23, v24; + var x = "var"; + + function closure() { + return x; + } + + assert(closure(), "var", "find_var_htab returned wrong slot index"); +} + +test_find_var_htab();