summaryrefslogtreecommitdiff
path: root/deps/v8/src/execution/isolate-data.h
blob: 9886287fe082461af560f0f2dd146fb82f931d31 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
// 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_EXECUTION_ISOLATE_DATA_H_
#define V8_EXECUTION_ISOLATE_DATA_H_

#include "src/builtins/builtins.h"
#include "src/codegen/constants-arch.h"
#include "src/codegen/external-reference-table.h"
#include "src/execution/stack-guard.h"
#include "src/execution/thread-local-top.h"
#include "src/heap/linear-allocation-area.h"
#include "src/roots/roots.h"
#include "src/sandbox/external-pointer-table.h"
#include "src/utils/utils.h"
#include "testing/gtest/include/gtest/gtest_prod.h"  // nogncheck

namespace v8 {
namespace internal {

class Isolate;

// IsolateData fields, defined as: V(Offset, Size, Name)
#define ISOLATE_DATA_FIELDS(V)                                                \
  /* Misc. fields. */                                                         \
  V(kCageBaseOffset, kSystemPointerSize, cage_base)                           \
  V(kStackGuardOffset, StackGuard::kSizeInBytes, stack_guard)                 \
  V(kIsMarkingFlag, kUInt8Size, is_marking_flag)                              \
  V(kIsMinorMarkingFlag, kUInt8Size, is_minor_marking_flag)                   \
  V(kIsProfilingOffset, kUInt8Size, is_profiling)                             \
  V(kStackIsIterableOffset, kUInt8Size, stack_is_iterable)                    \
  IF_TARGET_ARCH_64_BIT(V, kTablesAlignmentPaddingOffset,                     \
                        kSystemPointerSize - 4, tables_alignment_padding)     \
  /* Tier 0 tables (small but fast access). */                                \
  V(kBuiltinTier0EntryTableOffset,                                            \
    Builtins::kBuiltinTier0Count* kSystemPointerSize,                         \
    builtin_tier0_entry_table)                                                \
  V(kBuiltinsTier0TableOffset,                                                \
    Builtins::kBuiltinTier0Count* kSystemPointerSize, builtin_tier0_table)    \
  /* Misc. fields. */                                                         \
  V(kEmbedderDataOffset, Internals::kNumIsolateDataSlots* kSystemPointerSize, \
    embedder_data)                                                            \
  V(kFastCCallCallerFPOffset, kSystemPointerSize, fast_c_call_caller_fp)      \
  V(kFastCCallCallerPCOffset, kSystemPointerSize, fast_c_call_caller_pc)      \
  V(kFastApiCallTargetOffset, kSystemPointerSize, fast_api_call_target)       \
  V(kLongTaskStatsCounterOffset, kSizetSize, long_task_stats_counter)         \
  ISOLATE_DATA_FIELDS_POINTER_COMPRESSION(V)                                  \
  /* Full tables (arbitrary size, potentially slower access). */              \
  V(kRootsTableOffset, RootsTable::kEntriesCount* kSystemPointerSize,         \
    roots_table)                                                              \
  V(kExternalReferenceTableOffset, ExternalReferenceTable::kSizeInBytes,      \
    external_reference_table)                                                 \
  V(kThreadLocalTopOffset, ThreadLocalTop::kSizeInBytes, thread_local_top)    \
  V(kBuiltinEntryTableOffset, Builtins::kBuiltinCount* kSystemPointerSize,    \
    builtin_entry_table)                                                      \
  V(kBuiltinTableOffset, Builtins::kBuiltinCount* kSystemPointerSize,         \
    builtin_table)                                                            \
  /* Linear allocation areas for the heap's new and old space */              \
  V(kNewAllocationInfo, LinearAllocationArea::kSize, new_allocation_info)     \
  V(kOldAllocationInfo, LinearAllocationArea::kSize, old_allocation_info)

#ifdef V8_COMPRESS_POINTERS
#define ISOLATE_DATA_FIELDS_POINTER_COMPRESSION(V)            \
  V(kExternalPointerTableOffset, ExternalPointerTable::kSize, \
    external_pointer_table)                                   \
  V(kSharedExternalPointerTableOffset, kSystemPointerSize,    \
    shared_external_pointer_table)
#else
#define ISOLATE_DATA_FIELDS_POINTER_COMPRESSION(V)
#endif  // V8_COMPRESS_POINTERS

// This class contains a collection of data accessible from both C++ runtime
// and compiled code (including builtins, interpreter bytecode handlers and
// optimized code). The compiled code accesses the isolate data fields
// indirectly via the root register.
class IsolateData final {
 public:
  IsolateData(Isolate* isolate, Address cage_base)
      : cage_base_(cage_base), stack_guard_(isolate) {}

