5#ifndef V8_SANDBOX_JS_DISPATCH_TABLE_INL_H_
6#define V8_SANDBOX_JS_DISPATCH_TABLE_INL_H_
17#ifdef V8_ENABLE_LEAPTIERING
22void JSDispatchEntry::MakeJSDispatchEntry(
Address object,
Address entrypoint,
26 DCHECK_EQ((
object << kObjectPointerShift) >> kObjectPointerShift,
object);
29 (
object << kObjectPointerShift) | (
parameter_count & kParameterCountMask);
30 DCHECK(!(payload & kMarkingBit));
31 if (mark_as_alive) payload |= kMarkingBit;
32#ifdef V8_TARGET_ARCH_32_BIT
34 next_free_entry_.store(0, std::memory_order_relaxed);
36 encoded_word_.store(payload, std::memory_order_relaxed);
37 entrypoint_.store(entrypoint, std::memory_order_relaxed);
38 DCHECK(!IsFreelistEntry());
41Address JSDispatchEntry::GetEntrypoint()
const {
42 CHECK(!IsFreelistEntry());
43 return entrypoint_.load(std::memory_order_relaxed);
46Address JSDispatchEntry::GetCodePointer()
const {
47 CHECK(!IsFreelistEntry());
51 Address payload = encoded_word_.load(std::memory_order_relaxed);
59uint16_t JSDispatchEntry::GetParameterCount()
const {
64 CHECK(!IsFreelistEntry());
65#ifdef V8_TARGET_ARCH_32_BIT
66 return parameter_count_.load(std::memory_order_relaxed);
68 static_assert(kParameterCountMask != 0);
69 Address payload = encoded_word_.load(std::memory_order_relaxed);
70 return payload & kParameterCountMask;
75 uint32_t index = HandleToIndex(
handle);
76 return at(index).GetCode();
81 SetCodeAndEntrypointNoWriteBarrier(
handle, new_code,
82 new_code->instruction_start());
85void JSDispatchTable::SetCodeKeepTieringRequestNoWriteBarrier(
87 if (IsTieringRequested(
handle)) {
88 SetCodeAndEntrypointNoWriteBarrier(
handle, new_code, GetEntrypoint(
handle));
90 SetCodeAndEntrypointNoWriteBarrier(
handle, new_code,
91 new_code->instruction_start());
95void JSDispatchTable::SetCodeAndEntrypointNoWriteBarrier(
102 uint32_t index = HandleToIndex(
handle);
103 DCHECK_GE(index, kEndOfInternalReadOnlySegment);
105 at(index).SetCodeAndEntrypointPointer(new_code.ptr(), new_entrypoint);
112 uint32_t index = HandleToIndex(
handle);
113 DCHECK_GE(index, kEndOfInternalReadOnlySegment);
115 at(index).SetEntrypointPointer(
116 isolate->builtin_entry_table()[
static_cast<uint32_t
>(builtin)]);
120 uint32_t index = HandleToIndex(
handle);
121 DCHECK_GE(index, kEndOfInternalReadOnlySegment);
122 Address entrypoint = at(index).GetEntrypoint();
123 Address code_entrypoint = at(index).GetCode()->instruction_start();
124 return code_entrypoint != entrypoint;
130 uint32_t index = HandleToIndex(
handle);
131 DCHECK_GE(index, kEndOfInternalReadOnlySegment);
132 Address entrypoint = at(index).GetEntrypoint();
133 Address code_entrypoint = at(index).GetCode()->instruction_start();
134 if (entrypoint == code_entrypoint)
return false;
136 static_cast<Builtin>(builtin));
140 uint32_t index = HandleToIndex(
handle);
141 DCHECK_GE(index, kEndOfInternalReadOnlySegment);
143 at(index).SetEntrypointPointer(at(index).GetCode()->instruction_start());
153 "JSDispatchTable::AllocateAndInitializeEntry");
156std::optional<JSDispatchHandle> JSDispatchTable::TryAllocateAndInitializeEntry(
158 DCHECK(space->BelongsTo(
this));
162 if (
auto maybe_index = TryAllocateEntry(space)) {
163 index = *maybe_index;
167 JSDispatchEntry& entry = at(index);
169 entry.MakeJSDispatchEntry(new_code.address(), new_code->instruction_start(),
171 return IndexToHandle(index);
174void JSDispatchEntry::SetCodeAndEntrypointPointer(
Address new_object,
176 Address old_payload = encoded_word_.load(std::memory_order_relaxed);
177 Address marking_bit = old_payload & kMarkingBit;
181 Address object = (new_object << kObjectPointerShift) & ~kMarkingBit;
183 encoded_word_.store(new_payload, std::memory_order_relaxed);
184 entrypoint_.store(new_entrypoint, std::memory_order_relaxed);
185 DCHECK(!IsFreelistEntry());
188void JSDispatchEntry::SetEntrypointPointer(
Address new_entrypoint) {
189 entrypoint_.store(new_entrypoint, std::memory_order_relaxed);
192void JSDispatchEntry::MakeFreelistEntry(uint32_t next_entry_index) {
193#ifdef V8_TARGET_ARCH_64_BIT
195 entrypoint_.store(payload, std::memory_order_relaxed);
198 next_free_entry_.store(next_entry_index + 1, std::memory_order_relaxed);
199 entrypoint_.store(
kNullAddress, std::memory_order_relaxed);
201 encoded_word_.store(
kNullAddress, std::memory_order_relaxed);
202 DCHECK(IsFreelistEntry());
205bool JSDispatchEntry::IsFreelistEntry()
const {
206#ifdef V8_TARGET_ARCH_64_BIT
207 auto entrypoint = entrypoint_.load(std::memory_order_relaxed);
210 return next_free_entry_.load(std::memory_order_relaxed) != 0;
214uint32_t JSDispatchEntry::GetNextFreelistEntryIndex()
const {
215 DCHECK(IsFreelistEntry());
216#ifdef V8_TARGET_ARCH_64_BIT
217 return static_cast<uint32_t
>(entrypoint_.load(std::memory_order_relaxed));
219 return next_free_entry_.load(std::memory_order_relaxed) - 1;
223void JSDispatchEntry::Mark() {
224 Address old_value = encoded_word_.load(std::memory_order_relaxed);
225 Address new_value = old_value | kMarkingBit;
229 static_assert(JSDispatchTable::kWriteBarrierSetsEntryMarkBit);
230 encoded_word_.compare_exchange_strong(old_value, new_value,
231 std::memory_order_relaxed);
234void JSDispatchEntry::Unmark() {
235 Address value = encoded_word_.load(std::memory_order_relaxed);
236 value &= ~kMarkingBit;
237 encoded_word_.store(value, std::memory_order_relaxed);
240bool JSDispatchEntry::IsMarked()
const {
241 Address value = encoded_word_.load(std::memory_order_relaxed);
242 return value & kMarkingBit;
246 uint32_t index = HandleToIndex(
handle);
247 return at(index).GetEntrypoint();
251 uint32_t index = HandleToIndex(
handle);
252 Address ptr = at(index).GetCodePointer();
258 uint32_t index = HandleToIndex(
handle);
259 return at(index).GetParameterCount();
263 uint32_t index = HandleToIndex(
handle);
266 if (index < kEndOfInternalReadOnlySegment)
return;
272#if defined(DEBUG) || defined(VERIFY_HEAP)
275 DCHECK(space->BelongsTo(
this));
276 DCHECK(ro_space->BelongsTo(
this));
280 uint32_t index = HandleToIndex(
handle);
281 if (ro_space->Contains(index)) {
282 CHECK(at(index).IsMarked());
284 CHECK(space->Contains(index));
289template <
typename Callback>
290void JSDispatchTable::IterateActiveEntriesIn(Space* space, Callback
callback) {
291 IterateEntriesIn(space, [&](uint32_t index) {
292 if (!at(index).IsFreelistEntry()) {
298template <
typename Callback>
299void JSDispatchTable::IterateMarkedEntriesIn(Space* space, Callback
callback) {
300 IterateEntriesIn(space, [&](uint32_t index) {
301 if (at(index).IsMarked()) {
307template <
typename Callback>
308uint32_t JSDispatchTable::Sweep(Space* space, Counters* counters,
310 uint32_t num_live_entries = GenericSweep(space,
callback);
311 counters->js_dispatch_table_entries_count()->AddSample(num_live_entries);
312 return num_live_entries;
316bool JSDispatchTable::IsCompatibleCode(
Tagged<Code> code,
339 if (code->kind() == CodeKind::FOR_TESTING) {
342 DCHECK(code->is_builtin());
344 switch (code->builtin_id()) {
345 case Builtin::kIllegal:
346 case Builtin::kCompileLazy:
347 case Builtin::kInterpreterEntryTrampoline:
348 case Builtin::kInstantiateAsmJs:
349 case Builtin::kDebugBreakTrampoline:
350#ifdef V8_ENABLE_WEBASSEMBLY
351 case Builtin::kJSToWasmWrapper:
352 case Builtin::kJSToJSWrapper:
353 case Builtin::kJSToJSWrapperInvalidSig:
354 case Builtin::kWasmPromising:
355#if V8_ENABLE_DRUMBRAKE
356 case Builtin::kGenericJSToWasmInterpreterWrapper:
358 case Builtin::kWasmStressSwitch:
#define SBXCHECK(condition)
static int GetFormalParameterCount(Builtin builtin)
Address InstructionStartOf(Builtin builtin) const
static EmbeddedData FromBlob()
static V8_INLINE bool InYoungGeneration(Tagged< Object > object)
static V8_INLINE constexpr bool HasHeapObjectTag(Address value)
static V8_EXPORT_PRIVATE void FatalProcessOutOfMemory(Isolate *isolate, const char *location, const OOMDetails &details=kNoOOMDetails)
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Tagged(T object) -> Tagged< T >
constexpr uint16_t kDontAdaptArgumentsSentinel
base::StrongAlias< JSDispatchHandleAliasTag, uint32_t > JSDispatchHandle
constexpr JSDispatchHandle kNullJSDispatchHandle(0)
V8_INLINE bool IsValidTieringBuiltin(TieringBuiltin builtin)
static constexpr Address kNullAddress
RwxMemoryWriteScope CFIMetadataWriteScope
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
#define DCHECK_IMPLIES(v1, v2)
#define DCHECK_GE(v1, v2)
#define DCHECK(condition)
#define DCHECK_EQ(v1, v2)