// 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. #ifndef V8_CODEGEN_HANDLER_TABLE_H_ #define V8_CODEGEN_HANDLER_TABLE_H_ #include "src/base/bit-field.h" #include "src/common/assert-scope.h" #include "src/common/globals.h" namespace v8 { namespace internal { class Assembler; class ByteArray; class BytecodeArray; namespace wasm { class WasmCode; } // namespace wasm // HandlerTable is a byte array containing entries for exception handlers in // the code object it is associated with. The tables come in two flavors: // 1) Based on ranges: Used for unoptimized code. Stored in a {ByteArray} that // is attached to each {BytecodeArray}. Contains one entry per exception // handler and a range representing the try-block covered by that handler. // Layout looks as follows: // [ range-start , range-end , handler-offset , handler-data ] // 2) Based on return addresses: Used for turbofanned code. Stored directly in // the instruction stream of the {Code} object. Contains one entry per // call-site that could throw an exception. Layout looks as follows: // [ return-address-offset , handler-offset ] class V8_EXPORT_PRIVATE HandlerTable { public: // Conservative prediction whether a given handler will locally catch an // exception or cause a re-throw to outside the code boundary. Since this is // undecidable it is merely an approximation (e.g. useful for debugger). enum CatchPrediction { UNCAUGHT, // The handler will (likely) rethrow the exception. CAUGHT, // The exception will be caught by the handler. PROMISE, // The exception will be caught and cause a promise rejection. DESUGARING, // The exception will be caught, but both the exception and // the catching are part of a desugaring and should therefore // not be visible to the user (we won't notify the debugger of // such exceptions). ASYNC_AWAIT, // The exception will be caught and cause a promise rejection // in the desugaring of an async function, so special // async/await handling in the debugger can take place. UNCAUGHT_ASYNC_AWAIT, // The exception will be caught and cause a promise // rejection in the desugaring of an async REPL // script. The corresponding message object needs to // be kept alive on the Isolate though. }; enum EncodingMode { kRangeBasedEncoding, kReturnAddressBasedEncoding }; // Constructors for the various encodings. explicit HandlerTable(Code code); explicit HandlerTable(ByteArray byte_array); explicit HandlerTable(const wasm::WasmCode* code); explicit HandlerTable(BytecodeArray bytecode_array); HandlerTable(Address handler_table, int handler_table_size, EncodingMode encoding_mode); // Getters for handler table based on ranges. int GetRangeStart(int index) const; int GetRangeEnd(int index) const; int GetRangeHandler(int index) const; int GetRangeData(int index) const; // Setters for handler table based on ranges. void SetRangeStart(int index, int value); void SetRangeEnd(int index, int value); void SetRangeHandler(int index, int offset, CatchPrediction pred); void SetRangeData(int index, int value); // Returns the required length of the underlying byte array. static int LengthForRange(int entries); // Emitters for handler table based on return addresses. static int EmitReturnTableStart(Assembler* masm); static void EmitReturnEntry(Assembler* masm, int offset, int handler); // Lookup handler in a table based on ranges. The {pc_offset} is an offset to // the start of the potentially throwing instruction (using return addresses // for this value would be invalid). int LookupRange(int pc_offset, int* data, CatchPrediction* prediction); // Lookup handler in a table based on return addresses. int LookupReturn(int pc_offset); // Returns the number of entries in the table. int NumberOfRangeEntries() const; int NumberOfReturnEntries() const; #ifdef ENABLE_DISASSEMBLER void HandlerTableRangePrint(std::ostream& os); // NOLINT void HandlerTableReturnPrint(std::ostream& os); // NOLINT #endif private: // Getters for handler table based on ranges. CatchPrediction GetRangePrediction(int index) const; // Gets entry size based on mode. static int EntrySizeFromMode(EncodingMode mode); // Getters for handler table based on return addresses. int GetReturnOffset(int index) const; int GetReturnHandler(int index) const; // Number of entries in the loaded handler table. const int number_of_entries_; #ifdef DEBUG // The encoding mode of the table. Mostly useful for debugging to check that // used accessors and constructors fit together. const EncodingMode mode_; #endif // Direct pointer into the encoded data. This pointer potentially points into // objects on the GC heap (either {ByteArray} or {Code}) and could become // stale during a collection. Hence we disallow any allocation. const Address raw_encoded_data_; DISALLOW_HEAP_ALLOCATION(no_gc_) // Layout description for handler table based on ranges. static const int kRangeStartIndex = 0; static const int kRangeEndIndex = 1; static const int kRangeHandlerIndex = 2; static const int kRangeDataIndex = 3; static const int kRangeEntrySize = 4; // Layout description for handler table based on return addresses. static const int kReturnOffsetIndex = 0; static const int kReturnHandlerIndex = 1; static const int kReturnEntrySize = 2; // Encoding of the {handler} field. using HandlerPredictionField = base::BitField<CatchPrediction, 0, 3>; using HandlerOffsetField = base::BitField<int, 3, 29>; }; } // namespace internal } // namespace v8 #endif // V8_CODEGEN_HANDLER_TABLE_H_