mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 15:40:19 +00:00
LibJS/Bytecode: Always resolve this
binding into dedicated register
We already have a dedicated register slot for `this`, so instead of having ResolveThisBinding take a `dst` operand, just write the value directly into the `this` register every time.
This commit is contained in:
parent
9d57b55f24
commit
507f83a615
Notes:
sideshowbarker
2024-07-17 01:27:18 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/507f83a615 Pull-request: https://github.com/SerenityOS/serenity/pull/24504
6 changed files with 35 additions and 39 deletions
|
@ -58,8 +58,8 @@ public:
|
|||
auto const& source_map() const { return m_source_map; }
|
||||
void add_source_map_entry(size_t bytecode_offset, SourceRecord const& source_record) { m_source_map.set(bytecode_offset, source_record); }
|
||||
|
||||
auto const& this_() const { return m_this; }
|
||||
void set_this(ScopedOperand operand) { m_this = operand; }
|
||||
[[nodiscard]] bool has_resolved_this() const { return m_has_resolved_this; }
|
||||
void set_has_resolved_this() { m_has_resolved_this = true; }
|
||||
|
||||
[[nodiscard]] size_t last_instruction_start_offset() const { return m_last_instruction_start_offset; }
|
||||
void set_last_instruction_start_offset(size_t offset) { m_last_instruction_start_offset = offset; }
|
||||
|
@ -73,11 +73,10 @@ private:
|
|||
BasicBlock const* m_finalizer { nullptr };
|
||||
String m_name;
|
||||
bool m_terminated { false };
|
||||
bool m_has_resolved_this { false };
|
||||
|
||||
HashMap<size_t, SourceRecord> m_source_map;
|
||||
|
||||
Optional<ScopedOperand> m_this;
|
||||
|
||||
size_t m_last_instruction_start_offset { 0 };
|
||||
};
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ Generator::Generator(VM& vm, GCPtr<ECMAScriptFunctionObject const> function, Mus
|
|||
, m_regex_table(make<RegexTable>())
|
||||
, m_constants(vm.heap())
|
||||
, m_accumulator(*this, Operand(Register::accumulator()))
|
||||
, m_this_value(*this, Operand(Register::this_value()))
|
||||
, m_must_propagate_completion(must_propagate_completion == MustPropagateCompletion::Yes)
|
||||
, m_function(function)
|
||||
{
|
||||
|
@ -571,8 +572,7 @@ CodeGenerationErrorOr<Generator::ReferenceOperands> Generator::emit_super_refere
|
|||
// https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation
|
||||
// 1. Let env be GetThisEnvironment().
|
||||
// 2. Let actualThis be ? env.GetThisBinding().
|
||||
auto actual_this = allocate_register();
|
||||
emit<Bytecode::Op::ResolveThisBinding>(actual_this);
|
||||
auto actual_this = get_this();
|
||||
|
||||
Optional<ScopedOperand> computed_property_value;
|
||||
|
||||
|
@ -1081,16 +1081,16 @@ void Generator::set_local_initialized(u32 local_index)
|
|||
|
||||
ScopedOperand Generator::get_this(Optional<ScopedOperand> preferred_dst)
|
||||
{
|
||||
if (m_current_basic_block->this_().has_value())
|
||||
return m_current_basic_block->this_().value();
|
||||
if (m_root_basic_blocks[0]->this_().has_value()) {
|
||||
m_current_basic_block->set_this(m_root_basic_blocks[0]->this_().value());
|
||||
return m_root_basic_blocks[0]->this_().value();
|
||||
if (m_current_basic_block->has_resolved_this())
|
||||
return this_value();
|
||||
if (m_root_basic_blocks[0]->has_resolved_this()) {
|
||||
m_current_basic_block->set_has_resolved_this();
|
||||
return this_value();
|
||||
}
|
||||
auto dst = preferred_dst.has_value() ? preferred_dst.value() : allocate_register();
|
||||
emit<Bytecode::Op::ResolveThisBinding>(dst);
|
||||
m_current_basic_block->set_this(dst);
|
||||
return dst;
|
||||
emit<Bytecode::Op::ResolveThisBinding>();
|
||||
m_current_basic_block->set_has_resolved_this();
|
||||
return this_value();
|
||||
}
|
||||
|
||||
ScopedOperand Generator::accumulator()
|
||||
|
@ -1098,6 +1098,11 @@ ScopedOperand Generator::accumulator()
|
|||
return m_accumulator;
|
||||
}
|
||||
|
||||
ScopedOperand Generator::this_value()
|
||||
{
|
||||
return m_this_value;
|
||||
}
|
||||
|
||||
bool Generator::fuse_compare_and_jump(ScopedOperand const& condition, Label true_target, Label false_target)
|
||||
{
|
||||
auto& last_instruction = *reinterpret_cast<Instruction const*>(m_current_basic_block->data() + m_current_basic_block->last_instruction_start_offset());
|
||||
|
|
|
@ -46,6 +46,7 @@ public:
|
|||
[[nodiscard]] ScopedOperand allocate_register();
|
||||
[[nodiscard]] ScopedOperand local(u32 local_index);
|
||||
[[nodiscard]] ScopedOperand accumulator();
|
||||
[[nodiscard]] ScopedOperand this_value();
|
||||
|
||||
void free_register(Register);
|
||||
|
||||
|
@ -377,6 +378,7 @@ private:
|
|||
MarkedVector<Value> m_constants;
|
||||
|
||||
ScopedOperand m_accumulator;
|
||||
ScopedOperand m_this_value;
|
||||
Vector<Register> m_free_registers;
|
||||
|
||||
u32 m_next_register { Register::reserved_register_count };
|
||||
|
|
|
@ -1563,7 +1563,8 @@ ThrowCompletionOr<void> DeleteByIdWithThis::execute_impl(Bytecode::Interpreter&
|
|||
ThrowCompletionOr<void> ResolveThisBinding::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto& cached_this_value = interpreter.reg(Register::this_value());
|
||||
if (cached_this_value.is_empty()) {
|
||||
if (!cached_this_value.is_empty())
|
||||
return {};
|
||||
// OPTIMIZATION: Because the value of 'this' cannot be reassigned during a function execution, it's
|
||||
// resolved once and then saved for subsequent use.
|
||||
auto& running_execution_context = interpreter.running_execution_context();
|
||||
|
@ -1573,8 +1574,6 @@ ThrowCompletionOr<void> ResolveThisBinding::execute_impl(Bytecode::Interpreter&
|
|||
auto& vm = interpreter.vm();
|
||||
cached_this_value = TRY(vm.resolve_this_binding());
|
||||
}
|
||||
}
|
||||
interpreter.set(dst(), cached_this_value);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -2655,9 +2654,9 @@ ByteString IteratorNext::to_byte_string_impl(Executable const& executable) const
|
|||
format_operand("iterator_record"sv, m_iterator_record, executable));
|
||||
}
|
||||
|
||||
ByteString ResolveThisBinding::to_byte_string_impl(Bytecode::Executable const& executable) const
|
||||
ByteString ResolveThisBinding::to_byte_string_impl(Bytecode::Executable const&) const
|
||||
{
|
||||
return ByteString::formatted("ResolveThisBinding {}", format_operand("dst"sv, m_dst, executable));
|
||||
return "ResolveThisBinding"sv;
|
||||
}
|
||||
|
||||
ByteString ResolveSuperBase::to_byte_string_impl(Bytecode::Executable const& executable) const
|
||||
|
|
|
@ -2550,23 +2550,14 @@ private:
|
|||
|
||||
class ResolveThisBinding final : public Instruction {
|
||||
public:
|
||||
explicit ResolveThisBinding(Operand dst)
|
||||
ResolveThisBinding()
|
||||
: Instruction(Type::ResolveThisBinding)
|
||||
, m_dst(dst)
|
||||
{
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void visit_operands_impl(Function<void(Operand&)> visitor)
|
||||
{
|
||||
visitor(m_dst);
|
||||
}
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
|
||||
private:
|
||||
Operand m_dst;
|
||||
void visit_operands_impl(Function<void(Operand&)>) { }
|
||||
};
|
||||
|
||||
class ResolveSuperBase final : public Instruction {
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace JS::Bytecode {
|
|||
|
||||
ScopedOperandImpl::~ScopedOperandImpl()
|
||||
{
|
||||
if (!m_generator.is_finished() && m_operand.is_register() && m_operand.as_register().index() != 0)
|
||||
if (!m_generator.is_finished() && m_operand.is_register() && m_operand.as_register().index() >= Register::reserved_register_count)
|
||||
m_generator.free_register(m_operand.as_register());
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue