From c951b76a3bee9f7c4d31adb9d75b54b5f569629f Mon Sep 17 00:00:00 2001 From: Dan McDonald Date: Fri, 18 Apr 2025 16:21:11 -0400 Subject: [PATCH] deps: patch V8 for illumos illumos pointers are VA48, can allocate from the top of the 64-bit range as well. PR-URL: https://github.com/nodejs/node/pull/58070 Reviewed-By: Antoine du Hamel Reviewed-By: Darshan Sen Reviewed-By: Joyee Cheung Reviewed-By: Rafael Gonzaga --- common.gypi | 2 +- deps/v8/src/codegen/code-stub-assembler.cc | 9 +++++++++ deps/v8/src/sandbox/js-dispatch-table-inl.h | 14 ++++++++++++++ deps/v8/src/sandbox/js-dispatch-table.h | 15 +++++++++++++++ 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/common.gypi b/common.gypi index 00ee757687..c3cfd0ff83 100644 --- a/common.gypi +++ b/common.gypi @@ -38,7 +38,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.4', + 'v8_embedder_string': '-node.5', ##### V8 defaults for Node.js ##### diff --git a/deps/v8/src/codegen/code-stub-assembler.cc b/deps/v8/src/codegen/code-stub-assembler.cc index 5d81da4b97..9071cb487d 100644 --- a/deps/v8/src/codegen/code-stub-assembler.cc +++ b/deps/v8/src/codegen/code-stub-assembler.cc @@ -1941,7 +1941,16 @@ TNode CodeStubAssembler::LoadCodeObjectFromJSDispatchTable( // The LSB is used as marking bit by the js dispatch table, so here we have // to set it using a bitwise OR as it may or may not be set. value = UncheckedCast(WordOr( +#if defined(__illumos__) && defined(V8_HOST_ARCH_64_BIT) + // Pointers in illumos span both the low 2^47 range and the high 2^47 range + // as well. Checking the high bit being set in illumos means all higher bits + // need to be set to 1 after shifting right. + // Try WordSar() so any high-bit check wouldn't be necessary. + WordSar(UncheckedCast(value), + IntPtrConstant(JSDispatchEntry::kObjectPointerShift)), +#else WordShr(value, UintPtrConstant(JSDispatchEntry::kObjectPointerShift)), +#endif /* __illumos__ */ UintPtrConstant(kHeapObjectTag))); return CAST(BitcastWordToTagged(value)); } diff --git a/deps/v8/src/sandbox/js-dispatch-table-inl.h b/deps/v8/src/sandbox/js-dispatch-table-inl.h index c22ebee353..67d43a1e1c 100644 --- a/deps/v8/src/sandbox/js-dispatch-table-inl.h +++ b/deps/v8/src/sandbox/js-dispatch-table-inl.h @@ -23,7 +23,9 @@ void JSDispatchEntry::MakeJSDispatchEntry(Address object, Address entrypoint, uint16_t parameter_count, bool mark_as_alive) { DCHECK_EQ(object & kHeapObjectTag, 0); +#if !defined(__illumos__) || !defined(V8_TARGET_ARCH_64_BIT) DCHECK_EQ((object << kObjectPointerShift) >> kObjectPointerShift, object); +#endif /* __illumos__ */ Address payload = (object << kObjectPointerShift) | (parameter_count & kParameterCountMask); @@ -49,7 +51,14 @@ Address JSDispatchEntry::GetCodePointer() const { // and so may be 0 or 1 here. As the return value is a tagged pointer, the // bit must be 1 when returned, so we need to set it here. Address payload = encoded_word_.load(std::memory_order_relaxed); +#if defined(__illumos__) && defined(V8_TARGET_ARCH_64_BIT) + // Unsigned types won't sign-extend on shift-right, but we need to do + // this with illumos VA48 addressing. + return (Address)((intptr_t)payload >> (int)kObjectPointerShift) | + kHeapObjectTag; +#else return (payload >> kObjectPointerShift) | kHeapObjectTag; +#endif /* __illumos__ */ } Tagged JSDispatchEntry::GetCode() const { @@ -205,7 +214,12 @@ void JSDispatchEntry::MakeFreelistEntry(uint32_t next_entry_index) { bool JSDispatchEntry::IsFreelistEntry() const { #ifdef V8_TARGET_ARCH_64_BIT auto entrypoint = entrypoint_.load(std::memory_order_relaxed); +#ifdef __illumos__ + // See the illumos definition of kFreeEntryTag for why we have to do this. + return (entrypoint & 0xffff000000000000ull) == kFreeEntryTag; +#else return (entrypoint & kFreeEntryTag) == kFreeEntryTag; +#endif /* __illumos__ */ #else return next_free_entry_.load(std::memory_order_relaxed) != 0; #endif diff --git a/deps/v8/src/sandbox/js-dispatch-table.h b/deps/v8/src/sandbox/js-dispatch-table.h index 81ddc4a904..800ae681c6 100644 --- a/deps/v8/src/sandbox/js-dispatch-table.h +++ b/deps/v8/src/sandbox/js-dispatch-table.h @@ -78,7 +78,22 @@ struct JSDispatchEntry { #if defined(V8_TARGET_ARCH_64_BIT) // Freelist entries contain the index of the next free entry in their lower 32 // bits and are tagged with this tag. +#ifdef __illumos__ + // In illumos 64-bit apps, pointers are allocated both the bottom 2^47 range + // AND the top 2^47 range in the 64-bit space. Instead of 47 bits of VA space + // we have 48 bits. This means, however, the top 16-bits may be 0xffff. We + // therefore pick a different value for the kFreeEntryTag. If/when we go to + // VA57, aka 5-level paging, we'll need to revisit this again, as will node + // by default, since the fixed-bits on the high end will shrink from top + // 16-bits to top 8-bits. + // + // Unless illumos ships an Oracle-Solaris-like VA47 link-time options to + // restrict pointers from allocating from above the Virtual Address hole, + // we need to be mindful of this. + static constexpr Address kFreeEntryTag = 0xfeed000000000000ull; +#else static constexpr Address kFreeEntryTag = 0xffff000000000000ull; +#endif /* __illumos__ */ #ifdef V8_TARGET_BIG_ENDIAN // 2-byte parameter count is on the least significant side of encoded_word_. static constexpr int kBigEndianParamCountOffset =