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.)
This commit is contained in:
Andreas Kling 2023-06-16 10:51:40 +02:00
parent c9bd324369
commit d364d99cb8
Notes: sideshowbarker 2024-07-16 22:18:54 +09:00
4 changed files with 26 additions and 0 deletions

View file

@ -1966,6 +1966,7 @@ Bytecode::CodeGenerationErrorOr<void> UpdateExpression::generate_bytecode(Byteco
Optional<Bytecode::Register> previous_value_for_postfix_reg;
if (!m_prefixed) {
previous_value_for_postfix_reg = generator.allocate_register();
generator.emit<Bytecode::Op::ToNumeric>();
generator.emit<Bytecode::Op::Store>(*previous_value_for_postfix_reg);
}

View file

@ -88,6 +88,7 @@
O(SuperCall) \
O(Throw) \
O(ThrowIfNotObject) \
O(ToNumeric) \
O(Typeof) \
O(TypeofVariable) \
O(UnaryMinus) \

View file

@ -1091,6 +1091,12 @@ ThrowCompletionOr<void> TypeofVariable::execute_impl(Bytecode::Interpreter& inte
return {};
}
ThrowCompletionOr<void> 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;
}
}

View file

@ -835,6 +835,19 @@ public:
void replace_references_impl(Register, Register) { }
};
class ToNumeric final : public Instruction {
public:
ToNumeric()
: Instruction(Type::ToNumeric)
{
}
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) { }
};
class Throw final : public Instruction {
public:
constexpr static bool IsTerminator = true;