mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-30 00:31:14 +00:00
LibJS/Bytecode: Keep completion value of switch case if falling through
We do this by moving the `LoadImmediate undefined` instruction to a separate basic block which jumps to the case's block unconditionally. We enter a case initially using this wrapper, but when falling through, we directly jump to the next case's block.
This commit is contained in:
parent
02b74e5a70
commit
50d6b1ba19
Notes:
sideshowbarker
2024-07-17 01:27:18 +09:00
Author: https://github.com/BertalanD Commit: https://github.com/SerenityOS/serenity/commit/50d6b1ba19 Pull-request: https://github.com/SerenityOS/serenity/pull/19684
|
@ -2196,7 +2196,7 @@ Bytecode::CodeGenerationErrorOr<void> SwitchStatement::generate_labelled_evaluat
|
|||
TRY(m_discriminant->generate_bytecode(generator));
|
||||
generator.emit<Bytecode::Op::Store>(discriminant_reg);
|
||||
Vector<Bytecode::BasicBlock&> case_blocks;
|
||||
Bytecode::BasicBlock* default_block { nullptr };
|
||||
Bytecode::BasicBlock* entry_block_for_default { nullptr };
|
||||
Bytecode::BasicBlock* next_test_block = &generator.make_block();
|
||||
|
||||
auto has_lexical_declarations = this->has_lexical_declarations();
|
||||
|
@ -2207,22 +2207,30 @@ Bytecode::CodeGenerationErrorOr<void> SwitchStatement::generate_labelled_evaluat
|
|||
|
||||
for (auto& switch_case : m_cases) {
|
||||
auto& case_block = generator.make_block();
|
||||
auto& case_entry_block = generator.make_block();
|
||||
if (switch_case->test()) {
|
||||
generator.switch_to_basic_block(*next_test_block);
|
||||
TRY(switch_case->test()->generate_bytecode(generator));
|
||||
generator.emit<Bytecode::Op::StrictlyEquals>(discriminant_reg);
|
||||
next_test_block = &generator.make_block();
|
||||
generator.emit<Bytecode::Op::JumpConditional>().set_targets(Bytecode::Label { case_block }, Bytecode::Label { *next_test_block });
|
||||
generator.emit<Bytecode::Op::JumpConditional>().set_targets(Bytecode::Label { case_entry_block }, Bytecode::Label { *next_test_block });
|
||||
} else {
|
||||
default_block = &case_block;
|
||||
entry_block_for_default = &case_entry_block;
|
||||
}
|
||||
|
||||
// Initialize the completion value of the switch statement to empty. We can't do this in the case's basic block directly,
|
||||
// as we must not clobber the possible non-empty completion value of the previous case when falling through.
|
||||
generator.switch_to_basic_block(case_entry_block);
|
||||
generator.emit<Bytecode::Op::LoadImmediate>(js_undefined());
|
||||
generator.emit<Bytecode::Op::Jump>().set_targets(Bytecode::Label { case_block }, {});
|
||||
|
||||
case_blocks.append(case_block);
|
||||
}
|
||||
generator.switch_to_basic_block(*next_test_block);
|
||||
auto& end_block = generator.make_block();
|
||||
|
||||
if (default_block != nullptr) {
|
||||
generator.emit<Bytecode::Op::Jump>().set_targets(Bytecode::Label { *default_block }, {});
|
||||
if (entry_block_for_default != nullptr) {
|
||||
generator.emit<Bytecode::Op::Jump>().set_targets(Bytecode::Label { *entry_block_for_default }, {});
|
||||
} else {
|
||||
generator.emit<Bytecode::Op::LoadImmediate>(js_undefined());
|
||||
generator.emit<Bytecode::Op::Jump>().set_targets(Bytecode::Label { end_block }, {});
|
||||
|
@ -2232,7 +2240,6 @@ Bytecode::CodeGenerationErrorOr<void> SwitchStatement::generate_labelled_evaluat
|
|||
for (auto& switch_case : m_cases) {
|
||||
generator.switch_to_basic_block(*current_block);
|
||||
|
||||
generator.emit<Bytecode::Op::LoadImmediate>(js_undefined());
|
||||
for (auto& statement : switch_case->children()) {
|
||||
TRY(statement->generate_bytecode(generator));
|
||||
if (generator.is_current_block_terminated())
|
||||
|
|
Loading…
Reference in a new issue