Saturday, July 04, 2026

Re: lang/node, wip v8-wasm support for yarn berry

Attached is your diff against 24.18.0 in -current. I don't see any wasm-related tests failing here, but the failure cases that you mentioned seem to be the same as or similar to random failures we're seeing while building the chromiums when running the wasm version of rollup. I'll test drive that for a bit, but what these patches do, or how they might fix things is beyond my capabilities, so I hope that someone else will look over them as well, particularly if this might improve things for other ports including v8 (chromiums, deno, codex...) On 7/2/26 10:36 AM, Fabien Romano wrote: > > On 7/1/26 23:13, Volker Schlecht wrote: >> On 7/1/26 11:26 PM, Fabien Romano wrote: >>> I have a few wasm issues in node v8 for which I have patches. >> >> Please share, I'll be happy to include them in the port. >> >> > > Actually, I was gathering info in a draft email. > I still have to update system & ports on my side to confirm the issue. > > That's a first step for wasm. Hope the diff applies. > I manually remove a hack in Makefile. > > # node+v8/js-wasm randomly fool itself resulting in > # Range Error: Maximum call stack size exceeded > # XXX enabling pointer compression without enabling sandbox is unsupported by V8 > # XXX further reduce v8 flags to narrow the code path change to audit (?) > CONFIGURE_ARGS+= --experimental-enable-pointer-compression \ > --experimental-pointer-compression-shared-cage > > Using those two configure args, berry is stable (tested on 24.17). > By default, the v8 test build with pointer-compression and sandbox enabled... > so I blindly try to do the same in node except for sandbox (see configure.py). > I hit just one "Maximum call stack size exceeded" while building electron, once. > Since then, parcel, swc, electron all extract/install into pobj without issue. > > I could make a short reproducer... there is an AI one (repro.sh). > Open and configure it to your system. > > With an online install, with --stack-trace-limit=10000, I get: > RangeError: ansi-styles@npm:3.2.1: Maximum call stack size exceeded > at wasm-function[104]:0xbc29 > at wasm-function[104]:0xbc9d > ... 7506 frames of wasm-function[104] ... > at wasm-function[188]:0x11867 > at new PI (.../yarn.js:148:193125) > at new hs (.../yarn.js:148:199501) > at Object.Dit (.../yarn.js:191:212680) > at async e.fetchFromNetwork (.../yarn.js:693:3984) > at async e.fetchPackageFromCache (.../yarn.js:198:3374) > at async e.fetch (.../yarn.js:693:3337) > > I'm trying to understand how it derails in the libzip wasm embeded in berry. > AI tried to stress the same libzip function. It only reproduce inside berry. > The pointer-compression hack may be a hint for an expert who know v8 internals. > > It should be reproducible offline also (I'm trying an other repro atm). > If you create a package that uses a local .tgz dependency, install it with berry > (tested on corepack yarn 4.17.0), *without a cache*, it could fail. > The code path that triggers looks very specific to what berry is doing. > I didn't manage to get similar traces using node or v8 tests. > > I had another issue with regexp. > I work around it with --regexp-interpret-all in electron. > You can stress test node parallel/test-worker-heap-snapshot.js to reproduce. > > Program terminated with signal SIGTRAP, Trace/breakpoint trap. > #0 v8::internal::RegExpMacroAssemblerX64::CheckStackGuardState(...) > > I also add the below change while working on node v8 tests. > I just don't remember if this actually fixed a test. > OpenBSD has the same 512kB thread stack size by default. > > In deps/v8/src/base/platform/platform-posix.cc > > @@ -1258,7 +1266,7 @@ bool Thread::Start() { > if (result != 0) return false; > size_t stack_size = stack_size_; > if (stack_size == 0) { > -#if V8_OS_DARWIN > +#if V8_OS_DARWIN || V8_OS_OPENBSD > // Default on Mac OS X is 512kB -- bump up to 1MB > stack_size = 1 * 1024 * 1024; > #elif V8_OS_AIX > > The below patches may also apply to other V8 copies (chromium ...) > If I remember correctly, new V8 uses guard pages in StackSegment(). > Maybe someone can give a look. > Otherwise, I may write a v8 port to run tests for this purpose. > > For node we have to use the embedded version for tests. > I joined a dirty node-v8-test port I made just to run tests (without gclient). > I don't think we should run node v8 test by default considering the complexity. > > In node-v8-test, you may want to adjust deps/v8/.gn, examples : > > # Disable pointer compression and sandbox like Node build > # while debugging OpenBSD Wasm stack failures. > v8_enable_pointer_compression = false > v8_enable_pointer_compression_shared_cage = false > v8_enable_31bit_smis_on_64bit_arch = false > v8_enable_external_code_space = false > v8_enable_sandbox = false > > # # debug > # enable_profiling = true > # symbol_level = 2 > # v8_code_comments = true > # v8_enable_debugging_features = true > # v8_enable_disassembler = true > # v8_enable_object_print = true > # v8_enable_slow_dchecks = true > # v8_symbol_level = 2 >

Index: Makefile
===================================================================
RCS file: /cvs/ports/lang/node/Makefile,v
retrieving revision 1.169
diff -u -p -r1.169 Makefile
--- Makefile	30 Jun 2026 18:46:22 -0000	1.169
+++ Makefile	4 Jul 2026 12:13:11 -0000
@@ -13,6 +13,7 @@ DIST_TUPLE =		github qbit node-pledge 1.
 DISTNAME =		node-${NODE_VERSION}
 PKGNAME =		${DISTNAME:S/v//g}
 EPOCH =			0
+REVISION =		0
 
 CATEGORIES =		lang devel
 
Index: patches/patch-deps_v8_src_base_platform-posix_cc
===================================================================
RCS file: /cvs/ports/lang/node/patches/patch-deps_v8_src_base_platform-posix_cc,v
retrieving revision 1.8
diff -u -p -r1.8 patch-deps_v8_src_base_platform-posix_cc
--- patches/patch-deps_v8_src_base_platform-posix_cc	9 May 2026 13:26:47 -0000	1.8
+++ patches/patch-deps_v8_src_base_platform-posix_cc	4 Jul 2026 12:13:11 -0000
@@ -15,7 +15,7 @@ Index: deps/v8/src/base/platform/platfor
  }
  
 +#if V8_OS_OPENBSD
-+// Allow OpenBSD's mmap to select a random address on OpenBSD 
++// Allow OpenBSD's mmap to select a random address on OpenBSD
  // static
  void* OS::GetRandomMmapAddr() {
 +  return nullptr;
@@ -43,6 +43,15 @@ Index: deps/v8/src/base/platform/platfor
    return true;
  #else
    // TODO(bbudge) Return true for all POSIX platforms.
+@@ -1258,7 +1266,7 @@ bool Thread::Start() {
+   if (result != 0) return false;
+   size_t stack_size = stack_size_;
+   if (stack_size == 0) {
+-#if V8_OS_DARWIN
++#if V8_OS_DARWIN || V8_OS_OPENBSD
+     // Default on Mac OS X is 512kB -- bump up to 1MB
+     stack_size = 1 * 1024 * 1024;
+ #elif V8_OS_AIX
 @@ -1358,7 +1366,7 @@ void Thread::SetThreadLocal(LocalStorageKey key, void*
  // keep this version in POSIX as most Linux-compatible derivatives will
  // support it. MacOS and FreeBSD are different here.
Index: patches/patch-deps_v8_src_wasm_stacks_cc
===================================================================
RCS file: patches/patch-deps_v8_src_wasm_stacks_cc
diff -N patches/patch-deps_v8_src_wasm_stacks_cc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ patches/patch-deps_v8_src_wasm_stacks_cc	4 Jul 2026 12:13:11 -0000
@@ -0,0 +1,49 @@
+Index: deps/v8/src/wasm/stacks.cc
+--- deps/v8/src/wasm/stacks.cc.orig
++++ deps/v8/src/wasm/stacks.cc
+@@ -4,6 +4,10 @@
+ 
+ #include "src/wasm/stacks.h"
+ 
++#if V8_OS_OPENBSD
++#include <sys/mman.h>
++#endif
++
+ #include "src/base/platform/platform.h"
+ #include "src/execution/simulator.h"
+ #include "src/wasm/wasm-engine.h"
+@@ -66,9 +70,18 @@ StackMemory::StackSegment::StackSegment(size_t pages) 
+   DCHECK_GE(pages, 1);
+   PageAllocator* allocator = GetPlatformPageAllocator();
+   size_ = pages * allocator->AllocatePageSize();
++#if V8_OS_OPENBSD
++  limit_ = static_cast<uint8_t*>(mmap(nullptr, size_, PROT_READ | PROT_WRITE,
++                                      MAP_PRIVATE | MAP_ANON | MAP_STACK, -1,
++                                      0));
++  if (limit_ == MAP_FAILED) {
++    limit_ = nullptr;
++  }
++#else
+   limit_ = static_cast<uint8_t*>(
+       allocator->AllocatePages(nullptr, size_, allocator->AllocatePageSize(),
+                                PageAllocator::kReadWrite));
++#endif
+   if (limit_ == nullptr) {
+     V8::FatalProcessOutOfMemory(nullptr,
+                                 "StackMemory::StackSegment::StackSegment");
+@@ -77,9 +90,15 @@ StackMemory::StackSegment::StackSegment(size_t pages) 
+ 
+ StackMemory::StackSegment::~StackSegment() {
+   PageAllocator* allocator = GetPlatformPageAllocator();
++#if V8_OS_OPENBSD
++  if (munmap(limit_, size_) != 0) {
++    V8::FatalProcessOutOfMemory(nullptr, "Release stack memory");
++  }
++#else
+   if (!allocator->DecommitPages(limit_, size_)) {
+     V8::FatalProcessOutOfMemory(nullptr, "Decommit stack memory");
+   }
++#endif
+ }
+ 
+ bool StackMemory::Grow(Address current_fp) {
Index: patches/patch-deps_v8_src_wasm_wasm-objects_cc
===================================================================
RCS file: patches/patch-deps_v8_src_wasm_wasm-objects_cc
diff -N patches/patch-deps_v8_src_wasm_wasm-objects_cc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ patches/patch-deps_v8_src_wasm_wasm-objects_cc	4 Jul 2026 12:13:11 -0000
@@ -0,0 +1,21 @@
+Index: deps/v8/src/wasm/wasm-objects.cc
+--- deps/v8/src/wasm/wasm-objects.cc.orig
++++ deps/v8/src/wasm/wasm-objects.cc
+@@ -2854,8 +2854,16 @@ DirectHandle<WasmContinuationObject> WasmContinuationO
+     Isolate* isolate, wasm::StackMemory* stack,
+     wasm::JumpBuffer::StackState state, DirectHandle<HeapObject> parent,
+     AllocationType allocation_type) {
+-  stack->jmpbuf()->stack_limit = stack->jslimit();
++    stack->jmpbuf()->stack_limit = stack->jslimit();
++#if V8_OS_OPENBSD
++  // OpenBSD MAP_STACK mappings cannot be entered with rsp exactly equal to the
++  // high end of the mapping. The first push from that value traps with
++  // SEGV_ACCERR, even though push would write below rsp. Keep the initial stack
++  // pointer strictly inside the mapped stack.
++  stack->jmpbuf()->sp = stack->base() - kSystemPointerSize;
++#else
+   stack->jmpbuf()->sp = stack->base();
++#endif
+   stack->jmpbuf()->fp = kNullAddress;
+   stack->jmpbuf()->state = state;
+   DirectHandle<WasmContinuationObject> result =

No comments:

Post a Comment