1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-23 09:27:35 +00:00

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.
This commit is contained in:
Luke Wilde 2022-03-14 02:34:01 +00:00 committed by Ali Mohammad Pur
parent ada8880f58
commit 858bcac4c7
2 changed files with 36 additions and 20 deletions

View file

@ -76,6 +76,33 @@ Label Generator::nearest_continuable_scope() const
return m_continuable_scopes.last(); 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<Bytecode::Op::CreateEnvironment>(
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<Bytecode::Op::LeaveEnvironment>(
mode == BindingMode::Lexical
? Bytecode::Op::EnvironmentMode::Lexical
: Bytecode::Op::EnvironmentMode::Var);
}
}
}
void Generator::begin_continuable_scope(Label continue_target) void Generator::begin_continuable_scope(Label continue_target)
{ {
m_continuable_scopes.append(continue_target); m_continuable_scopes.append(continue_target);

View file

@ -150,31 +150,16 @@ public:
} }
return false; return false;
} }
void begin_variable_scope(BindingMode mode = BindingMode::Lexical, SurroundingScopeKind kind = SurroundingScopeKind::Block)
{ void begin_variable_scope(BindingMode mode = BindingMode::Lexical, SurroundingScopeKind kind = SurroundingScopeKind::Block);
m_variable_scopes.append({ kind, mode, {} }); void end_variable_scope();
if (mode != BindingMode::Global) {
emit<Bytecode::Op::CreateEnvironment>(
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<Bytecode::Op::LeaveEnvironment>(
mode == BindingMode::Lexical
? Bytecode::Op::EnvironmentMode::Lexical
: Bytecode::Op::EnvironmentMode::Var);
}
}
enum class BlockBoundaryType { enum class BlockBoundaryType {
Break, Break,
Continue, Continue,
Unwind, Unwind,
LeaveLexicalEnvironment,
LeaveVariableEnvironment,
}; };
template<typename OpType> template<typename OpType>
void perform_needed_unwinds(bool is_break_node = false) requires(OpType::IsTerminator) void perform_needed_unwinds(bool is_break_node = false) requires(OpType::IsTerminator)
@ -191,6 +176,10 @@ public:
break; break;
if (boundary == BlockBoundaryType::Unwind) if (boundary == BlockBoundaryType::Unwind)
emit<Bytecode::Op::LeaveUnwindContext>(); emit<Bytecode::Op::LeaveUnwindContext>();
else if (boundary == BlockBoundaryType::LeaveLexicalEnvironment)
emit<Bytecode::Op::LeaveEnvironment>(Bytecode::Op::EnvironmentMode::Lexical);
else if (boundary == BlockBoundaryType::LeaveVariableEnvironment)
emit<Bytecode::Op::LeaveEnvironment>(Bytecode::Op::EnvironmentMode::Var);
} }
} }