From d364d99cb86561b1c2e3683157cd112b7ed1bcc8 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 16 Jun 2023 10:51:40 +0200 Subject: [PATCH] LibJS/Bytecode: Perform ToNumeric on accumulator before postfix inc/dec This ensures we get the expected behavior of code like: let a = [] let b = a++ (Where b should be 0, not [], because JavaScript.) --- Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp | 1 + Userland/Libraries/LibJS/Bytecode/Instruction.h | 1 + Userland/Libraries/LibJS/Bytecode/Op.cpp | 11 +++++++++++ Userland/Libraries/LibJS/Bytecode/Op.h | 13 +++++++++++++ 4 files changed, 26 insertions(+) diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index 75475a0205..5cbd85f117 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -1966,6 +1966,7 @@ Bytecode::CodeGenerationErrorOr UpdateExpression::generate_bytecode(Byteco Optional previous_value_for_postfix_reg; if (!m_prefixed) { previous_value_for_postfix_reg = generator.allocate_register(); + generator.emit(); generator.emit(*previous_value_for_postfix_reg); } diff --git a/Userland/Libraries/LibJS/Bytecode/Instruction.h b/Userland/Libraries/LibJS/Bytecode/Instruction.h index b9c79726a9..a581d9af22 100644 --- a/Userland/Libraries/LibJS/Bytecode/Instruction.h +++ b/Userland/Libraries/LibJS/Bytecode/Instruction.h @@ -88,6 +88,7 @@ O(SuperCall) \ O(Throw) \ O(ThrowIfNotObject) \ + O(ToNumeric) \ O(Typeof) \ O(TypeofVariable) \ O(UnaryMinus) \ diff --git a/Userland/Libraries/LibJS/Bytecode/Op.cpp b/Userland/Libraries/LibJS/Bytecode/Op.cpp index bb02103fe9..7ffde48f20 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Op.cpp @@ -1091,6 +1091,12 @@ ThrowCompletionOr TypeofVariable::execute_impl(Bytecode::Interpreter& inte return {}; } +ThrowCompletionOr ToNumeric::execute_impl(Bytecode::Interpreter& interpreter) const +{ + interpreter.accumulator() = TRY(interpreter.accumulator().to_numeric(interpreter.vm())); + return {}; +} + DeprecatedString Load::to_deprecated_string_impl(Bytecode::Executable const&) const { return DeprecatedString::formatted("Load {}", m_src); @@ -1448,4 +1454,9 @@ DeprecatedString TypeofVariable::to_deprecated_string_impl(Bytecode::Executable return DeprecatedString::formatted("TypeofVariable {} ({})", m_identifier, executable.identifier_table->get(m_identifier)); } +DeprecatedString ToNumeric::to_deprecated_string_impl(Bytecode::Executable const&) const +{ + return "ToNumeric"sv; +} + } diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index 7f04671b2f..11449abec8 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -835,6 +835,19 @@ public: void replace_references_impl(Register, Register) { } }; +class ToNumeric final : public Instruction { +public: + ToNumeric() + : Instruction(Type::ToNumeric) + { + } + + ThrowCompletionOr 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) { } +}; + class Throw final : public Instruction { public: constexpr static bool IsTerminator = true;