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