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