LibJS: Add PutByNumericId and change PutById to be string key only

Previously, PutById constructed a PropertyKey from the identifier,
which coerced numeric-like strings to numbers. This moves that decision
to bytecode generation: the bytecode generator now emits PutByNumericId
for numeric keys and PutById for string keys. This removes per-execution
parsing from the interpreter.

1.4x speedup on the following microbenchmark:
```js
const o = {};
for (let i = 0; i < 10_000_000; i++) {
    o.a = 1;
    o.b = 2;
    o.c = 3;
}
```
This commit is contained in:
Aliaksandr Kalenik 2025-09-13 16:20:41 +02:00 committed by Andreas Kling
commit e81833423b
Notes: github-actions[bot] 2025-09-13 18:03:43 +00:00
7 changed files with 83 additions and 7 deletions

View file

@ -665,6 +665,7 @@ FLATTEN_ON_CLANG void Interpreter::run_bytecode(size_t entry_point)
HANDLE_INSTRUCTION(PostfixDecrement);
HANDLE_INSTRUCTION(PostfixIncrement);
HANDLE_INSTRUCTION(PutById);
HANDLE_INSTRUCTION(PutByNumericId);
HANDLE_INSTRUCTION(PutByIdWithThis);
HANDLE_INSTRUCTION(PutBySpread);
HANDLE_INSTRUCTION(PutByValue);
@ -2632,7 +2633,19 @@ ThrowCompletionOr<void> PutById::execute_impl(Bytecode::Interpreter& interpreter
auto value = interpreter.get(m_src);
auto base = interpreter.get(m_base);
auto base_identifier = interpreter.current_executable().get_identifier(m_base_identifier);
PropertyKey name = interpreter.current_executable().get_identifier(m_property);
PropertyKey name { interpreter.current_executable().get_identifier(m_property), PropertyKey::StringMayBeNumber::No };
auto& cache = interpreter.current_executable().property_lookup_caches[m_cache_index];
TRY(put_by_property_key(vm, base, base, value, base_identifier, name, m_kind, &cache));
return {};
}
ThrowCompletionOr<void> PutByNumericId::execute_impl(Bytecode::Interpreter& interpreter) const
{
auto& vm = interpreter.vm();
auto value = interpreter.get(m_src);
auto base = interpreter.get(m_base);
auto base_identifier = interpreter.current_executable().get_identifier(m_base_identifier);
PropertyKey name { m_property_index };
auto& cache = interpreter.current_executable().property_lookup_caches[m_cache_index];
TRY(put_by_property_key(vm, base, base, value, base_identifier, name, m_kind, &cache));
return {};
@ -3557,6 +3570,16 @@ ByteString PutById::to_byte_string_impl(Bytecode::Executable const& executable)
kind);
}
ByteString PutByNumericId::to_byte_string_impl(Bytecode::Executable const& executable) const
{
auto kind = property_kind_to_string(m_kind);
return ByteString::formatted("PutByNumericId {}, {}, {}, kind:{}",
format_operand("base"sv, m_base, executable),
m_property_index,
format_operand("src"sv, m_src, executable),
kind);
}
ByteString PutByIdWithThis::to_byte_string_impl(Bytecode::Executable const& executable) const
{
auto kind = property_kind_to_string(m_kind);