• 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/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