mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 18:42:43 +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) | ||||
|         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); | ||||
|     else | ||||
|     } else { | ||||
|         generator.perform_needed_unwinds<Bytecode::Op::Return>(); | ||||
|         generator.emit<Bytecode::Op::Return>(); | ||||
|     } | ||||
| 
 | ||||
|     return {}; | ||||
| } | ||||
|  | @ -1279,6 +1282,7 @@ Bytecode::CodeGenerationErrorOr<void> IfStatement::generate_bytecode(Bytecode::G | |||
| 
 | ||||
| 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.nearest_continuable_scope(), | ||||
|         {}); | ||||
|  | @ -1438,6 +1442,7 @@ Bytecode::CodeGenerationErrorOr<void> ThrowStatement::generate_bytecode(Bytecode | |||
| 
 | ||||
| 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.nearest_breakable_scope(), | ||||
|         {}); | ||||
|  | @ -1502,6 +1507,7 @@ Bytecode::CodeGenerationErrorOr<void> TryStatement::generate_bytecode(Bytecode:: | |||
|     auto& target_block = generator.make_block(); | ||||
|     generator.switch_to_basic_block(saved_block); | ||||
|     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); | ||||
|     TRY(m_block->generate_bytecode(generator)); | ||||
|  | @ -1514,6 +1520,7 @@ Bytecode::CodeGenerationErrorOr<void> TryStatement::generate_bytecode(Bytecode:: | |||
|             next_block = █ | ||||
|         } | ||||
|     } | ||||
|     generator.end_boundary(Bytecode::Generator::BlockBoundaryType::Unwind); | ||||
| 
 | ||||
|     generator.switch_to_basic_block(next_block ? *next_block : saved_block); | ||||
|     return {}; | ||||
|  |  | |||
|  | @ -79,11 +79,13 @@ Label Generator::nearest_continuable_scope() const | |||
| void Generator::begin_continuable_scope(Label continue_target) | ||||
| { | ||||
|     m_continuable_scopes.append(continue_target); | ||||
|     start_boundary(BlockBoundaryType::Continue); | ||||
| } | ||||
| 
 | ||||
| void Generator::end_continuable_scope() | ||||
| { | ||||
|     m_continuable_scopes.take_last(); | ||||
|     end_boundary(BlockBoundaryType::Continue); | ||||
| } | ||||
| Label Generator::nearest_breakable_scope() const | ||||
| { | ||||
|  | @ -92,11 +94,13 @@ Label Generator::nearest_breakable_scope() const | |||
| void Generator::begin_breakable_scope(Label breakable_target) | ||||
| { | ||||
|     m_breakable_scopes.append(breakable_target); | ||||
|     start_boundary(BlockBoundaryType::Break); | ||||
| } | ||||
| 
 | ||||
| void Generator::end_breakable_scope() | ||||
| { | ||||
|     m_breakable_scopes.take_last(); | ||||
|     end_boundary(BlockBoundaryType::Break); | ||||
| } | ||||
| 
 | ||||
| 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: | ||||
|     Generator(); | ||||
|     ~Generator(); | ||||
|  | @ -189,6 +219,7 @@ private: | |||
|     Vector<Label> m_continuable_scopes; | ||||
|     Vector<Label> m_breakable_scopes; | ||||
|     Vector<LexicalScope> m_variable_scopes; | ||||
|     Vector<BlockBoundaryType> m_boundaries; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Ali Mohammad Pur
						Ali Mohammad Pur