mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 18:08:12 +00:00
LibJS: Introduce Builtins
Builtins are functions that can be detected during bytecode generation and enable fast-paths in the JIT.
This commit is contained in:
parent
b9141d85d8
commit
86b85aa68b
13 changed files with 191 additions and 4 deletions
|
@ -1521,6 +1521,8 @@ Bytecode::CodeGenerationErrorOr<void> CallExpression::generate_bytecode(Bytecode
|
|||
generator.emit<Bytecode::Op::LoadImmediate>(js_undefined());
|
||||
generator.emit<Bytecode::Op::Store>(this_reg);
|
||||
|
||||
Optional<Bytecode::Builtin> builtin;
|
||||
|
||||
if (is<NewExpression>(this)) {
|
||||
TRY(m_callee->generate_bytecode(generator));
|
||||
generator.emit<Bytecode::Op::Store>(callee_reg);
|
||||
|
@ -1528,6 +1530,7 @@ Bytecode::CodeGenerationErrorOr<void> CallExpression::generate_bytecode(Bytecode
|
|||
auto& member_expression = static_cast<MemberExpression const&>(*m_callee);
|
||||
TRY(get_base_and_value_from_member_expression(generator, member_expression, this_reg));
|
||||
generator.emit<Bytecode::Op::Store>(callee_reg);
|
||||
builtin = Bytecode::get_builtin(member_expression);
|
||||
} else if (is<OptionalChain>(*m_callee)) {
|
||||
auto& optional_chain = static_cast<OptionalChain const&>(*m_callee);
|
||||
TRY(generate_optional_chain(generator, optional_chain, callee_reg, this_reg));
|
||||
|
@ -1581,7 +1584,7 @@ Bytecode::CodeGenerationErrorOr<void> CallExpression::generate_bytecode(Bytecode
|
|||
generator.emit<Bytecode::Op::Store>(Bytecode::Register { first_argument_reg.value().index() + register_offset });
|
||||
register_offset += 1;
|
||||
}
|
||||
generator.emit<Bytecode::Op::Call>(call_type, callee_reg, this_reg, first_argument_reg.value_or(Bytecode::Register { 0 }), arguments().size(), expression_string_index);
|
||||
generator.emit<Bytecode::Op::Call>(call_type, callee_reg, this_reg, first_argument_reg.value_or(Bytecode::Register { 0 }), arguments().size(), expression_string_index, builtin);
|
||||
}
|
||||
|
||||
return {};
|
||||
|
|
26
Userland/Libraries/LibJS/Bytecode/Builtins.cpp
Normal file
26
Userland/Libraries/LibJS/Bytecode/Builtins.cpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Simon Wanner <simon@skyrising.xyz>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/AST.h>
|
||||
#include <LibJS/Bytecode/Builtins.h>
|
||||
|
||||
namespace JS::Bytecode {
|
||||
|
||||
Optional<Builtin> get_builtin(MemberExpression const& expression)
|
||||
{
|
||||
if (expression.is_computed() || !expression.object().is_identifier() || !expression.property().is_identifier())
|
||||
return {};
|
||||
auto base_name = static_cast<Identifier const&>(expression.object()).string();
|
||||
auto property_name = static_cast<Identifier const&>(expression.property()).string();
|
||||
#define CHECK_MEMBER_BUILTIN(name, snake_case_name, base, property, ...) \
|
||||
if (base_name == #base##sv && property_name == #property##sv) \
|
||||
return Builtin::name;
|
||||
JS_ENUMERATE_BUILTINS(CHECK_MEMBER_BUILTIN)
|
||||
#undef CHECK_MEMBER_BUILTIN
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
66
Userland/Libraries/LibJS/Bytecode/Builtins.h
Normal file
66
Userland/Libraries/LibJS/Bytecode/Builtins.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Simon Wanner <simon@skyrising.xyz>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Format.h>
|
||||
#include <LibJS/Forward.h>
|
||||
|
||||
namespace JS::Bytecode {
|
||||
|
||||
// TitleCaseName, snake_case_name, base, property, argument_count
|
||||
#define JS_ENUMERATE_BUILTINS(O)
|
||||
|
||||
enum class Builtin {
|
||||
#define DEFINE_BUILTIN_ENUM(name, ...) name,
|
||||
JS_ENUMERATE_BUILTINS(DEFINE_BUILTIN_ENUM)
|
||||
#undef DEFINE_BUILTIN_ENUM
|
||||
__Count,
|
||||
};
|
||||
|
||||
static StringView builtin_name(Builtin value)
|
||||
{
|
||||
switch (value) {
|
||||
#define DEFINE_BUILTIN_CASE(name, snake_case_name, base, property, ...) \
|
||||
case Builtin::name: \
|
||||
return #base "." #property##sv;
|
||||
JS_ENUMERATE_BUILTINS(DEFINE_BUILTIN_CASE)
|
||||
#undef DEFINE_BUILTIN_CASE
|
||||
case Builtin::__Count:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
inline size_t builtin_argument_count(Builtin value)
|
||||
{
|
||||
switch (value) {
|
||||
#define DEFINE_BUILTIN_CASE(name, snake_case_name, base, property, arg_count, ...) \
|
||||
case Builtin::name: \
|
||||
return arg_count;
|
||||
JS_ENUMERATE_BUILTINS(DEFINE_BUILTIN_CASE)
|
||||
#undef DEFINE_BUILTIN_CASE
|
||||
case Builtin::__Count:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
Optional<Builtin> get_builtin(MemberExpression const& expression);
|
||||
|
||||
}
|
||||
|
||||
namespace AK {
|
||||
|
||||
template<>
|
||||
struct Formatter<JS::Bytecode::Builtin> : Formatter<StringView> {
|
||||
ErrorOr<void> format(FormatBuilder& builder, JS::Bytecode::Builtin value)
|
||||
{
|
||||
return Formatter<StringView>::format(builder, builtin_name(value));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -1514,6 +1514,8 @@ static StringView call_type_to_string(CallType type)
|
|||
DeprecatedString Call::to_deprecated_string_impl(Bytecode::Executable const& executable) const
|
||||
{
|
||||
auto type = call_type_to_string(m_type);
|
||||
if (m_builtin.has_value())
|
||||
return DeprecatedString::formatted("Call{} callee:{}, this:{}, first_arg:{} (builtin {})", type, m_callee, m_this_value, m_first_argument, m_builtin.value());
|
||||
if (m_expression_string.has_value())
|
||||
return DeprecatedString::formatted("Call{} callee:{}, this:{}, first_arg:{} ({})", type, m_callee, m_this_value, m_first_argument, executable.get_string(m_expression_string.value()));
|
||||
return DeprecatedString::formatted("Call{} callee:{}, this:{}, first_arg:{}", type, m_callee, m_first_argument, m_this_value);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <AK/StdLibExtras.h>
|
||||
#include <LibCrypto/BigInt/SignedBigInteger.h>
|
||||
#include <LibJS/Bytecode/Builtins.h>
|
||||
#include <LibJS/Bytecode/IdentifierTable.h>
|
||||
#include <LibJS/Bytecode/Instruction.h>
|
||||
#include <LibJS/Bytecode/Label.h>
|
||||
|
@ -984,7 +985,7 @@ enum class CallType {
|
|||
|
||||
class Call final : public Instruction {
|
||||
public:
|
||||
Call(CallType type, Register callee, Register this_value, Register first_argument, u32 argument_count, Optional<StringTableIndex> expression_string = {})
|
||||
Call(CallType type, Register callee, Register this_value, Register first_argument, u32 argument_count, Optional<StringTableIndex> expression_string = {}, Optional<Builtin> builtin = {})
|
||||
: Instruction(Type::Call, sizeof(*this))
|
||||
, m_callee(callee)
|
||||
, m_this_value(this_value)
|
||||
|
@ -992,6 +993,7 @@ public:
|
|||
, m_argument_count(argument_count)
|
||||
, m_type(type)
|
||||
, m_expression_string(expression_string)
|
||||
, m_builtin(builtin)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1003,6 +1005,8 @@ public:
|
|||
Register first_argument() const { return m_first_argument; }
|
||||
u32 argument_count() const { return m_argument_count; }
|
||||
|
||||
Optional<Builtin> const& builtin() const { return m_builtin; }
|
||||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const;
|
||||
|
||||
|
@ -1013,6 +1017,7 @@ private:
|
|||
u32 m_argument_count { 0 };
|
||||
CallType m_type;
|
||||
Optional<StringTableIndex> m_expression_string;
|
||||
Optional<Builtin> m_builtin;
|
||||
};
|
||||
|
||||
class CallWithArgumentArray final : public Instruction {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue