1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-22 14:35:07 +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:
Andreas Kling 2023-06-16 10:25:05 +02:00
parent a33af174b2
commit c9bd324369
5 changed files with 45 additions and 4 deletions

View file

@ -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);

View file

@ -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());
}
} }

View file

@ -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;
}; };
} }

View file

@ -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

View file

@ -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 {