mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-10-04 07:09:41 +00:00
LibJS: Emit bytecode for function declaration instantiation
By doing that all instructions required for instantiation are emitted once in compilation and then reused for subsequent calls, instead of running generic instantiation process for each call.
This commit is contained in:
parent
89a007327a
commit
a4f70986a0
Notes:
sideshowbarker
2024-07-17 10:31:19 +09:00
Author: https://github.com/kalenikaliaksandr
Commit: a4f70986a0
Pull-request: https://github.com/SerenityOS/serenity/pull/24272
15 changed files with 440 additions and 449 deletions
|
@ -228,7 +228,7 @@ ThrowCompletionOr<Value> Interpreter::run(Script& script_record, JS::GCPtr<Envir
|
|||
|
||||
// 13. If result.[[Type]] is normal, then
|
||||
if (result.type() == Completion::Type::Normal) {
|
||||
auto executable_result = JS::Bytecode::Generator::generate(vm, script, {});
|
||||
auto executable_result = JS::Bytecode::Generator::generate_from_ast_node(vm, script, {});
|
||||
|
||||
if (executable_result.is_error()) {
|
||||
if (auto error_string = executable_result.error().to_string(); error_string.is_error())
|
||||
|
@ -345,6 +345,7 @@ FLATTEN_ON_CLANG void Interpreter::run_bytecode(size_t entry_point)
|
|||
}
|
||||
|
||||
auto& running_execution_context = vm().running_execution_context();
|
||||
auto* arguments = running_execution_context.arguments.data();
|
||||
auto* locals = running_execution_context.locals.data();
|
||||
auto& accumulator = this->accumulator();
|
||||
auto& executable = current_executable();
|
||||
|
@ -387,6 +388,18 @@ FLATTEN_ON_CLANG void Interpreter::run_bytecode(size_t entry_point)
|
|||
DISPATCH_NEXT(SetLocal);
|
||||
}
|
||||
|
||||
handle_GetArgument: {
|
||||
auto const& instruction = *reinterpret_cast<Op::GetArgument const*>(&bytecode[program_counter]);
|
||||
set(instruction.dst(), arguments[instruction.index()]);
|
||||
DISPATCH_NEXT(GetArgument);
|
||||
}
|
||||
|
||||
handle_SetArgument: {
|
||||
auto const& instruction = *reinterpret_cast<Op::SetArgument const*>(&bytecode[program_counter]);
|
||||
arguments[instruction.index()] = get(instruction.src());
|
||||
DISPATCH_NEXT(SetArgument);
|
||||
}
|
||||
|
||||
handle_Mov: {
|
||||
auto& instruction = *reinterpret_cast<Op::Mov const*>(&bytecode[program_counter]);
|
||||
set(instruction.dst(), get(instruction.src()));
|
||||
|
@ -547,7 +560,10 @@ FLATTEN_ON_CLANG void Interpreter::run_bytecode(size_t entry_point)
|
|||
HANDLE_INSTRUCTION(ConcatString);
|
||||
HANDLE_INSTRUCTION(CopyObjectExcludingProperties);
|
||||
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK(CreateLexicalEnvironment);
|
||||
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK(CreateVariableEnvironment);
|
||||
HANDLE_INSTRUCTION(CreateVariable);
|
||||
HANDLE_INSTRUCTION(CreateRestParams);
|
||||
HANDLE_INSTRUCTION(CreateArguments);
|
||||
HANDLE_INSTRUCTION(Decrement);
|
||||
HANDLE_INSTRUCTION(DeleteById);
|
||||
HANDLE_INSTRUCTION(DeleteByIdWithThis);
|
||||
|
@ -687,6 +703,7 @@ Interpreter::ResultAndReturnRegister Interpreter::run_executable(Executable& exe
|
|||
if (running_execution_context.registers.size() < executable.number_of_registers)
|
||||
running_execution_context.registers.resize(executable.number_of_registers);
|
||||
|
||||
TemporaryChange restore_arguments { m_arguments, running_execution_context.arguments.span() };
|
||||
TemporaryChange restore_registers { m_registers, running_execution_context.registers.span() };
|
||||
TemporaryChange restore_locals { m_locals, running_execution_context.locals.span() };
|
||||
TemporaryChange restore_constants { m_constants, executable.constants.span() };
|
||||
|
@ -776,9 +793,26 @@ void Interpreter::enter_object_environment(Object& object)
|
|||
running_execution_context.lexical_environment = new_object_environment(object, true, old_environment);
|
||||
}
|
||||
|
||||
ThrowCompletionOr<NonnullGCPtr<Bytecode::Executable>> compile(VM& vm, ASTNode const& node, ReadonlySpan<FunctionParameter> parameters, FunctionKind kind, DeprecatedFlyString const& name)
|
||||
ThrowCompletionOr<NonnullGCPtr<Bytecode::Executable>> compile(VM& vm, ASTNode const& node, FunctionKind kind, DeprecatedFlyString const& name)
|
||||
{
|
||||
auto executable_result = Bytecode::Generator::generate(vm, node, parameters, kind);
|
||||
auto executable_result = Bytecode::Generator::generate_from_ast_node(vm, node, kind);
|
||||
if (executable_result.is_error())
|
||||
return vm.throw_completion<InternalError>(ErrorType::NotImplemented, TRY_OR_THROW_OOM(vm, executable_result.error().to_string()));
|
||||
|
||||
auto bytecode_executable = executable_result.release_value();
|
||||
bytecode_executable->name = name;
|
||||
|
||||
if (Bytecode::g_dump_bytecode)
|
||||
bytecode_executable->dump();
|
||||
|
||||
return bytecode_executable;
|
||||
}
|
||||
|
||||
ThrowCompletionOr<NonnullGCPtr<Bytecode::Executable>> compile(VM& vm, ECMAScriptFunctionObject const& function)
|
||||
{
|
||||
auto const& name = function.name();
|
||||
|
||||
auto executable_result = Bytecode::Generator::generate_from_function(vm, function);
|
||||
if (executable_result.is_error())
|
||||
return vm.throw_completion<InternalError>(ErrorType::NotImplemented, TRY_OR_THROW_OOM(vm, executable_result.error().to_string()));
|
||||
|
||||
|
@ -1230,6 +1264,15 @@ void CreateLexicalEnvironment::execute_impl(Bytecode::Interpreter& interpreter)
|
|||
running_execution_context.saved_lexical_environments.append(make_and_swap_envs(running_execution_context.lexical_environment));
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> CreateVariableEnvironment::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto& running_execution_context = interpreter.vm().running_execution_context();
|
||||
auto var_environment = new_declarative_environment(*running_execution_context.lexical_environment);
|
||||
running_execution_context.variable_environment = var_environment;
|
||||
running_execution_context.lexical_environment = var_environment;
|
||||
return {};
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> EnterObjectEnvironment::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto object = TRY(interpreter.get(m_object).to_object(interpreter.vm()));
|
||||
|
@ -1258,6 +1301,41 @@ ThrowCompletionOr<void> CreateVariable::execute_impl(Bytecode::Interpreter& inte
|
|||
return create_variable(interpreter.vm(), name, m_mode, m_is_global, m_is_immutable, m_is_strict);
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> CreateRestParams::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto const& arguments = interpreter.vm().running_execution_context().arguments;
|
||||
auto arguments_count = interpreter.vm().running_execution_context().passed_argument_count;
|
||||
auto array = MUST(Array::create(interpreter.realm(), 0));
|
||||
for (size_t rest_index = m_rest_index; rest_index < arguments_count; ++rest_index)
|
||||
array->indexed_properties().append(arguments[rest_index]);
|
||||
interpreter.set(m_dst, array);
|
||||
return {};
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> CreateArguments::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto const& function = interpreter.vm().running_execution_context().function;
|
||||
auto const& arguments = interpreter.vm().running_execution_context().arguments;
|
||||
auto const& environment = interpreter.vm().running_execution_context().lexical_environment;
|
||||
|
||||
auto passed_arguments = ReadonlySpan<Value> { arguments.data(), interpreter.vm().running_execution_context().passed_argument_count };
|
||||
Object* arguments_object;
|
||||
if (m_kind == Kind::Mapped) {
|
||||
arguments_object = create_mapped_arguments_object(interpreter.vm(), *function, function->formal_parameters(), passed_arguments, *environment);
|
||||
} else {
|
||||
arguments_object = create_unmapped_arguments_object(interpreter.vm(), passed_arguments);
|
||||
}
|
||||
|
||||
if (m_is_immutable) {
|
||||
MUST(environment->create_immutable_binding(interpreter.vm(), interpreter.vm().names.arguments.as_string(), false));
|
||||
} else {
|
||||
MUST(environment->create_mutable_binding(interpreter.vm(), interpreter.vm().names.arguments.as_string(), false));
|
||||
}
|
||||
MUST(environment->initialize_binding(interpreter.vm(), interpreter.vm().names.arguments.as_string(), arguments_object, Environment::InitializeBindingHint::Normal));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> SetVariable::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto& vm = interpreter.vm();
|
||||
|
@ -1277,6 +1355,18 @@ ThrowCompletionOr<void> SetLocal::execute_impl(Bytecode::Interpreter&) const
|
|||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> SetArgument::execute_impl(Bytecode::Interpreter&) const
|
||||
{
|
||||
// Handled in the interpreter loop.
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> GetArgument::execute_impl(Bytecode::Interpreter&) const
|
||||
{
|
||||
// Handled in the interpreter loop.
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> GetById::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto base_identifier = interpreter.current_executable().get_identifier(m_base_identifier);
|
||||
|
@ -1959,12 +2049,27 @@ ByteString CreateLexicalEnvironment::to_byte_string_impl(Bytecode::Executable co
|
|||
return "CreateLexicalEnvironment"sv;
|
||||
}
|
||||
|
||||
ByteString CreateVariableEnvironment::to_byte_string_impl(Bytecode::Executable const&) const
|
||||
{
|
||||
return "CreateVariableEnvironment"sv;
|
||||
}
|
||||
|
||||
ByteString CreateVariable::to_byte_string_impl(Bytecode::Executable const& executable) const
|
||||
{
|
||||
auto mode_string = m_mode == EnvironmentMode::Lexical ? "Lexical" : "Variable";
|
||||
return ByteString::formatted("CreateVariable env:{} immutable:{} global:{} {}", mode_string, m_is_immutable, m_is_global, executable.identifier_table->get(m_identifier));
|
||||
}
|
||||
|
||||
ByteString CreateRestParams::to_byte_string_impl(Bytecode::Executable const& executable) const
|
||||
{
|
||||
return ByteString::formatted("CreateRestParams {}, rest_index:{}", format_operand("dst"sv, m_dst, executable), m_rest_index);
|
||||
}
|
||||
|
||||
ByteString CreateArguments::to_byte_string_impl(Bytecode::Executable const&) const
|
||||
{
|
||||
return ByteString::formatted("CreateArguments {} immutable:{}", m_kind == Kind::Mapped ? "mapped"sv : "unmapped"sv, m_is_immutable);
|
||||
}
|
||||
|
||||
ByteString EnterObjectEnvironment::to_byte_string_impl(Executable const& executable) const
|
||||
{
|
||||
return ByteString::formatted("EnterObjectEnvironment {}",
|
||||
|
@ -1988,6 +2093,16 @@ ByteString SetLocal::to_byte_string_impl(Bytecode::Executable const& executable)
|
|||
format_operand("src"sv, src(), executable));
|
||||
}
|
||||
|
||||
ByteString GetArgument::to_byte_string_impl(Bytecode::Executable const& executable) const
|
||||
{
|
||||
return ByteString::formatted("GetArgument {}, {}", index(), format_operand("dst"sv, dst(), executable));
|
||||
}
|
||||
|
||||
ByteString SetArgument::to_byte_string_impl(Bytecode::Executable const& executable) const
|
||||
{
|
||||
return ByteString::formatted("SetArgument {}, {}", index(), format_operand("src"sv, src(), executable));
|
||||
}
|
||||
|
||||
static StringView property_kind_to_string(PropertyKind kind)
|
||||
{
|
||||
switch (kind) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue