v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
handler-table.cc
Go to the documentation of this file.
1// Copyright 2018 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include <algorithm>
8#include <iomanip>
9
10#include "src/base/iterator.h"
14
15#if V8_ENABLE_WEBASSEMBLY
17#endif // V8_ENABLE_WEBASSEMBLY
18
19namespace v8 {
20namespace internal {
21
23 : HandlerTable(code->handler_table_address(), code->handler_table_size(),
24 kReturnAddressBasedEncoding) {}
25
26#if V8_ENABLE_WEBASSEMBLY
28 : HandlerTable(code->handler_table(), code->handler_table_size(),
29 kReturnAddressBasedEncoding) {}
30#endif // V8_ENABLE_WEBASSEMBLY
31
33 : HandlerTable(bytecode_array->handler_table()) {}
34
36 : HandlerTable(reinterpret_cast<Address>(byte_array->begin()),
37 byte_array->length(), kRangeBasedEncoding) {}
38
39HandlerTable::HandlerTable(Address handler_table, int handler_table_size,
40 EncodingMode encoding_mode)
41 : number_of_entries_(handler_table_size / EntrySizeFromMode(encoding_mode) /
42 sizeof(int32_t)),
43#ifdef DEBUG
44 mode_(encoding_mode),
45#endif
46 raw_encoded_data_(handler_table) {
47 // Check padding.
48 static_assert(4 < kReturnEntrySize * sizeof(int32_t), "allowed padding");
49 // For return address encoding, maximum padding is 4; otherwise, there should
50 // be no padding.
51 DCHECK_GE(kReturnAddressBasedEncoding == encoding_mode ? 4 : 0,
52 handler_table_size %
53 (EntrySizeFromMode(encoding_mode) * sizeof(int32_t)));
54}
55
56// static
58 switch (mode) {
60 return kReturnEntrySize;
62 return kRangeEntrySize;
63 }
65}
66
67int HandlerTable::GetRangeStart(int index) const {
71 return Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t));
72}
73
74int HandlerTable::GetRangeEnd(int index) const {
78 return Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t));
79}
80
85 return base::Relaxed_Load(
86 &Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)));
87}
88
92
93int HandlerTable::GetRangeData(int index) const {
97 return Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t));
98}
99
104
108
113 auto& mem = Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t));
115}
116
117int HandlerTable::GetReturnOffset(int index) const {
121 return Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t));
122}
123
124int HandlerTable::GetReturnHandler(int index) const {
129 Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)));
130}
131
132void HandlerTable::SetRangeStart(int index, int value) {
134 Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)) = value;
135}
136
137void HandlerTable::SetRangeEnd(int index, int value) {
138 int offset = index * kRangeEntrySize + kRangeEndIndex;
139 Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)) = value;
140}
141
142void HandlerTable::SetRangeHandler(int index, int handler_offset,
143 CatchPrediction prediction) {
144 int value = HandlerOffsetField::encode(handler_offset) |
148 Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)) = value;
149}
150
151void HandlerTable::SetRangeData(int index, int value) {
152 int offset = index * kRangeEntrySize + kRangeDataIndex;
153 Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)) = value;
154}
155
156// static
158 return entries * kRangeEntrySize * sizeof(int32_t);
159}
160
161// static
164 masm->RecordComment(";;; Exception handler table.");
165 int table_start = masm->pc_offset();
166 return table_start;
167}
168
169// static
170void HandlerTable::EmitReturnEntry(Assembler* masm, int offset, int handler) {
171 masm->dd(offset);
172 masm->dd(HandlerOffsetField::encode(handler));
173}
174
179
184
186 int innermost_handler = kNoHandlerFound;
187#ifdef DEBUG
188 // Assuming that ranges are well nested, we don't need to track the innermost
189 // offsets. This is just to verify that the table is actually well nested.
190 int innermost_start = std::numeric_limits<int>::min();
191 int innermost_end = std::numeric_limits<int>::max();
192#endif
193 for (int i = 0; i < NumberOfRangeEntries(); ++i) {
194 int start_offset = GetRangeStart(i);
195 int end_offset = GetRangeEnd(i);
196 if (end_offset <= pc_offset) continue;
197 if (start_offset > pc_offset) break;
198 DCHECK_GE(start_offset, innermost_start);
199 DCHECK_LT(end_offset, innermost_end);
200 innermost_handler = i;
201#ifdef DEBUG
202 innermost_start = start_offset;
203 innermost_end = end_offset;
204#endif
205 }
206 return innermost_handler;
207}
208
210 // We only implement the methods needed by the standard libraries we care
211 // about. This is not technically a full random access iterator by the spec.
212 struct Iterator : base::iterator<std::random_access_iterator_tag, int> {
213 Iterator(HandlerTable* tbl, int idx) : table(tbl), index(idx) {}
214 value_type operator*() const { return table->GetReturnOffset(index); }
215 bool operator!=(const Iterator& other) const { return !(*this == other); }
216 bool operator==(const Iterator& other) const {
217 return index == other.index;
218 }
219 // GLIBCXX_DEBUG checks uses the <= comparator.
220 bool operator<=(const Iterator& other) { return index <= other.index; }
221 Iterator& operator++() {
222 index++;
223 return *this;
224 }
225 Iterator& operator--() {
226 index--;
227 return *this;
228 }
229 Iterator& operator+=(difference_type offset) {
230 index += offset;
231 return *this;
232 }
233 difference_type operator-(const Iterator& other) const {
234 return index - other.index;
235 }
236 HandlerTable* table;
237 int index;
238 };
239 Iterator begin{this, 0}, end{this, NumberOfReturnEntries()};
240 SLOW_DCHECK(std::is_sorted(begin, end)); // Must be sorted.
241 Iterator result = std::lower_bound(begin, end, pc_offset);
242 if (result != end && *result == pc_offset) {
243 return GetReturnHandler(result.index);
244 }
245 return -1;
246}
247
248#ifdef ENABLE_DISASSEMBLER
249
250void HandlerTable::HandlerTableRangePrint(std::ostream& os) {
251 os << " from to hdlr (prediction, data)\n";
252 for (int i = 0; i < NumberOfRangeEntries(); ++i) {
253 int pc_start = GetRangeStart(i);
254 int pc_end = GetRangeEnd(i);
255 int handler_offset = GetRangeHandler(i);
256 int handler_data = GetRangeData(i);
258 os << " (" << std::setw(4) << pc_start << "," << std::setw(4) << pc_end
259 << ") -> " << std::setw(4) << handler_offset
260 << " (prediction=" << prediction << ", data=" << handler_data << ")\n";
261 }
262}
263
264void HandlerTable::HandlerTableReturnPrint(std::ostream& os) {
265 os << " offset handler\n";
266 for (int i = 0; i < NumberOfReturnEntries(); ++i) {
268 int handler_offset = GetReturnHandler(i);
269 os << std::hex << " " << std::setw(4) << pc_offset << " -> "
270 << std::setw(4) << handler_offset << std::dec << "\n";
271 }
272}
273
274#endif // ENABLE_DISASSEMBLER
275
276} // namespace internal
277} // namespace v8
#define SLOW_DCHECK(condition)
Definition checks.h:21
static constexpr T decode(U value)
Definition bit-field.h:66
static constexpr U encode(T value)
Definition bit-field.h:55
static V8_NODISCARD constexpr U update(U previous, T value)
Definition bit-field.h:61
V8_INLINE void RecordComment(const char *comment, const SourceLocation &loc=SourceLocation::Current())
Definition assembler.h:417
static const int kRangeDataIndex
int GetRangeStart(int index) const
HandlerTable(Tagged< InstructionStream > code)
int LookupHandlerIndexForRange(int pc_offset) const
int GetRangeData(int index) const
CatchPrediction GetRangePrediction(int index) const
int GetReturnOffset(int index) const
static const int kRangeStartIndex
static int LengthForRange(int entries)
static const int kReturnOffsetIndex
void MarkHandlerUsed(int index)
static void EmitReturnEntry(Assembler *masm, int offset, int handler)
int GetRangeHandler(int index) const
static int EntrySizeFromMode(EncodingMode mode)
static const int kReturnHandlerIndex
void SetRangeHandler(int index, int offset, CatchPrediction pred)
bool HandlerWasUsed(int index) const
static const int kReturnEntrySize
int GetRangeHandlerBitfield(int index) const
void SetRangeData(int index, int value)
void SetRangeEnd(int index, int value)
static const int kRangeHandlerIndex
static const int kRangeEndIndex
int GetRangeEnd(int index) const
int GetReturnHandler(int index) const
static const int kNoHandlerFound
static const int kRangeEntrySize
static int EmitReturnTableStart(Assembler *masm)
void SetRangeStart(int index, int value)
int LookupReturn(int pc_offset)
static constexpr int kMetadataAlignment
RecordWriteMode const mode_
int end
OptionalOpIndex index
int32_t offset
ZoneVector< RpoNumber > & result
ZoneVector< Entry > entries
int pc_offset
void Relaxed_Store(volatile Atomic8 *ptr, Atomic8 value)
Definition atomicops.h:189
Atomic8 Relaxed_Load(volatile const Atomic8 *ptr)
Definition atomicops.h:234
bool operator!=(ExternalReference lhs, ExternalReference rhs)
return value
Definition map-inl.h:893
V8_INLINE Builtin operator++(Builtin &builtin)
Definition builtins.h:80
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485