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
5#include "src/handler-table.h"
6
7#include <iomanip>
8
9#include "src/assembler-inl.h"
10#include "src/objects-inl.h"
11#include "src/objects/code-inl.h"
12
13namespace v8 {
14namespace internal {
15
16HandlerTable::HandlerTable(Code code)
17 : HandlerTable(code->InstructionStart(), code->has_handler_table()
18 ? code->handler_table_offset()
19 : 0) {}
20
21HandlerTable::HandlerTable(BytecodeArray bytecode_array)
22 : HandlerTable(bytecode_array->handler_table()) {}
23
24HandlerTable::HandlerTable(ByteArray byte_array)
25 : number_of_entries_(byte_array->length() / kRangeEntrySize /
26 sizeof(int32_t)),
27#ifdef DEBUG
28 mode_(kRangeBasedEncoding),
29#endif
30 raw_encoded_data_(
31 reinterpret_cast<Address>(byte_array->GetDataStartAddress())) {
32}
33
34// TODO(jgruber,v8:8758): This constructor should eventually take the handler
35// table size in addition to the offset. That way the {HandlerTable} class
36// remains independent of how the offset/size is encoded in the various code
37// objects. This could even allow us to change the encoding to no longer expect
38// the "number of entries" in the beginning.
39HandlerTable::HandlerTable(Address instruction_start,
40 size_t handler_table_offset)
41 : number_of_entries_(0),
42#ifdef DEBUG
43 mode_(kReturnAddressBasedEncoding),
44#endif
45 raw_encoded_data_(instruction_start + handler_table_offset) {
46 if (handler_table_offset > 0) {
47 number_of_entries_ = Memory<int32_t>(raw_encoded_data_);
48 raw_encoded_data_ += sizeof(int32_t);
49 }
50}
51
52int HandlerTable::GetRangeStart(int index) const {
53 DCHECK_EQ(kRangeBasedEncoding, mode_);
54 DCHECK_LT(index, NumberOfRangeEntries());
55 int offset = index * kRangeEntrySize + kRangeStartIndex;
56 return Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t));
57}
58
59int HandlerTable::GetRangeEnd(int index) const {
60 DCHECK_EQ(kRangeBasedEncoding, mode_);
61 DCHECK_LT(index, NumberOfRangeEntries());
62 int offset = index * kRangeEntrySize + kRangeEndIndex;
63 return Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t));
64}
65
66int HandlerTable::GetRangeHandler(int index) const {
67 DCHECK_EQ(kRangeBasedEncoding, mode_);
68 DCHECK_LT(index, NumberOfRangeEntries());
69 int offset = index * kRangeEntrySize + kRangeHandlerIndex;
70 return HandlerOffsetField::decode(
71 Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)));
72}
73
74int HandlerTable::GetRangeData(int index) const {
75 DCHECK_EQ(kRangeBasedEncoding, mode_);
76 DCHECK_LT(index, NumberOfRangeEntries());
77 int offset = index * kRangeEntrySize + kRangeDataIndex;
78 return Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t));
79}
80
81HandlerTable::CatchPrediction HandlerTable::GetRangePrediction(
82 int index) const {
83 DCHECK_EQ(kRangeBasedEncoding, mode_);
84 DCHECK_LT(index, NumberOfRangeEntries());
85 int offset = index * kRangeEntrySize + kRangeHandlerIndex;
86 return HandlerPredictionField::decode(
87 Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)));
88}
89
90int HandlerTable::GetReturnOffset(int index) const {
91 DCHECK_EQ(kReturnAddressBasedEncoding, mode_);
92 DCHECK_LT(index, NumberOfReturnEntries());
93 int offset = index * kReturnEntrySize + kReturnOffsetIndex;
94 return Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t));
95}
96
97int HandlerTable::GetReturnHandler(int index) const {
98 DCHECK_EQ(kReturnAddressBasedEncoding, mode_);
99 DCHECK_LT(index, NumberOfReturnEntries());
100 int offset = index * kReturnEntrySize + kReturnHandlerIndex;
101 return HandlerOffsetField::decode(
102 Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)));
103}
104
105void HandlerTable::SetRangeStart(int index, int value) {
106 int offset = index * kRangeEntrySize + kRangeStartIndex;
107 Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)) = value;
108}
109
110void HandlerTable::SetRangeEnd(int index, int value) {
111 int offset = index * kRangeEntrySize + kRangeEndIndex;
112 Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)) = value;
113}
114
115void HandlerTable::SetRangeHandler(int index, int handler_offset,
116 CatchPrediction prediction) {
117 int value = HandlerOffsetField::encode(handler_offset) |
118 HandlerPredictionField::encode(prediction);
119 int offset = index * kRangeEntrySize + kRangeHandlerIndex;
120 Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)) = value;
121}
122
123void HandlerTable::SetRangeData(int index, int value) {
124 int offset = index * kRangeEntrySize + kRangeDataIndex;
125 Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)) = value;
126}
127
128// static
129int HandlerTable::LengthForRange(int entries) {
130 return entries * kRangeEntrySize * sizeof(int32_t);
131}
132
133// static
134int HandlerTable::EmitReturnTableStart(Assembler* masm, int entries) {
135 masm->DataAlign(sizeof(int32_t)); // Make sure entries are aligned.
136 masm->RecordComment(";;; Exception handler table.");
137 int table_start = masm->pc_offset();
138 masm->dd(entries);
139 return table_start;
140}
141
142// static
143void HandlerTable::EmitReturnEntry(Assembler* masm, int offset, int handler) {
144 masm->dd(offset);
145 masm->dd(HandlerOffsetField::encode(handler));
146}
147
148int HandlerTable::NumberOfRangeEntries() const {
149 DCHECK_EQ(kRangeBasedEncoding, mode_);
150 return number_of_entries_;
151}
152
153int HandlerTable::NumberOfReturnEntries() const {
154 DCHECK_EQ(kReturnAddressBasedEncoding, mode_);
155 return number_of_entries_;
156}
157
158int HandlerTable::LookupRange(int pc_offset, int* data_out,
159 CatchPrediction* prediction_out) {
160 int innermost_handler = -1;
161#ifdef DEBUG
162 // Assuming that ranges are well nested, we don't need to track the innermost
163 // offsets. This is just to verify that the table is actually well nested.
164 int innermost_start = std::numeric_limits<int>::min();
165 int innermost_end = std::numeric_limits<int>::max();
166#endif
167 for (int i = 0; i < NumberOfRangeEntries(); ++i) {
168 int start_offset = GetRangeStart(i);
169 int end_offset = GetRangeEnd(i);
170 int handler_offset = GetRangeHandler(i);
171 int handler_data = GetRangeData(i);
172 CatchPrediction prediction = GetRangePrediction(i);
173 if (pc_offset >= start_offset && pc_offset < end_offset) {
174 DCHECK_GE(start_offset, innermost_start);
175 DCHECK_LT(end_offset, innermost_end);
176 innermost_handler = handler_offset;
177#ifdef DEBUG
178 innermost_start = start_offset;
179 innermost_end = end_offset;
180#endif
181 if (data_out) *data_out = handler_data;
182 if (prediction_out) *prediction_out = prediction;
183 }
184 }
185 return innermost_handler;
186}
187
188// TODO(turbofan): Make sure table is sorted and use binary search.
189int HandlerTable::LookupReturn(int pc_offset) {
190 for (int i = 0; i < NumberOfReturnEntries(); ++i) {
191 int return_offset = GetReturnOffset(i);
192 if (pc_offset == return_offset) {
193 return GetReturnHandler(i);
194 }
195 }
196 return -1;
197}
198
199#ifdef ENABLE_DISASSEMBLER
200
201void HandlerTable::HandlerTableRangePrint(std::ostream& os) {
202 os << " from to hdlr (prediction, data)\n";
203 for (int i = 0; i < NumberOfRangeEntries(); ++i) {
204 int pc_start = GetRangeStart(i);
205 int pc_end = GetRangeEnd(i);
206 int handler_offset = GetRangeHandler(i);
207 int handler_data = GetRangeData(i);
208 CatchPrediction prediction = GetRangePrediction(i);
209 os << " (" << std::setw(4) << pc_start << "," << std::setw(4) << pc_end
210 << ") -> " << std::setw(4) << handler_offset
211 << " (prediction=" << prediction << ", data=" << handler_data << ")\n";
212 }
213}
214
215void HandlerTable::HandlerTableReturnPrint(std::ostream& os) {
216 os << " offset handler\n";
217 for (int i = 0; i < NumberOfReturnEntries(); ++i) {
218 int pc_offset = GetReturnOffset(i);
219 int handler_offset = GetReturnHandler(i);
220 os << std::hex << " " << std::setw(4) << pc_offset << " -> "
221 << std::setw(4) << handler_offset << std::dec << "\n";
222 }
223}
224
225#endif // ENABLE_DISASSEMBLER
226
227} // namespace internal
228} // namespace v8
229