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