mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 15:32:46 +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(); | ||||
|     generator.emit<Bytecode::Op::Store>(object_reg); | ||||
| 
 | ||||
|     generator.push_home_object(object_reg); | ||||
| 
 | ||||
|     for (auto& property : m_properties) { | ||||
|         Bytecode::Op::PropertyKind property_kind; | ||||
|         switch (property->type()) { | ||||
|  | @ -917,6 +919,8 @@ Bytecode::CodeGenerationErrorOr<void> ObjectExpression::generate_bytecode(Byteco | |||
|     } | ||||
| 
 | ||||
|     generator.emit<Bytecode::Op::Load>(object_reg); | ||||
| 
 | ||||
|     generator.pop_home_object(); | ||||
|     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::NewFunction>(*this); | ||||
|     generator.emit_new_function(*this); | ||||
| 
 | ||||
|     if (has_name) { | ||||
|         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(); | ||||
| } | ||||
| 
 | ||||
| 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_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 end_continuable_scope(); | ||||
|     void begin_breakable_scope(Label breakable_target, Vector<DeprecatedFlyString> const& language_label_set); | ||||
|  | @ -237,6 +241,7 @@ private: | |||
|     Vector<LabelableScope> m_breakable_scopes; | ||||
|     Vector<LexicalScope> m_variable_scopes; | ||||
|     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(); | ||||
|     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 {}; | ||||
| } | ||||
| 
 | ||||
|  | @ -785,6 +789,12 @@ ThrowCompletionOr<void> EnterUnwindContext::execute_impl(Bytecode::Interpreter& | |||
|     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) | ||||
| { | ||||
|     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 | ||||
| { | ||||
|     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 | ||||
|  |  | |||
|  | @ -777,19 +777,21 @@ private: | |||
| 
 | ||||
| class NewFunction final : public Instruction { | ||||
| public: | ||||
|     explicit NewFunction(FunctionNode const& function_node) | ||||
|     explicit NewFunction(FunctionNode const& function_node, Optional<Register> home_object = {}) | ||||
|         : Instruction(Type::NewFunction) | ||||
|         , m_function_node(function_node) | ||||
|         , m_home_object(move(home_object)) | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|     ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const; | ||||
|     DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; | ||||
|     void replace_references_impl(BasicBlock const&, BasicBlock const&) { } | ||||
|     void replace_references_impl(Register, Register) { } | ||||
|     void replace_references_impl(Register, Register); | ||||
| 
 | ||||
| private: | ||||
|     FunctionNode const& m_function_node; | ||||
|     Optional<Register> m_home_object; | ||||
| }; | ||||
| 
 | ||||
| class Return final : public Instruction { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling