11cb0ef41Sopenharmony_ci// Copyright 2018 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include "src/codegen/handler-table.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include <algorithm>
81cb0ef41Sopenharmony_ci#include <iomanip>
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ci#include "src/base/iterator.h"
111cb0ef41Sopenharmony_ci#include "src/codegen/assembler-inl.h"
121cb0ef41Sopenharmony_ci#include "src/objects/code-inl.h"
131cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h"
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_ci#if V8_ENABLE_WEBASSEMBLY
161cb0ef41Sopenharmony_ci#include "src/wasm/wasm-code-manager.h"
171cb0ef41Sopenharmony_ci#endif  // V8_ENABLE_WEBASSEMBLY
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_cinamespace v8 {
201cb0ef41Sopenharmony_cinamespace internal {
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ciHandlerTable::HandlerTable(Code code)
231cb0ef41Sopenharmony_ci    : HandlerTable(code.HandlerTableAddress(), code.handler_table_size(),
241cb0ef41Sopenharmony_ci                   kReturnAddressBasedEncoding) {}
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_ci#if V8_ENABLE_WEBASSEMBLY
271cb0ef41Sopenharmony_ciHandlerTable::HandlerTable(const wasm::WasmCode* code)
281cb0ef41Sopenharmony_ci    : HandlerTable(code->handler_table(), code->handler_table_size(),
291cb0ef41Sopenharmony_ci                   kReturnAddressBasedEncoding) {}
301cb0ef41Sopenharmony_ci#endif  // V8_ENABLE_WEBASSEMBLY
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_ciHandlerTable::HandlerTable(BytecodeArray bytecode_array)
331cb0ef41Sopenharmony_ci    : HandlerTable(bytecode_array.handler_table()) {}
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ciHandlerTable::HandlerTable(ByteArray byte_array)
361cb0ef41Sopenharmony_ci    : HandlerTable(reinterpret_cast<Address>(byte_array.GetDataStartAddress()),
371cb0ef41Sopenharmony_ci                   byte_array.length(), kRangeBasedEncoding) {}
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ciHandlerTable::HandlerTable(Address handler_table, int handler_table_size,
401cb0ef41Sopenharmony_ci                           EncodingMode encoding_mode)
411cb0ef41Sopenharmony_ci    : number_of_entries_(handler_table_size / EntrySizeFromMode(encoding_mode) /
421cb0ef41Sopenharmony_ci                         sizeof(int32_t)),
431cb0ef41Sopenharmony_ci#ifdef DEBUG
441cb0ef41Sopenharmony_ci      mode_(encoding_mode),
451cb0ef41Sopenharmony_ci#endif
461cb0ef41Sopenharmony_ci      raw_encoded_data_(handler_table) {
471cb0ef41Sopenharmony_ci  // Check padding.
481cb0ef41Sopenharmony_ci  static_assert(4 < kReturnEntrySize * sizeof(int32_t), "allowed padding");
491cb0ef41Sopenharmony_ci  // For return address encoding, maximum padding is 4; otherwise, there should
501cb0ef41Sopenharmony_ci  // be no padding.
511cb0ef41Sopenharmony_ci  DCHECK_GE(kReturnAddressBasedEncoding == encoding_mode ? 4 : 0,
521cb0ef41Sopenharmony_ci            handler_table_size %
531cb0ef41Sopenharmony_ci                (EntrySizeFromMode(encoding_mode) * sizeof(int32_t)));
541cb0ef41Sopenharmony_ci}
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci// static
571cb0ef41Sopenharmony_ciint HandlerTable::EntrySizeFromMode(EncodingMode mode) {
581cb0ef41Sopenharmony_ci  switch (mode) {
591cb0ef41Sopenharmony_ci    case kReturnAddressBasedEncoding:
601cb0ef41Sopenharmony_ci      return kReturnEntrySize;
611cb0ef41Sopenharmony_ci    case kRangeBasedEncoding:
621cb0ef41Sopenharmony_ci      return kRangeEntrySize;
631cb0ef41Sopenharmony_ci  }
641cb0ef41Sopenharmony_ci  UNREACHABLE();
651cb0ef41Sopenharmony_ci}
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ciint HandlerTable::GetRangeStart(int index) const {
681cb0ef41Sopenharmony_ci  DCHECK_EQ(kRangeBasedEncoding, mode_);
691cb0ef41Sopenharmony_ci  DCHECK_LT(index, NumberOfRangeEntries());
701cb0ef41Sopenharmony_ci  int offset = index * kRangeEntrySize + kRangeStartIndex;
711cb0ef41Sopenharmony_ci  return Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t));
721cb0ef41Sopenharmony_ci}
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ciint HandlerTable::GetRangeEnd(int index) const {
751cb0ef41Sopenharmony_ci  DCHECK_EQ(kRangeBasedEncoding, mode_);
761cb0ef41Sopenharmony_ci  DCHECK_LT(index, NumberOfRangeEntries());
771cb0ef41Sopenharmony_ci  int offset = index * kRangeEntrySize + kRangeEndIndex;
781cb0ef41Sopenharmony_ci  return Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t));
791cb0ef41Sopenharmony_ci}
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ciint HandlerTable::GetRangeHandler(int index) const {
821cb0ef41Sopenharmony_ci  DCHECK_EQ(kRangeBasedEncoding, mode_);
831cb0ef41Sopenharmony_ci  DCHECK_LT(index, NumberOfRangeEntries());
841cb0ef41Sopenharmony_ci  int offset = index * kRangeEntrySize + kRangeHandlerIndex;
851cb0ef41Sopenharmony_ci  return HandlerOffsetField::decode(
861cb0ef41Sopenharmony_ci      Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)));
871cb0ef41Sopenharmony_ci}
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ciint HandlerTable::GetRangeData(int index) const {
901cb0ef41Sopenharmony_ci  DCHECK_EQ(kRangeBasedEncoding, mode_);
911cb0ef41Sopenharmony_ci  DCHECK_LT(index, NumberOfRangeEntries());
921cb0ef41Sopenharmony_ci  int offset = index * kRangeEntrySize + kRangeDataIndex;
931cb0ef41Sopenharmony_ci  return Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t));
941cb0ef41Sopenharmony_ci}
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ciHandlerTable::CatchPrediction HandlerTable::GetRangePrediction(
971cb0ef41Sopenharmony_ci    int index) const {
981cb0ef41Sopenharmony_ci  DCHECK_EQ(kRangeBasedEncoding, mode_);
991cb0ef41Sopenharmony_ci  DCHECK_LT(index, NumberOfRangeEntries());
1001cb0ef41Sopenharmony_ci  int offset = index * kRangeEntrySize + kRangeHandlerIndex;
1011cb0ef41Sopenharmony_ci  return HandlerPredictionField::decode(
1021cb0ef41Sopenharmony_ci      Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)));
1031cb0ef41Sopenharmony_ci}
1041cb0ef41Sopenharmony_ci
1051cb0ef41Sopenharmony_ciint HandlerTable::GetReturnOffset(int index) const {
1061cb0ef41Sopenharmony_ci  DCHECK_EQ(kReturnAddressBasedEncoding, mode_);
1071cb0ef41Sopenharmony_ci  DCHECK_LT(index, NumberOfReturnEntries());
1081cb0ef41Sopenharmony_ci  int offset = index * kReturnEntrySize + kReturnOffsetIndex;
1091cb0ef41Sopenharmony_ci  return Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t));
1101cb0ef41Sopenharmony_ci}
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ciint HandlerTable::GetReturnHandler(int index) const {
1131cb0ef41Sopenharmony_ci  DCHECK_EQ(kReturnAddressBasedEncoding, mode_);
1141cb0ef41Sopenharmony_ci  DCHECK_LT(index, NumberOfReturnEntries());
1151cb0ef41Sopenharmony_ci  int offset = index * kReturnEntrySize + kReturnHandlerIndex;
1161cb0ef41Sopenharmony_ci  return HandlerOffsetField::decode(
1171cb0ef41Sopenharmony_ci      Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)));
1181cb0ef41Sopenharmony_ci}
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_civoid HandlerTable::SetRangeStart(int index, int value) {
1211cb0ef41Sopenharmony_ci  int offset = index * kRangeEntrySize + kRangeStartIndex;
1221cb0ef41Sopenharmony_ci  Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)) = value;
1231cb0ef41Sopenharmony_ci}
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_civoid HandlerTable::SetRangeEnd(int index, int value) {
1261cb0ef41Sopenharmony_ci  int offset = index * kRangeEntrySize + kRangeEndIndex;
1271cb0ef41Sopenharmony_ci  Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)) = value;
1281cb0ef41Sopenharmony_ci}
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_civoid HandlerTable::SetRangeHandler(int index, int handler_offset,
1311cb0ef41Sopenharmony_ci                                   CatchPrediction prediction) {
1321cb0ef41Sopenharmony_ci  int value = HandlerOffsetField::encode(handler_offset) |
1331cb0ef41Sopenharmony_ci              HandlerPredictionField::encode(prediction);
1341cb0ef41Sopenharmony_ci  int offset = index * kRangeEntrySize + kRangeHandlerIndex;
1351cb0ef41Sopenharmony_ci  Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)) = value;
1361cb0ef41Sopenharmony_ci}
1371cb0ef41Sopenharmony_ci
1381cb0ef41Sopenharmony_civoid HandlerTable::SetRangeData(int index, int value) {
1391cb0ef41Sopenharmony_ci  int offset = index * kRangeEntrySize + kRangeDataIndex;
1401cb0ef41Sopenharmony_ci  Memory<int32_t>(raw_encoded_data_ + offset * sizeof(int32_t)) = value;
1411cb0ef41Sopenharmony_ci}
1421cb0ef41Sopenharmony_ci
1431cb0ef41Sopenharmony_ci// static
1441cb0ef41Sopenharmony_ciint HandlerTable::LengthForRange(int entries) {
1451cb0ef41Sopenharmony_ci  return entries * kRangeEntrySize * sizeof(int32_t);
1461cb0ef41Sopenharmony_ci}
1471cb0ef41Sopenharmony_ci
1481cb0ef41Sopenharmony_ci// static
1491cb0ef41Sopenharmony_ciint HandlerTable::EmitReturnTableStart(Assembler* masm) {
1501cb0ef41Sopenharmony_ci  masm->DataAlign(Code::kMetadataAlignment);
1511cb0ef41Sopenharmony_ci  masm->RecordComment(";;; Exception handler table.");
1521cb0ef41Sopenharmony_ci  int table_start = masm->pc_offset();
1531cb0ef41Sopenharmony_ci  return table_start;
1541cb0ef41Sopenharmony_ci}
1551cb0ef41Sopenharmony_ci
1561cb0ef41Sopenharmony_ci// static
1571cb0ef41Sopenharmony_civoid HandlerTable::EmitReturnEntry(Assembler* masm, int offset, int handler) {
1581cb0ef41Sopenharmony_ci  masm->dd(offset);
1591cb0ef41Sopenharmony_ci  masm->dd(HandlerOffsetField::encode(handler));
1601cb0ef41Sopenharmony_ci}
1611cb0ef41Sopenharmony_ci
1621cb0ef41Sopenharmony_ciint HandlerTable::NumberOfRangeEntries() const {
1631cb0ef41Sopenharmony_ci  DCHECK_EQ(kRangeBasedEncoding, mode_);
1641cb0ef41Sopenharmony_ci  return number_of_entries_;
1651cb0ef41Sopenharmony_ci}
1661cb0ef41Sopenharmony_ci
1671cb0ef41Sopenharmony_ciint HandlerTable::NumberOfReturnEntries() const {
1681cb0ef41Sopenharmony_ci  DCHECK_EQ(kReturnAddressBasedEncoding, mode_);
1691cb0ef41Sopenharmony_ci  return number_of_entries_;
1701cb0ef41Sopenharmony_ci}
1711cb0ef41Sopenharmony_ci
1721cb0ef41Sopenharmony_ciint HandlerTable::LookupRange(int pc_offset, int* data_out,
1731cb0ef41Sopenharmony_ci                              CatchPrediction* prediction_out) {
1741cb0ef41Sopenharmony_ci  int innermost_handler = -1;
1751cb0ef41Sopenharmony_ci#ifdef DEBUG
1761cb0ef41Sopenharmony_ci  // Assuming that ranges are well nested, we don't need to track the innermost
1771cb0ef41Sopenharmony_ci  // offsets. This is just to verify that the table is actually well nested.
1781cb0ef41Sopenharmony_ci  int innermost_start = std::numeric_limits<int>::min();
1791cb0ef41Sopenharmony_ci  int innermost_end = std::numeric_limits<int>::max();
1801cb0ef41Sopenharmony_ci#endif
1811cb0ef41Sopenharmony_ci  for (int i = 0; i < NumberOfRangeEntries(); ++i) {
1821cb0ef41Sopenharmony_ci    int start_offset = GetRangeStart(i);
1831cb0ef41Sopenharmony_ci    int end_offset = GetRangeEnd(i);
1841cb0ef41Sopenharmony_ci    int handler_offset = GetRangeHandler(i);
1851cb0ef41Sopenharmony_ci    int handler_data = GetRangeData(i);
1861cb0ef41Sopenharmony_ci    CatchPrediction prediction = GetRangePrediction(i);
1871cb0ef41Sopenharmony_ci    if (pc_offset >= start_offset && pc_offset < end_offset) {
1881cb0ef41Sopenharmony_ci      DCHECK_GE(start_offset, innermost_start);
1891cb0ef41Sopenharmony_ci      DCHECK_LT(end_offset, innermost_end);
1901cb0ef41Sopenharmony_ci      innermost_handler = handler_offset;
1911cb0ef41Sopenharmony_ci#ifdef DEBUG
1921cb0ef41Sopenharmony_ci      innermost_start = start_offset;
1931cb0ef41Sopenharmony_ci      innermost_end = end_offset;
1941cb0ef41Sopenharmony_ci#endif
1951cb0ef41Sopenharmony_ci      if (data_out) *data_out = handler_data;
1961cb0ef41Sopenharmony_ci      if (prediction_out) *prediction_out = prediction;
1971cb0ef41Sopenharmony_ci    }
1981cb0ef41Sopenharmony_ci  }
1991cb0ef41Sopenharmony_ci  return innermost_handler;
2001cb0ef41Sopenharmony_ci}
2011cb0ef41Sopenharmony_ci
2021cb0ef41Sopenharmony_ciint HandlerTable::LookupReturn(int pc_offset) {
2031cb0ef41Sopenharmony_ci  // We only implement the methods needed by the standard libraries we care
2041cb0ef41Sopenharmony_ci  // about. This is not technically a full random access iterator by the spec.
2051cb0ef41Sopenharmony_ci  struct Iterator : base::iterator<std::random_access_iterator_tag, int> {
2061cb0ef41Sopenharmony_ci    Iterator(HandlerTable* tbl, int idx) : table(tbl), index(idx) {}
2071cb0ef41Sopenharmony_ci    value_type operator*() const { return table->GetReturnOffset(index); }
2081cb0ef41Sopenharmony_ci    bool operator!=(const Iterator& other) const { return !(*this == other); }
2091cb0ef41Sopenharmony_ci    bool operator==(const Iterator& other) const {
2101cb0ef41Sopenharmony_ci      return index == other.index;
2111cb0ef41Sopenharmony_ci    }
2121cb0ef41Sopenharmony_ci    // GLIBCXX_DEBUG checks uses the <= comparator.
2131cb0ef41Sopenharmony_ci    bool operator<=(const Iterator& other) { return index <= other.index; }
2141cb0ef41Sopenharmony_ci    Iterator& operator++() {
2151cb0ef41Sopenharmony_ci      index++;
2161cb0ef41Sopenharmony_ci      return *this;
2171cb0ef41Sopenharmony_ci    }
2181cb0ef41Sopenharmony_ci    Iterator& operator--() {
2191cb0ef41Sopenharmony_ci      index--;
2201cb0ef41Sopenharmony_ci      return *this;
2211cb0ef41Sopenharmony_ci    }
2221cb0ef41Sopenharmony_ci    Iterator& operator+=(difference_type offset) {
2231cb0ef41Sopenharmony_ci      index += offset;
2241cb0ef41Sopenharmony_ci      return *this;
2251cb0ef41Sopenharmony_ci    }
2261cb0ef41Sopenharmony_ci    difference_type operator-(const Iterator& other) const {
2271cb0ef41Sopenharmony_ci      return index - other.index;
2281cb0ef41Sopenharmony_ci    }
2291cb0ef41Sopenharmony_ci    HandlerTable* table;
2301cb0ef41Sopenharmony_ci    int index;
2311cb0ef41Sopenharmony_ci  };
2321cb0ef41Sopenharmony_ci  Iterator begin{this, 0}, end{this, NumberOfReturnEntries()};
2331cb0ef41Sopenharmony_ci  SLOW_DCHECK(std::is_sorted(begin, end));  // Must be sorted.
2341cb0ef41Sopenharmony_ci  Iterator result = std::lower_bound(begin, end, pc_offset);
2351cb0ef41Sopenharmony_ci  bool exact_match = result != end && *result == pc_offset;
2361cb0ef41Sopenharmony_ci  return exact_match ? GetReturnHandler(result.index) : -1;
2371cb0ef41Sopenharmony_ci}
2381cb0ef41Sopenharmony_ci
2391cb0ef41Sopenharmony_ci#ifdef ENABLE_DISASSEMBLER
2401cb0ef41Sopenharmony_ci
2411cb0ef41Sopenharmony_civoid HandlerTable::HandlerTableRangePrint(std::ostream& os) {
2421cb0ef41Sopenharmony_ci  os << "   from   to       hdlr (prediction,   data)\n";
2431cb0ef41Sopenharmony_ci  for (int i = 0; i < NumberOfRangeEntries(); ++i) {
2441cb0ef41Sopenharmony_ci    int pc_start = GetRangeStart(i);
2451cb0ef41Sopenharmony_ci    int pc_end = GetRangeEnd(i);
2461cb0ef41Sopenharmony_ci    int handler_offset = GetRangeHandler(i);
2471cb0ef41Sopenharmony_ci    int handler_data = GetRangeData(i);
2481cb0ef41Sopenharmony_ci    CatchPrediction prediction = GetRangePrediction(i);
2491cb0ef41Sopenharmony_ci    os << "  (" << std::setw(4) << pc_start << "," << std::setw(4) << pc_end
2501cb0ef41Sopenharmony_ci       << ")  ->  " << std::setw(4) << handler_offset
2511cb0ef41Sopenharmony_ci       << " (prediction=" << prediction << ", data=" << handler_data << ")\n";
2521cb0ef41Sopenharmony_ci  }
2531cb0ef41Sopenharmony_ci}
2541cb0ef41Sopenharmony_ci
2551cb0ef41Sopenharmony_civoid HandlerTable::HandlerTableReturnPrint(std::ostream& os) {
2561cb0ef41Sopenharmony_ci  os << "  offset   handler\n";
2571cb0ef41Sopenharmony_ci  for (int i = 0; i < NumberOfReturnEntries(); ++i) {
2581cb0ef41Sopenharmony_ci    int pc_offset = GetReturnOffset(i);
2591cb0ef41Sopenharmony_ci    int handler_offset = GetReturnHandler(i);
2601cb0ef41Sopenharmony_ci    os << std::hex << "    " << std::setw(4) << pc_offset << "  ->  "
2611cb0ef41Sopenharmony_ci       << std::setw(4) << handler_offset << std::dec << "\n";
2621cb0ef41Sopenharmony_ci  }
2631cb0ef41Sopenharmony_ci}
2641cb0ef41Sopenharmony_ci
2651cb0ef41Sopenharmony_ci#endif  // ENABLE_DISASSEMBLER
2661cb0ef41Sopenharmony_ci
2671cb0ef41Sopenharmony_ci}  // namespace internal
2681cb0ef41Sopenharmony_ci}  // namespace v8
269