/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 | | } |