LibJS: Call AsmInt directly from run_executable

Remove the empty AsmInterpreter wrapper and the VM::run_bytecode()
trampoline now that the bytecode interpreter only enters AsmInt. Move
the stack-limit check and generated assembly entry call into
run_executable(), then drop the stale wrapper source file and includes.
This commit is contained in:
Andreas Kling 2026-06-14 16:07:07 +02:00 committed by Andreas Kling
parent 060ba41a84
commit 8fee268851
7 changed files with 29 additions and 93 deletions

View file

@ -1,29 +0,0 @@
/*
* Copyright (c) 2026, the Ladybird developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Bytecode/AsmInterpreter/AsmInterpreter.h>
#include <LibJS/Runtime/ExecutionContext.h>
#include <LibJS/Runtime/VM.h>
#include <LibJS/Runtime/Value.h>
extern "C" void asm_register_slow_path_stats();
namespace JS::Bytecode {
// Defined in generated assembly (asmint_x86_64.S or asmint_aarch64.S)
extern "C" void asm_interpreter_entry(u8 const* bytecode, u32 entry_point, Value* values, VM* vm);
void AsmInterpreter::run(VM& vm, size_t entry_point)
{
asm_register_slow_path_stats();
auto& context = vm.running_execution_context();
auto* bytecode = context.executable->bytecode.data();
auto* values = context.registers_and_constants_and_locals_and_arguments_span().data();
asm_interpreter_entry(bytecode, static_cast<u32>(entry_point), values, &vm);
}
}

View file

@ -1,22 +0,0 @@
/*
* Copyright (c) 2026, the Ladybird developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Types.h>
namespace JS {
class VM;
namespace Bytecode {
class AsmInterpreter {
public:
static void run(VM&, size_t entry_point);
};
}
}

View file

@ -5,7 +5,7 @@
*/
#include <AK/ScopeGuard.h>
#include <LibJS/Bytecode/AsmInterpreter/AsmInterpreter.h>
#include <AK/Types.h>
#include <LibJS/Bytecode/Builtins.h>
#include <LibJS/Bytecode/Instruction.h>
#include <LibJS/Bytecode/Op.h>
@ -1534,7 +1534,10 @@ NEVER_INLINE static ThrowCompletionOr<void> execute_asm_call(
auto* callee_context = stack.allocate(registers_and_locals_count, constants, max(arguments.size(), argument_count));
if (!callee_context) [[unlikely]]
return vm.throw_completion<InternalError>(ErrorType::CallStackSizeExceeded);
ScopeGuard deallocate_guard = [&stack, stack_mark] { stack.deallocate(stack_mark); };
ScopeGuard deallocate_guard = [&stack, stack_mark] {
if (stack.top() > stack_mark)
stack.deallocate(stack_mark);
};
auto* callee_context_argument_values = callee_context->arguments_data();
auto const callee_context_argument_count = callee_context->argument_count;
@ -1652,7 +1655,10 @@ static ThrowCompletionOr<void> call_with_argument_array(
auto* callee_context = stack.allocate(registers_and_locals_count, constants, max(argument_array_length, argument_count));
if (!callee_context) [[unlikely]]
return vm.throw_completion<InternalError>(ErrorType::CallStackSizeExceeded);
ScopeGuard deallocate_guard = [&stack, stack_mark] { stack.deallocate(stack_mark); };
ScopeGuard deallocate_guard = [&stack, stack_mark] {
if (stack.top() > stack_mark)
stack.deallocate(stack_mark);
};
auto* callee_context_argument_values = callee_context->arguments_data();
auto const callee_context_argument_count = callee_context->argument_count;
@ -1977,7 +1983,10 @@ i64 asm_slow_path_super_call_with_argument_array(VM* vm, u32 pc)
auto completion = vm->throw_completion<InternalError>(ErrorType::CallStackSizeExceeded);
return handle_asm_exception(*vm, pc, completion.value());
}
ScopeGuard deallocate_guard = [&stack, stack_mark] { stack.deallocate(stack_mark); };
ScopeGuard deallocate_guard = [&stack, stack_mark] {
if (stack.top() > stack_mark)
stack.deallocate(stack_mark);
};
auto* callee_context_argument_values = callee_context->arguments_data();
auto const callee_context_argument_count = callee_context->argument_count;

View file

@ -2738,7 +2738,7 @@ handler Call
# The native threw. Hand the thrown Value off to a C++ helper, which
# unwinds the callee frame off the interpreter stack and calls through
# to VM::handle_exception. Return value follows the standard asm
# slow-path convention (see AsmInterpreter.cpp:127):
# slow-path convention:
# >= 0 : an enclosing handler was found; the result is the new
# program counter to resume at inside the (post-unwind)
# running execution context.

View file

@ -6,54 +6,35 @@
*/
#include <AK/Debug.h>
#include <AK/HashTable.h>
#include <AK/NumericLimits.h>
#include <AK/TemporaryChange.h>
#include <LibGC/ConservativeHashTable.h>
#include <LibGC/RootHashMap.h>
#include <LibGC/RootHashTable.h>
#include <LibJS/Bytecode/AsmInterpreter/AsmInterpreter.h>
#include <LibJS/Bytecode/BasicBlock.h>
#include <LibJS/Bytecode/Builtins.h>
#include <LibJS/Bytecode/Debug.h>
#include <LibJS/Bytecode/FormatOperand.h>
#include <LibJS/Bytecode/Instruction.h>
#include <LibJS/Bytecode/Label.h>
#include <LibJS/Bytecode/Op.h>
#include <LibJS/Bytecode/PropertyAccess.h>
#include <LibJS/Export.h>
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Accessor.h>
#include <LibJS/Runtime/Array.h>
#include <LibJS/Runtime/AsyncFromSyncIterator.h>
#include <LibJS/Runtime/AsyncFromSyncIteratorPrototype.h>
#include <LibJS/Runtime/AsyncGenerator.h>
#include <LibJS/Runtime/BigInt.h>
#include <LibJS/Runtime/ClassConstruction.h>
#include <LibJS/Runtime/DeclarativeEnvironment.h>
#include <LibJS/Runtime/ECMAScriptFunctionObject.h>
#include <LibJS/Runtime/Environment.h>
#include <LibJS/Runtime/FunctionEnvironment.h>
#include <LibJS/Runtime/GeneratorObject.h>
#include <LibJS/Runtime/GlobalEnvironment.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/Iterator.h>
#include <LibJS/Runtime/ModuleEnvironment.h>
#include <LibJS/Runtime/NativeFunction.h>
#include <LibJS/Runtime/Realm.h>
#include <LibJS/Runtime/Reference.h>
#include <LibJS/Runtime/RegExpObject.h>
#include <LibJS/Runtime/TypedArray.h>
#include <LibJS/Runtime/VM.h>
#include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <LibJS/SourceTextModule.h>
#include <math.h>
namespace JS {
using namespace Bytecode;
extern "C" void asm_register_slow_path_stats();
// Defined in generated assembly (asmint_x86_64.S or asmint_aarch64.S)
extern "C" void asm_interpreter_entry(u8 const* bytecode, u32 entry_point, Value* values, VM* vm);
bool Bytecode::g_dump_bytecode = false;
// 16.1.6 ScriptEvaluation ( scriptRecord ), https://tc39.es/ecma262/#sec-runtime-semantics-scriptevaluation
@ -279,16 +260,6 @@ NEVER_INLINE void VM::unwind_inline_frame_for_exception()
m_running_execution_context = caller_frame;
}
void VM::run_bytecode(size_t entry_point)
{
if (vm().interpreter_stack().is_exhausted() || vm().did_reach_stack_space_limit()) [[unlikely]] {
reg(Register::exception()) = vm().throw_completion<InternalError>(ErrorType::CallStackSizeExceeded).value();
return;
}
AsmInterpreter::run(*this, entry_point);
}
Utf16FlyString const& VM::get_identifier(IdentifierTableIndex index) const
{
return m_running_execution_context->executable->get_identifier(index);
@ -327,7 +298,16 @@ ThrowCompletionOr<Value> VM::run_executable(ExecutionContext& context, Executabl
if (reg(Register::this_value()).is_special_empty_value())
reg(Register::this_value()) = context.this_value.value_or(js_special_empty_value());
run_bytecode(entry_point);
if (vm().interpreter_stack().is_exhausted() || vm().did_reach_stack_space_limit()) [[unlikely]] {
reg(Register::exception()) = vm().throw_completion<InternalError>(ErrorType::CallStackSizeExceeded).value();
} else {
asm_register_slow_path_stats();
auto* bytecode = executable.bytecode.data();
auto* values = context.registers_and_constants_and_locals_and_arguments_span().data();
asm_interpreter_entry(bytecode, entry_point, values, this);
}
dbgln_if(JS_BYTECODE_DEBUG, "VM did run bytecode unit {}", context.executable);

View file

@ -1,7 +1,6 @@
include(libjs_generators)
set(SOURCES
Bytecode/AsmInterpreter/AsmInterpreter.cpp
Bytecode/AsmInterpreter/AsmSlowPaths.cpp
Bytecode/BasicBlock.cpp
Bytecode/Executable.cpp

View file

@ -513,7 +513,6 @@ private:
void set_well_known_symbols(WellKnownSymbols well_known_symbols) { m_well_known_symbols = move(well_known_symbols); }
void run_queued_promise_jobs_impl();
void run_bytecode(size_t entry_point);
static VM* s_the;