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