From 070c6121120d14a1b25d98e8aafd8630f963cf9f Mon Sep 17 00:00:00 2001
From: PurHur
Date: Fri, 28 Aug 2026 01:19:16 +0000
Subject: [PATCH] Self-host: add mb_get_info JIT units to compile spine (#35570
follow-up).
Sync spine coverage for JitMbGetInfo/MbGetInfoJitHelper/MbGetInfoRuntime after
Co-authored-by: Cursor
#35570 landed without spine includes; refresh 7962/7962 footnotes and gen-0 stamp.
---
README.md | 8 +-
docs/bootstrap-inventory.md | 78 ++++++++++++-------
docs/bootstrap-profile.json | 12 ++-
docs/bootstrap-selfhost.md | 2 +-
docs/capabilities.md | 2 +-
docs/pages/capability-comparison.html | 2 +-
docs/pages/development-status.md | 8 +-
docs/pages/index.html | 4 +-
docs/roadmap-wave3.md | 2 +-
docs/self-host-target.md | 6 +-
.../.m3_compiler_lib_sidecar.sha | 2 +-
.../compiler_lib_spine_smoke/main.php | 3 +
test/unit/BootstrapSelfhostBundleTest.php | 4 +-
13 files changed, 81 insertions(+), 52 deletions(-)
diff --git a/README.md b/README.md
index 5342d1f160..44eac5188c 100755
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@
> **Stable line (2026)** — First maintained **stable** release **[v1.0.0](https://github.com/PurHur/php-compiler/releases/tag/v1.0.0)**; **v1.1.0** prep adds M5 fast-path stability, enum/property-hook parity, `preg_match` JIT, `spl_autoload*`, and php-in-PHP JIT helpers. Demo-ready VM + AOT for a **web-capable PHP subset**, reference examples **000–009**, and an experimental **self-host** path. Not full Zend PHP compatibility — see [what’s missing](https://purhur.github.io/php-compiler/docs/pages/missing-implementation.html).
-**Snapshot (Jul 2026, `master` — v1.1.0 prep):** VM + AOT for shipped examples ✅ · examples web smoke ✅ · self-host spine **7959** / **7959** · **1555** builtins · M5 fast ✅ / strict 🚧 · M3/M4 emit = blob copy ([#21860](https://github.com/PurHur/php-compiler/issues/21860)) · VM probe ~**20ms**
+**Snapshot (Jul 2026, `master` — v1.1.0 prep):** VM + AOT for shipped examples ✅ · examples web smoke ✅ · self-host spine **7962** / **7962** · **1555** builtins · M5 fast ✅ / strict 🚧 · M3/M4 emit = blob copy ([#21860](https://github.com/PurHur/php-compiler/issues/21860)) · VM probe ~**20ms**
---
@@ -23,7 +23,7 @@
| **AOT (`phpc build`)** | ✅ For curated subset | Standalone binaries for examples **000–009** and small CGI apps; not arbitrary Composer stacks |
| **JIT (`bin/jit.php`)** | 🚧 Partial | LLVM IR for many constructs; **MCJIT execute** still flaky ([#98](https://github.com/PurHur/php-compiler/issues/98)); EH scripts VM-fallback ([#2114](https://github.com/PurHur/php-compiler/issues/2114)) |
| **Language wave 3** | ✅ Closed batch | **7410/7412** language + **7410/7412** stdlib tracker items ([#1380](https://github.com/PurHur/php-compiler/issues/1380)); closures, try/catch, generators (VM), `parent::class`, backed enums (VM), intersection AOT checks |
-| **Self-host north star** | 🚧 ~65% | M3/M4 emit paths are blob copies ([#21860](https://github.com/PurHur/php-compiler/issues/21860)); `--strict` red; spine **7959** / **7959**; vendor prelink **7410/7412** ([#1492](https://github.com/PurHur/php-compiler/issues/1492)) |
+| **Self-host north star** | 🚧 ~65% | M3/M4 emit paths are blob copies ([#21860](https://github.com/PurHur/php-compiler/issues/21860)); `--strict` red; spine **7962** / **7962**; vendor prelink **7410/7412** ([#1492](https://github.com/PurHur/php-compiler/issues/1492)) |
### What you can rely on today
@@ -40,7 +40,7 @@ Counts from `php script/bootstrap-spine-count.php` (literal `require_once` in `c
| Milestone | Status | What it means |
|-----------|--------|----------------|
| **M0–M1** | ✅ | `compiler_minimal` + compile-smoke bundles link and run natively |
-| **M2** | ✅ **7959** / **7959** | Full Phase A inventory in spine smoke; native link + lint ✅ |
+| **M2** | ✅ **7962** / **7962** | Full Phase A inventory in spine smoke; native link + lint ✅ |
| **M3** | 🚧 | HelloWorld probe output is a prelinked blob **COPY**, not a native emit ([#21860](https://github.com/PurHur/php-compiler/issues/21860)) |
| **M4** | 🚧 | ladder runs, but gen-1→gen-2 is a sidecar **COPY** ([#21860](https://github.com/PurHur/php-compiler/issues/21860)) — gen-0/gen-2/gen-3 being byte-identical follows from that, and is not fixpoint evidence |
| **M5** | 🚧 | `make north-star5-verify-fast` (daily) ✅; vendor **7410/7412** ✅; gen-0 sidecars refreshed; **`--strict` red at step 4a2** ([#21417](https://github.com/PurHur/php-compiler/issues/21417)) |
@@ -259,7 +259,7 @@ Full matrices (auto-generated): [`docs/capabilities.md`](docs/capabilities.md) (
**Self-host (experimental, not “stable app” scope)**
-See [Current implementation status](#current-implementation-status-july-2026) for the full M0–M5 ladder. Summary: M0–M5 bootstrap gates ✅; spine **7959** / **7959**; M3 strict native + inventory argv ✅; M4 full `bootstrap-loop-probe` ✅; M5 **`north-star5-verify-fast`** (daily) ✅ — **`--strict` red at step 4a2** ([#21417](https://github.com/PurHur/php-compiler/issues/21417)) ([#1492](https://github.com/PurHur/php-compiler/issues/1492), [#8559](https://github.com/PurHur/php-compiler/issues/8559)). Recent: native spine bundle probe, fast VM execute smoke ([#2201](https://github.com/PurHur/php-compiler/issues/2201)), `GeneratorYieldSourceMarker` spine unit ([#10356](https://github.com/PurHur/php-compiler/pull/10356)).
+See [Current implementation status](#current-implementation-status-july-2026) for the full M0–M5 ladder. Summary: M0–M5 bootstrap gates ✅; spine **7962** / **7962**; M3 strict native + inventory argv ✅; M4 full `bootstrap-loop-probe` ✅; M5 **`north-star5-verify-fast`** (daily) ✅ — **`--strict` red at step 4a2** ([#21417](https://github.com/PurHur/php-compiler/issues/21417)) ([#1492](https://github.com/PurHur/php-compiler/issues/1492), [#8559](https://github.com/PurHur/php-compiler/issues/8559)). Recent: native spine bundle probe, fast VM execute smoke ([#2201](https://github.com/PurHur/php-compiler/issues/2201)), `GeneratorYieldSourceMarker` spine unit ([#10356](https://github.com/PurHur/php-compiler/pull/10356)).
**What we do not target in v1.x**
diff --git a/docs/bootstrap-inventory.md b/docs/bootstrap-inventory.md
index 26e19f3670..44390a1e67 100644
--- a/docs/bootstrap-inventory.md
+++ b/docs/bootstrap-inventory.md
@@ -8,11 +8,11 @@ Regenerate: `php script/bootstrap-inventory.php`
| Metric | Count |
|--------|------:|
-| PHP files on vm.php path | 7959 |
-| Phase A inventory files (M2 ratio SSOT) | 7959 |
+| PHP files on vm.php path | 7962 |
+| Phase A inventory files (M2 ratio SSOT) | 7962 |
| Phase A ratio-deferred paths | 0 |
| Source constructs flagged (blockers) | 0 |
-| Source constructs flagged (warnings) | 25330 |
+| Source constructs flagged (warnings) | 25333 |
## Compiler CFG gaps (`lib/Compiler.php`)
@@ -1559,6 +1559,7 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
| `ext/mbstring/JitMbEncodingRegistry.php` | 0 | 3 |
| `ext/mbstring/JitMbEreg.php` | 0 | 1 |
| `ext/mbstring/JitMbEregSearch.php` | 0 | 10 |
+| `ext/mbstring/JitMbGetInfo.php` | 0 | 2 |
| `ext/mbstring/JitMbHttpInput.php` | 0 | 2 |
| `ext/mbstring/JitMbHttpOutput.php` | 0 | 2 |
| `ext/mbstring/JitMbInternalEncoding.php` | 0 | 2 |
@@ -1591,6 +1592,7 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
| `ext/mbstring/MbDetectOrderJitHelper.php` | 0 | 1 |
| `ext/mbstring/MbEncodingAliasesJitHelper.php` | 0 | 1 |
| `ext/mbstring/MbEregJitHelper.php` | 0 | 2 |
+| `ext/mbstring/MbGetInfoJitHelper.php` | 0 | 1 |
| `ext/mbstring/MbHttpInputJitHelper.php` | 0 | 1 |
| `ext/mbstring/MbHttpOutputJitHelper.php` | 0 | 1 |
| `ext/mbstring/MbInternalEncodingJitHelper.php` | 0 | 1 |
@@ -1648,7 +1650,7 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
| `ext/mbstring/mb_ereg_search_setpos.php` | 0 | 3 |
| `ext/mbstring/mb_eregi.php` | 0 | 3 |
| `ext/mbstring/mb_eregi_replace.php` | 0 | 3 |
-| `ext/mbstring/mb_get_info.php` | 0 | 3 |
+| `ext/mbstring/mb_get_info.php` | 0 | 2 |
| `ext/mbstring/mb_http_input.php` | 0 | 2 |
| `ext/mbstring/mb_http_output.php` | 0 | 2 |
| `ext/mbstring/mb_internal_encoding.php` | 0 | 2 |
@@ -5885,6 +5887,7 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
| `lib/JIT/Builtin/MbDetectOrderRuntime.php` | 0 | 1 |
| `lib/JIT/Builtin/MbEncodingAliasesRuntime.php` | 0 | 1 |
| `lib/JIT/Builtin/MbEregRuntime.php` | 0 | 1 |
+| `lib/JIT/Builtin/MbGetInfoRuntime.php` | 0 | 1 |
| `lib/JIT/Builtin/MbHttpInputRuntime.php` | 0 | 1 |
| `lib/JIT/Builtin/MbHttpOutputRuntime.php` | 0 | 1 |
| `lib/JIT/Builtin/MbInternalEncodingRuntime.php` | 0 | 1 |
@@ -10288,7 +10291,7 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
### `ext/dom/DomUserScriptAttributeCacheLlvm.php`
**Warnings** (review for bootstrap subset):
-- 19 class method(s)
+- 22 class method(s)
### `ext/dom/DomUserScriptDoctypeLlvm.php`
@@ -10949,8 +10952,8 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
### `ext/dom/JitDomImportNode.php`
**Warnings** (review for bootstrap subset):
-- new JITVariable (line 845)
-- 18 class method(s)
+- new JITVariable (line 849)
+- 19 class method(s)
### `ext/dom/JitDomImportSimpleXmlUserScript.php`
@@ -11038,13 +11041,13 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
### `ext/dom/JitDomLoadHTMLUserScript.php`
**Warnings** (review for bootstrap subset):
-- new JITVariable (line 311)
-- new JITVariable (line 312)
-- new JITVariable (line 313)
+- new JITVariable (line 315)
- new JITVariable (line 316)
-- new JITVariable (line 321)
-- new JITVariable (line 434)
-- new JITVariable (line 451)
+- new JITVariable (line 317)
+- new JITVariable (line 320)
+- new JITVariable (line 325)
+- new JITVariable (line 438)
+- new JITVariable (line 455)
- 21 class method(s)
### `ext/dom/JitDomLoadUserScript.php`
@@ -20071,6 +20074,12 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
- new ArgumentCountError (line 384)
- 18 class method(s)
+### `ext/mbstring/JitMbGetInfo.php`
+
+**Warnings** (review for bootstrap subset):
+- new ArgumentCountError (line 36)
+- 4 class method(s)
+
### `ext/mbstring/JitMbHttpInput.php`
**Warnings** (review for bootstrap subset):
@@ -20239,6 +20248,11 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
- new HashTable (line 42)
- 8 class method(s)
+### `ext/mbstring/MbGetInfoJitHelper.php`
+
+**Warnings** (review for bootstrap subset):
+- 5 class method(s)
+
### `ext/mbstring/MbHttpInputJitHelper.php`
**Warnings** (review for bootstrap subset):
@@ -20660,9 +20674,8 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
### `ext/mbstring/mb_get_info.php`
**Warnings** (review for bootstrap subset):
-- new ArgumentCountError (line 28)
-- new ArgumentCountError (line 46)
-- 3 class method(s)
+- new ArgumentCountError (line 29)
+- 2 class method(s)
### `ext/mbstring/mb_http_input.php`
@@ -51277,6 +51290,11 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
**Warnings** (review for bootstrap subset):
- 9 class method(s)
+### `lib/JIT/Builtin/MbGetInfoRuntime.php`
+
+**Warnings** (review for bootstrap subset):
+- 5 class method(s)
+
### `lib/JIT/Builtin/MbHttpInputRuntime.php`
**Warnings** (review for bootstrap subset):
@@ -51861,12 +51879,12 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
### `lib/JIT/Builtin/RecursiveLeavesFlattenRuntime.php`
**Warnings** (review for bootstrap subset):
-- new Variable (line 146)
-- new Variable (line 186)
-- new Variable (line 194)
-- new Variable (line 238)
-- new Variable (line 241)
-- 6 class method(s)
+- new Variable (line 155)
+- new Variable (line 196)
+- new Variable (line 204)
+- new Variable (line 276)
+- new Variable (line 279)
+- 7 class method(s)
- 2 closure(s)
### `lib/JIT/Builtin/RecursiveTreeIteratorBuildRuntime.php`
@@ -55603,12 +55621,12 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
### `lib/JIT/Call/RecursiveIteratorIteratorConstruct.php`
**Warnings** (review for bootstrap subset):
-- new ArgumentCountError (line 33)
-- new Variable (line 51)
-- new Variable (line 57)
-- new Variable (line 104)
-- new Variable (line 118)
-- 5 class method(s)
+- new ArgumentCountError (line 36)
+- new Variable (line 56)
+- new Variable (line 62)
+- new Variable (line 109)
+- new Variable (line 123)
+- 6 class method(s)
### `lib/JIT/Call/RecursiveTreeIteratorConstruct.php`
@@ -63547,8 +63565,8 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
**Warnings** (review for bootstrap subset):
- new HashTable (line 32)
- new HashTable (line 33)
-- new Variable (line 54)
-- new Variable (line 57)
+- new Variable (line 60)
+- new Variable (line 63)
- 3 class method(s)
### `lib/VM/RedundantIterableUnionCheck.php`
diff --git a/docs/bootstrap-profile.json b/docs/bootstrap-profile.json
index 4a7c7b64eb..186069d99b 100644
--- a/docs/bootstrap-profile.json
+++ b/docs/bootstrap-profile.json
@@ -333,6 +333,7 @@
"ext/dom/DomCreateElementJitHelper.php",
"ext/dom/DomCreateElementNSJitHelper.php",
"ext/dom/DomDocumentPropertySupport.php",
+ "ext/dom/DomDocumentValidateJitHelper.php",
"ext/dom/DomElementTextContentJitHelper.php",
"ext/dom/DomExceptionConstants.php",
"ext/dom/DomGetElementByIdJitHelper.php",
@@ -507,6 +508,7 @@
"ext/dom/JitDomReplaceChildLiveSlots.php",
"ext/dom/JitDomReplaceData.php",
"ext/dom/JitDomRequireDomNodeArg.php",
+ "ext/dom/JitDomSave.php",
"ext/dom/JitDomSaveHTML.php",
"ext/dom/JitDomSaveHTMLFile.php",
"ext/dom/JitDomSaveHTMLUserScript.php",
@@ -1563,6 +1565,7 @@
"ext/mbstring/JitMbEncodingRegistry.php",
"ext/mbstring/JitMbEreg.php",
"ext/mbstring/JitMbEregSearch.php",
+ "ext/mbstring/JitMbGetInfo.php",
"ext/mbstring/JitMbHttpInput.php",
"ext/mbstring/JitMbHttpOutput.php",
"ext/mbstring/JitMbInternalEncoding.php",
@@ -1595,6 +1598,7 @@
"ext/mbstring/MbDetectOrderJitHelper.php",
"ext/mbstring/MbEncodingAliasesJitHelper.php",
"ext/mbstring/MbEregJitHelper.php",
+ "ext/mbstring/MbGetInfoJitHelper.php",
"ext/mbstring/MbHttpInputJitHelper.php",
"ext/mbstring/MbHttpOutputJitHelper.php",
"ext/mbstring/MbInternalEncodingJitHelper.php",
@@ -5774,6 +5778,7 @@
"lib/JIT/Builtin/DomC14NRuntime.php",
"lib/JIT/Builtin/DomCreateElementNSRuntime.php",
"lib/JIT/Builtin/DomCreateElementRuntime.php",
+ "lib/JIT/Builtin/DomDocumentValidateRuntime.php",
"lib/JIT/Builtin/DomElementTextContentRuntime.php",
"lib/JIT/Builtin/DomGetElementByIdRuntime.php",
"lib/JIT/Builtin/DomGetElementsByTagNameRuntime.php",
@@ -5965,6 +5970,7 @@
"lib/JIT/Builtin/MbDetectOrderRuntime.php",
"lib/JIT/Builtin/MbEncodingAliasesRuntime.php",
"lib/JIT/Builtin/MbEregRuntime.php",
+ "lib/JIT/Builtin/MbGetInfoRuntime.php",
"lib/JIT/Builtin/MbHttpInputRuntime.php",
"lib/JIT/Builtin/MbHttpOutputRuntime.php",
"lib/JIT/Builtin/MbInternalEncodingRuntime.php",
@@ -6608,9 +6614,11 @@
"lib/JIT/Call/DomDocumentLoadHTMLFile.php",
"lib/JIT/Call/DomDocumentLoadXML.php",
"lib/JIT/Call/DomDocumentNormalizeDocument.php",
+ "lib/JIT/Call/DomDocumentSave.php",
"lib/JIT/Call/DomDocumentSaveHTML.php",
"lib/JIT/Call/DomDocumentSaveHTMLFile.php",
"lib/JIT/Call/DomDocumentSaveXML.php",
+ "lib/JIT/Call/DomDocumentValidateMethod.php",
"lib/JIT/Call/DomElementGetAttribute.php",
"lib/JIT/Call/DomElementGetAttributeNS.php",
"lib/JIT/Call/DomElementGetAttributeNode.php",
@@ -8188,9 +8196,9 @@
"test/bootstrap-aot/lib_opcode/main.php"
],
"totals": {
- "inventory_files": 7954,
+ "inventory_files": 7962,
"excluded": 0,
- "eligible": 7954,
+ "eligible": 7962,
"aot_lint_targets": 113,
"aot_link_targets": 100,
"aot_link_lib_targets": 1
diff --git a/docs/bootstrap-selfhost.md b/docs/bootstrap-selfhost.md
index d59351ff81..e2ffea7133 100644
--- a/docs/bootstrap-selfhost.md
+++ b/docs/bootstrap-selfhost.md
@@ -2,7 +2,7 @@
**Gen-0 without Zend:** `BOOTSTRAP_M5_NO_ZEND=1 make bootstrap-selfhost-link` installs `prelinked/bootstrap-gen0/bin-compile-aot` and links `compiler_minimal` without `php bin/compile.php` ([#3053](https://github.com/PurHur/php-compiler/issues/3053)). **M5 lib spine compile:** `BOOTSTRAP_NO_ZEND_FALLBACK=1 make bootstrap-selfhost-lib-spine-smoke` (default in link script) refuses host `php bin/compile.php` on the spine emit path ([#8716](https://github.com/PurHur/php-compiler/issues/8716)). **Contributor workflow:** [bootstrap-dev-workflow.md](bootstrap-dev-workflow.md) (tiered gen-1+ path, spine checklist, CI).
-**Project north star:** The **compiler fully compiles itself** — native AOT from `lib/` (no `vendor/` at cold boot), then compiles PHP and rebuilds the next compiler revision without Zend. **M2 spine:** **7959** / **7959** Phase A inventory (`php script/bootstrap-spine-count.php`; `check-selfhost-spine-coverage-sync.php`). **M5 daily gate:** `make north-star5-verify-fast` (~1–2 min) ✅; **`--strict`** (~1h) pre-merge only. Committed `prelinked/bootstrap-gen0/` sidecars + vendor **7410/7412** cold boot. **Hot loop:** VM driver execute probe ~**20ms**; full spine relink only with `BOOTSTRAP_VM_DRIVER_EXECUTE_PROBE_FULL_LINK=1` ([#2201](https://github.com/PurHur/php-compiler/issues/2201)). **Living tracker:** [#1492](https://github.com/PurHur/php-compiler/issues/1492) (was [#1056](https://github.com/PurHur/php-compiler/issues/1056)) · **re-root doc:** [self-host-target.md](self-host-target.md) · **generation ladder:** [bootstrap-generations.md](bootstrap-generations.md) · **M5 fast path:** [bootstrap-m5-fast-path.md](bootstrap-m5-fast-path.md) · public status: [development-status § North star](https://purhur.github.io/php-compiler/development-status.html#north-star-self-host). Parent tracking: [#78](https://github.com/PurHur/php-compiler/issues/78) (roadmap), [#212](https://github.com/PurHur/php-compiler/issues/212) (closed umbrella).
+**Project north star:** The **compiler fully compiles itself** — native AOT from `lib/` (no `vendor/` at cold boot), then compiles PHP and rebuilds the next compiler revision without Zend. **M2 spine:** **7962** / **7962** Phase A inventory (`php script/bootstrap-spine-count.php`; `check-selfhost-spine-coverage-sync.php`). **M5 daily gate:** `make north-star5-verify-fast` (~1–2 min) ✅; **`--strict`** (~1h) pre-merge only. Committed `prelinked/bootstrap-gen0/` sidecars + vendor **7410/7412** cold boot. **Hot loop:** VM driver execute probe ~**20ms**; full spine relink only with `BOOTSTRAP_VM_DRIVER_EXECUTE_PROBE_FULL_LINK=1` ([#2201](https://github.com/PurHur/php-compiler/issues/2201)). **Living tracker:** [#1492](https://github.com/PurHur/php-compiler/issues/1492) (was [#1056](https://github.com/PurHur/php-compiler/issues/1056)) · **re-root doc:** [self-host-target.md](self-host-target.md) · **generation ladder:** [bootstrap-generations.md](bootstrap-generations.md) · **M5 fast path:** [bootstrap-m5-fast-path.md](bootstrap-m5-fast-path.md) · public status: [development-status § North star](https://purhur.github.io/php-compiler/development-status.html#north-star-self-host). Parent tracking: [#78](https://github.com/PurHur/php-compiler/issues/78) (roadmap), [#212](https://github.com/PurHur/php-compiler/issues/212) (closed umbrella).
## Current gates
diff --git a/docs/capabilities.md b/docs/capabilities.md
index 7c82748f65..96bfdd1499 100644
--- a/docs/capabilities.md
+++ b/docs/capabilities.md
@@ -1078,7 +1078,7 @@ Auto-generated by `script/capability-matrix.php`. Do not edit by hand.
| `stream_context_set_option` | yes | yes | yes | standard | JIT PHPT; AOT PHPT |
| `stream_context_set_params` | yes | yes | yes | standard | AOT PHPT |
| `stream_copy_to_stream` | yes | yes | yes | standard | JIT PHPT |
-| `stream_filter_append` | yes | yes | yes | standard | JIT PHPT |
+| `stream_filter_append` | yes | yes | yes | standard | JIT PHPT; AOT PHPT |
| `stream_filter_prepend` | yes | yes | yes | standard | |
| `stream_filter_register` | yes | yes | yes | standard | |
| `stream_filter_remove` | yes | yes | yes | standard | |
diff --git a/docs/pages/capability-comparison.html b/docs/pages/capability-comparison.html
index fb331743f6..0020c0b623 100644
--- a/docs/pages/capability-comparison.html
+++ b/docs/pages/capability-comparison.html
@@ -52,7 +52,7 @@ PHP capability comparison
This is not a full php-src inventory — only items we measure in
capabilities-syntax.md
and capabilities.md.
- Generated 2026-08-27 (matrix mtime).
+ Generated 2026-08-28 (matrix mtime).
diff --git a/docs/pages/development-status.md b/docs/pages/development-status.md
index 5615fd67c0..10bb50f087 100644
--- a/docs/pages/development-status.md
+++ b/docs/pages/development-status.md
@@ -15,7 +15,7 @@ permalink: /development-status.html
| **North star** | Compiler compiles itself without Zend ([#1492](https://github.com/PurHur/php-compiler/issues/1492)) |
| **v1.1.0 theme** | M5 fast-path stability; enum/property hooks; `preg_match` JIT; `spl_autoload*`; php-in-PHP JIT helpers ([#78](https://github.com/PurHur/php-compiler/issues/78)) |
| **Wave 3** | Language **7410/7412** · Stdlib **7410/7412** on master ([#1380](https://github.com/PurHur/php-compiler/issues/1380)) |
-| **Spine SSOT** | `php script/bootstrap-spine-count.php` → **7959** / **7959** |
+| **Spine SSOT** | `php script/bootstrap-spine-count.php` → **7962** / **7962** |
| **Builtin matrix** | **1555** functions ([`docs/capabilities.md`](https://github.com/PurHur/php-compiler/blob/master/docs/capabilities.md)) |
| **Try it** | [`docs/GETTING-STARTED.md`](https://github.com/PurHur/php-compiler/blob/master/docs/GETTING-STARTED.md) |
@@ -50,7 +50,7 @@ permalink: /development-status.html
### Still open (high signal)
- **MCJIT execute** — `bin/jit.php -r` SIGSEGV ([#98](https://github.com/PurHur/php-compiler/issues/98))
-- **Literal spine ratio** — **7959/7959** ✅ (Jul 2026)
+- **Literal spine ratio** — **7962/7962** ✅ (Jul 2026)
- **Compile-spine stub retirement** — shrink `PHP_COMPILER_SELFHOST_AOT` on M3 allowlist ([#1402](https://github.com/PurHur/php-compiler/issues/1402))
- **007-ThrowsWeb AOT execute** — invalid POST segfault at runtime (link OK; slice `EXAMPLES_AOT_SMOKE_ONLY=007`)
- **LLVM 14+ upgrade** — experimental `script/install-llvm14.sh` ([#174](https://github.com/PurHur/php-compiler/issues/174))
@@ -62,7 +62,7 @@ permalink: /development-status.html
- **`phpc` CLI** — `run`, `serve`, `build`, `deploy`, `lint`, `test`, `init`, `doctor`
- **Examples 000–009** — VM and AOT link/execute for the curated web subset
- **Self-host M0** — `compiler_minimal bundle OK` ✅
-- **Self-host M2** — spine **7959/7959** ✅; native link + lint ✅
+- **Self-host M2** — spine **7962/7962** ✅; native link + lint ✅
- **Self-host M3** — HelloWorld strict `emit_path=native` ✅ ([#1493](https://github.com/PurHur/php-compiler/issues/1493)); inventory argv `bin/compile.php` ✅ ([#3024](https://github.com/PurHur/php-compiler/issues/3024) closed); compile-smoke strict native ✅ ([#1937](https://github.com/PurHur/php-compiler/issues/1937))
- **Self-host M4** — `make bootstrap-loop-probe` full ladder ✅; gen-2→gen-3 full-spine recompile ✅
- **Self-host M3–M5** — vendor prelink **7410/7412** ✅; **`make north-star5-verify-fast`** daily ✅; VM probe ~**20ms**. **`--strict` red** ([#21417](https://github.com/PurHur/php-compiler/issues/21417)) and **M3/M4 emit paths are prelinked blob COPIES, not native compiles** ([#21860](https://github.com/PurHur/php-compiler/issues/21860)) — the byte-identical gen-0/gen-2/gen-3 result follows from copying and is not fixpoint evidence
@@ -92,7 +92,7 @@ See [`docs/bootstrap-selfhost.md`](https://github.com/PurHur/php-compiler/blob/m
|-----------|--------|
| **M0** — Small `lib/` bundle runs | ✅ |
| **M1** — Compiler-shaped bundle + compile-smoke | ✅ |
-| **M2** — Spine toward full inventory | ✅ **7959** / **7959** |
+| **M2** — Spine toward full inventory | ✅ **7962** / **7962** |
| **M3** — Native compiles PHP (no Zend emit) | ✅ Smoke + inventory argv driver strict native |
| **M4** — Bootstrap loop (next revision) | ✅ `bootstrap-loop-probe` full ladder |
| **M5** — Full self-host, no `vendor/` cold boot | ✅ Presenter strict + compiled-only empty `build/` cold boot ([#3053](https://github.com/PurHur/php-compiler/issues/3053)) |
diff --git a/docs/pages/index.html b/docs/pages/index.html
index b84649c484..40ad5f40bd 100644
--- a/docs/pages/index.html
+++ b/docs/pages/index.html
@@ -391,7 +391,7 @@ Self-host progress
fix/spine-aot-jit-blockers @ a8cffaa0e (15 Jun 2026, LLVM 9).
- M2 spine SSOT: php script/bootstrap-spine-count.php → **7959** / **7959** Phase A inventory (literal coverage ✅).
+ M2 spine SSOT: php script/bootstrap-spine-count.php → **7962** / **7962** Phase A inventory (literal coverage ✅).
M4: make bootstrap-loop-probe full ladder ✅.
M5: make north-star5-verify-fast ✅ daily; --strict pre-merge; VM driver probe ~20ms in CI loops.
Remaining: MCJIT execute ([#98](https://github.com/PurHur/php-compiler/issues/98)); honest PHP main() in full spine AOT (native bundle-OK probe is bootstrap smoke).
@@ -437,7 +437,7 @@
M4
✓
M5
Vendor prelink 7410/7410 ✅; committed .o cold boot ✅;
- north-star5-verify-fast ✅ daily; --strict pre-merge; spine **7959** / **7959**; prelinked gen-0 refreshed;
+ north-star5-verify-fast ✅ daily; --strict pre-merge; spine **7962** / **7962**; prelinked gen-0 refreshed;
fast VM execute probe (~20ms); compiled-only cold boot via BOOTSTRAP_M5_NO_ZEND=1 ✅
(#3053,
#8559,
diff --git a/docs/roadmap-wave3.md b/docs/roadmap-wave3.md
index 2b7e85218b..0c8e0039a3 100644
--- a/docs/roadmap-wave3.md
+++ b/docs/roadmap-wave3.md
@@ -19,7 +19,7 @@ Regenerate capability truth: `php script/capability-matrix.php`, `php script/cap
Related merges outside this wave: `goto` ([#1228](https://github.com/PurHur/php-compiler/issues/1228) / [#1333](https://github.com/PurHur/php-compiler/pull/1333)), anonymous classes ([#1233](https://github.com/PurHur/php-compiler/issues/1233) / [#1386](https://github.com/PurHur/php-compiler/pull/1386)).
-**M2 spine:** **7959** / **7959** (`php script/bootstrap-spine-count.php`) — full Phase A inventory in `compiler_lib_spine_smoke`; coverage sync ✅ (`check-selfhost-spine-coverage-sync.php`). Native spine **link** + **lint** ✅ ([#2134](https://github.com/PurHur/php-compiler/issues/2134), [#8559](https://github.com/PurHur/php-compiler/issues/8559)). **M5 daily gate:** `make north-star5-verify-fast` + VM probe ~20ms ([#2201](https://github.com/PurHur/php-compiler/issues/2201)); `--strict` pre-merge only. M4 gen-2→gen-3 recompile ✅. Target doc: [self-host-target.md](self-host-target.md)
+**M2 spine:** **7962** / **7962** (`php script/bootstrap-spine-count.php`) — full Phase A inventory in `compiler_lib_spine_smoke`; coverage sync ✅ (`check-selfhost-spine-coverage-sync.php`). Native spine **link** + **lint** ✅ ([#2134](https://github.com/PurHur/php-compiler/issues/2134), [#8559](https://github.com/PurHur/php-compiler/issues/8559)). **M5 daily gate:** `make north-star5-verify-fast` + VM probe ~20ms ([#2201](https://github.com/PurHur/php-compiler/issues/2201)); `--strict` pre-merge only. M4 gen-2→gen-3 recompile ✅. Target doc: [self-host-target.md](self-host-target.md)
## Language (#1354–#1366)
diff --git a/docs/self-host-target.md b/docs/self-host-target.md
index 4a0d771ac8..8bf478d830 100644
--- a/docs/self-host-target.md
+++ b/docs/self-host-target.md
@@ -35,7 +35,7 @@ That is **M5**. Everything below is the honest path from today’s bootstrap to
|-------|-------|--------|
| **Bootstrap driver** | Prelinked gen-0 refreshed via honest inventory argv emit; native `build/bin-compile-aot-inventory` for M4/M5 | Compiled `bin/compile.php` only |
| **Bundle size** | **7410/7412** literal Phase A inventory in spine smoke | Full vm.php closure |
-| **Inventory coverage** | **7959** / **7959** ✅ | Full closure |
+| **Inventory coverage** | **7962** / **7962** ✅ | Full closure |
| **HelloWorld** | ✅ `emit_path=native` via gen-0 argv emit helper (`DRIVER -o OUT SOURCE`; [#22178](https://github.com/PurHur/php-compiler/issues/22178)) | Native compile for arbitrary PHP |
| **Bootstrap loop (M4)** | `make bootstrap-loop-probe` full ladder ✅ — gen-1→gen-2, gen-2→gen-3 full spine, full-revision argv | Native full revision rebuild |
| **Vendor** | **7410/7412** vendor `object_ok`; committed `.o` cold boot without `vendor/` ✅; `make north-star5-verify-fast` daily ✅; `--strict` ❌ **red at step 4a2** ([#21417](https://github.com/PurHur/php-compiler/issues/21417)) | No Zend `vendor/autoload.php` at bootstrap |
@@ -69,7 +69,7 @@ That is **M5**. Everything below is the honest path from today’s bootstrap to
|-----------|----------------|--------|-----|
| **M0** | AOT can link a **small** honest `lib/` subset | ✅ | 100% |
| **M1** | Bundle is **compiler-shaped** (lint + compile-smoke) | ✅ | 100% |
-| **M2** | Spine grows toward full `bin/vm.php` inventory | ✅ **7959** / **7959** | **100%** |
+| **M2** | Spine grows toward full `bin/vm.php` inventory | ✅ **7962** / **7962** | **100%** |
| **M3** | Self-host binary **compiles external PHP** (HelloWorld) without Zend emit | ✅ `emit_path=native` via gen-0 argv helper ([#22178](https://github.com/PurHur/php-compiler/issues/22178)) | **~90%** |
| **M4** | Self-host binary **rebuilds** the next compiler tree | 🚧 ladder runs but gen-1→gen-2 is a COPY ([#21860](https://github.com/PurHur/php-compiler/issues/21860)) | **~60%** |
| **M5** | Full self-host; Zend retired from loop | 🚧 `north-star5-verify-fast` daily ✅; **`--strict` red at step 4a2** ([#21417](https://github.com/PurHur/php-compiler/issues/21417)); `BOOTSTRAP_M5_NO_ZEND=1` empty `build/` ([#3053](https://github.com/PurHur/php-compiler/issues/3053)) | **~75%** |
@@ -80,7 +80,7 @@ That is **M5**. Everything below is the honest path from today’s bootstrap to
| Indicator | Formula | Jul 2026 |
|-----------|---------|----------|
-| **M2 spine progress** | `require_once` units in `compiler_lib_spine_smoke` ÷ Phase A inventory file count | **7959** / **7959** (`php script/bootstrap-spine-count.php`) |
+| **M2 spine progress** | `require_once` units in `compiler_lib_spine_smoke` ÷ Phase A inventory file count | **7962** / **7962** (`php script/bootstrap-spine-count.php`) |
| **Public “Self-host” row** | Same M2 ratio until M3–M5 gates add weight ([`development-status.md`](pages/development-status.md)) | **~97%** |
| **M5 vendor prelink** | `object_ok` packages ÷ 3 | **3 / 3** (cfg, types, llvm) |
| **Composite (internal)** | Milestone weights in table above (M0–M1 = 100%, M2 = spine %, M3–M5 = gate %) | **~65%** |
diff --git a/prelinked/bootstrap-gen0/.m3_compiler_lib_sidecar.sha b/prelinked/bootstrap-gen0/.m3_compiler_lib_sidecar.sha
index fed00d2ed9..f7d6919d0b 100755
--- a/prelinked/bootstrap-gen0/.m3_compiler_lib_sidecar.sha
+++ b/prelinked/bootstrap-gen0/.m3_compiler_lib_sidecar.sha
@@ -1 +1 @@
-4d9f8b1ddbf6c1d1a6a839e388603d306d28a1b7
\ No newline at end of file
+70c519af4bf35c8c09e22efe099e889197e56d08
diff --git a/test/selfhost/compiler_lib_spine_smoke/main.php b/test/selfhost/compiler_lib_spine_smoke/main.php
index 0a1b520790..dbd97b4b93 100644
--- a/test/selfhost/compiler_lib_spine_smoke/main.php
+++ b/test/selfhost/compiler_lib_spine_smoke/main.php
@@ -1349,6 +1349,7 @@
require_once __DIR__.'/../../../ext/mbstring/JitMbScrub.php';
require_once __DIR__.'/../../../ext/mbstring/JitMbEreg.php';
require_once __DIR__.'/../../../ext/mbstring/JitMbEregSearch.php';
+require_once __DIR__.'/../../../ext/mbstring/JitMbGetInfo.php';
require_once __DIR__.'/../../../ext/mbstring/JitMbSearch.php';
require_once __DIR__.'/../../../ext/mbstring/JitMbStrPad.php';
require_once __DIR__.'/../../../ext/mbstring/JitMbStrSplit.php';
@@ -1371,6 +1372,7 @@
require_once __DIR__.'/../../../ext/mbstring/MbNumericEntityJitHelper.php';
require_once __DIR__.'/../../../ext/mbstring/MbPreferredMimeNameJitHelper.php';
require_once __DIR__.'/../../../ext/mbstring/MbEncodingAliasesJitHelper.php';
+require_once __DIR__.'/../../../ext/mbstring/MbGetInfoJitHelper.php';
require_once __DIR__.'/../../../ext/mbstring/MbScrubJitHelper.php';
require_once __DIR__.'/../../../ext/mbstring/MbStrlenJitHelper.php';
require_once __DIR__.'/../../../ext/mbstring/MbTrimJitHelper.php';
@@ -8057,6 +8059,7 @@
require_once __DIR__.'/../../../lib/JIT/Builtin/MbConvertVariablesRuntime.php';
require_once __DIR__.'/../../../lib/JIT/Builtin/MbDetectEncodingRuntime.php';
require_once __DIR__.'/../../../lib/JIT/Builtin/MbDetectOrderRuntime.php';
+require_once __DIR__.'/../../../lib/JIT/Builtin/MbGetInfoRuntime.php';
require_once __DIR__.'/../../../lib/JIT/Builtin/MbMimeheaderRuntime.php';
require_once __DIR__.'/../../../lib/JIT/Builtin/MbPreferredMimeNameRuntime.php';
require_once __DIR__.'/../../../lib/JIT/Builtin/MbEncodingAliasesRuntime.php';
diff --git a/test/unit/BootstrapSelfhostBundleTest.php b/test/unit/BootstrapSelfhostBundleTest.php
index 3cc39d0b32..a4d71592d8 100644
--- a/test/unit/BootstrapSelfhostBundleTest.php
+++ b/test/unit/BootstrapSelfhostBundleTest.php
@@ -563,8 +563,8 @@ public function testCompilerLibSpineSmokeBundleUnitCountAndKeyUnits(): void
$this->assertFileExists($entry);
$contents = (string) file_get_contents($entry);
$count = bootstrap_spine_counts(self::$root)['spine'];
- // Spine ratio 7959/7959 — Phase A inventory in compiler_lib_spine_smoke (#2202, #34216).
- $this->assertSame(7959, $count, 'M2 spine require_once units track Phase A inventory (#8559, #9234, #11629, #18550); coverage sync defers PregJitHelperThinAot (#24115) + NetworkServicesNameLookupThinAot (#27103)');
+ // Spine ratio 7962/7962 — Phase A inventory in compiler_lib_spine_smoke (#2202, #34216).
+ $this->assertSame(7962, $count, 'M2 spine require_once units track Phase A inventory (#8559, #9234, #11629, #18550); coverage sync defers PregJitHelperThinAot (#24115) + NetworkServicesNameLookupThinAot (#27103)');
foreach (self::LIB_SPINE_SMOKE_NEW_UNITS as $unit) {
$this->assertStringContainsString(
"require_once __DIR__.'/../../../{$unit}';",