mirror of
https://github.com/RGBCube/serenity
synced 2025-05-22 16:35:08 +00:00
LibJS: Leave the unwind context on break/continue/return in bytecode
Otherwise we'd keep the old unwind context, and end up never invoking the other handlers up the stack.
This commit is contained in:
parent
41184c960d
commit
ba9c4959d6
3 changed files with 44 additions and 2 deletions
|
@ -1207,10 +1207,13 @@ Bytecode::CodeGenerationErrorOr<void> ReturnStatement::generate_bytecode(Bytecod
|
||||||
if (m_argument)
|
if (m_argument)
|
||||||
TRY(m_argument->generate_bytecode(generator));
|
TRY(m_argument->generate_bytecode(generator));
|
||||||
|
|
||||||
if (generator.is_in_generator_or_async_function())
|
if (generator.is_in_generator_or_async_function()) {
|
||||||
|
generator.perform_needed_unwinds<Bytecode::Op::Yield>();
|
||||||
generator.emit<Bytecode::Op::Yield>(nullptr);
|
generator.emit<Bytecode::Op::Yield>(nullptr);
|
||||||
else
|
} else {
|
||||||
|
generator.perform_needed_unwinds<Bytecode::Op::Return>();
|
||||||
generator.emit<Bytecode::Op::Return>();
|
generator.emit<Bytecode::Op::Return>();
|
||||||
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -1279,6 +1282,7 @@ Bytecode::CodeGenerationErrorOr<void> IfStatement::generate_bytecode(Bytecode::G
|
||||||
|
|
||||||
Bytecode::CodeGenerationErrorOr<void> ContinueStatement::generate_bytecode(Bytecode::Generator& generator) const
|
Bytecode::CodeGenerationErrorOr<void> ContinueStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||||
{
|
{
|
||||||
|
generator.perform_needed_unwinds<Bytecode::Op::Jump>();
|
||||||
generator.emit<Bytecode::Op::Jump>().set_targets(
|
generator.emit<Bytecode::Op::Jump>().set_targets(
|
||||||
generator.nearest_continuable_scope(),
|
generator.nearest_continuable_scope(),
|
||||||
{});
|
{});
|
||||||
|
@ -1438,6 +1442,7 @@ Bytecode::CodeGenerationErrorOr<void> ThrowStatement::generate_bytecode(Bytecode
|
||||||
|
|
||||||
Bytecode::CodeGenerationErrorOr<void> BreakStatement::generate_bytecode(Bytecode::Generator& generator) const
|
Bytecode::CodeGenerationErrorOr<void> BreakStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||||
{
|
{
|
||||||
|
generator.perform_needed_unwinds<Bytecode::Op::Jump>(true);
|
||||||
generator.emit<Bytecode::Op::Jump>().set_targets(
|
generator.emit<Bytecode::Op::Jump>().set_targets(
|
||||||
generator.nearest_breakable_scope(),
|
generator.nearest_breakable_scope(),
|
||||||
{});
|
{});
|
||||||
|
@ -1502,6 +1507,7 @@ Bytecode::CodeGenerationErrorOr<void> TryStatement::generate_bytecode(Bytecode::
|
||||||
auto& target_block = generator.make_block();
|
auto& target_block = generator.make_block();
|
||||||
generator.switch_to_basic_block(saved_block);
|
generator.switch_to_basic_block(saved_block);
|
||||||
generator.emit<Bytecode::Op::EnterUnwindContext>(Bytecode::Label { target_block }, handler_target, finalizer_target);
|
generator.emit<Bytecode::Op::EnterUnwindContext>(Bytecode::Label { target_block }, handler_target, finalizer_target);
|
||||||
|
generator.start_boundary(Bytecode::Generator::BlockBoundaryType::Unwind);
|
||||||
|
|
||||||
generator.switch_to_basic_block(target_block);
|
generator.switch_to_basic_block(target_block);
|
||||||
TRY(m_block->generate_bytecode(generator));
|
TRY(m_block->generate_bytecode(generator));
|
||||||
|
@ -1514,6 +1520,7 @@ Bytecode::CodeGenerationErrorOr<void> TryStatement::generate_bytecode(Bytecode::
|
||||||
next_block = █
|
next_block = █
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
generator.end_boundary(Bytecode::Generator::BlockBoundaryType::Unwind);
|
||||||
|
|
||||||
generator.switch_to_basic_block(next_block ? *next_block : saved_block);
|
generator.switch_to_basic_block(next_block ? *next_block : saved_block);
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -79,11 +79,13 @@ Label Generator::nearest_continuable_scope() const
|
||||||
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);
|
||||||
|
start_boundary(BlockBoundaryType::Continue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Generator::end_continuable_scope()
|
void Generator::end_continuable_scope()
|
||||||
{
|
{
|
||||||
m_continuable_scopes.take_last();
|
m_continuable_scopes.take_last();
|
||||||
|
end_boundary(BlockBoundaryType::Continue);
|
||||||
}
|
}
|
||||||
Label Generator::nearest_breakable_scope() const
|
Label Generator::nearest_breakable_scope() const
|
||||||
{
|
{
|
||||||
|
@ -92,11 +94,13 @@ Label Generator::nearest_breakable_scope() const
|
||||||
void Generator::begin_breakable_scope(Label breakable_target)
|
void Generator::begin_breakable_scope(Label breakable_target)
|
||||||
{
|
{
|
||||||
m_breakable_scopes.append(breakable_target);
|
m_breakable_scopes.append(breakable_target);
|
||||||
|
start_boundary(BlockBoundaryType::Break);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Generator::end_breakable_scope()
|
void Generator::end_breakable_scope()
|
||||||
{
|
{
|
||||||
m_breakable_scopes.take_last();
|
m_breakable_scopes.take_last();
|
||||||
|
end_boundary(BlockBoundaryType::Break);
|
||||||
}
|
}
|
||||||
|
|
||||||
CodeGenerationErrorOr<void> Generator::emit_load_from_reference(JS::ASTNode const& node)
|
CodeGenerationErrorOr<void> Generator::emit_load_from_reference(JS::ASTNode const& node)
|
||||||
|
|
|
@ -171,6 +171,36 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class BlockBoundaryType {
|
||||||
|
Break,
|
||||||
|
Continue,
|
||||||
|
Unwind,
|
||||||
|
};
|
||||||
|
template<typename OpType>
|
||||||
|
void perform_needed_unwinds(bool is_break_node = false) requires(OpType::IsTerminator)
|
||||||
|
{
|
||||||
|
Optional<BlockBoundaryType> boundary_to_stop_at;
|
||||||
|
if constexpr (IsSame<OpType, Bytecode::Op::Return> || IsSame<OpType, Bytecode::Op::Yield>)
|
||||||
|
VERIFY(!is_break_node);
|
||||||
|
else
|
||||||
|
boundary_to_stop_at = is_break_node ? BlockBoundaryType::Break : BlockBoundaryType::Continue;
|
||||||
|
|
||||||
|
for (size_t i = m_boundaries.size(); i > 0; --i) {
|
||||||
|
auto boundary = m_boundaries[i - 1];
|
||||||
|
if (boundary_to_stop_at.has_value() && boundary == *boundary_to_stop_at)
|
||||||
|
break;
|
||||||
|
if (boundary == BlockBoundaryType::Unwind)
|
||||||
|
emit<Bytecode::Op::LeaveUnwindContext>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void start_boundary(BlockBoundaryType type) { m_boundaries.append(type); }
|
||||||
|
void end_boundary(BlockBoundaryType type)
|
||||||
|
{
|
||||||
|
VERIFY(m_boundaries.last() == type);
|
||||||
|
m_boundaries.take_last();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Generator();
|
Generator();
|
||||||
~Generator();
|
~Generator();
|
||||||
|
@ -189,6 +219,7 @@ private:
|
||||||
Vector<Label> m_continuable_scopes;
|
Vector<Label> m_continuable_scopes;
|
||||||
Vector<Label> m_breakable_scopes;
|
Vector<Label> m_breakable_scopes;
|
||||||
Vector<LexicalScope> m_variable_scopes;
|
Vector<LexicalScope> m_variable_scopes;
|
||||||
|
Vector<BlockBoundaryType> m_boundaries;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue