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