mirror of
https://github.com/RGBCube/serenity
synced 2025-05-22 15:05: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:
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