1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 00:27:45 +00:00

LibJS: Add file & line number to bytecode VM stack traces :^)

This works by adding source start/end offset to every bytecode
instruction. In the future we can make this more efficient by keeping
a map of bytecode ranges to source ranges in the Executable instead,
but let's just get traces working first.

Co-Authored-By: Andrew Kaster <akaster@serenityos.org>
This commit is contained in:
Andreas Kling 2023-09-01 16:53:55 +02:00
parent 0b66656ca9
commit 1c06111cbd
16 changed files with 157 additions and 26 deletions

View file

@ -152,6 +152,7 @@ ThrowCompletionOr<Value> ECMAScriptFunctionObject::internal_call(Value this_argu
// Non-standard
callee_context.arguments.extend(move(arguments_list));
callee_context.instruction_stream_iterator = vm.bytecode_interpreter().instruction_stream_iterator();
// 2. Let calleeContext be PrepareForOrdinaryCall(F, undefined).
// NOTE: We throw if the end of the native stack is reached, so unlike in the spec this _does_ need an exception check.
@ -221,6 +222,7 @@ ThrowCompletionOr<NonnullGCPtr<Object>> ECMAScriptFunctionObject::internal_const
// Non-standard
callee_context.arguments.extend(move(arguments_list));
callee_context.instruction_stream_iterator = vm.bytecode_interpreter().instruction_stream_iterator();
// 4. Let calleeContext be PrepareForOrdinaryCall(F, newTarget).
// NOTE: We throw if the end of the native stack is reached, so unlike in the spec this _does_ need an exception check.

View file

@ -83,9 +83,12 @@ void Error::populate_stack()
if (function_name.is_empty())
function_name = "<unknown>"sv;
UnrealizedSourceRange range = {};
if (context->instruction_stream_iterator.has_value())
range = context->instruction_stream_iterator->source_range();
TracebackFrame frame {
.function_name = move(function_name),
.source_range_storage = context->source_range,
.source_range_storage = range,
};
m_traceback.append(move(frame));

View file

@ -33,7 +33,7 @@ ExecutionContext ExecutionContext::copy() const
copy.lexical_environment = lexical_environment;
copy.variable_environment = variable_environment;
copy.private_environment = private_environment;
copy.source_range = source_range;
copy.instruction_stream_iterator = instruction_stream_iterator;
copy.function_name = function_name;
copy.this_value = this_value;
copy.is_strict_mode = is_strict_mode;

View file

@ -10,6 +10,7 @@
#include <AK/DeprecatedFlyString.h>
#include <AK/WeakPtr.h>
#include <LibJS/Bytecode/Instruction.h>
#include <LibJS/Forward.h>
#include <LibJS/Heap/MarkedVector.h>
#include <LibJS/Module.h>
@ -43,7 +44,7 @@ public:
// Non-standard: This points at something that owns this ExecutionContext, in case it needs to be protected from GC.
GCPtr<Cell> context_owner;
UnrealizedSourceRange source_range;
Optional<Bytecode::InstructionStreamIterator&> instruction_stream_iterator;
DeprecatedFlyString function_name;
Value this_value;
MarkedVector<Value> arguments;

View file

@ -6,6 +6,7 @@
*/
#include <LibJS/AST.h>
#include <LibJS/Bytecode/Interpreter.h>
#include <LibJS/Runtime/FunctionEnvironment.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/NativeFunction.h>
@ -128,9 +129,9 @@ ThrowCompletionOr<Value> NativeFunction::internal_call(Value this_argument, Mark
// Note: This is already the default value.
// 8. Perform any necessary implementation-defined initialization of calleeContext.
callee_context.this_value = this_argument;
callee_context.arguments.extend(move(arguments_list));
callee_context.instruction_stream_iterator = vm.bytecode_interpreter().instruction_stream_iterator();
callee_context.lexical_environment = caller_context.lexical_environment;
callee_context.variable_environment = caller_context.variable_environment;
@ -192,8 +193,8 @@ ThrowCompletionOr<NonnullGCPtr<Object>> NativeFunction::internal_construct(Marke
// Note: This is already the default value.
// 8. Perform any necessary implementation-defined initialization of calleeContext.
callee_context.arguments.extend(move(arguments_list));
callee_context.instruction_stream_iterator = vm.bytecode_interpreter().instruction_stream_iterator();
callee_context.lexical_environment = caller_context.lexical_environment;
callee_context.variable_environment = caller_context.variable_environment;

View file

@ -746,8 +746,8 @@ void VM::dump_backtrace() const
{
for (ssize_t i = m_execution_context_stack.size() - 1; i >= 0; --i) {
auto& frame = m_execution_context_stack[i];
if (frame->source_range.source_code) {
auto source_range = frame->source_range.realize();
if (frame->instruction_stream_iterator->source_code()) {
auto source_range = frame->instruction_stream_iterator->source_range().realize();
dbgln("-> {} @ {}:{},{}", frame->function_name, source_range.filename(), source_range.start.line, source_range.start.column);
} else {
dbgln("-> {}", frame->function_name);