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 16 HandlerTable::HandlerTable(Code* code) 17 : HandlerTable(code->InstructionStart(), code->handler_table_offset()) {} 18 19 HandlerTable::HandlerTable(BytecodeArray* bytecode_array) 20 : HandlerTable(bytecode_array->handler_table()) {} 21 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 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 45 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 52 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 59 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 67 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 74 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 83 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 90 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 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 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 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 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 122 int HandlerTable::LengthForRange(int entries) { 123 return entries * kRangeEntrySize * sizeof(int32_t); 124 } 125 126 // static 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 136 void HandlerTable::EmitReturnEntry(Assembler* masm, int offset, int handler) { 137 masm->dd(offset); 138 masm->dd(HandlerOffsetField::encode(handler)); 139 } 140 141 int HandlerTable::NumberOfRangeEntries() const { 142 DCHECK_EQ(kRangeBasedEncoding, mode_); 143 return number_of_entries_; 144 } 145 146 int HandlerTable::NumberOfReturnEntries() const { 147 DCHECK_EQ(kReturnAddressBasedEncoding, mode_); 148 return number_of_entries_; 149 } 150 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. 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 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 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