// 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) \ /* 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) \ /* 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) \ ISOLATE_DATA_FIELDS_SANDBOXED_EXTERNAL_POINTERS(V) \ V(kStackIsIterableOffset, kUInt8Size, stack_is_iterable) #ifdef V8_SANDBOXED_EXTERNAL_POINTERS #define ISOLATE_DATA_FIELDS_SANDBOXED_EXTERNAL_POINTERS(V) \ V(kExternalPointerTableOffset, ExternalPointerTable::kSize, \ external_pointer_table) #else #define ISOLATE_DATA_FIELDS_SANDBOXED_EXTERNAL_POINTERS(V) #endif // V8_SANDBOXED_EXTERNAL_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
(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(&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::value); Address start = reinterpret_cast(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