LibJS: Check TDZ state in asm environment calls

GetCalleeAndThisFromEnvironment treated a binding as initialized when
its value slot was not <empty>. Declarative bindings do not encode TDZ
in that slot, though: uninitialized bindings keep a separate initialized
flag and their value starts as undefined.

That let the first slow-path TDZ failure populate the environment cache,
then a second call at the same site reused the cached coordinate and
turned the required ReferenceError into a TypeError from calling
undefined.

Check Binding.initialized in the asm fast path instead and cover the
cached second-hit case with a regression test.
This commit is contained in:
Andreas Kling
2026-04-19 22:53:46 +02:00
committed by Andreas Kling
parent d8aee7f1e6
commit e5d4c5cce8
Notes: github-actions[bot] 2026-04-20 09:24:39 +00:00
2 changed files with 26 additions and 3 deletions

View File

@@ -1301,10 +1301,11 @@ handler GetCalleeAndThisFromEnvironment
load64 t0, [t3, BINDINGS_DATA_PTR]
mul t2, t2, SIZEOF_BINDING
add t0, t2
# TDZ state lives in Binding.initialized; the value slot itself starts as
# undefined, so checking for EMPTY would miss cached second-hit calls.
load8 t1, [t0, BINDING_INITIALIZED]
branch_zero t1, .slow
load64 t1, [t0, BINDING_VALUE]
# Check value is not empty (TDZ)
mov t4, EMPTY_TAG_SHIFTED
branch_eq t1, t4, .slow
store_operand m_callee, t1
# this = undefined (DeclarativeEnvironment.with_base_object() always returns nullptr)
mov t0, UNDEFINED_SHIFTED