mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 01:02:45 +00:00 
			
		
		
		
	LibJS/Bytecode: Set "home object" of functions within object expression
We manage this by having a stack of home objects in Generator, and then adding an optional home object parameter to the NewFunction instruction.
This commit is contained in:
		
							parent
							
								
									a33af174b2
								
							
						
					
					
						commit
						c9bd324369
					
				
					 5 changed files with 45 additions and 4 deletions
				
			
		|  | @ -876,6 +876,8 @@ Bytecode::CodeGenerationErrorOr<void> ObjectExpression::generate_bytecode(Byteco | ||||||
|     auto object_reg = generator.allocate_register(); |     auto object_reg = generator.allocate_register(); | ||||||
|     generator.emit<Bytecode::Op::Store>(object_reg); |     generator.emit<Bytecode::Op::Store>(object_reg); | ||||||
| 
 | 
 | ||||||
|  |     generator.push_home_object(object_reg); | ||||||
|  | 
 | ||||||
|     for (auto& property : m_properties) { |     for (auto& property : m_properties) { | ||||||
|         Bytecode::Op::PropertyKind property_kind; |         Bytecode::Op::PropertyKind property_kind; | ||||||
|         switch (property->type()) { |         switch (property->type()) { | ||||||
|  | @ -917,6 +919,8 @@ Bytecode::CodeGenerationErrorOr<void> ObjectExpression::generate_bytecode(Byteco | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     generator.emit<Bytecode::Op::Load>(object_reg); |     generator.emit<Bytecode::Op::Load>(object_reg); | ||||||
|  | 
 | ||||||
|  |     generator.pop_home_object(); | ||||||
|     return {}; |     return {}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -996,7 +1000,7 @@ Bytecode::CodeGenerationErrorOr<void> FunctionExpression::generate_bytecode(Byte | ||||||
|         generator.emit<Bytecode::Op::CreateVariable>(*name_identifier, Bytecode::Op::EnvironmentMode::Lexical, true); |         generator.emit<Bytecode::Op::CreateVariable>(*name_identifier, Bytecode::Op::EnvironmentMode::Lexical, true); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     generator.emit<Bytecode::Op::NewFunction>(*this); |     generator.emit_new_function(*this); | ||||||
| 
 | 
 | ||||||
|     if (has_name) { |     if (has_name) { | ||||||
|         generator.emit<Bytecode::Op::SetVariable>(*name_identifier, Bytecode::Op::SetVariable::InitializationMode::Initialize, Bytecode::Op::EnvironmentMode::Lexical); |         generator.emit<Bytecode::Op::SetVariable>(*name_identifier, Bytecode::Op::SetVariable::InitializationMode::Initialize, Bytecode::Op::EnvironmentMode::Lexical); | ||||||
|  |  | ||||||
|  | @ -448,4 +448,22 @@ void Generator::generate_continue(DeprecatedFlyString const& continue_label) | ||||||
|     VERIFY_NOT_REACHED(); |     VERIFY_NOT_REACHED(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void Generator::push_home_object(Register register_) | ||||||
|  | { | ||||||
|  |     m_home_objects.append(register_); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Generator::pop_home_object() | ||||||
|  | { | ||||||
|  |     m_home_objects.take_last(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Generator::emit_new_function(FunctionNode const& function_node) | ||||||
|  | { | ||||||
|  |     if (m_home_objects.is_empty()) | ||||||
|  |         emit<Op::NewFunction>(function_node); | ||||||
|  |     else | ||||||
|  |         emit<Op::NewFunction>(function_node, m_home_objects.last()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -83,6 +83,10 @@ public: | ||||||
|     CodeGenerationErrorOr<void> emit_store_to_reference(JS::ASTNode const&); |     CodeGenerationErrorOr<void> emit_store_to_reference(JS::ASTNode const&); | ||||||
|     CodeGenerationErrorOr<void> emit_delete_reference(JS::ASTNode const&); |     CodeGenerationErrorOr<void> emit_delete_reference(JS::ASTNode const&); | ||||||
| 
 | 
 | ||||||
|  |     void push_home_object(Register); | ||||||
|  |     void pop_home_object(); | ||||||
|  |     void emit_new_function(JS::FunctionNode const&); | ||||||
|  | 
 | ||||||
|     void begin_continuable_scope(Label continue_target, Vector<DeprecatedFlyString> const& language_label_set); |     void begin_continuable_scope(Label continue_target, Vector<DeprecatedFlyString> const& language_label_set); | ||||||
|     void end_continuable_scope(); |     void end_continuable_scope(); | ||||||
|     void begin_breakable_scope(Label breakable_target, Vector<DeprecatedFlyString> const& language_label_set); |     void begin_breakable_scope(Label breakable_target, Vector<DeprecatedFlyString> const& language_label_set); | ||||||
|  | @ -237,6 +241,7 @@ private: | ||||||
|     Vector<LabelableScope> m_breakable_scopes; |     Vector<LabelableScope> m_breakable_scopes; | ||||||
|     Vector<LexicalScope> m_variable_scopes; |     Vector<LexicalScope> m_variable_scopes; | ||||||
|     Vector<BlockBoundaryType> m_boundaries; |     Vector<BlockBoundaryType> m_boundaries; | ||||||
|  |     Vector<Register> m_home_objects; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -732,6 +732,10 @@ ThrowCompletionOr<void> NewFunction::execute_impl(Bytecode::Interpreter& interpr | ||||||
| { | { | ||||||
|     auto& vm = interpreter.vm(); |     auto& vm = interpreter.vm(); | ||||||
|     interpreter.accumulator() = ECMAScriptFunctionObject::create(interpreter.realm(), m_function_node.name(), m_function_node.source_text(), m_function_node.body(), m_function_node.parameters(), m_function_node.function_length(), vm.lexical_environment(), vm.running_execution_context().private_environment, m_function_node.kind(), m_function_node.is_strict_mode(), m_function_node.might_need_arguments_object(), m_function_node.contains_direct_call_to_eval(), m_function_node.is_arrow_function()); |     interpreter.accumulator() = ECMAScriptFunctionObject::create(interpreter.realm(), m_function_node.name(), m_function_node.source_text(), m_function_node.body(), m_function_node.parameters(), m_function_node.function_length(), vm.lexical_environment(), vm.running_execution_context().private_environment, m_function_node.kind(), m_function_node.is_strict_mode(), m_function_node.might_need_arguments_object(), m_function_node.contains_direct_call_to_eval(), m_function_node.is_arrow_function()); | ||||||
|  |     if (m_home_object.has_value()) { | ||||||
|  |         auto home_object_value = interpreter.reg(m_home_object.value()); | ||||||
|  |         static_cast<ECMAScriptFunctionObject&>(interpreter.accumulator().as_function()).set_home_object(&home_object_value.as_object()); | ||||||
|  |     } | ||||||
|     return {}; |     return {}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -785,6 +789,12 @@ ThrowCompletionOr<void> EnterUnwindContext::execute_impl(Bytecode::Interpreter& | ||||||
|     return {}; |     return {}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void NewFunction::replace_references_impl(Register from, Register to) | ||||||
|  | { | ||||||
|  |     if (m_home_object == from) | ||||||
|  |         m_home_object = to; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void EnterUnwindContext::replace_references_impl(BasicBlock const& from, BasicBlock const& to) | void EnterUnwindContext::replace_references_impl(BasicBlock const& from, BasicBlock const& to) | ||||||
| { | { | ||||||
|     if (&m_entry_point.block() == &from) |     if (&m_entry_point.block() == &from) | ||||||
|  | @ -1270,7 +1280,9 @@ DeprecatedString SuperCall::to_deprecated_string_impl(Bytecode::Executable const | ||||||
| 
 | 
 | ||||||
| DeprecatedString NewFunction::to_deprecated_string_impl(Bytecode::Executable const&) const | DeprecatedString NewFunction::to_deprecated_string_impl(Bytecode::Executable const&) const | ||||||
| { | { | ||||||
|     return "NewFunction"; |     if (m_home_object.has_value()) | ||||||
|  |         return DeprecatedString::formatted("NewFunction home_object:{}", m_home_object.value()); | ||||||
|  |     return "NewFunction"sv; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| DeprecatedString NewClass::to_deprecated_string_impl(Bytecode::Executable const&) const | DeprecatedString NewClass::to_deprecated_string_impl(Bytecode::Executable const&) const | ||||||
|  |  | ||||||
|  | @ -777,19 +777,21 @@ private: | ||||||
| 
 | 
 | ||||||
| class NewFunction final : public Instruction { | class NewFunction final : public Instruction { | ||||||
| public: | public: | ||||||
|     explicit NewFunction(FunctionNode const& function_node) |     explicit NewFunction(FunctionNode const& function_node, Optional<Register> home_object = {}) | ||||||
|         : Instruction(Type::NewFunction) |         : Instruction(Type::NewFunction) | ||||||
|         , m_function_node(function_node) |         , m_function_node(function_node) | ||||||
|  |         , m_home_object(move(home_object)) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const; |     ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const; | ||||||
|     DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; |     DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; | ||||||
|     void replace_references_impl(BasicBlock const&, BasicBlock const&) { } |     void replace_references_impl(BasicBlock const&, BasicBlock const&) { } | ||||||
|     void replace_references_impl(Register, Register) { } |     void replace_references_impl(Register, Register); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     FunctionNode const& m_function_node; |     FunctionNode const& m_function_node; | ||||||
|  |     Optional<Register> m_home_object; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class Return final : public Instruction { | class Return final : public Instruction { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling