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 | #ifndef V8_HANDLER_TABLE_H_ |
6 | #define V8_HANDLER_TABLE_H_ |
7 | |
8 | #include "src/assert-scope.h" |
9 | #include "src/globals.h" |
10 | #include "src/utils.h" |
11 | |
12 | namespace v8 { |
13 | namespace internal { |
14 | |
15 | class Assembler; |
16 | class ByteArray; |
17 | class BytecodeArray; |
18 | |
19 | // HandlerTable is a byte array containing entries for exception handlers in |
20 | // the code object it is associated with. The tables come in two flavors: |
21 | // 1) Based on ranges: Used for unoptimized code. Stored in a {ByteArray} that |
22 | // is attached to each {BytecodeArray}. Contains one entry per exception |
23 | // handler and a range representing the try-block covered by that handler. |
24 | // Layout looks as follows: |
25 | // [ range-start , range-end , handler-offset , handler-data ] |
26 | // 2) Based on return addresses: Used for turbofanned code. Stored directly in |
27 | // the instruction stream of the {Code} object. Contains one entry per |
28 | // call-site that could throw an exception. Layout looks as follows: |
29 | // [ return-address-offset , handler-offset ] |
30 | class V8_EXPORT_PRIVATE HandlerTable { |
31 | public: |
32 | // Conservative prediction whether a given handler will locally catch an |
33 | // exception or cause a re-throw to outside the code boundary. Since this is |
34 | // undecidable it is merely an approximation (e.g. useful for debugger). |
35 | enum CatchPrediction { |
36 | UNCAUGHT, // The handler will (likely) rethrow the exception. |
37 | CAUGHT, // The exception will be caught by the handler. |
38 | PROMISE, // The exception will be caught and cause a promise rejection. |
39 | DESUGARING, // The exception will be caught, but both the exception and |
40 | // the catching are part of a desugaring and should therefore |
41 | // not be visible to the user (we won't notify the debugger of |
42 | // such exceptions). |
43 | ASYNC_AWAIT, // The exception will be caught and cause a promise rejection |
44 | // in the desugaring of an async function, so special |
45 | // async/await handling in the debugger can take place. |
46 | }; |
47 | |
48 | // Constructors for the various encodings. |
49 | explicit HandlerTable(Code code); |
50 | explicit HandlerTable(ByteArray byte_array); |
51 | explicit HandlerTable(BytecodeArray bytecode_array); |
52 | explicit HandlerTable(Address instruction_start, size_t handler_table_offset); |
53 | |
54 | // Getters for handler table based on ranges. |
55 | int GetRangeStart(int index) const; |
56 | int GetRangeEnd(int index) const; |
57 | int GetRangeHandler(int index) const; |
58 | int GetRangeData(int index) const; |
59 | |
60 | // Setters for handler table based on ranges. |
61 | void SetRangeStart(int index, int value); |
62 | void SetRangeEnd(int index, int value); |
63 | void SetRangeHandler(int index, int offset, CatchPrediction pred); |
64 | void SetRangeData(int index, int value); |
65 | |
66 | // Returns the required length of the underlying byte array. |
67 | static int LengthForRange(int entries); |
68 | |
69 | // Emitters for handler table based on return addresses. |
70 | static int EmitReturnTableStart(Assembler* masm, int entries); |
71 | static void EmitReturnEntry(Assembler* masm, int offset, int handler); |
72 | |
73 | // Lookup handler in a table based on ranges. The {pc_offset} is an offset to |
74 | // the start of the potentially throwing instruction (using return addresses |
75 | // for this value would be invalid). |
76 | int LookupRange(int pc_offset, int* data, CatchPrediction* prediction); |
77 | |
78 | // Lookup handler in a table based on return addresses. |
79 | int LookupReturn(int pc_offset); |
80 | |
81 | // Returns the number of entries in the table. |
82 | int NumberOfRangeEntries() const; |
83 | int NumberOfReturnEntries() const; |
84 | |
85 | #ifdef ENABLE_DISASSEMBLER |
86 | void HandlerTableRangePrint(std::ostream& os); // NOLINT |
87 | void HandlerTableReturnPrint(std::ostream& os); // NOLINT |
88 | #endif |
89 | |
90 | private: |
91 | enum EncodingMode { kRangeBasedEncoding, kReturnAddressBasedEncoding }; |
92 | |
93 | // Getters for handler table based on ranges. |
94 | CatchPrediction GetRangePrediction(int index) const; |
95 | |
96 | // Getters for handler table based on return addresses. |
97 | int GetReturnOffset(int index) const; |
98 | int GetReturnHandler(int index) const; |
99 | |
100 | // Number of entries in the loaded handler table. |
101 | int number_of_entries_; |
102 | |
103 | #ifdef DEBUG |
104 | // The encoding mode of the table. Mostly useful for debugging to check that |
105 | // used accessors and constructors fit together. |
106 | EncodingMode mode_; |
107 | #endif |
108 | |
109 | // Direct pointer into the encoded data. This pointer points into object on |
110 | // the GC heap (either {ByteArray} or {Code}) and hence would become stale |
111 | // during a collection. Hence we disallow any allocation. |
112 | Address raw_encoded_data_; |
113 | DISALLOW_HEAP_ALLOCATION(no_gc_) |
114 | |
115 | // Layout description for handler table based on ranges. |
116 | static const int kRangeStartIndex = 0; |
117 | static const int kRangeEndIndex = 1; |
118 | static const int kRangeHandlerIndex = 2; |
119 | static const int kRangeDataIndex = 3; |
120 | static const int kRangeEntrySize = 4; |
121 | |
122 | // Layout description for handler table based on return addresses. |
123 | static const int kReturnOffsetIndex = 0; |
124 | static const int kReturnHandlerIndex = 1; |
125 | static const int kReturnEntrySize = 2; |
126 | |
127 | // Encoding of the {handler} field. |
128 | class HandlerPredictionField : public BitField<CatchPrediction, 0, 3> {}; |
129 | class HandlerOffsetField : public BitField<int, 3, 29> {}; |
130 | }; |
131 | |
132 | } // namespace internal |
133 | } // namespace v8 |
134 | |
135 | #endif // V8_HANDLER_TABLE_H_ |
136 | |