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