  IsolateData(const IsolateData&) = delete;
  IsolateData& operator=(const IsolateData&) = delete;

  static constexpr intptr_t kIsolateRootBias = kRootRegisterBias;

  // The value of the kRootRegister.
  Address isolate_root() const {
    return reinterpret_cast<Address>(this) + kIsolateRootBias;
  }

  // Root-register-relative offsets.

#define V(Offset, Size, Name) \
  static constexpr int Name##_offset() { return Offset - kIsolateRootBias; }
  ISOLATE_DATA_FIELDS(V)
#undef V

  static constexpr int root_slot_offset(RootIndex root_index) {
    return roots_table_offset() + RootsTable::offset_of(root_index);
  }

  static constexpr int BuiltinEntrySlotOffset(Builtin id) {
    DCHECK(Builtins::IsBuiltinId(id));
    return (Builtins::IsTier0(id) ? builtin_tier0_entry_table_offset()
                                  : builtin_entry_table_offset()) +
           Builtins::ToInt(id) * kSystemPointerSize;
  }
  // TODO(ishell): remove in favour of typified id version.
  static constexpr int builtin_slot_offset(int builtin_index) {
    return BuiltinSlotOffset(Builtins::FromInt(builtin_index));
  }
  static constexpr int BuiltinSlotOffset(Builtin id) {
    return (Builtins::IsTier0(id) ? builtin_tier0_table_offset()
                                  : builtin_table_offset()) +
           Builtins::ToInt(id) * kSystemPointerSize;
  }

#define V(Offset, Size, Name) \
  Address Name##_address() { return reinterpret_cast<Address>(&Name##_); }
  ISOLATE_DATA_FIELDS(V)
#undef V

  Address fast_c_call_caller_fp() const { return fast_c_call_caller_fp_; }
  Address fast_c_call_caller_pc() const { return fast_c_call_caller_pc_; }
  Address fast_api_call_target() const { return fast_api_call_target_; }
  // The value of kPointerCageBaseRegister.
  Address cage_base() const { return cage_base_; }
  StackGuard* stack_guard() { return &stack_guard_; }
  Address* builtin_tier0_entry_table() { return builtin_tier0_entry_table_; }
  Address* builtin_tier0_table() { return builtin_tier0_table_; }
  RootsTable& roots() { return roots_table_; }
  const RootsTable& roots() const { return roots_table_; }
  ExternalReferenceTable* external_reference_table() {
    return &external_reference_table_;
  }
  ThreadLocalTop& thread_local_top() { return thread_local_top_; }
  ThreadLocalTop const& thread_local_top() const { return thread_local_top_; }
  Address* builtin_entry_table() { return builtin_entry_table_; }
  Address* builtin_table() { return builtin_table_; }
  uint8_t stack_is_iterable() const { return stack_is_iterable_; }

  // Returns true if this address points to data stored in this instance. If
  // it's the case then the value can be accessed indirectly through the root
  // register.
  bool contains(Address address) const {
    static_assert(std::is_unsigned<Address>::value);
    Address start = reinterpret_cast<Address>(this);
    return (address - start) < sizeof(*this);
  }

 private:
  // Static layout definition.
  //
  // Note: The location of fields within IsolateData is significant. The
  // closer they are to the value of kRootRegister (i.e.: isolate_root()), the
  // cheaper it is to access them. See also: https://crbug.com/993264.
  // The recommended guideline is to put frequently-accessed fields close to
  // the beginning of IsolateData.
#define FIELDS(V)                                                      \
  ISOLATE_DATA_FIELDS(V)                                               \
  /* This padding aligns IsolateData size by 8 bytes. */               \
  V(kPaddingOffset,                                                    \
    8 + RoundUp<8>(static_cast<int>(kPaddingOffset)) - kPaddingOffset) \
  /* Total size. */                                                    \
  V(kSize, 0)

  DEFINE_FIELD_OFFSET_CONSTANTS(0, FIELDS)
#undef FIELDS

  const Address cage_base_;

  // Fields related to the system and JS stack. In particular, this contains
  // the stack limit used by stack checks in generated code.
  StackGuard stack_guard_;

  //
  // Hot flags that are regularily checked.
  //

  // These flags are regularily checked by write barriers.
  // Only valid values are 0 or 1.
  uint8_t is_marking_flag_ = false;
  uint8_t is_minor_marking_flag_ = false;

  // true if the Isolate is being profiled. Causes collection of extra compile
  // info.
  // This flag is checked on every API callback/getter call.
  // Only valid values are 0 or 1.
  std::atomic<uint8_t> is_profiling_{false};

