feat(patches): make the JS dispatch table reservation a per-isolate CreateParams field - #7
Merged
Conversation
…reateParams field
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Team Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Without the sandbox (our iOS build is
sandbox=false,pointer_compression=false, lite/jitless), the onlyExternalEntityTablean isolate creates is the JSDispatchTable.SegmentedTable::InitializereserveskJSDispatchTableReservationSize— 256 MB of address space, per isolate — and callsFatalProcessOutOfMemory("SegmentedTable::InitializeTable (subspace allocation)")when the reservation fails.iOS budgets per-process virtual address space by device RAM, so an app running ~10 worker isolates can hit that abort simply by creating another worker. 256 MB is a maximum the isolate will never approach; nothing forces it to be reserved up front.
What the patch adds
patches/v8_js_dispatch_table_reservation.patchmakes the reservation a per-isolate embedder parameter, defaulting to today's behavior:with a feature macro next to the class so embedders can compile against old and new headers:
Internally the size is threaded
api.cc→Isolate::set_js_dispatch_table_reservation_size→Isolate::Init→JSDispatchTable::Initialize(size)→ExternalEntityTable::Initialize(size)→SegmentedTable::Initialize(size), where it replaceskReservationSizein the subspace allocation, theEmulatedVirtualAddressSubspacefallback and the alignment DCHECK. Every existing caller keeps callingInitialize()and gets the compile-time default.Files touched (9):
include/v8-isolate.h,src/api/api.cc,src/common/segmented-table.h,src/common/segmented-table-inl.h,src/execution/isolate.h,src/execution/isolate.cc,src/sandbox/external-entity-table.h,src/sandbox/external-entity-table-inl.h,src/sandbox/js-dispatch-table.h.Validation rules
api.ccrejects bad values throughUtils::ApiCheck.0means "use V8's default"; any other value must beJSDispatchTable::kReservationSizeGranularity(the table segment size),JSDispatchTable::kMinReservationSize,kJSDispatchTableReservationSize(256 MB, or 16 MB in lower-limits mode).The minimum, and why
ExternalEntityTable::InitializemapskNumReadOnlySegments(64 KB / kSegmentSize, i.e. always 64 KB worth) of read-only segments at offset 0 before anything else; the null entry lives there. A reservation that only covers those leaves nothing to allocate from, so the minimum adds one allocatable segment on top. Concretely: 80 KB where segments are 16 KB (iOS/macOS arm64, Android, and any 4 KB-page POSIX host, which use the 16 KB segment pool) and 128 KB where they are 64 KB (Windows, 64 KB-page Linux).What is not changed
kJSDispatchHandleShift,kMaxJSDispatchEntriesandSegmentedTable::kMaxCapacityare untouched — the handle encoding is baked into generated code and the snapshot.kReservationSizestays the compile-time maximum; only the live reservation becomes configurable. An isolate that outgrows its smaller reservation still aborts inAllocateAndInitializeSegment, exactly as one that outgrows 256 MB does today.The size is deliberately not stored in a member:
sizeof(JSDispatchTable)is pinned byInternals::kExternalEntityTableSize, and everyIsolateDatafield afterjs_dispatch_table_(kIsolateApiCallbackThunkArgumentOffset,kContinuationPreservedEmbedderDataOffset, …) is laid out relative to it. Growing the table would breakIsolate::CheckIsolateLayout(). All existing uses ofkReservationSizefor the live reservation were insideInitialize(), so the parameter suffices.kReservationSizemoved out of theV8_TARGET_ARCH_64_BITblock insegmented-table.hso the new default argument also compiles for the 32-bit Android targets, where it stays unused (segments are individually mapped there).Compile check
Not a full build —
include/v8-isolate.hwould rebuild the world. Instead each affected translation unit was compiled with its exactninja -t commandsinvocation in an existing release host build dir (macOS arm64,is_debug=false, sandbox + pointer compression on, so thesizeof/layoutstatic_asserts are live). All exited 0 with no new diagnostics:obj/v8_base_without_compiler/api.oobj/v8_base_without_compiler/isolate.oobj/v8_base_without_compiler/js-dispatch-table.oobj/v8_base_without_compiler/external-pointer-table.oobj/v8_base_without_compiler/trusted-pointer-table.oobj/v8_base_without_compiler/code-pointer-table.oobj/v8_base_without_compiler/cppheap-pointer-table.oobj/v8_base_without_compiler/wasm-code-pointer-table.oPlus a standalone embedder TU compiled against
include/with the same flags, which#errors if the macro is missing and sets the field under#ifdef V8_HAS_JS_DISPATCH_TABLE_RESERVATION_PARAM, proving the header contract.The patch was also verified to apply cleanly with
git applyto a pristine14.9.207.39tree (the tagconfig.envpins), and the result byte-compared against the tree that was compiled.A full matrix build is the real verification — the host compile check covers one platform and one arg set; iOS/visionOS/Android and the 32-bit Android targets are only exercised by CI.
No version bump, tag or release in this PR.