diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index 2bcdf5125c..75475a0205 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -876,6 +876,8 @@ Bytecode::CodeGenerationErrorOr ObjectExpression::generate_bytecode(Byteco auto object_reg = generator.allocate_register(); generator.emit(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 ObjectExpression::generate_bytecode(Byteco } generator.emit(object_reg); + + generator.pop_home_object(); return {}; } @@ -996,7 +1000,7 @@ Bytecode::CodeGenerationErrorOr FunctionExpression::generate_bytecode(Byte generator.emit(*name_identifier, Bytecode::Op::EnvironmentMode::Lexical, true); } - generator.emit(*this); + generator.emit_new_function(*this); if (has_name) { generator.emit(*name_identifier, Bytecode::Op::SetVariable::InitializationMode::Initialize, Bytecode::Op::EnvironmentMode::Lexical); diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.cpp b/Userland/Libraries/LibJS/Bytecode/Generator.cpp index 586809eeb7..320ba9bf52 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Generator.cpp @@ -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(function_node); + else + emit(function_node, m_home_objects.last()); +} + } diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.h b/Userland/Libraries/LibJS/Bytecode/Generator.h index 724c18b03f..f4d9dbdf84 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.h +++ b/Userland/Libraries/LibJS/Bytecode/Generator.h @@ -83,6 +83,10 @@ public: CodeGenerationErrorOr emit_store_to_reference(JS::ASTNode const&); CodeGenerationErrorOr 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 const& language_label_set); void end_continuable_scope(); void begin_breakable_scope(Label breakable_target, Vector const& language_label_set); @@ -237,6 +241,7 @@ private: Vector m_breakable_scopes; Vector m_variable_scopes; Vector m_boundaries; + Vector m_home_objects; }; } diff --git a/Userland/Libraries/LibJS/Bytecode/Op.cpp b/Userland/Libraries/LibJS/Bytecode/Op.cpp index f7f912811d..bb02103fe9 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Op.cpp @@ -732,6 +732,10 @@ ThrowCompletionOr 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(interpreter.accumulator().as_function()).set_home_object(&home_object_value.as_object()); + } return {}; } @@ -785,6 +789,12 @@ ThrowCompletionOr 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 diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index 5d1cace67e..7f04671b2f 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -777,19 +777,21 @@ private: class NewFunction final : public Instruction { public: - explicit NewFunction(FunctionNode const& function_node) + explicit NewFunction(FunctionNode const& function_node, Optional home_object = {}) : Instruction(Type::NewFunction) , m_function_node(function_node) + , m_home_object(move(home_object)) { } ThrowCompletionOr 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 m_home_object; }; class Return final : public Instruction {