  //
  // Not super hot flags, which are put here because we have to align the
  // builtin entry table to kSystemPointerSize anyway.
  //

  // Whether the SafeStackFrameIterator can successfully iterate the current
  // stack. Only valid values are 0 or 1.
  uint8_t stack_is_iterable_ = 1;

#if V8_TARGET_ARCH_64_BIT
  // Ensure the following tables are kSystemPointerSize-byte aligned.
  // 32-bit architectures currently don't require the alignment.
  static_assert(FIELD_SIZE(kTablesAlignmentPaddingOffset) > 0);
  uint8_t tables_alignment_padding_[FIELD_SIZE(kTablesAlignmentPaddingOffset)];
#endif  // V8_TARGET_ARCH_64_BIT

  // Tier 0 tables. See also builtin_entry_table_ and builtin_table_.
  Address builtin_tier0_entry_table_[Builtins::kBuiltinTier0Count] = {};
  Address builtin_tier0_table_[Builtins::kBuiltinTier0Count] = {};

  // These fields are accessed through the API, offsets must be kept in sync
  // with v8::internal::Internals (in include/v8-internal.h) constants. The
  // layout consistency is verified in Isolate::CheckIsolateLayout() using
  // runtime checks.
  void* embedder_data_[Internals::kNumIsolateDataSlots] = {};

  // Stores the state of the caller for TurboAssembler::CallCFunction so that
  // the sampling CPU profiler can iterate the stack during such calls. These
  // are stored on IsolateData so that they can be stored to with only one move
  // instruction in compiled code.
  //
  // The FP and PC that are saved right before TurboAssembler::CallCFunction.
  Address fast_c_call_caller_fp_ = kNullAddress;
  Address fast_c_call_caller_pc_ = kNullAddress;
  // The address of the fast API callback right before it's executed from
  // generated code.
  Address fast_api_call_target_ = kNullAddress;

  // Used for implementation of LongTaskStats. Counts the number of potential
  // long tasks.
  size_t long_task_stats_counter_ = 0;

  // Table containing pointers to external objects.
#ifdef V8_COMPRESS_POINTERS
  ExternalPointerTable external_pointer_table_;
  ExternalPointerTable* shared_external_pointer_table_;
#endif

  RootsTable roots_table_;
  ExternalReferenceTable external_reference_table_;

  ThreadLocalTop thread_local_top_;

  // The entry points for builtins. This corresponds to
  // Code::InstructionStart() for each Code object in the builtins table below.
  // The entry table is in IsolateData for easy access through kRootRegister.
  Address builtin_entry_table_[Builtins::kBuiltinCount] = {};

  // The entries in this array are tagged pointers to Code objects.
  Address builtin_table_[Builtins::kBuiltinCount] = {};

  LinearAllocationArea new_allocation_info_;
  LinearAllocationArea old_allocation_info_;

  // Ensure the size is 8-byte aligned in order to make alignment of the field
  // following the IsolateData field predictable. This solves the issue with
  // C++ compilers for 32-bit platforms which are not consistent at aligning
  // int64_t fields.
  // In order to avoid dealing with zero-size arrays the padding size is always
  // in the range [8, 15).
  static_assert(kPaddingOffsetEnd + 1 - kPaddingOffset >= 8);
  char padding_[kPaddingOffsetEnd + 1 - kPaddingOffset];

  V8_INLINE static void AssertPredictableLayout();

  friend class Isolate;
  friend class Heap;
  FRIEND_TEST(HeapTest, ExternalLimitDefault);
  FRIEND_TEST(HeapTest, ExternalLimitStaysAboveDefaultForExplicitHandling);
};

// IsolateData object must have "predictable" layout which does not change when
// cross-compiling to another platform. Otherwise there may be compatibility
// issues because of different compilers used for snapshot generator and
// actual V8 code.
void IsolateData::AssertPredictableLayout() {
  static_assert(std::is_standard_layout<RootsTable>::value);
  static_assert(std::is_standard_layout<ThreadLocalTop>::value);
  static_assert(std::is_standard_layout<ExternalReferenceTable>::value);
  static_assert(std::is_standard_layout<IsolateData>::value);
#define V(Offset, Size, Name) \
  static_assert(offsetof(IsolateData, Name##_) == Offset);
  ISOLATE_DATA_FIELDS(V)
#undef V
  static_assert(sizeof(IsolateData) == IsolateData::kSize);
}

#undef ISOLATE_DATA_FIELDS_POINTER_COMPRESSION
#undef ISOLATE_DATA_FIELDS

}  // namespace internal
}  // namespace v8

#endif  // V8_EXECUTION_ISOLATE_DATA_H_