From 858bcac4c7baa26a7a31310d5d220f60a43f5cd9 Mon Sep 17 00:00:00 2001 From: Luke Wilde Date: Mon, 14 Mar 2022 02:34:01 +0000 Subject: [PATCH] LibJS/Bytecode: Unwind environments before block terminating instruction When we reach a block terminating instruction (e.g. Break, Throw), we cannot generate anymore instructions after it. This would not allow us to leave any lexical/variable environments. This uses the mechanism introduced in ba9c49 to unwind environments when we encounter these instructions. --- .../Libraries/LibJS/Bytecode/Generator.cpp | 27 +++++++++++++++++ Userland/Libraries/LibJS/Bytecode/Generator.h | 29 ++++++------------- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.cpp b/Userland/Libraries/LibJS/Bytecode/Generator.cpp index cc79dde944..31e1a4fe61 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Generator.cpp @@ -76,6 +76,33 @@ Label Generator::nearest_continuable_scope() const return m_continuable_scopes.last(); } +void Generator::begin_variable_scope(BindingMode mode, SurroundingScopeKind kind) +{ + m_variable_scopes.append({ kind, mode, {} }); + if (mode != BindingMode::Global) { + start_boundary(mode == BindingMode::Lexical ? BlockBoundaryType::LeaveLexicalEnvironment : BlockBoundaryType::LeaveVariableEnvironment); + emit( + mode == BindingMode::Lexical + ? Bytecode::Op::EnvironmentMode::Lexical + : Bytecode::Op::EnvironmentMode::Var); + } +} + +void Generator::end_variable_scope() +{ + auto mode = m_variable_scopes.take_last().mode; + if (mode != BindingMode::Global) { + end_boundary(mode == BindingMode::Lexical ? BlockBoundaryType::LeaveLexicalEnvironment : BlockBoundaryType::LeaveVariableEnvironment); + + if (!m_current_basic_block->is_terminated()) { + emit( + mode == BindingMode::Lexical + ? Bytecode::Op::EnvironmentMode::Lexical + : Bytecode::Op::EnvironmentMode::Var); + } + } +} + void Generator::begin_continuable_scope(Label continue_target) { m_continuable_scopes.append(continue_target); diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.h b/Userland/Libraries/LibJS/Bytecode/Generator.h index 80db80d34f..91662a9aea 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.h +++ b/Userland/Libraries/LibJS/Bytecode/Generator.h @@ -150,31 +150,16 @@ public: } return false; } - void begin_variable_scope(BindingMode mode = BindingMode::Lexical, SurroundingScopeKind kind = SurroundingScopeKind::Block) - { - m_variable_scopes.append({ kind, mode, {} }); - if (mode != BindingMode::Global) { - emit( - mode == BindingMode::Lexical - ? Bytecode::Op::EnvironmentMode::Lexical - : Bytecode::Op::EnvironmentMode::Var); - } - } - void end_variable_scope() - { - auto mode = m_variable_scopes.take_last().mode; - if (mode != BindingMode::Global && !m_current_basic_block->is_terminated()) { - emit( - mode == BindingMode::Lexical - ? Bytecode::Op::EnvironmentMode::Lexical - : Bytecode::Op::EnvironmentMode::Var); - } - } + + void begin_variable_scope(BindingMode mode = BindingMode::Lexical, SurroundingScopeKind kind = SurroundingScopeKind::Block); + void end_variable_scope(); enum class BlockBoundaryType { Break, Continue, Unwind, + LeaveLexicalEnvironment, + LeaveVariableEnvironment, }; template void perform_needed_unwinds(bool is_break_node = false) requires(OpType::IsTerminator) @@ -191,6 +176,10 @@ public: break; if (boundary == BlockBoundaryType::Unwind) emit(); + else if (boundary == BlockBoundaryType::LeaveLexicalEnvironment) + emit(Bytecode::Op::EnvironmentMode::Lexical); + else if (boundary == BlockBoundaryType::LeaveVariableEnvironment) + emit(Bytecode::Op::EnvironmentMode::Var); } }