Coverage Report

Created: 2026-10-28 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibJS/Bytecode/Executable.cpp
Line
Count
Source
1
/*
2
 * Copyright (c) 2021-2024, Andreas Kling <kling@serenityos.org>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#include <LibJS/Bytecode/BasicBlock.h>
8
#include <LibJS/Bytecode/Executable.h>
9
#include <LibJS/Bytecode/Instruction.h>
10
#include <LibJS/Bytecode/RegexTable.h>
11
#include <LibJS/SourceCode.h>
12
13
namespace JS::Bytecode {
14
15
JS_DEFINE_ALLOCATOR(Executable);
16
17
Executable::Executable(
18
    Vector<u8> bytecode,
19
    NonnullOwnPtr<IdentifierTable> identifier_table,
20
    NonnullOwnPtr<StringTable> string_table,
21
    NonnullOwnPtr<RegexTable> regex_table,
22
    Vector<Value> constants,
23
    NonnullRefPtr<SourceCode const> source_code,
24
    size_t number_of_property_lookup_caches,
25
    size_t number_of_global_variable_caches,
26
    size_t number_of_registers,
27
    bool is_strict_mode)
28
22
    : bytecode(move(bytecode))
29
22
    , string_table(move(string_table))
30
22
    , identifier_table(move(identifier_table))
31
22
    , regex_table(move(regex_table))
32
22
    , constants(move(constants))
33
22
    , source_code(move(source_code))
34
22
    , number_of_registers(number_of_registers)
35
22
    , is_strict_mode(is_strict_mode)
36
22
{
37
22
    property_lookup_caches.resize(number_of_property_lookup_caches);
38
22
    global_variable_caches.resize(number_of_global_variable_caches);
39
22
}
40
41
22
Executable::~Executable() = default;
42
43
void Executable::dump() const
44
0
{
45
0
    warnln("\033[37;1mJS bytecode executable\033[0m \"{}\"", name);
46
0
    InstructionStreamIterator it(bytecode, this);
47
48
0
    size_t basic_block_offset_index = 0;
49
50
0
    while (!it.at_end()) {
51
0
        bool print_basic_block_marker = false;
52
0
        if (basic_block_offset_index < basic_block_start_offsets.size()
53
0
            && it.offset() == basic_block_start_offsets[basic_block_offset_index]) {
54
0
            ++basic_block_offset_index;
55
0
            print_basic_block_marker = true;
56
0
        }
57
58
0
        StringBuilder builder;
59
0
        builder.appendff("[{:4x}] ", it.offset());
60
0
        if (print_basic_block_marker)
61
0
            builder.appendff("{:4}: ", basic_block_offset_index - 1);
62
0
        else
63
0
            builder.append("      "sv);
64
0
        builder.append((*it).to_byte_string(*this));
65
66
0
        warnln("{}", builder.string_view());
67
68
0
        ++it;
69
0
    }
70
71
0
    if (!exception_handlers.is_empty()) {
72
0
        warnln("");
73
0
        warnln("Exception handlers:");
74
0
        for (auto& handlers : exception_handlers) {
75
0
            warnln("    from {:4x} to {:4x} handler {:4x} finalizer {:4x}",
76
0
                handlers.start_offset,
77
0
                handlers.end_offset,
78
0
                handlers.handler_offset.value_or(0),
79
0
                handlers.finalizer_offset.value_or(0));
80
0
        }
81
0
    }
82
83
0
    warnln("");
84
0
}
85
86
void Executable::visit_edges(Visitor& visitor)
87
0
{
88
0
    Base::visit_edges(visitor);
89
0
    visitor.visit(constants);
90
0
}
91
92
Optional<Executable::ExceptionHandlers const&> Executable::exception_handlers_for_offset(size_t offset) const
93
12
{
94
12
    for (auto& handlers : exception_handlers) {
95
0
        if (handlers.start_offset <= offset && offset < handlers.end_offset)
96
0
            return handlers;
97
0
    }
98
12
    return {};
99
12
}
100
101
UnrealizedSourceRange Executable::source_range_at(size_t offset) const
102
0
{
103
0
    if (offset >= bytecode.size())
104
0
        return {};
105
0
    auto it = InstructionStreamIterator(bytecode.span().slice(offset), this);
106
0
    VERIFY(!it.at_end());
107
0
    auto mapping = source_map.get(offset);
108
0
    if (!mapping.has_value())
109
0
        return {};
110
0
    return UnrealizedSourceRange {
111
0
        .source_code = source_code,
112
0
        .start_offset = mapping->source_start_offset,
113
0
        .end_offset = mapping->source_end_offset,
114
0
    };
115
0
}
116
117
}