diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index 0266c87c9f8..69d4f58bac8 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -2373,15 +2373,22 @@ Bytecode::CodeGenerationErrorOr> UpdateExpression::g auto reference = TRY(generator.emit_load_from_reference(*m_argument)); Optional previous_value_for_postfix; - if (!m_prefixed) { - previous_value_for_postfix = Bytecode::Operand(generator.allocate_register()); - generator.emit(*previous_value_for_postfix, *reference.loaded_value); - } - if (m_op == UpdateOp::Increment) - generator.emit(*reference.loaded_value); - else - generator.emit(*reference.loaded_value); + if (m_op == UpdateOp::Increment) { + if (m_prefixed) { + generator.emit(*reference.loaded_value); + } else { + previous_value_for_postfix = Bytecode::Operand(generator.allocate_register()); + generator.emit(*previous_value_for_postfix, *reference.loaded_value); + } + } else { + if (m_prefixed) { + generator.emit(*reference.loaded_value); + } else { + previous_value_for_postfix = Bytecode::Operand(generator.allocate_register()); + generator.emit(*previous_value_for_postfix, *reference.loaded_value); + } + } if (is(*m_argument)) (void)TRY(generator.emit_store_to_reference(static_cast(*m_argument), *reference.loaded_value)); diff --git a/Userland/Libraries/LibJS/Bytecode/Instruction.h b/Userland/Libraries/LibJS/Bytecode/Instruction.h index 158f68c041d..b5ebcbe311a 100644 --- a/Userland/Libraries/LibJS/Bytecode/Instruction.h +++ b/Userland/Libraries/LibJS/Bytecode/Instruction.h @@ -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) \ diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index 50cb939283f..fc8f8c47c78 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -1113,6 +1113,31 @@ ThrowCompletionOr Increment::execute_impl(Bytecode::Interpreter& interpret return {}; } +ThrowCompletionOr 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::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 Decrement::execute_impl(Bytecode::Interpreter& interpreter) const { auto& vm = interpreter.vm(); @@ -1127,6 +1152,21 @@ ThrowCompletionOr Decrement::execute_impl(Bytecode::Interpreter& interpret return {}; } +ThrowCompletionOr 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 Throw::execute_impl(Bytecode::Interpreter& interpreter) const { return throw_completion(interpreter.get(src())); @@ -1356,12 +1396,6 @@ ThrowCompletionOr TypeofVariable::execute_impl(Bytecode::Interpreter& inte return {}; } -ThrowCompletionOr ToNumeric::execute_impl(Bytecode::Interpreter& interpreter) const -{ - interpreter.set(dst(), TRY(interpreter.get(src()).to_numeric(interpreter.vm()))); - return {}; -} - ThrowCompletionOr 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; diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index 3843964d640..f78690f5b0a 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -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 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) {