// Copyright 2018 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/handler-table.h" #include #include "src/assembler-inl.h" #include "src/objects-inl.h" #include "src/objects/code-inl.h" namespace v8 { namespace internal { HandlerTable::HandlerTable(Code* code) : HandlerTable(code->InstructionStart(), code->handler_table_offset()) {} HandlerTable::HandlerTable(BytecodeArray* bytecode_array) : HandlerTable(bytecode_array->handler_table()) {} HandlerTable::HandlerTable(ByteArray* byte_array) : number_of_entries_(byte_array->length() / kRangeEntrySize / sizeof(int32_t)), #ifdef DEBUG mode_(kRangeBasedEncoding), #endif raw_encoded_data_( reinterpret_cast
(byte_array->GetDataStartAddress())) { } HandlerTable::HandlerTable(Address instruction_start, size_t handler_table_offset) : number_of_entries_(0), #ifdef DEBUG mode_(kReturnAddressBasedEncoding), #endif raw_encoded_data_(instruction_start + handler_table_offset) { if (handler_table_offset > 0) { number_of_entries_ = Memory(raw_encoded_data_); raw_encoded_data_ += sizeof(int32_t); } } int HandlerTable::GetRangeStart(int index) const { DCHECK_EQ(kRangeBasedEncoding, mode_); DCHECK_LT(index, NumberOfRangeEntries()); int offset = index * kRangeEntrySize + kRangeStartIndex; return Memory(raw_encoded_data_ + offset * sizeof(int32_t)); } int HandlerTable::GetRangeEnd(int index) const { DCHECK_EQ(kRangeBasedEncoding, mode_); DCHECK_LT(index, NumberOfRangeEntries()); int offset = index * kRangeEntrySize + kRangeEndIndex; return Memory(raw_encoded_data_ + offset * sizeof(int32_t)); } int HandlerTable::GetRangeHandler(int index) const { DCHECK_EQ(kRangeBasedEncoding, mode_); DCHECK_LT(index, NumberOfRangeEntries()); int offset = index * kRangeEntrySize + kRangeHandlerIndex; return HandlerOffsetField::decode( Memory(raw_encoded_data_ + offset * sizeof(int32_t))); } int HandlerTable::GetRangeData(int index) const { DCHECK_EQ(kRangeBasedEncoding, mode_); DCHECK_LT(index, NumberOfRangeEntries()); int offset = index * kRangeEntrySize + kRangeDataIndex; return Memory(raw_encoded_data_ + offset * sizeof(int32_t)); } HandlerTable::CatchPrediction HandlerTable::GetRangePrediction( int index) const { DCHECK_EQ(kRangeBasedEncoding, mode_); DCHECK_LT(index, NumberOfRangeEntries()); int offset = index * kRangeEntrySize + kRangeHandlerIndex; return HandlerPredictionField::decode( Memory(raw_encoded_data_ + offset * sizeof(int32_t))); } int HandlerTable::GetReturnOffset(int index) const { DCHECK_EQ(kReturnAddressBasedEncoding, mode_); DCHECK_LT(index, NumberOfReturnEntries()); int offset = index * kReturnEntrySize + kReturnOffsetIndex; return Memory(raw_encoded_data_ + offset * sizeof(int32_t)); } int HandlerTable::GetReturnHandler(int index) const { DCHECK_EQ(kReturnAddressBasedEncoding, mode_); DCHECK_LT(index, NumberOfReturnEntries()); int offset = index * kReturnEntrySize + kReturnHandlerIndex; return HandlerOffsetField::decode( Memory(raw_encoded_data_ + offset * sizeof(int32_t))); } void HandlerTable::SetRangeStart(int index, int value) { int offset = index * kRangeEntrySize + kRangeStartIndex; Memory(raw_encoded_data_ + offset * sizeof(int32_t)) = value; } void HandlerTable::SetRangeEnd(int index, int value) { int offset = index * kRangeEntrySize + kRangeEndIndex; Memory(raw_encoded_data_ + offset * sizeof(int32_t)) = value; } void HandlerTable::SetRangeHandler(int index, int handler_offset, CatchPrediction prediction) { int value = HandlerOffsetField::encode(handler_offset) | HandlerPredictionField::encode(prediction); int offset = index * kRangeEntrySize + kRangeHandlerIndex; Memory(raw_encoded_data_ + offset * sizeof(int32_t)) = value; } void HandlerTable::SetRangeData(int index, int value) { int offset = index * kRangeEntrySize + kRangeDataIndex; Memory(raw_encoded_data_ + offset * sizeof(int32_t)) = value; } // static int HandlerTable::LengthForRange(int entries) { return entries * kRangeEntrySize * sizeof(int32_t); } // static int HandlerTable::EmitReturnTableStart(Assembler* masm, int entries) { masm->DataAlign(sizeof(int32_t)); // Make sure entries are aligned. masm->RecordComment(";;; Exception handler table."); int table_start = masm->pc_offset(); masm->dd(entries); return table_start; } // static void HandlerTable::EmitReturnEntry(Assembler* masm, int offset, int handler) { masm->dd(offset); masm->dd(HandlerOffsetField::encode(handler)); } int HandlerTable::NumberOfRangeEntries() const { DCHECK_EQ(kRangeBasedEncoding, mode_); return number_of_entries_; } int HandlerTable::NumberOfReturnEntries() const { DCHECK_EQ(kReturnAddressBasedEncoding, mode_); return number_of_entries_; } int HandlerTable::LookupRange(int pc_offset, int* data_out, CatchPrediction* prediction_out) { int innermost_handler = -1; #ifdef DEBUG // Assuming that ranges are well nested, we don't need to track the innermost // offsets. This is just to verify that the table is actually well nested. int innermost_start = std::numeric_limits::min(); int innermost_end = std::numeric_limits::max(); #endif for (int i = 0; i < NumberOfRangeEntries(); ++i) { int start_offset = GetRangeStart(i); int end_offset = GetRangeEnd(i); int handler_offset = GetRangeHandler(i); int handler_data = GetRangeData(i); CatchPrediction prediction = GetRangePrediction(i); if (pc_offset >= start_offset && pc_offset < end_offset) { DCHECK_GE(start_offset, innermost_start); DCHECK_LT(end_offset, innermost_end); innermost_handler = handler_offset; #ifdef DEBUG innermost_start = start_offset; innermost_end = end_offset; #endif if (data_out) *data_out = handler_data; if (prediction_out) *prediction_out = prediction; } } return innermost_handler; } // TODO(turbofan): Make sure table is sorted and use binary search. int HandlerTable::LookupReturn(int pc_offset) { for (int i = 0; i < NumberOfReturnEntries(); ++i) { int return_offset = GetReturnOffset(i); if (pc_offset == return_offset) { return GetReturnHandler(i); } } return -1; } #ifdef ENABLE_DISASSEMBLER void HandlerTable::HandlerTableRangePrint(std::ostream& os) { os << " from to hdlr (prediction, data)\n"; for (int i = 0; i < NumberOfRangeEntries(); ++i) { int pc_start = GetRangeStart(i); int pc_end = GetRangeEnd(i); int handler_offset = GetRangeHandler(i); int handler_data = GetRangeData(i); CatchPrediction prediction = GetRangePrediction(i); os << " (" << std::setw(4) << pc_start << "," << std::setw(4) << pc_end << ") -> " << std::setw(4) << handler_offset << " (prediction=" << prediction << ", data=" << handler_data << ")\n"; } } void HandlerTable::HandlerTableReturnPrint(std::ostream& os) { os << " offset handler\n"; for (int i = 0; i < NumberOfReturnEntries(); ++i) { int pc_offset = GetReturnOffset(i); int handler_offset = GetReturnHandler(i); os << std::hex << " " << std::setw(4) << pc_offset << " -> " << std::setw(4) << handler_offset << std::dec << "\n"; } } #endif // ENABLE_DISASSEMBLER } // namespace internal } // namespace v8