• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
19 namespace v8 {
20 namespace internal {
21 
22 class 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.
70 class IsolateData final {
71  public:
IsolateData(Isolate * isolate,Address cage_base)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.
isolate_root()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; }
ISOLATE_DATA_FIELDS(V)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 
BuiltinEntrySlotOffset(Builtin id)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.
builtin_slot_offset(int builtin_index)103   static constexpr int builtin_slot_offset(int builtin_index) {
104     return BuiltinSlotOffset(Builtins::FromInt(builtin_index));
105   }
BuiltinSlotOffset(Builtin id)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##_); }
ISOLATE_DATA_FIELDS(V)114   ISOLATE_DATA_FIELDS(V)
115 #undef V
116 
117   Address fast_c_call_caller_fp() const { return fast_c_call_caller_fp_; }
fast_c_call_caller_pc()118   Address fast_c_call_caller_pc() const { return fast_c_call_caller_pc_; }
fast_api_call_target()119   Address fast_api_call_target() const { return fast_api_call_target_; }
120   // The value of kPointerCageBaseRegister.
cage_base()121   Address cage_base() const { return cage_base_; }
stack_guard()122   StackGuard* stack_guard() { return &stack_guard_; }
builtin_tier0_entry_table()123   Address* builtin_tier0_entry_table() { return builtin_tier0_entry_table_; }
builtin_tier0_table()124   Address* builtin_tier0_table() { return builtin_tier0_table_; }
roots()125   RootsTable& roots() { return roots_table_; }
roots()126   const RootsTable& roots() const { return roots_table_; }
external_reference_table()127   ExternalReferenceTable* external_reference_table() {
128     return &external_reference_table_;
129   }
thread_local_top()130   ThreadLocalTop& thread_local_top() { return thread_local_top_; }
thread_local_top()131   ThreadLocalTop const& thread_local_top() const { return thread_local_top_; }
builtin_entry_table()132   Address* builtin_entry_table() { return builtin_entry_table_; }
builtin_table()133   Address* builtin_table() { return builtin_table_; }
stack_is_iterable()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.
contains(Address address)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.
AssertPredictableLayout()242 void 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