LibJS/Bytecode: Dedicated instructions for postfix increment/decrement

Instead of splitting the postfix variants into ToNumeric + Inc/Dec,
we now have dedicated PostfixIncrement and PostfixDecrement instructions
that handle both outputs in one go.
This commit is contained in:
Andreas Kling 2024-02-20 11:45:01 +01:00
parent c4f49e343a
commit 9d9b737a58
Notes: sideshowbarker 2024-07-17 03:00:02 +09:00
4 changed files with 96 additions and 27 deletions

View file

@ -2373,15 +2373,22 @@ Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> UpdateExpression::g
auto reference = TRY(generator.emit_load_from_reference(*m_argument));
Optional<Bytecode::Operand> previous_value_for_postfix;
if (!m_prefixed) {
previous_value_for_postfix = Bytecode::Operand(generator.allocate_register());
generator.emit<Bytecode::Op::ToNumeric>(*previous_value_for_postfix, *reference.loaded_value);
}
if (m_op == UpdateOp::Increment)
generator.emit<Bytecode::Op::Increment>(*reference.loaded_value);
else
generator.emit<Bytecode::Op::Decrement>(*reference.loaded_value);
if (m_op == UpdateOp::Increment) {
if (m_prefixed) {
generator.emit<Bytecode::Op::Increment>(*reference.loaded_value);
} else {
previous_value_for_postfix = Bytecode::Operand(generator.allocate_register());
generator.emit<Bytecode::Op::PostfixIncrement>(*previous_value_for_postfix, *reference.loaded_value);
}
} else {
if (m_prefixed) {
generator.emit<Bytecode::Op::Decrement>(*reference.loaded_value);
} else {
previous_value_for_postfix = Bytecode::Operand(generator.allocate_register());
generator.emit<Bytecode::Op::PostfixDecrement>(*previous_value_for_postfix, *reference.loaded_value);
}
}
if (is<Identifier>(*m_argument))
(void)TRY(generator.emit_store_to_reference(static_cast<Identifier const&>(*m_argument), *reference.loaded_value));

View file

@ -91,6 +91,8 @@
O(NewString) \
O(NewTypeError) \
O(Not) \
O(PostfixDecrement) \
O(PostfixIncrement) \
O(PutById) \
O(PutByIdWithThis) \
O(PutByValue) \
@ -111,7 +113,6 @@
O(ThrowIfNotObject) \
O(ThrowIfNullish) \
O(ThrowIfTDZ) \
O(ToNumeric) \
O(Typeof) \
O(TypeofVariable) \
O(UnaryMinus) \

View file

