v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
embedder-data-slot-inl.h
Go to the documentation of this file.
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_OBJECTS_EMBEDDER_DATA_SLOT_INL_H_
6#define V8_OBJECTS_EMBEDDER_DATA_SLOT_INL_H_
7
9// Include the non-inl header before the rest of the headers.
10
11#include "src/base/memory.h"
12#include "src/common/globals.h"
18#include "src/sandbox/isolate.h"
19
20// Has to be the last include (doesn't have include guards):
22
23namespace v8 {
24namespace internal {
25
27 int entry_index)
28 : SlotBase(FIELD_ADDR(array,
29 EmbedderDataArray::OffsetOfElementAt(entry_index))) {}
30
32 int embedder_field_index)
34 object, object->GetEmbedderFieldOffset(embedder_field_index))) {}
35
37 // TODO(v8) initialize the slot with Smi::zero() instead. This'll also
38 // guarantee that we don't need a write barrier.
39 DCHECK(IsSmi(initial_value) ||
42#ifdef V8_COMPRESS_POINTERS
43 ObjectSlot(address() + kRawPayloadOffset).Relaxed_Store(Smi::zero());
44#endif
45}
46
50
53#ifdef V8_COMPRESS_POINTERS
54 // See gc_safe_store() for the reasons behind two stores.
55 ObjectSlot(address() + kRawPayloadOffset).Relaxed_Store(Smi::zero());
56#endif
57}
58
59// static
61 int entry_index, Tagged<Object> value) {
62#ifdef V8_COMPRESS_POINTERS
63 CHECK(IsSmi(value) ||
66#endif
67 int slot_offset = EmbedderDataArray::OffsetOfElementAt(entry_index);
68 ObjectSlot(FIELD_ADDR(array, slot_offset + kTaggedPayloadOffset))
69 .Relaxed_Store(value);
70 WRITE_BARRIER(array, slot_offset + kTaggedPayloadOffset, value);
71#ifdef V8_COMPRESS_POINTERS
72 // See gc_safe_store() for the reasons behind two stores.
73 ObjectSlot(FIELD_ADDR(array, slot_offset + kRawPayloadOffset))
75#endif
76}
77
78// static
80 int embedder_field_index,
81 Tagged<Object> value) {
82#ifdef V8_COMPRESS_POINTERS
83 CHECK(IsSmi(value) ||
86#endif
87 int slot_offset = object->GetEmbedderFieldOffset(embedder_field_index);
88 ObjectSlot(FIELD_ADDR(object, slot_offset + kTaggedPayloadOffset))
89 .Relaxed_Store(value);
90 WRITE_BARRIER(object, slot_offset + kTaggedPayloadOffset, value);
91#ifdef V8_COMPRESS_POINTERS
92 // See gc_safe_store() for the reasons behind two stores.
93 ObjectSlot(FIELD_ADDR(object, slot_offset + kRawPayloadOffset))
95#endif
96}
97
99 void** out_pointer) const {
100 // We don't care about atomicity of access here because embedder slots
101 // are accessed this way only from the main thread via API during "mutator"
102 // phase which is propely synched with GC (concurrent marker may still look
103 // at the tagged part of the embedder slot but read-only access is ok).
104#ifdef V8_ENABLE_SANDBOX
105 // The raw part must always contain a valid external pointer table index.
106 *out_pointer = reinterpret_cast<void*>(
108 address() + kExternalPointerOffset, isolate));
109 return true;
110#else
111 Address raw_value;
113 // TODO(ishell, v8:8875): When pointer compression is enabled 8-byte size
114 // fields (external pointers, doubles and BigInt data) are only kTaggedSize
115 // aligned so we have to use unaligned pointer friendly way of accessing
116 // them in order to avoid undefined behavior in C++ code.
118 } else {
119 raw_value = *location();
120 }
121 *out_pointer = reinterpret_cast<void*>(raw_value);
122 return HAS_SMI_TAG(raw_value);
123#endif // V8_ENABLE_SANDBOX
124}
125
128 void* ptr) {
129 Address value = reinterpret_cast<Address>(ptr);
130 if (!HAS_SMI_TAG(value)) return false;
131#ifdef V8_ENABLE_SANDBOX
132 // When the sandbox is enabled, the external pointer handles in
133 // EmbedderDataSlots are lazily initialized: initially they contain the null
134 // external pointer handle (see EmbedderDataSlot::Initialize), and only once
135 // an external pointer is stored in them are they properly initialized.
136 // TODO(saelo): here we currently have to use the accessor on the host object
137 // as we may need a write barrier. This is a bit awkward. Maybe we should
138 // introduce helper methods on the ExternalPointerSlot class that allow us to
139 // determine whether the slot needs to be initialized, in which case a write
140 // barrier can be performed here.
141 size_t offset = address() - host.address() + kExternalPointerOffset;
142 host->WriteLazilyInitializedExternalPointerField<kEmbedderDataSlotPayloadTag>(
145 return true;
146#else
147 gc_safe_store(isolate, value);
148 return true;
149#endif // V8_ENABLE_SANDBOX
150}
151
153 IsolateForSandbox isolate, const DisallowGarbageCollection& no_gc) const {
154 // We don't care about atomicity of access here because embedder slots
155 // are accessed this way only by serializer from the main thread when
156 // GC is not active (concurrent marker may still look at the tagged part
157 // of the embedder slot but read-only access is ok).
158#ifdef V8_COMPRESS_POINTERS
159 // TODO(ishell, v8:8875): When pointer compression is enabled 8-byte size
160 // fields (external pointers, doubles and BigInt data) are only kTaggedSize
161 // aligned so we have to use unaligned pointer friendly way of accessing them
162 // in order to avoid undefined behavior in C++ code.
164#else
165 return *location();
166#endif
167}
168
171 const DisallowGarbageCollection& no_gc) {
172 gc_safe_store(isolate, data);
173}
174
176#ifdef V8_COMPRESS_POINTERS
177 static_assert(kSmiShiftSize == 0);
178 static_assert(SmiValuesAre31Bits());
179 static_assert(kTaggedSize == kInt32Size);
180
181 // We have to do two 32-bit stores here because
182 // 1) tagged part modifications must be atomic to be properly synchronized
183 // with the concurrent marker.
184 // 2) atomicity of full pointer store is not guaranteed for embedder slots
185 // since the address of the slot may not be kSystemPointerSize aligned
186 // (only kTaggedSize alignment is guaranteed).
187 // TODO(ishell, v8:8875): revisit this once the allocation alignment
188 // inconsistency is fixed.
189 Address lo = static_cast<intptr_t>(static_cast<int32_t>(value));
191 Tagged_t hi = static_cast<Tagged_t>(value >> 32);
192 // The raw part of the payload does not contain a valid tagged value, so we
193 // need to use a raw store operation for it here.
195 reinterpret_cast<AtomicTagged_t*>(address() + kRawPayloadOffset), hi);
196#else
198 .Relaxed_Store(Tagged<Smi>(value));
199#endif
200}
201
203 const DisallowGarbageCollection& no_gc) {
204 // Serialization must avoid writing external pointer handles. If we were to
205 // accidentally write an external pointer handle, that ends up deserializing
206 // as a dangling pointer. For consistency it would be nice to avoid writing
207 // external pointers also in the wide-pointer case, but as we can't
208 // distinguish between Smi values and pointers we just leave them be.
209#ifdef V8_ENABLE_SANDBOX
210 auto* location = reinterpret_cast<ExternalPointerHandle*>(
213#else // !V8_ENABLE_SANDBOX
214 return false;
215#endif // !V8_ENABLE_SANDBOX
216}
217
218} // namespace internal
219} // namespace v8
220
222
223#endif // V8_OBJECTS_EMBEDDER_DATA_SLOT_INL_H_
static void Relaxed_Store(T *addr, typename std::remove_reference< T >::type new_value)
static T Relaxed_Load(T *addr)
static constexpr int OffsetOfElementAt(int index)
V8_INLINE void store_raw(IsolateForSandbox isolate, RawData data, const DisallowGarbageCollection &no_gc)
V8_INLINE void store_smi(Tagged< Smi > value)
V8_INLINE Tagged< Object > load_tagged() const
V8_INLINE V8_WARN_UNUSED_RESULT bool store_aligned_pointer(IsolateForSandbox isolate, Tagged< HeapObject > host, void *ptr)
static constexpr int kTaggedPayloadOffset
V8_INLINE bool ToAlignedPointer(IsolateForSandbox isolate, void **out_result) const
V8_INLINE void gc_safe_store(IsolateForSandbox isolate, Address value)
static constexpr int kExternalPointerOffset
V8_INLINE bool MustClearDuringSerialization(const DisallowGarbageCollection &no_gc)
static V8_INLINE void store_tagged(Tagged< EmbedderDataArray > array, int entry_index, Tagged< Object > value)
V8_INLINE void Initialize(Tagged< Object > initial_value)
V8_INLINE RawData load_raw(IsolateForSandbox isolate, const DisallowGarbageCollection &no_gc) const
void Relaxed_Store(Tagged< Object > value) const
Definition slots-inl.h:100
Tagged< Object > Relaxed_Load() const
Definition slots-inl.h:82
static V8_EXPORT_PRIVATE bool Contains(Address address)
static constexpr Tagged< Smi > zero()
Definition smi.h:99
static V8_INLINE constexpr Address GetPtrComprCageBaseAddress(Address on_heap_addr)
#define COMPRESS_POINTERS_BOOL
Definition globals.h:99
#define HAS_SMI_TAG(value)
Definition globals.h:1771
Isolate * isolate
int32_t offset
static V ReadUnalignedValue(Address p)
Definition memory.h:28
constexpr int kTaggedSize
Definition globals.h:542
SlotTraits::TObjectSlot ObjectSlot
Definition globals.h:1243
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
Address Tagged_t
Definition globals.h:547
V8_INLINE Address ReadExternalPointerField(Address field_address, IsolateForSandbox isolate)
constexpr ExternalPointerHandle kNullExternalPointerHandle
constexpr bool SmiValuesAre31Bits()
constexpr int kInt32Size
Definition globals.h:401
const int kSmiShiftSize
@ kEmbedderDataSlotPayloadTag
base::AtomicWord AtomicTagged_t
Definition globals.h:548
uint32_t ExternalPointerHandle
return value
Definition map-inl.h:893
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
#define FIELD_ADDR(p, offset)
#define WRITE_BARRIER(object, offset, value)
#define CHECK(condition)
Definition logging.h:124
#define DCHECK(condition)
Definition logging.h:482