Home | History | Annotate | Download | only in src
      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