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_EXECUTION_ISOLATE_DATA_H_
6#define V8_EXECUTION_ISOLATE_DATA_H_
7
8#include "src/builtins/builtins.h"
9#include "src/codegen/constants-arch.h"
10#include "src/codegen/external-reference-table.h"
11#include "src/execution/stack-guard.h"
12#include "src/execution/thread-local-top.h"
13#include "src/heap/linear-allocation-area.h"
14#include "src/roots/roots.h"
15#include "src/sandbox/external-pointer-table.h"
16#include "src/utils/utils.h"
17#include "testing/gtest/include/gtest/gtest_prod.h"  // nogncheck
18
19namespace v8 {
20namespace internal {
21
22class Isolate;
23
24// IsolateData fields, defined as: V(Offset, Size, Name)
25#define ISOLATE_DATA_FIELDS(V)                                                \
26  /* Misc. fields. */                                                         \
27  V(kCageBaseOffset, kSystemPointerSize, cage_base)                           \
28  V(kStackGuardOffset, StackGuard::kSizeInBytes, stack_guard)                 \
29  /* Tier 0 tables (small but fast access). */                                \
30  V(kBuiltinTier0EntryTableOffset,                                            \
31    Builtins::kBuiltinTier0Count* kSystemPointerSize,                         \
32    builtin_tier0_entry_table)                                                \
33  V(kBuiltinsTier0TableOffset,                                                \
34    Builtins::kBuiltinTier0Count* kSystemPointerSize, builtin_tier0_table)    \
35  /* Misc. fields. */                                                         \
36  V(kEmbedderDataOffset, Internals::kNumIsolateDataSlots* kSystemPointerSize, \
37    embedder_data)                                                            \
38  V(kFastCCallCallerFPOffset, kSystemPointerSize, fast_c_call_caller_fp)      \
39  V(kFastCCallCallerPCOffset, kSystemPointerSize, fast_c_call_caller_pc)      \
40  V(kFastApiCallTargetOffset, kSystemPointerSize, fast_api_call_target)       \
41  V(kLongTaskStatsCounterOffset, kSizetSize, long_task_stats_counter)         \
42  /* Full tables (arbitrary size, potentially slower access). */              \
43  V(kRootsTableOffset, RootsTable::kEntriesCount* kSystemPointerSize,         \
44    roots_table)                                                              \
45  V(kExternalReferenceTableOffset, ExternalReferenceTable::kSizeInBytes,      \
46    external_reference_table)                                                 \
47  V(kThreadLocalTopOffset, ThreadLocalTop::kSizeInBytes, thread_local_top)    \
48  V(kBuiltinEntryTableOffset, Builtins::kBuiltinCount* kSystemPointerSize,    \
49    builtin_entry_table)                                                      \
50  V(kBuiltinTableOffset, Builtins::kBuiltinCount* kSystemPointerSize,         \
51    builtin_table)                                                            \
52  /* Linear allocation areas for the heap's new and old space */              \
53  V(kNewAllocationInfo, LinearAllocationArea::kSize, new_allocation_info)     \
54  V(kOldAllocationInfo, LinearAllocationArea::kSize, old_allocation_info)     \
55  ISOLATE_DATA_FIELDS_SANDBOXED_EXTERNAL_POINTERS(V)                          \
56  V(kStackIsIterableOffset, kUInt8Size, stack_is_iterable)
57
58#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
59#define ISOLATE_DATA_FIELDS_SANDBOXED_EXTERNAL_POINTERS(V)    \
60  V(kExternalPointerTableOffset, ExternalPointerTable::kSize, \
61    external_pointer_table)
62#else
63#define ISOLATE_DATA_FIELDS_SANDBOXED_EXTERNAL_POINTERS(V)
64#endif  // V8_SANDBOXED_EXTERNAL_POINTERS
65
66// This class contains a collection of data accessible from both C++ runtime
67// and compiled code (including builtins, interpreter bytecode handlers and
68// optimized code). The compiled code accesses the isolate data fields
69// indirectly via the root register.
70class IsolateData final {
71 public:
72  IsolateData(Isolate* isolate, Address cage_base)
73      : cage_base_(cage_base), stack_guard_(isolate) {}
74
75  IsolateData(const IsolateData&) = delete;
76  IsolateData& operator=(const IsolateData&) = delete;
77
78  static constexpr intptr_t kIsolateRootBias = kRootRegisterBias;
79
80  // The value of the kRootRegister.
81  Address isolate_root() const {
82    return reinterpret_cast<Address>(this) + kIsolateRootBias;
83  }
84
85  // Root-register-relative offsets.
86
87#define V(Offset, Size, Name) \
88  static constexpr int Name##_offset() { return Offset - kIsolateRootBias; }
89  ISOLATE_DATA_FIELDS(V)
90#undef V
91
92  static constexpr int root_slot_offset(RootIndex root_index) {
93    return roots_table_offset() + RootsTable::offset_of(root_index);
94  }
95
96  static constexpr int BuiltinEntrySlotOffset(Builtin id) {
97    DCHECK(Builtins::IsBuiltinId(id));
98    return (Builtins::IsTier0(id) ? builtin_tier0_entry_table_offset()
99                                  : builtin_entry_table_offset()) +
100           Builtins::ToInt(id) * kSystemPointerSize;
101  }
102  // TODO(ishell): remove in favour of typified id version.
103  static constexpr int builtin_slot_offset(int builtin_index) {
104    return BuiltinSlotOffset(Builtins::FromInt(builtin_index));
105  }
106  static constexpr int BuiltinSlotOffset(Builtin id) {
107    return (Builtins::IsTier0(id) ? builtin_tier0_table_offset()
108                                  : builtin_table_offset()) +
109           Builtins::ToInt(id) * kSystemPointerSize;
110  }
111
112#define V(Offset, Size, Name) \
113  Address Name##_address() { return reinterpret_cast<Address>(&Name##_); }
114  ISOLATE_DATA_FIELDS(V)
115#undef V
116
117  Address fast_c_call_caller_fp() const { return fast_c_call_caller_fp_; }
118  Address fast_c_call_caller_pc() const { return fast_c_call_caller_pc_; }
119  Address fast_api_call_target() const { return fast_api_call_target_; }
120  // The value of kPointerCageBaseRegister.
121  Address cage_base() const { return cage_base_; }
122  StackGuard* stack_guard() { return &stack_guard_; }
123  Address* builtin_tier0_entry_table() { return builtin_tier0_entry_table_; }
124  Address* builtin_tier0_table() { return builtin_tier0_table_; }
125  RootsTable& roots() { return roots_table_; }
126  const RootsTable& roots() const { return roots_table_; }
127  ExternalReferenceTable* external_reference_table() {
128    return &external_reference_table_;
129  }
130  ThreadLocalTop& thread_local_top() { return thread_local_top_; }
131  ThreadLocalTop const& thread_local_top() const { return thread_local_top_; }
132  Address* builtin_entry_table() { return builtin_entry_table_; }
133  Address* builtin_table() { return builtin_table_; }
134  uint8_t stack_is_iterable() const { return stack_is_iterable_; }
135
136  // Returns true if this address points to data stored in this instance. If
137  // it's the case then the value can be accessed indirectly through the root
138  // register.
139  bool contains(Address address) const {
140    STATIC_ASSERT(std::is_unsigned<Address>::value);
141    Address start = reinterpret_cast<Address>(this);
142    return (address - start) < sizeof(*this);
143  }
144
145 private:
146  // Static layout definition.
147  //
148  // Note: The location of fields within IsolateData is significant. The
149  // closer they are to the value of kRootRegister (i.e.: isolate_root()), the
150  // cheaper it is to access them. See also: https://crbug.com/993264.
151  // The recommended guideline is to put frequently-accessed fields close to
152  // the beginning of IsolateData.
153#define FIELDS(V)                                                      \
154  ISOLATE_DATA_FIELDS(V)                                               \
155  /* This padding aligns IsolateData size by 8 bytes. */               \
156  V(kPaddingOffset,                                                    \
157    8 + RoundUp<8>(static_cast<int>(kPaddingOffset)) - kPaddingOffset) \
158  /* Total size. */                                                    \
159  V(kSize, 0)
160
161  DEFINE_FIELD_OFFSET_CONSTANTS(0, FIELDS)
162#undef FIELDS
163
164  const Address cage_base_;
165
166  // Fields related to the system and JS stack. In particular, this contains
167  // the stack limit used by stack checks in generated code.
168  StackGuard stack_guard_;
169
170  // Tier 0 tables. See also builtin_entry_table_ and builtin_table_.
171  Address builtin_tier0_entry_table_[Builtins::kBuiltinTier0Count] = {};
172  Address builtin_tier0_table_[Builtins::kBuiltinTier0Count] = {};
173
174  // These fields are accessed through the API, offsets must be kept in sync
175  // with v8::internal::Internals (in include/v8-internal.h) constants. The
176  // layout consistency is verified in Isolate::CheckIsolateLayout() using
177  // runtime checks.
178  void* embedder_data_[Internals::kNumIsolateDataSlots] = {};
179
180  // Stores the state of the caller for TurboAssembler::CallCFunction so that
181  // the sampling CPU profiler can iterate the stack during such calls. These
182  // are stored on IsolateData so that they can be stored to with only one move
183  // instruction in compiled code.
184  //
185  // The FP and PC that are saved right before TurboAssembler::CallCFunction.
186  Address fast_c_call_caller_fp_ = kNullAddress;
187  Address fast_c_call_caller_pc_ = kNullAddress;
188  // The address of the fast API callback right before it's executed from
189  // generated code.
190  Address fast_api_call_target_ = kNullAddress;
191
192  // Used for implementation of LongTaskStats. Counts the number of potential
193  // long tasks.
194  size_t long_task_stats_counter_ = 0;
195
196  RootsTable roots_table_;
197  ExternalReferenceTable external_reference_table_;
198
199  ThreadLocalTop thread_local_top_;
200
201  // The entry points for builtins. This corresponds to
202  // Code::InstructionStart() for each Code object in the builtins table below.
203  // The entry table is in IsolateData for easy access through kRootRegister.
204  Address builtin_entry_table_[Builtins::kBuiltinCount] = {};
205
206  // The entries in this array are tagged pointers to Code objects.
207  Address builtin_table_[Builtins::kBuiltinCount] = {};
208
209  LinearAllocationArea new_allocation_info_;
210  LinearAllocationArea old_allocation_info_;
211
212  // Table containing pointers to external objects.
213#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
214  ExternalPointerTable external_pointer_table_;
215#endif
216
217  // Whether the SafeStackFrameIterator can successfully iterate the current
218  // stack. Only valid values are 0 or 1.
219  uint8_t stack_is_iterable_ = 1;
220
221  // Ensure the size is 8-byte aligned in order to make alignment of the field
222  // following the IsolateData field predictable. This solves the issue with
223  // C++ compilers for 32-bit platforms which are not consistent at aligning
224  // int64_t fields.
225  // In order to avoid dealing with zero-size arrays the padding size is always
226  // in the range [8, 15).
227  STATIC_ASSERT(kPaddingOffsetEnd + 1 - kPaddingOffset >= 8);
228  char padding_[kPaddingOffsetEnd + 1 - kPaddingOffset];
229
230  V8_INLINE static void AssertPredictableLayout();
231
232  friend class Isolate;
233  friend class Heap;
234  FRIEND_TEST(HeapTest, ExternalLimitDefault);
235  FRIEND_TEST(HeapTest, ExternalLimitStaysAboveDefaultForExplicitHandling);
236};
237
238// IsolateData object must have "predictable" layout which does not change when
239// cross-compiling to another platform. Otherwise there may be compatibility
240// issues because of different compilers used for snapshot generator and
241// actual V8 code.
242void IsolateData::AssertPredictableLayout() {
243  STATIC_ASSERT(std::is_standard_layout<RootsTable>::value);
244  STATIC_ASSERT(std::is_standard_layout<ThreadLocalTop>::value);
245  STATIC_ASSERT(std::is_standard_layout<ExternalReferenceTable>::value);
246  STATIC_ASSERT(std::is_standard_layout<IsolateData>::value);
247#define V(Offset, Size, Name) \
248  STATIC_ASSERT(offsetof(IsolateData, Name##_) == Offset);
249  ISOLATE_DATA_FIELDS(V)
250#undef V
251  STATIC_ASSERT(sizeof(IsolateData) == IsolateData::kSize);
252}
253
254#undef ISOLATE_DATA_FIELDS_SANDBOXED_EXTERNAL_POINTERS
255#undef ISOLATE_DATA_FIELDS
256
257}  // namespace internal
258}  // namespace v8
259
260#endif  // V8_EXECUTION_ISOLATE_DATA_H_
261