LibJS: Split PutBy* instructions into specialized per-kind variants

This allows the compiler to fold away lots of unused code for each kind.

1.10x speed-up on MicroBench/pic-add-own.js :^)
This commit is contained in:
Andreas Kling 2025-10-10 12:09:34 +02:00 committed by Andreas Kling
commit b47f8f94fe
Notes: github-actions[bot] 2025-10-11 18:10:13 +00:00
5 changed files with 439 additions and 305 deletions

View file

@ -1205,109 +1205,153 @@ private:
Operand m_src;
};
class PutById final : public Instruction {
public:
explicit PutById(Operand base, IdentifierTableIndex property, Operand src, PutKind kind, u32 cache_index, Optional<IdentifierTableIndex> base_identifier = {})
: Instruction(Type::PutById)
, m_base(base)
, m_property(property)
, m_src(src)
, m_kind(kind)
, m_cache_index(cache_index)
, m_base_identifier(move(base_identifier))
{
}
#define DECLARE_PUT_KIND_BY_ID(kind) \
class Put##kind##ById final : public Instruction { \
public: \
explicit Put##kind##ById(Operand base, IdentifierTableIndex property, Operand src, u32 cache_index, Optional<IdentifierTableIndex> base_identifier = {}) \
: Instruction(Type::Put##kind##ById) \
, m_base(base) \
, m_property(property) \
, m_src(src) \
, m_cache_index(cache_index) \
, m_base_identifier(move(base_identifier)) \
{ \
} \
\
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const; \
ByteString to_byte_string_impl(Bytecode::Executable const&) const; \
void visit_operands_impl(Function<void(Operand&)> visitor) \
{ \
visitor(m_base); \
visitor(m_src); \
} \
\
Operand base() const { return m_base; } \
IdentifierTableIndex property() const { return m_property; } \
Operand src() const { return m_src; } \
u32 cache_index() const { return m_cache_index; } \
\
private: \
Operand m_base; \
IdentifierTableIndex m_property; \
Operand m_src; \
u32 m_cache_index { 0 }; \
Optional<IdentifierTableIndex> m_base_identifier {}; \
};
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
void visit_operands_impl(Function<void(Operand&)> visitor)
{
visitor(m_base);
visitor(m_src);
}
JS_ENUMERATE_PUT_KINDS(DECLARE_PUT_KIND_BY_ID)
Operand base() const { return m_base; }
IdentifierTableIndex property() const { return m_property; }
Operand src() const { return m_src; }
PutKind kind() const { return m_kind; }
u32 cache_index() const { return m_cache_index; }
#define DECLARE_PUT_KIND_BY_NUMERIC_ID(kind) \
class Put##kind##ByNumericId final : public Instruction { \
public: \
explicit Put##kind##ByNumericId(Operand base, u32 property, Operand src, u32 cache_index, Optional<IdentifierTableIndex> base_identifier = {}) \
: Instruction(Type::Put##kind##ByNumericId) \
, m_base(base) \
, m_property(property) \
, m_src(src) \
, m_cache_index(cache_index) \
, m_base_identifier(move(base_identifier)) \
{ \
} \
\
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const; \
ByteString to_byte_string_impl(Bytecode::Executable const&) const; \
void visit_operands_impl(Function<void(Operand&)> visitor) \
{ \
visitor(m_base); \
visitor(m_src); \
} \
\
Operand base() const { return m_base; } \
u32 property() const { return m_property; } \
Operand src() const { return m_src; } \
u32 cache_index() const { return m_cache_index; } \
\
private: \
Operand m_base; \
u32 m_property; \
Operand m_src; \
u32 m_cache_index { 0 }; \
Optional<IdentifierTableIndex> m_base_identifier {}; \
};
private:
Operand m_base;
IdentifierTableIndex m_property;
Operand m_src;
PutKind m_kind;
u32 m_cache_index { 0 };
Optional<IdentifierTableIndex> m_base_identifier {};
};
JS_ENUMERATE_PUT_KINDS(DECLARE_PUT_KIND_BY_NUMERIC_ID)
class PutByNumericId final : public Instruction {
public:
explicit PutByNumericId(Operand base, u64 property_index, Operand src, PutKind kind, u32 cache_index, Optional<IdentifierTableIndex> base_identifier = {})
: Instruction(Type::PutByNumericId)
, m_base(base)
, m_property_index(property_index)
, m_src(src)
, m_kind(kind)
, m_cache_index(cache_index)
, m_base_identifier(move(base_identifier))
{
}
#define DECLARE_PUT_KIND_BY_ID_WITH_THIS(kind) \
class Put##kind##ByIdWithThis final : public Instruction { \
public: \
Put##kind##ByIdWithThis(Operand base, Operand this_value, IdentifierTableIndex property, Operand src, u32 cache_index) \
: Instruction(Type::Put##kind##ByIdWithThis) \
, m_base(base) \
, m_this_value(this_value) \
, m_property(property) \
, m_src(src) \
, m_cache_index(cache_index) \
{ \
} \
\
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const; \
ByteString to_byte_string_impl(Bytecode::Executable const&) const; \
void visit_operands_impl(Function<void(Operand&)> visitor) \
{ \
visitor(m_base); \
visitor(m_this_value); \
visitor(m_src); \
} \
\
Operand base() const { return m_base; } \
Operand this_value() const { return m_this_value; } \
IdentifierTableIndex property() const { return m_property; } \
Operand src() const { return m_src; } \
u32 cache_index() const { return m_cache_index; } \
\
private: \
Operand m_base; \
Operand m_this_value; \
IdentifierTableIndex m_property; \
Operand m_src; \
u32 m_cache_index { 0 }; \
};
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
void visit_operands_impl(Function<void(Operand&)> visitor)
{
visitor(m_base);
visitor(m_src);
}
JS_ENUMERATE_PUT_KINDS(DECLARE_PUT_KIND_BY_ID_WITH_THIS)
private:
Operand m_base;
u64 m_property_index;
Operand m_src;
PutKind m_kind;
u32 m_cache_index { 0 };
Optional<IdentifierTableIndex> m_base_identifier {};
};
#define DECLARE_PUT_KIND_BY_NUMERIC_ID_WITH_THIS(kind) \
class Put##kind##ByNumericIdWithThis final : public Instruction { \
public: \
Put##kind##ByNumericIdWithThis(Operand base, Operand this_value, u32 property, Operand src, u32 cache_index) \
: Instruction(Type::Put##kind##ByNumericIdWithThis) \
, m_base(base) \
, m_this_value(this_value) \
, m_property(property) \
, m_src(src) \
, m_cache_index(cache_index) \
{ \
} \
\
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const; \
ByteString to_byte_string_impl(Bytecode::Executable const&) const; \
void visit_operands_impl(Function<void(Operand&)> visitor) \
{ \
visitor(m_base); \
visitor(m_this_value); \
visitor(m_src); \
} \
\
Operand base() const { return m_base; } \
Operand this_value() const { return m_this_value; } \
u32 property() const { return m_property; } \
Operand src() const { return m_src; } \
u32 cache_index() const { return m_cache_index; } \
\
private: \
Operand m_base; \
Operand m_this_value; \
u32 m_property; \
Operand m_src; \
u32 m_cache_index { 0 }; \
};
class PutByIdWithThis final : public Instruction {
public:
PutByIdWithThis(Operand base, Operand this_value, IdentifierTableIndex property, Operand src, PutKind kind, u32 cache_index)
: Instruction(Type::PutByIdWithThis)
, m_base(base)
, m_this_value(this_value)
, m_property(property)
, m_src(src)
, m_kind(kind)
, m_cache_index(cache_index)
{
}
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
void visit_operands_impl(Function<void(Operand&)> visitor)
{
visitor(m_base);
visitor(m_this_value);
visitor(m_src);
}
Operand base() const { return m_base; }
Operand this_value() const { return m_this_value; }
IdentifierTableIndex property() const { return m_property; }
Operand src() const { return m_src; }
PutKind kind() const { return m_kind; }
u32 cache_index() const { return m_cache_index; }
private:
Operand m_base;
Operand m_this_value;
IdentifierTableIndex m_property;
Operand m_src;
PutKind m_kind;
u32 m_cache_index { 0 };
};
JS_ENUMERATE_PUT_KINDS(DECLARE_PUT_KIND_BY_NUMERIC_ID_WITH_THIS)
class PutPrivateById final : public Instruction {
public:
@ -1461,75 +1505,75 @@ private:
Operand m_this_value;
};
class PutByValue final : public Instruction {
public:
PutByValue(Operand base, Operand property, Operand src, PutKind kind = PutKind::Normal, Optional<IdentifierTableIndex> base_identifier = {})
: Instruction(Type::PutByValue)
, m_base(base)
, m_property(property)
, m_src(src)
, m_kind(kind)
, m_base_identifier(move(base_identifier))
{
}
#define DECLARE_PUT_KIND_BY_VALUE(kind) \
class Put##kind##ByValue final : public Instruction { \
public: \
Put##kind##ByValue(Operand base, Operand property, Operand src, Optional<IdentifierTableIndex> base_identifier = {}) \
: Instruction(Type::Put##kind##ByValue) \
, m_base(base) \
, m_property(property) \
, m_src(src) \
, m_base_identifier(move(base_identifier)) \
{ \
} \
\
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const; \
ByteString to_byte_string_impl(Bytecode::Executable const&) const; \
void visit_operands_impl(Function<void(Operand&)> visitor) \
{ \
visitor(m_base); \
visitor(m_property); \
visitor(m_src); \
} \
\
Operand base() const { return m_base; } \
Operand property() const { return m_property; } \
Operand src() const { return m_src; } \
\
private: \
Operand m_base; \
Operand m_property; \
Operand m_src; \
Optional<IdentifierTableIndex> m_base_identifier; \
};
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
void visit_operands_impl(Function<void(Operand&)> visitor)
{
visitor(m_base);
visitor(m_property);
visitor(m_src);
}
JS_ENUMERATE_PUT_KINDS(DECLARE_PUT_KIND_BY_VALUE)
Operand base() const { return m_base; }
Operand property() const { return m_property; }
Operand src() const { return m_src; }
PutKind kind() const { return m_kind; }
#define DECLARE_PUT_KIND_BY_VALUE_WITH_THIS(kind) \
class Put##kind##ByValueWithThis final : public Instruction { \
public: \
Put##kind##ByValueWithThis(Operand base, Operand property, Operand this_value, Operand src) \
: Instruction(Type::Put##kind##ByValueWithThis) \
, m_base(base) \
, m_property(property) \
, m_this_value(this_value) \
, m_src(src) \
{ \
} \
\
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const; \
ByteString to_byte_string_impl(Bytecode::Executable const&) const; \
void visit_operands_impl(Function<void(Operand&)> visitor) \
{ \
visitor(m_base); \
visitor(m_property); \
visitor(m_this_value); \
visitor(m_src); \
} \
\
Operand base() const { return m_base; } \
Operand property() const { return m_property; } \
Operand this_value() const { return m_this_value; } \
Operand src() const { return m_src; } \
\
private: \
Operand m_base; \
Operand m_property; \
Operand m_this_value; \
Operand m_src; \
};
private:
Operand m_base;
Operand m_property;
Operand m_src;
PutKind m_kind;
Optional<IdentifierTableIndex> m_base_identifier;
};
class PutByValueWithThis final : public Instruction {
public:
PutByValueWithThis(Operand base, Operand property, Operand this_value, Operand src, PutKind kind = PutKind::Normal)
: Instruction(Type::PutByValueWithThis)
, m_base(base)
, m_property(property)
, m_this_value(this_value)
, m_src(src)
, m_kind(kind)
{
}
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
void visit_operands_impl(Function<void(Operand&)> visitor)
{
visitor(m_base);
visitor(m_property);
visitor(m_this_value);
visitor(m_src);
}
Operand base() const { return m_base; }
Operand property() const { return m_property; }
Operand this_value() const { return m_this_value; }
Operand src() const { return m_src; }
PutKind kind() const { return m_kind; }
private:
Operand m_base;
Operand m_property;
Operand m_this_value;
Operand m_src;
PutKind m_kind;
};
JS_ENUMERATE_PUT_KINDS(DECLARE_PUT_KIND_BY_VALUE_WITH_THIS)
class DeleteByValue final : public Instruction {
public: