• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/codegen/handler-table.h"
6 
7 #include <algorithm>
8 #include <iomanip>
9 
10 #include "src/base/iterator.h"
11 #include "src/codegen/assembler-inl.h"
12 #include "src/objects/code-inl.h"
13 #include "src/objects/objects-inl.h"
14 
15 #if V8_ENABLE_WEBASSEMBLY
16 #include "src/wasm/wasm-code-manager.h"
17 #endif  // V8_ENABLE_WEBASSEMBLY
18 
19 namespace v8 {
20 namespace internal {
21 
HandlerTable(Code code)22 HandlerTable::HandlerTable(Code code)
23     : HandlerTable(code.HandlerTableAddress(), code.handler_table_size(),
24                    kReturnAddressBasedEncoding) {}
25 
26 #if V8_ENABLE_WEBASSEMBLY
HandlerTable(const wasm::WasmCode * code)27 HandlerTable::HandlerTable(const wasm::WasmCode* code)
28     : HandlerTable(code->handler_table(), code->handler_table_size(),
29                    kReturnAddressBasedEncoding) {}
30 #endif  // V8_ENABLE_WEBASSEMBLY
31 
HandlerTable(BytecodeArray bytecode_array)32 HandlerTable::HandlerTable(BytecodeArray bytecode_array)
33     : HandlerTable(bytecode_array.handler_table()) {}
34 
HandlerTable(ByteArray byte_array)35 HandlerTable::HandlerTable(ByteArray byte_array)
36     : HandlerTable(reinterpret_cast<Address>(byte_array.GetDataStartAddress()),
37                    byte_array.length(), kRangeBasedEncoding) {}
38 
HandlerTable(Address handler_table,int handler_table_size,EncodingMode encoding_mode)39 HandlerTable::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
EntrySizeFromMode(EncodingMode mode)57 int HandlerTable::EntrySizeFromMode(EncodingMode mode) {
58   switch (mode) {
59     case kReturnAddressBasedEncoding:
60       return kReturnEntrySize;
61     case kRangeBasedEncoding:
62       return kRangeEntrySize;
63   }
64   UNREACHABLE();
65 }
66 
GetRangeStart(int index) const67 int HandlerTable::GetRangeStart(int index) const {
68   DCHECK_EQ(kRangeBasedEncoding, mode_);
69   DCHECK_LT(index, NumberOfRangeEntries());
70   int offset = index * kRangeEntrySize + kRangeStartIndex;
71   return Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t));
72 }
73 
GetRangeEnd(int index) const74 int HandlerTable::GetRangeEnd(int index) const {
75   DCHECK_EQ(kRangeBasedEncoding, mode_);
76   DCHECK_LT(index, NumberOfRangeEntries());
77   int offset = index * kRangeEntrySize + kRangeEndIndex;
78   return Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t));
79 }
80 
GetRangeHandler(int index) const81 int HandlerTable::GetRangeHandler(int index) const {
82   DCHECK_EQ(kRangeBasedEncoding, mode_);
83   DCHECK_LT(index, NumberOfRangeEntries());
84   int offset = index * kRangeEntrySize + kRangeHandlerIndex;
85   return HandlerOffsetField::decode(
86       Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)));
87 }
88 
GetRangeData(int index) const89 int HandlerTable::GetRangeData(int index) const {
90   DCHECK_EQ(kRangeBasedEncoding, mode_);
91   DCHECK_LT(index, NumberOfRangeEntries());
92   int offset = index * kRangeEntrySize + kRangeDataIndex;
93   return Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t));
94 }
95 
GetRangePrediction(int index) const96 HandlerTable::CatchPrediction HandlerTable::GetRangePrediction(
97     int index) const {
98   DCHECK_EQ(kRangeBasedEncoding, mode_);
99   DCHECK_LT(index, NumberOfRangeEntries());
100   int offset = index * kRangeEntrySize + kRangeHandlerIndex;
101   return HandlerPredictionField::decode(
102       Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)));
103 }
104 
GetReturnOffset(int index) const105 int HandlerTable::GetReturnOffset(int index) const {
106   DCHECK_EQ(kReturnAddressBasedEncoding, mode_);
107   DCHECK_LT(index, NumberOfReturnEntries());
108   int offset = index * kReturnEntrySize + kReturnOffsetIndex;
109   return Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t));
110 }
111 
GetReturnHandler(int index) const112 int HandlerTable::GetReturnHandler(int index) const {
113   DCHECK_EQ(kReturnAddressBasedEncoding, mode_);
114   DCHECK_LT(index, NumberOfReturnEntries());
115   int offset = index * kReturnEntrySize + kReturnHandlerIndex;
116   return HandlerOffsetField::decode(
117       Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)));
118 }
119 
SetRangeStart(int index,int value)120 void HandlerTable::SetRangeStart(int index, int value) {
121   int offset = index * kRangeEntrySize + kRangeStartIndex;
122   Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)) = value;
123 }
124 
SetRangeEnd(int index,int value)125 void HandlerTable::SetRangeEnd(int index, int value) {
126   int offset = index * kRangeEntrySize + kRangeEndIndex;
127   Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)) = value;
128 }
129 
SetRangeHandler(int index,int handler_offset,CatchPrediction prediction)130 void HandlerTable::SetRangeHandler(int index, int handler_offset,
131                                    CatchPrediction prediction) {
132   int value = HandlerOffsetField::encode(handler_offset) |
133               HandlerPredictionField::encode(prediction);
134   int offset = index * kRangeEntrySize + kRangeHandlerIndex;
135   Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)) = value;
136 }
137 
SetRangeData(int index,int value)138 void HandlerTable::SetRangeData(int index, int value) {
139   int offset = index * kRangeEntrySize + kRangeDataIndex;
140   Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)) = value;
141 }
142 
143 // static
LengthForRange(int entries)144 int HandlerTable::LengthForRange(int entries) {
145   return entries * kRangeEntrySize * sizeof(int32_t);
146 }
147 
148 // static
EmitReturnTableStart(Assembler * masm)149 int HandlerTable::EmitReturnTableStart(Assembler* masm) {
150   masm->DataAlign(Code::kMetadataAlignment);
151   masm->RecordComment(";;; Exception handler table.");
152   int table_start = masm->pc_offset();
153   return table_start;
154 }
155 
156 // static
EmitReturnEntry(Assembler * masm,int offset,int handler)157 void HandlerTable::EmitReturnEntry(Assembler* masm, int offset, int handler) {
158   masm->dd(offset);
159   masm->dd(HandlerOffsetField::encode(handler));
160 }
161 
NumberOfRangeEntries() const162 int HandlerTable::NumberOfRangeEntries() const {
163   DCHECK_EQ(kRangeBasedEncoding, mode_);
164   return number_of_entries_;
165 }
166 
NumberOfReturnEntries() const167 int HandlerTable::NumberOfReturnEntries() const {
168   DCHECK_EQ(kReturnAddressBasedEncoding, mode_);
169   return number_of_entries_;
170 }
171 
LookupRange(int pc_offset,int * data_out,CatchPrediction * prediction_out)172 int HandlerTable::LookupRange(int pc_offset, int* data_out,
173                               CatchPrediction* prediction_out) {
174   int innermost_handler = -1;
175 #ifdef DEBUG
176   // Assuming that ranges are well nested, we don't need to track the innermost
177   // offsets. This is just to verify that the table is actually well nested.
178   int innermost_start = std::numeric_limits<int>::min();
179   int innermost_end = std::numeric_limits<int>::max();
180 #endif
181   for (int i = 0; i < NumberOfRangeEntries(); ++i) {
182     int start_offset = GetRangeStart(i);
183     int end_offset = GetRangeEnd(i);
184     int handler_offset = GetRangeHandler(i);
185     int handler_data = GetRangeData(i);
186     CatchPrediction prediction = GetRangePrediction(i);
187     if (pc_offset >= start_offset && pc_offset < end_offset) {
188       DCHECK_GE(start_offset, innermost_start);
189       DCHECK_LT(end_offset, innermost_end);
190       innermost_handler = handler_offset;
191 #ifdef DEBUG
192       innermost_start = start_offset;
193       innermost_end = end_offset;
194 #endif
195       if (data_out) *data_out = handler_data;
196       if (prediction_out) *prediction_out = prediction;
197     }
198   }
199   return innermost_handler;
200 }
201 
LookupReturn(int pc_offset)202 int HandlerTable::LookupReturn(int pc_offset) {
203   // We only implement the methods needed by the standard libraries we care
204   // about. This is not technically a full random access iterator by the spec.
205   struct Iterator : base::iterator<std::random_access_iterator_tag, int> {
206     Iterator(HandlerTable* tbl, int idx) : table(tbl), index(idx) {}
207     value_type operator*() const { return table->GetReturnOffset(index); }
208     bool operator!=(const Iterator& other) const { return !(*this == other); }
209     bool operator==(const Iterator& other) const {
210       return index == other.index;
211     }
212     // GLIBCXX_DEBUG checks uses the <= comparator.
213     bool operator<=(const Iterator& other) { return index <= other.index; }
214     Iterator& operator++() {
215       index++;
216       return *this;
217     }
218     Iterator& operator--() {
219       index--;
220       return *this;
221     }
222     Iterator& operator+=(difference_type offset) {
223       index += offset;
224       return *this;
225     }
226     difference_type operator-(const Iterator& other) const {
227       return index - other.index;
228     }
229     HandlerTable* table;
230     int index;
231   };
232   Iterator begin{this, 0}, end{this, NumberOfReturnEntries()};
233   SLOW_DCHECK(std::is_sorted(begin, end));  // Must be sorted.
234   Iterator result = std::lower_bound(begin, end, pc_offset);
235   bool exact_match = result != end && *result == pc_offset;
236   return exact_match ? GetReturnHandler(result.index) : -1;
237 }
238 
239 #ifdef ENABLE_DISASSEMBLER
240 
HandlerTableRangePrint(std::ostream & os)241 void HandlerTable::HandlerTableRangePrint(std::ostream& os) {
242   os << "   from   to       hdlr (prediction,   data)\n";
243   for (int i = 0; i < NumberOfRangeEntries(); ++i) {
244     int pc_start = GetRangeStart(i);
245     int pc_end = GetRangeEnd(i);
246     int handler_offset = GetRangeHandler(i);
247     int handler_data = GetRangeData(i);
248     CatchPrediction prediction = GetRangePrediction(i);
249     os << "  (" << std::setw(4) << pc_start << "," << std::setw(4) << pc_end
250        << ")  ->  " << std::setw(4) << handler_offset
251        << " (prediction=" << prediction << ", data=" << handler_data << ")\n";
252   }
253 }
254 
HandlerTableReturnPrint(std::ostream & os)255 void HandlerTable::HandlerTableReturnPrint(std::ostream& os) {
256   os << "  offset   handler\n";
257   for (int i = 0; i < NumberOfReturnEntries(); ++i) {
258     int pc_offset = GetReturnOffset(i);
259     int handler_offset = GetReturnHandler(i);
260     os << std::hex << "    " << std::setw(4) << pc_offset << "  ->  "
261        << std::setw(4) << handler_offset << std::dec << "\n";
262   }
263 }
264 
265 #endif  // ENABLE_DISASSEMBLER
266 
267 }  // namespace internal
268 }  // namespace v8
269