@ -1113,6 +1113,31 @@ ThrowCompletionOr<void> Increment::execute_impl(Bytecode::Interpreter& interpret
return {};
}
ThrowCompletionOr<void> PostfixIncrement::execute_impl(Bytecode::Interpreter& interpreter) const
{
auto& vm = interpreter.vm();
auto old_value = interpreter.get(m_src);
// OPTIMIZATION: Fast path for Int32 values.
if (old_value.is_int32()) {
auto integer_value = old_value.as_i32();
if (integer_value != NumericLimits<i32>::max()) [[likely]] {
interpreter.set(m_dst, old_value);
interpreter.set(m_src, Value { integer_value + 1 });
return {};
}
}
old_value = TRY(old_value.to_numeric(vm));
interpreter.set(m_dst, old_value);
if (old_value.is_number())
interpreter.set(m_src, Value(old_value.as_double() + 1));
else
interpreter.set(m_src, BigInt::create(vm, old_value.as_bigint().big_integer().plus(Crypto::SignedBigInteger { 1 })));
return {};
}
ThrowCompletionOr<void> Decrement::execute_impl(Bytecode::Interpreter& interpreter) const
{
auto& vm = interpreter.vm();
@ -1127,6 +1152,21 @@ ThrowCompletionOr<void> Decrement::execute_impl(Bytecode::Interpreter& interpret
return {};
}
ThrowCompletionOr<void> PostfixDecrement::execute_impl(Bytecode::Interpreter& interpreter) const
{
auto& vm = interpreter.vm();
auto old_value = interpreter.get(m_src);
old_value = TRY(old_value.to_numeric(vm));
interpreter.set(m_dst, old_value);
if (old_value.is_number())
interpreter.set(m_src, Value(old_value.as_double() - 1));
else
interpreter.set(m_src, BigInt::create(vm, old_value.as_bigint().big_integer().minus(Crypto::SignedBigInteger { 1 })));
return {};
}
ThrowCompletionOr<void> Throw::execute_impl(Bytecode::Interpreter& interpreter) const
{
return throw_completion(interpreter.get(src()));
@ -1356,12 +1396,6 @@ ThrowCompletionOr<void> TypeofVariable::execute_impl(Bytecode::Interpreter& inte
return {};
}
ThrowCompletionOr<void> ToNumeric::execute_impl(Bytecode::Interpreter& interpreter) const
{
interpreter.set(dst(), TRY(interpreter.get(src()).to_numeric(interpreter.vm())));
return {};
}
ThrowCompletionOr<void> BlockDeclarationInstantiation::execute_impl(Bytecode::Interpreter& interpreter) const
{
auto& vm = interpreter.vm();
@ -1763,9 +1797,23 @@ ByteString Increment::to_byte_string_impl(Bytecode::Executable const& executable
return ByteString::formatted("Increment {}", format_operand("dst"sv, m_dst, executable));
}
ByteString Decrement::to_byte_string_impl(Bytecode::Executable const&) const
ByteString PostfixIncrement::to_byte_string_impl(Bytecode::Executable const& executable) const
{
return "Decrement";
return ByteString::formatted("PostfixIncrement {}, {}",
format_operand("dst"sv, m_dst, executable),
format_operand("src"sv, m_dst, executable));
}
ByteString Decrement::to_byte_string_impl(Bytecode::Executable const& executable) const
{
return ByteString::formatted("Decrement {}", format_operand("dst"sv, m_dst, executable));
}
ByteString PostfixDecrement::to_byte_string_impl(Bytecode::Executable const& executable) const
{
return ByteString::formatted("PostfixDecrement {}, {}",
format_operand("dst"sv, m_dst, executable),
format_operand("src"sv, m_dst, executable));
}
ByteString Throw::to_byte_string_impl(Bytecode::Executable const& executable) const
@ -1974,13 +2022,6 @@ ByteString TypeofVariable::to_byte_string_impl(Bytecode::Executable const& execu
executable.identifier_table->get(m_identifier));
}
ByteString ToNumeric::to_byte_string_impl(Bytecode::Executable const& executable) const
{
return ByteString::formatted("ToNumeric {}, {}",
format_operand("dst"sv, m_dst, executable),
format_operand("src"sv, m_src, executable));
}
ByteString BlockDeclarationInstantiation::to_byte_string_impl(Bytecode::Executable const&) const
{
return "BlockDeclarationInstantiation"sv;

View file

@ -1347,6 +1347,26 @@ private:
Operand m_dst;
};
class PostfixIncrement final : public Instruction {
public:
explicit PostfixIncrement(Operand dst, Operand src)
: Instruction(Type::PostfixIncrement, sizeof(*this))
, m_dst(dst)
, m_src(src)
{
}
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
Operand dst() const { return m_dst; }
Operand src() const { return m_src; }
private:
Operand m_dst;
Operand m_src;
};
class Decrement final : public Instruction {
public:
explicit Decrement(Operand dst)
@ -1364,10 +1384,10 @@ private:
Operand m_dst;
};
class ToNumeric final : public Instruction {
class PostfixDecrement final : public Instruction {
public:
explicit ToNumeric(Operand dst, Operand src)
: Instruction(Type::ToNumeric, sizeof(*this))
explicit PostfixDecrement(Operand dst, Operand src)
: Instruction(Type::PostfixDecrement, sizeof(*this))
, m_dst(dst)
, m_src(src)
{