From 5e274fe6a04ebfc837bfa01e32d7365e4736ffff Mon Sep 17 00:00:00 2001 From: PurHur Date: Sun, 23 Aug 2026 02:55:14 +0000 Subject: [PATCH] Stdlib: openssl_x509_read thin AOT bake via OpenSSLCertificate (#34048) Compile-time PEM literals normalize through VmOpensslX509Native and allocate OpenSSLCertificate with __osslPem (peer openssl_pkey_get_private #34037); clears the leftover LogicException after #33497 TypeError/argc gates. Co-authored-by: Cursor --- README.md | 8 +- docs/bootstrap-inventory.md | 742 +++++++++--------- docs/bootstrap-selfhost.md | 2 +- docs/pages/development-status.md | 8 +- docs/pages/index.html | 4 +- docs/roadmap-wave3.md | 2 +- docs/self-host-target.md | 6 +- ext/openssl/JitOpensslX509Read.php | 125 +++ ext/openssl/OpensslCertificateJitSupport.php | 18 + ext/openssl/VmOpensslObjects.php | 16 +- ext/openssl/openssl_x509_read.php | 9 +- lib/JIT/Builtin/Type/Object_.php | 8 + .../issue_34048_openssl_x509_read_aot.php | 27 + .../compiler_lib_spine_smoke/main.php | 2 + test/unit/BootstrapSelfhostBundleTest.php | 4 +- ...ue34048OpensslX509ReadHappyPathAotTest.php | 80 ++ 16 files changed, 683 insertions(+), 378 deletions(-) create mode 100644 ext/openssl/JitOpensslX509Read.php create mode 100644 ext/openssl/OpensslCertificateJitSupport.php create mode 100644 test/repro/issue_34048_openssl_x509_read_aot.php create mode 100644 test/unit/Issue34048OpensslX509ReadHappyPathAotTest.php diff --git a/README.md b/README.md index d1e67f88e14..b06d73aabc4 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 **7755** / **7755** · **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 **7758** / **7761** · **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 **7755** / **7755**; 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 **7758** / **7761**; 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** | ✅ **7755** / **7755** | Full Phase A inventory in spine smoke; native link + lint ✅ | +| **M2** | ✅ **7758** / **7761** | 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 **7755** / **7755**; 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 **7758** / **7761**; 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 0355488975f..3daece4dbac 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 | 7755 | -| Phase A inventory files (M2 ratio SSOT) | 7755 | +| PHP files on vm.php path | 7761 | +| Phase A inventory files (M2 ratio SSOT) | 7761 | | Phase A ratio-deferred paths | 0 | | Source constructs flagged (blockers) | 0 | -| Source constructs flagged (warnings) | 24818 | +| Source constructs flagged (warnings) | 24829 | ## Compiler CFG gaps (`lib/Compiler.php`) @@ -1790,11 +1790,14 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag | `ext/openssl/JitOpensslPbkdf2.php` | 0 | 1 | | `ext/openssl/JitOpensslPkeyGetDetails.php` | 0 | 1 | | `ext/openssl/JitOpensslPkeyGetDetailsKernel.php` | 0 | 1 | +| `ext/openssl/JitOpensslPkeyGetPrivate.php` | 0 | 2 | +| `ext/openssl/JitOpensslPkeyGetPublic.php` | 0 | 2 | | `ext/openssl/JitOpensslPkeyKernel.php` | 0 | 1 | | `ext/openssl/JitOpensslPkeyNew.php` | 0 | 3 | | `ext/openssl/JitOpensslSign.php` | 0 | 1 | | `ext/openssl/JitOpensslSignKernel.php` | 0 | 1 | | `ext/openssl/JitOpensslX509.php` | 0 | 1 | +| `ext/openssl/JitOpensslX509Read.php` | 0 | 2 | | `ext/openssl/Module.php` | 0 | 67 | | `ext/openssl/OpensslCipherRegistry.php` | 0 | 1 | | `ext/openssl/OpensslConstants.php` | 0 | 1 | @@ -5904,7 +5907,8 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag | `lib/JIT/Builtin/RecursiveLeavesFlattenRuntime.php` | 0 | 7 | | `lib/JIT/Builtin/RecursiveTreeIteratorBuildRuntime.php` | 0 | 4 | | `lib/JIT/Builtin/Refcount.php` | 0 | 1 | -| `lib/JIT/Builtin/ReflectionClassIsFinalRuntime.php` | 0 | 1 | +| `lib/JIT/Builtin/ReflectionClassIsCloneableRuntime.php` | 0 | 2 | +| `lib/JIT/Builtin/ReflectionClassIsFinalRuntime.php` | 0 | 2 | | `lib/JIT/Builtin/ReflectionClassIsInstantiableRuntime.php` | 0 | 2 | | `lib/JIT/Builtin/ReflectionClassIsIterateableRuntime.php` | 0 | 1 | | `lib/JIT/Builtin/ReflectionClassKindNameTableRuntime.php` | 0 | 2 | @@ -6578,6 +6582,7 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag | `lib/JIT/Call/ReflectionClassGetReflectionConstant.php` | 0 | 1 | | `lib/JIT/Call/ReflectionClassGetShortName.php` | 0 | 1 | | `lib/JIT/Call/ReflectionClassInNamespace.php` | 0 | 1 | +| `lib/JIT/Call/ReflectionClassIsCloneable.php` | 0 | 1 | | `lib/JIT/Call/ReflectionClassIsFinal.php` | 0 | 1 | | `lib/JIT/Call/ReflectionClassIsInstantiable.php` | 0 | 1 | | `lib/JIT/Call/ReflectionClassIsIterateable.php` | 0 | 1 | @@ -6695,7 +6700,7 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag | `lib/JIT/CoalesceHelper.php` | 0 | 1 | | `lib/JIT/CompileCache.php` | 0 | 1 | | `lib/JIT/CompilerOperandChainNative.php` | 0 | 3 | -| `lib/JIT/Context.php` | 0 | 271 | +| `lib/JIT/Context.php` | 0 | 272 | | `lib/JIT/DatePeriodForeachSnapshot.php` | 0 | 3 | | `lib/JIT/DeprecatedCallGuard.php` | 0 | 1 | | `lib/JIT/DnfParamCheck.php` | 0 | 28 | @@ -21820,6 +21825,18 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag **Warnings** (review for bootstrap subset): - 13 class method(s) +### `ext/openssl/JitOpensslPkeyGetPrivate.php` + +**Warnings** (review for bootstrap subset): +- new JITVariable (line 79) +- 6 class method(s) + +### `ext/openssl/JitOpensslPkeyGetPublic.php` + +**Warnings** (review for bootstrap subset): +- new JITVariable (line 58) +- 2 class method(s) + ### `ext/openssl/JitOpensslPkeyKernel.php` **Warnings** (review for bootstrap subset): @@ -21847,6 +21864,12 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag **Warnings** (review for bootstrap subset): - 47 class method(s) +### `ext/openssl/JitOpensslX509Read.php` + +**Warnings** (review for bootstrap subset): +- new JITVariable (line 70) +- 5 class method(s) + ### `ext/openssl/Module.php` **Warnings** (review for bootstrap subset): @@ -22017,25 +22040,25 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag - new Variable (line 73) - new Variable (line 103) - new ObjectEntry (line 118) -- new Variable (line 121) -- new ObjectEntry (line 133) -- new Variable (line 139) -- new ObjectEntry (line 151) -- new Variable (line 154) -- new Variable (line 269) -- new Variable (line 279) -- new Variable (line 286) -- new Variable (line 311) -- new Variable (line 352) -- new Variable (line 399) -- new Variable (line 411) -- new Variable (line 419) -- new Variable (line 426) -- new Variable (line 445) -- new Variable (line 452) -- new Variable (line 476) -- new HashTable (line 478) -- new ClassEntry (line 719) +- new Variable (line 124) +- new ObjectEntry (line 136) +- new Variable (line 142) +- new ObjectEntry (line 154) +- new Variable (line 157) +- new Variable (line 283) +- new Variable (line 293) +- new Variable (line 300) +- new Variable (line 325) +- new Variable (line 366) +- new Variable (line 413) +- new Variable (line 425) +- new Variable (line 433) +- new Variable (line 440) +- new Variable (line 459) +- new Variable (line 466) +- new Variable (line 490) +- new HashTable (line 492) +- new ClassEntry (line 733) - 27 class method(s) ### `ext/openssl/VmOpensslPkcs12Native.php` @@ -22238,13 +22261,13 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag ### `ext/openssl/openssl_get_privatekey.php` **Warnings** (review for bootstrap subset): -- new ArgumentCountError (line 34) +- new ArgumentCountError (line 33) - 6 class method(s) ### `ext/openssl/openssl_get_publickey.php` **Warnings** (review for bootstrap subset): -- new ArgumentCountError (line 33) +- new ArgumentCountError (line 32) - 5 class method(s) ### `ext/openssl/openssl_open.php` @@ -22363,13 +22386,13 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag ### `ext/openssl/openssl_pkey_get_private.php` **Warnings** (review for bootstrap subset): -- new ArgumentCountError (line 35) +- new ArgumentCountError (line 33) - 6 class method(s) ### `ext/openssl/openssl_pkey_get_public.php` **Warnings** (review for bootstrap subset): -- new ArgumentCountError (line 33) +- new ArgumentCountError (line 32) - 5 class method(s) ### `ext/openssl/openssl_pkey_new.php` @@ -22508,7 +22531,7 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag ### `ext/openssl/openssl_x509_read.php` **Warnings** (review for bootstrap subset): -- new ArgumentCountError (line 33) +- new ArgumentCountError (line 31) - 4 class method(s) ### `ext/openssl/openssl_x509_verify.php` @@ -48712,128 +48735,128 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag - new VM\Variable (line 13049) - new VM (line 13055) - new VM\Variable (line 13068) -- new Variable (line 13303) -- new Type (line 13311) -- new Variable (line 13339) -- new Type (line 13347) -- new JIT\Call\RuntimeIndirectInstanceMethodCall (line 13352) -- new Variable (line 13387) -- new Type (line 13398) -- new Type (line 13609) -- new Variable (line 13760) -- new Variable (line 13824) -- new Variable (line 13856) -- new Operand\Literal (line 14002) -- new Operand\Literal (line 15146) -- new Type (line 15807) -- new Type (line 15839) -- new Type (line 15985) -- new Variable (line 16178) -- new Variable (line 16199) -- new Variable (line 16225) -- new Variable (line 16250) -- new Variable (line 16282) -- new Type (line 16290) -- new Variable (line 16309) -- new Type (line 16317) -- new Variable (line 16343) -- new Type (line 16351) -- new Variable (line 16374) -- new Variable (line 16392) -- new CompileError (line 17369) -- new CompileError (line 17506) -- new Variable (line 17571) -- new Variable (line 17615) -- new Variable (line 18112) -- new Variable (line 18132) -- new Variable (line 18153) -- new Variable (line 18336) -- new Variable (line 18365) -- new Variable (line 18408) -- new Type (line 18442) -- new Variable (line 18536) -- new Variable (line 18560) -- new Variable (line 18570) -- new Variable (line 18775) -- new Variable (line 18793) -- new Type (line 18839) -- new Variable (line 18860) -- new Variable (line 18915) -- new Variable (line 18959) -- new Variable (line 18984) -- new Type (line 19346) -- new Variable (line 19424) -- new Variable (line 19504) -- new Type (line 19516) -- new Type (line 19797) -- new Variable (line 19881) -- new Variable (line 19911) -- new Variable (line 19930) -- new Variable (line 19960) -- new Variable (line 19997) -- new Variable (line 20017) -- new Variable (line 20030) -- new Variable (line 20073) -- new OpCode (line 21127) -- new Variable (line 21128) -- new VM\Variable (line 21151) -- new Variable (line 21182) -- new Variable (line 21217) -- new Variable (line 21286) -- new Variable (line 21330) -- new Variable (line 21372) -- new Variable (line 21385) -- new Variable (line 21399) -- new OpCode (line 21421) -- new Variable (line 21422) -- new Variable (line 21744) -- new Variable (line 21800) -- new Variable (line 21838) -- new OpCode (line 21866) -- new Variable (line 21867) -- new Variable (line 21926) -- new OpCode (line 21934) -- new Variable (line 21935) -- new Variable (line 21964) -- new Variable (line 21999) -- new Variable (line 22039) -- new OpCode (line 22054) -- new Variable (line 22055) -- new Variable (line 22123) -- new Variable (line 22138) -- new Variable (line 22145) -- new OpCode (line 22155) -- new Variable (line 22156) -- new Variable (line 22259) -- new Variable (line 22281) -- new Variable (line 22349) -- new Operand\Literal (line 22358) -- new Variable (line 22373) -- new Variable (line 22708) -- new VM\PropertyIsInitializedHandler (line 22810) -- new JIT\Call\RuntimeIndirectInstanceMethodCall (line 23024) -- new JIT\Call\RuntimeIndirectInstanceMethodCall (line 23773) -- new JIT\Call\RuntimeIndirectInstanceMethodCall (line 24247) -- new JIT\Call\VmCoerceVariableToString (line 24374) -- new JIT\Call\NoOpConstruct (line 24549) -- new JIT\Call\IncludePathResolverResolve (line 24720) -- new Operand\Literal (line 24836) -- new Operand\Literal (line 24838) -- new Operand\Literal (line 24849) -- new JIT\Call\RuntimeIndirectStaticMethodCall (line 24895) -- new JIT\Call\NestedJitCompileScopeIsActiveTrue (line 24923) -- new JIT\Call\EmitCatchableError (line 24964) -- new JIT\Call\RuntimeIndirectStaticMethodCall (line 25106) -- new Operand\Literal (line 25905) -- new VM (line 26815) -- new VM\Variable (line 26824) -- new VM\ClassEntry (line 26923) -- new Func\PHP (line 26942) -- new VM\ClassEntry (line 26988) -- new Variable (line 27005) -- new Variable (line 27097) -- new Variable (line 27195) -- new Variable (line 28386) +- new Variable (line 13306) +- new Type (line 13314) +- new Variable (line 13342) +- new Type (line 13350) +- new JIT\Call\RuntimeIndirectInstanceMethodCall (line 13355) +- new Variable (line 13390) +- new Type (line 13401) +- new Type (line 13612) +- new Variable (line 13763) +- new Variable (line 13827) +- new Variable (line 13859) +- new Operand\Literal (line 14005) +- new Operand\Literal (line 15149) +- new Type (line 15810) +- new Type (line 15842) +- new Type (line 15988) +- new Variable (line 16181) +- new Variable (line 16202) +- new Variable (line 16228) +- new Variable (line 16253) +- new Variable (line 16285) +- new Type (line 16293) +- new Variable (line 16312) +- new Type (line 16320) +- new Variable (line 16346) +- new Type (line 16354) +- new Variable (line 16377) +- new Variable (line 16395) +- new CompileError (line 17372) +- new CompileError (line 17509) +- new Variable (line 17574) +- new Variable (line 17618) +- new Variable (line 18115) +- new Variable (line 18135) +- new Variable (line 18156) +- new Variable (line 18339) +- new Variable (line 18368) +- new Variable (line 18411) +- new Type (line 18445) +- new Variable (line 18539) +- new Variable (line 18563) +- new Variable (line 18573) +- new Variable (line 18778) +- new Variable (line 18796) +- new Type (line 18842) +- new Variable (line 18863) +- new Variable (line 18918) +- new Variable (line 18962) +- new Variable (line 18987) +- new Type (line 19349) +- new Variable (line 19427) +- new Variable (line 19507) +- new Type (line 19519) +- new Type (line 19800) +- new Variable (line 19884) +- new Variable (line 19914) +- new Variable (line 19933) +- new Variable (line 19963) +- new Variable (line 20000) +- new Variable (line 20020) +- new Variable (line 20033) +- new Variable (line 20076) +- new OpCode (line 21130) +- new Variable (line 21131) +- new VM\Variable (line 21154) +- new Variable (line 21185) +- new Variable (line 21220) +- new Variable (line 21289) +- new Variable (line 21333) +- new Variable (line 21375) +- new Variable (line 21388) +- new Variable (line 21402) +- new OpCode (line 21424) +- new Variable (line 21425) +- new Variable (line 21747) +- new Variable (line 21803) +- new Variable (line 21841) +- new OpCode (line 21869) +- new Variable (line 21870) +- new Variable (line 21929) +- new OpCode (line 21937) +- new Variable (line 21938) +- new Variable (line 21967) +- new Variable (line 22002) +- new Variable (line 22042) +- new OpCode (line 22057) +- new Variable (line 22058) +- new Variable (line 22126) +- new Variable (line 22141) +- new Variable (line 22148) +- new OpCode (line 22158) +- new Variable (line 22159) +- new Variable (line 22262) +- new Variable (line 22284) +- new Variable (line 22352) +- new Operand\Literal (line 22361) +- new Variable (line 22376) +- new Variable (line 22711) +- new VM\PropertyIsInitializedHandler (line 22813) +- new JIT\Call\RuntimeIndirectInstanceMethodCall (line 23027) +- new JIT\Call\RuntimeIndirectInstanceMethodCall (line 23776) +- new JIT\Call\RuntimeIndirectInstanceMethodCall (line 24250) +- new JIT\Call\VmCoerceVariableToString (line 24377) +- new JIT\Call\NoOpConstruct (line 24552) +- new JIT\Call\IncludePathResolverResolve (line 24723) +- new Operand\Literal (line 24839) +- new Operand\Literal (line 24841) +- new Operand\Literal (line 24852) +- new JIT\Call\RuntimeIndirectStaticMethodCall (line 24898) +- new JIT\Call\NestedJitCompileScopeIsActiveTrue (line 24926) +- new JIT\Call\EmitCatchableError (line 24967) +- new JIT\Call\RuntimeIndirectStaticMethodCall (line 25109) +- new Operand\Literal (line 25908) +- new VM (line 26818) +- new VM\Variable (line 26827) +- new VM\ClassEntry (line 26926) +- new Func\PHP (line 26945) +- new VM\ClassEntry (line 26991) +- new Variable (line 27008) +- new Variable (line 27100) +- new Variable (line 27198) +- new Variable (line 28389) - 513 class method(s) - 25 closure(s) @@ -51067,10 +51090,17 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag **Warnings** (review for bootstrap subset): - 11 class method(s) +### `lib/JIT/Builtin/ReflectionClassIsCloneableRuntime.php` + +**Warnings** (review for bootstrap subset): +- 5 class method(s) +- 1 closure(s) + ### `lib/JIT/Builtin/ReflectionClassIsFinalRuntime.php` **Warnings** (review for bootstrap subset): -- 4 class method(s) +- 5 class method(s) +- 1 closure(s) ### `lib/JIT/Builtin/ReflectionClassIsInstantiableRuntime.php` @@ -53071,38 +53101,38 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag ### `lib/JIT/Builtin/Type/Object_.php` **Warnings** (review for bootstrap subset): -- new Variable (line 604) -- new Variable (line 1031) -- new Variable (line 1070) -- new Variable (line 1104) -- new Variable (line 2168) -- new Variable (line 2614) -- new Variable (line 2679) -- new Variable (line 2700) -- new Variable (line 2712) -- new Variable (line 2725) -- new Variable (line 2935) -- new VMVariable (line 4742) -- new VMVariable (line 4762) +- new Variable (line 606) +- new Variable (line 1033) +- new Variable (line 1072) +- new Variable (line 1106) +- new Variable (line 2170) +- new Variable (line 2616) +- new Variable (line 2681) +- new Variable (line 2702) +- new Variable (line 2714) +- new Variable (line 2727) +- new Variable (line 2937) +- new VMVariable (line 4752) - new VMVariable (line 4772) -- new VMVariable (line 4792) -- new VMVariable (line 6040) -- new ReflectionClassConstant (line 6763) -- new Variable (line 7186) -- new Variable (line 7212) -- new Variable (line 7220) -- new Variable (line 7243) -- new Variable (line 7269) -- new Variable (line 7277) -- new Variable (line 7351) -- new Literal (line 7368) -- new Literal (line 7373) -- new Literal (line 7378) -- new Variable (line 7389) -- new Variable (line 7422) -- new Variable (line 7445) -- new Variable (line 7971) -- 315 class method(s) +- new VMVariable (line 4782) +- new VMVariable (line 4802) +- new VMVariable (line 6050) +- new ReflectionClassConstant (line 6783) +- new Variable (line 7206) +- new Variable (line 7232) +- new Variable (line 7240) +- new Variable (line 7263) +- new Variable (line 7289) +- new Variable (line 7297) +- new Variable (line 7371) +- new Literal (line 7388) +- new Literal (line 7393) +- new Literal (line 7398) +- new Variable (line 7409) +- new Variable (line 7442) +- new Variable (line 7465) +- new Variable (line 7991) +- 317 class method(s) - 8 closure(s) ### `lib/JIT/Builtin/Type/String_.php` @@ -54624,6 +54654,11 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag **Warnings** (review for bootstrap subset): - 1 class method(s) +### `lib/JIT/Call/ReflectionClassIsCloneable.php` + +**Warnings** (review for bootstrap subset): +- 1 class method(s) + ### `lib/JIT/Call/ReflectionClassIsFinal.php` **Warnings** (review for bootstrap subset): @@ -55397,177 +55432,178 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag - new Call\ReflectionClassGetMethod (line 1744) - new Call\ReflectionClassGetProperty (line 1745) - new Call\ReflectionClassGetReflectionConstant (line 1746) -- new Call\ReflectionClassIsFinal (line 1747) -- new Call\ReflectionClassIsInstantiable (line 1749) -- new Call\ReflectionClassKindQuery (line 1751) -- new Call\ReflectionClassKindQuery (line 1752) -- new Call\ReflectionClassKindQuery (line 1753) +- new Call\ReflectionClassIsFinal (line 1748) +- new Call\ReflectionClassIsInstantiable (line 1750) +- new Call\ReflectionClassIsCloneable (line 1752) - new Call\ReflectionClassKindQuery (line 1754) -- new Call\ReflectionClassIsIterateable (line 1755) -- new Call\ReflectionClassIsIterateable (line 1756) -- new Call\ReflectionClassNewLazyProxy (line 1758) -- new Call\ReflectionClassNewLazyGhost (line 1759) -- new Call\ReflectionPropertyConstruct (line 1762) -- new Call\ReflectionPropertyGetName (line 1763) -- new Call\ReflectionParameterConstruct (line 1764) -- new Call\ReflectionParameterGetName (line 1765) -- new Call\ReflectionPropertyGetAttributes (line 1766) -- new Call\ReflectionPropertyIsFinal (line 1767) -- new Call\ReflectionPropertyIsVirtual (line 1768) -- new Call\ReflectionPropertyGetRawValue (line 1769) -- new Call\ReflectionPropertySetRawValue (line 1770) -- new Call\ReflectionSetAccessible (line 1772) -- new Call\ReflectionPropertyGetValue (line 1773) -- new Call\ReflectionPropertySetValue (line 1774) -- new Call\ReflectionGetDeclaringClass (line 1776) -- new Call\ReflectionMethodConstruct (line 1782) -- new Call\ReflectionMethodGetName (line 1784) -- new Call\ReflectionGetDeclaringClass (line 1786) -- new Call\ReflectionSetAccessible (line 1791) -- new Call\ReflectionMethodInvoke (line 1792) -- new Call\ReflectionClassConstantConstruct (line 1793) -- new Call\ReflectionClassConstantGetName (line 1794) -- new Call\ReflectionPropertyGetMangledName (line 1796) -- new Call\ReflectionConstantConstruct (line 1799) -- new Call\ReflectionConstantGetName (line 1800) -- new Call\ReflectionConstantGetValue (line 1801) -- new Call\ReflectionConstantGetAttributes (line 1804) -- new Call\ReflectionClassConstantGetAttributes (line 1807) -- new Call\ReflectionMethodGetAttributes (line 1808) -- new Call\ReflectionFunctionConstruct (line 1809) -- new Call\ReflectionFunctionGetName (line 1810) -- new Call\ReflectionExtensionConstruct (line 1812) -- new Call\ReflectionExtensionGetName (line 1813) -- new Call\ReflectionExtensionGetVersion (line 1815) -- new Call\ReflectionFunctionIsVariadic (line 1817) -- new Call\ReflectionParameterIsSensitiveParameter (line 1819) -- new Call\ReflectionFunctionGetNamedArguments (line 1822) -- new Call\ReflectionMethodGetNamedArguments (line 1823) -- new Call\ReflectionAttributeGetName (line 1825) -- new Call\ReflectionAttributeGetTarget (line 1826) -- new Call\ReflectionAttributeNewInstance (line 1827) -- new Call\ReflectionEnumConstruct (line 1828) -- new Call\ReflectionEnumGetName (line 1829) -- new Call\ReflectionEnumHasCase (line 1830) -- new Call\ReflectionEnumGetCase (line 1831) -- new Call\ReflectionEnumGetCases (line 1832) -- new Call\ReflectionEnumIsBacked (line 1833) -- new Call\ReflectionEnumGetBackingType (line 1834) -- new Call\ReflectionEnumUnitCaseGetName (line 1835) -- new Call\ReflectionEnumUnitCaseGetName (line 1836) -- new Call\ReflectionEnumUnitCaseGetValue (line 1837) -- new Call\ReflectionNamedTypeGetName (line 1840) -- new Call\ExceptionGetMessage (line 1841) -- new Call\ExceptionGetCode (line 1842) -- new Call\ExceptionToString (line 1843) -- new Call\ExceptionGetTrace (line 1844) -- new Call\ExceptionGetTraceAsString (line 1845) -- new Call\ExceptionGetFile (line 1846) -- new Call\ExceptionGetLine (line 1847) -- new Call\ExceptionGetPrevious (line 1848) -- new Call\ExceptionConstruct (line 1872) -- new Call\ExceptionGetTrace (line 1884) -- new Call\ExceptionGetTraceAsString (line 1887) -- new Call\ExceptionGetMessage (line 1890) -- new Call\ExceptionGetCode (line 1893) -- new Call\ExceptionGetFile (line 1896) -- new Call\ExceptionGetLine (line 1899) -- new Call\ExceptionGetPrevious (line 1902) -- new Call\ExceptionGetMessage (line 1906) -- new Call\ExceptionGetCode (line 1907) -- new Call\ExceptionGetTrace (line 1909) -- new Call\ExceptionGetTraceAsString (line 1910) -- new Call\ExceptionGetFile (line 1911) -- new Call\ExceptionGetLine (line 1912) -- new Call\ExceptionGetPrevious (line 1913) -- new Call\DateTimeConstruct (line 1919) -- new Call\DateTimeImmutableConstruct (line 1920) -- new Call\DomDocumentConstruct (line 1922) -- new Call\DateTimeZoneConstruct (line 1923) -- new Call\DateIntervalConstruct (line 1924) -- new Call\DateIntervalFormat (line 1925) -- new Call\DatePeriodConstruct (line 1926) -- new Call\DatePeriodCreateFromISO8601String (line 1928) -- new Call\DatePeriodIteratorMethod (line 1930) -- new Call\DatePeriodAccessorMethod (line 1935) -- new Call\DateTimeFormat (line 1937) -- new Call\DateTimeFormat (line 1938) -- new Call\DateTimeCreateFromFormat (line 1940) -- new Call\DateTimeCreateFromFormat (line 1941) -- new Call\DateTimeCreateFromInterface (line 1943) -- new Call\DateTimeCreateFromInterface (line 1944) -- new Call\DateTimeCreateFromImmutable (line 1945) -- new Call\DateTimeImmutableCreateFromMutable (line 1946) -- new Call\DateTimeCreateFromTimestamp (line 1949) -- new Call\DateTimeCreateFromTimestamp (line 1950) -- new Call\DateTimeGetMicrosecond (line 1954) -- new Call\DateTimeGetMicrosecond (line 1955) -- new Call\DateTimeSetMicrosecond (line 1956) -- new Call\DateTimeSetMicrosecond (line 1957) -- new Call\DateIntervalCreateFromDateString (line 1960) -- new Call\DateTimeSetTimezone (line 1962) -- new Call\DateTimeGetTimezone (line 1963) -- new Call\DateTimeGetTimezone (line 1964) -- new Call\DateTimeGetOffset (line 1967) -- new Call\DateTimeGetOffset (line 1968) -- new Call\DateTimeSetTimezone (line 1974) -- new Call\DateTimeGetTimestamp (line 1978) -- new Call\DateTimeGetTimestamp (line 1979) -- new Call\DateTimeSetTimestamp (line 1980) -- new Call\DateTimeSetTimestamp (line 1982) -- new Call\DateTimeSetDate (line 1985) -- new Call\DateTimeSetDate (line 1986) -- new Call\DateTimeSetTime (line 1987) -- new Call\DateTimeSetTime (line 1988) -- new Call\DateTimeSetISODate (line 1989) -- new Call\DateTimeSetISODate (line 1990) -- new Call\DateTimeGetLastErrors (line 1992) -- new Call\DateTimeGetLastErrors (line 1993) -- new Call\DateTimeModify (line 1996) -- new Call\DateTimeModify (line 1997) -- new Call\DateTimeAdd (line 2000) -- new Call\DateTimeAdd (line 2001) -- new Call\DateTimeSub (line 2002) -- new Call\DateTimeSub (line 2003) -- new Call\DateTimeDiff (line 2005) -- new Call\DateTimeDiff (line 2006) -- new Call\DateTimeZoneGetTransitions (line 2008) -- new Call\DateTimeZoneGetName (line 2010) -- new Call\DateTimeZoneGetLocation (line 2012) -- new Call\DateTimeZoneGetOffset (line 2014) -- new Call\DateTimeZoneListIdentifiers (line 2016) -- new Call\DateTimeZoneListAbbreviations (line 2018) -- new Call\NumberFormatterCreate (line 2030) -- new Call\NumberFormatterFormat (line 2031) -- new Call\IntlDateFormatterCreate (line 2033) -- new Call\IntlDateFormatterFormat (line 2034) -- new Call\CollatorCompare (line 2036) -- new Call\NormalizerNormalize (line 2038) -- new Call\MessageFormatterConstruct (line 2040) -- new Call\MessageFormatterFormat (line 2041) -- new Call\TransliteratorCreate (line 2043) -- new Call\TransliteratorTransliterate (line 2044) -- new Call\FinfoConstruct (line 2046) -- new Call\FinfoFile (line 2047) -- new Call\FinfoBuffer (line 2048) -- new Call\PdoConstruct (line 2050) -- new Call\PdoGetAvailableDrivers (line 2051) -- new Call\PdoQuote (line 2052) -- new Call\DomXmlDocumentCreateFromString (line 2055) -- new Call\DomHtmlDocumentCreateFromString (line 2056) -- new Result (line 2444) -- new Result (line 2466) -- new Variable (line 3190) -- new Variable (line 3428) -- new Variable (line 3712) -- new Variable (line 3795) -- new VMVariable (line 3957) -- new VMVariable (line 3973) -- new VMVariable (line 3979) -- new VMVariable (line 3985) -- new VMVariable (line 3996) -- new Variable (line 4026) -- new Variable (line 4071) +- new Call\ReflectionClassKindQuery (line 1755) +- new Call\ReflectionClassKindQuery (line 1756) +- new Call\ReflectionClassKindQuery (line 1757) +- new Call\ReflectionClassIsIterateable (line 1758) +- new Call\ReflectionClassIsIterateable (line 1759) +- new Call\ReflectionClassNewLazyProxy (line 1761) +- new Call\ReflectionClassNewLazyGhost (line 1762) +- new Call\ReflectionPropertyConstruct (line 1765) +- new Call\ReflectionPropertyGetName (line 1766) +- new Call\ReflectionParameterConstruct (line 1767) +- new Call\ReflectionParameterGetName (line 1768) +- new Call\ReflectionPropertyGetAttributes (line 1769) +- new Call\ReflectionPropertyIsFinal (line 1770) +- new Call\ReflectionPropertyIsVirtual (line 1771) +- new Call\ReflectionPropertyGetRawValue (line 1772) +- new Call\ReflectionPropertySetRawValue (line 1773) +- new Call\ReflectionSetAccessible (line 1775) +- new Call\ReflectionPropertyGetValue (line 1776) +- new Call\ReflectionPropertySetValue (line 1777) +- new Call\ReflectionGetDeclaringClass (line 1779) +- new Call\ReflectionMethodConstruct (line 1785) +- new Call\ReflectionMethodGetName (line 1787) +- new Call\ReflectionGetDeclaringClass (line 1789) +- new Call\ReflectionSetAccessible (line 1794) +- new Call\ReflectionMethodInvoke (line 1795) +- new Call\ReflectionClassConstantConstruct (line 1796) +- new Call\ReflectionClassConstantGetName (line 1797) +- new Call\ReflectionPropertyGetMangledName (line 1799) +- new Call\ReflectionConstantConstruct (line 1802) +- new Call\ReflectionConstantGetName (line 1803) +- new Call\ReflectionConstantGetValue (line 1804) +- new Call\ReflectionConstantGetAttributes (line 1807) +- new Call\ReflectionClassConstantGetAttributes (line 1810) +- new Call\ReflectionMethodGetAttributes (line 1811) +- new Call\ReflectionFunctionConstruct (line 1812) +- new Call\ReflectionFunctionGetName (line 1813) +- new Call\ReflectionExtensionConstruct (line 1815) +- new Call\ReflectionExtensionGetName (line 1816) +- new Call\ReflectionExtensionGetVersion (line 1818) +- new Call\ReflectionFunctionIsVariadic (line 1820) +- new Call\ReflectionParameterIsSensitiveParameter (line 1822) +- new Call\ReflectionFunctionGetNamedArguments (line 1825) +- new Call\ReflectionMethodGetNamedArguments (line 1826) +- new Call\ReflectionAttributeGetName (line 1828) +- new Call\ReflectionAttributeGetTarget (line 1829) +- new Call\ReflectionAttributeNewInstance (line 1830) +- new Call\ReflectionEnumConstruct (line 1831) +- new Call\ReflectionEnumGetName (line 1832) +- new Call\ReflectionEnumHasCase (line 1833) +- new Call\ReflectionEnumGetCase (line 1834) +- new Call\ReflectionEnumGetCases (line 1835) +- new Call\ReflectionEnumIsBacked (line 1836) +- new Call\ReflectionEnumGetBackingType (line 1837) +- new Call\ReflectionEnumUnitCaseGetName (line 1838) +- new Call\ReflectionEnumUnitCaseGetName (line 1839) +- new Call\ReflectionEnumUnitCaseGetValue (line 1840) +- new Call\ReflectionNamedTypeGetName (line 1843) +- new Call\ExceptionGetMessage (line 1844) +- new Call\ExceptionGetCode (line 1845) +- new Call\ExceptionToString (line 1846) +- new Call\ExceptionGetTrace (line 1847) +- new Call\ExceptionGetTraceAsString (line 1848) +- new Call\ExceptionGetFile (line 1849) +- new Call\ExceptionGetLine (line 1850) +- new Call\ExceptionGetPrevious (line 1851) +- new Call\ExceptionConstruct (line 1875) +- new Call\ExceptionGetTrace (line 1887) +- new Call\ExceptionGetTraceAsString (line 1890) +- new Call\ExceptionGetMessage (line 1893) +- new Call\ExceptionGetCode (line 1896) +- new Call\ExceptionGetFile (line 1899) +- new Call\ExceptionGetLine (line 1902) +- new Call\ExceptionGetPrevious (line 1905) +- new Call\ExceptionGetMessage (line 1909) +- new Call\ExceptionGetCode (line 1910) +- new Call\ExceptionGetTrace (line 1912) +- new Call\ExceptionGetTraceAsString (line 1913) +- new Call\ExceptionGetFile (line 1914) +- new Call\ExceptionGetLine (line 1915) +- new Call\ExceptionGetPrevious (line 1916) +- new Call\DateTimeConstruct (line 1922) +- new Call\DateTimeImmutableConstruct (line 1923) +- new Call\DomDocumentConstruct (line 1925) +- new Call\DateTimeZoneConstruct (line 1926) +- new Call\DateIntervalConstruct (line 1927) +- new Call\DateIntervalFormat (line 1928) +- new Call\DatePeriodConstruct (line 1929) +- new Call\DatePeriodCreateFromISO8601String (line 1931) +- new Call\DatePeriodIteratorMethod (line 1933) +- new Call\DatePeriodAccessorMethod (line 1938) +- new Call\DateTimeFormat (line 1940) +- new Call\DateTimeFormat (line 1941) +- new Call\DateTimeCreateFromFormat (line 1943) +- new Call\DateTimeCreateFromFormat (line 1944) +- new Call\DateTimeCreateFromInterface (line 1946) +- new Call\DateTimeCreateFromInterface (line 1947) +- new Call\DateTimeCreateFromImmutable (line 1948) +- new Call\DateTimeImmutableCreateFromMutable (line 1949) +- new Call\DateTimeCreateFromTimestamp (line 1952) +- new Call\DateTimeCreateFromTimestamp (line 1953) +- new Call\DateTimeGetMicrosecond (line 1957) +- new Call\DateTimeGetMicrosecond (line 1958) +- new Call\DateTimeSetMicrosecond (line 1959) +- new Call\DateTimeSetMicrosecond (line 1960) +- new Call\DateIntervalCreateFromDateString (line 1963) +- new Call\DateTimeSetTimezone (line 1965) +- new Call\DateTimeGetTimezone (line 1966) +- new Call\DateTimeGetTimezone (line 1967) +- new Call\DateTimeGetOffset (line 1970) +- new Call\DateTimeGetOffset (line 1971) +- new Call\DateTimeSetTimezone (line 1977) +- new Call\DateTimeGetTimestamp (line 1981) +- new Call\DateTimeGetTimestamp (line 1982) +- new Call\DateTimeSetTimestamp (line 1983) +- new Call\DateTimeSetTimestamp (line 1985) +- new Call\DateTimeSetDate (line 1988) +- new Call\DateTimeSetDate (line 1989) +- new Call\DateTimeSetTime (line 1990) +- new Call\DateTimeSetTime (line 1991) +- new Call\DateTimeSetISODate (line 1992) +- new Call\DateTimeSetISODate (line 1993) +- new Call\DateTimeGetLastErrors (line 1995) +- new Call\DateTimeGetLastErrors (line 1996) +- new Call\DateTimeModify (line 1999) +- new Call\DateTimeModify (line 2000) +- new Call\DateTimeAdd (line 2003) +- new Call\DateTimeAdd (line 2004) +- new Call\DateTimeSub (line 2005) +- new Call\DateTimeSub (line 2006) +- new Call\DateTimeDiff (line 2008) +- new Call\DateTimeDiff (line 2009) +- new Call\DateTimeZoneGetTransitions (line 2011) +- new Call\DateTimeZoneGetName (line 2013) +- new Call\DateTimeZoneGetLocation (line 2015) +- new Call\DateTimeZoneGetOffset (line 2017) +- new Call\DateTimeZoneListIdentifiers (line 2019) +- new Call\DateTimeZoneListAbbreviations (line 2021) +- new Call\NumberFormatterCreate (line 2033) +- new Call\NumberFormatterFormat (line 2034) +- new Call\IntlDateFormatterCreate (line 2036) +- new Call\IntlDateFormatterFormat (line 2037) +- new Call\CollatorCompare (line 2039) +- new Call\NormalizerNormalize (line 2041) +- new Call\MessageFormatterConstruct (line 2043) +- new Call\MessageFormatterFormat (line 2044) +- new Call\TransliteratorCreate (line 2046) +- new Call\TransliteratorTransliterate (line 2047) +- new Call\FinfoConstruct (line 2049) +- new Call\FinfoFile (line 2050) +- new Call\FinfoBuffer (line 2051) +- new Call\PdoConstruct (line 2053) +- new Call\PdoGetAvailableDrivers (line 2054) +- new Call\PdoQuote (line 2055) +- new Call\DomXmlDocumentCreateFromString (line 2058) +- new Call\DomHtmlDocumentCreateFromString (line 2059) +- new Result (line 2447) +- new Result (line 2469) +- new Variable (line 3193) +- new Variable (line 3431) +- new Variable (line 3715) +- new Variable (line 3798) +- new VMVariable (line 3960) +- new VMVariable (line 3976) +- new VMVariable (line 3982) +- new VMVariable (line 3988) +- new VMVariable (line 3999) +- new Variable (line 4029) +- new Variable (line 4074) - 112 class method(s) - 33 closure(s) diff --git a/docs/bootstrap-selfhost.md b/docs/bootstrap-selfhost.md index 32dc163e807..648ca38ccb9 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:** **7755** / **7755** 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:** **7758** / **7761** 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/pages/development-status.md b/docs/pages/development-status.md index 31dec496029..b804aea7e8b 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` → **7755** / **7755** | +| **Spine SSOT** | `php script/bootstrap-spine-count.php` → **7758** / **7761** | | **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** — **7755/7755** ✅ (Jul 2026) +- **Literal spine ratio** — **7758/7761** ✅ (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 **7755/7755** ✅; native link + lint ✅ +- **Self-host M2** — spine **7758/7761** ✅; 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 | ✅ **7755** / **7755** | +| **M2** — Spine toward full inventory | ✅ **7758** / **7761** | | **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 2f74a49aa5f..e9639e31bec 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 → **7755** / **7755** Phase A inventory (literal coverage ✅). + M2 spine SSOT: php script/bootstrap-spine-count.php → **7758** / **7761** 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 **7755** / **7755**; prelinked gen-0 refreshed; + north-star5-verify-fast ✅ daily; --strict pre-merge; spine **7758** / **7761**; 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 339ff3aa243..5f07af313c3 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:** **7755** / **7755** (`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:** **7758** / **7761** (`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 6484d576133..20fc033774a 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** | **7755** / **7755** ✅ | Full closure | +| **Inventory coverage** | **7758** / **7761** ✅ | 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 | ✅ **7755** / **7755** | **100%** | +| **M2** | Spine grows toward full `bin/vm.php` inventory | ✅ **7758** / **7761** | **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 | **7755** / **7755** (`php script/bootstrap-spine-count.php`) | +| **M2 spine progress** | `require_once` units in `compiler_lib_spine_smoke` ÷ Phase A inventory file count | **7758** / **7761** (`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/ext/openssl/JitOpensslX509Read.php b/ext/openssl/JitOpensslX509Read.php new file mode 100644 index 00000000000..d6702bab4a9 --- /dev/null +++ b/ext/openssl/JitOpensslX509Read.php @@ -0,0 +1,125 @@ +type + || self::isCertificateObject($certificate) + || JITVariable::TYPE_VALUE === $certificate->type + ) { + return self::boxObjectArg($context, $certificate); + } + + throw new \LogicException( + 'openssl_x509_read() certificate must be a compile-time PEM string literal or ' + .'OpenSSLCertificate for JIT/AOT in this compiler build (issue #34048)' + ); + } + + /** + * Host FFI normalize + constant PEM on OpenSSLCertificate (#34048 bake path). + */ + public static function bakeFromPemLiteral(Context $context, string $pem): Value + { + if (!VmOpensslX509Native::available()) { + return self::boxedFalse($context); + } + + $normalized = VmOpensslX509Native::normalizeCertificatePem($pem); + if (false === $normalized || '' === $normalized) { + return self::boxedFalse($context); + } + + $slot = JitValueBox::alloc($context); + $ptr = JitValueBox::pointer($context, $slot); + $objectType = $context->type->object; + $className = OpensslCertificateJitSupport::CLASS_NAME; + $classId = $objectType->lookup($className); + $obj = $objectType->allocate($classId); + $objectType->markObjectConstructed($obj); + $pemStr = $context->builder->load($context->constantStringFromString($normalized)); + $pemVar = new JITVariable( + $context, + JITVariable::TYPE_STRING, + JITVariable::KIND_VALUE, + $pemStr + ); + $objectType->storeInstanceProperty( + $obj, + $className, + OpensslCertificateJitSupport::PROP_PEM, + $pemVar + ); + $context->builder->call( + $context->lookupFunction('__value__writeObject'), + $ptr, + $obj + ); + + return $ptr; + } + + private static function isCertificateObject(JITVariable $arg): bool + { + if (JITVariable::TYPE_OBJECT !== $arg->type) { + return false; + } + $class = $arg->classUserType; + if (null === $class || '' === $class) { + return true; + } + + return 0 === \strcasecmp($class, OpensslCertificateJitSupport::CLASS_NAME); + } + + private static function boxObjectArg(Context $context, JITVariable $certificate): Value + { + $obj = ReflectionSetup::loadObjectFromArg($context, $certificate); + $slot = JitValueBox::alloc($context); + $ptr = JitValueBox::pointer($context, $slot); + $context->builder->call( + $context->lookupFunction('__value__writeObject'), + $ptr, + $obj + ); + + return $ptr; + } + + private static function boxedFalse(Context $context): Value + { + $slot = JitValueBox::alloc($context); + JitValueBox::writeBool($context, $slot, $context->constantFromBool(false)); + + return JitValueBox::pointer($context, $slot); + } +} diff --git a/ext/openssl/OpensslCertificateJitSupport.php b/ext/openssl/OpensslCertificateJitSupport.php new file mode 100644 index 00000000000..2994e6ec8fa --- /dev/null +++ b/ext/openssl/OpensslCertificateJitSupport.php @@ -0,0 +1,18 @@ +constructed = true; self::$certStore[$entry->id] = $pem; + // Mirror PEM on the object for thin AOT consumers (#34048 peer OpenSSLAsymmetricKey). + $pemVar = $entry->allocateProperty(OpensslCertificateJitSupport::PROP_PEM); + $pemVar->string($pem); $var = new Variable(Variable::TYPE_OBJECT); $var->object($entry); @@ -250,7 +253,18 @@ public static function isAsymmetricKey(Variable $var): bool public static function certificatePem(ObjectEntry $entry): string { - return self::$certStore[$entry->id] ?? ''; + if (isset(self::$certStore[$entry->id])) { + return self::$certStore[$entry->id]; + } + // AOT-allocated certs store PEM on __osslPem (#34048). + if ($entry->hasProperty(OpensslCertificateJitSupport::PROP_PEM)) { + $prop = $entry->getProperty(OpensslCertificateJitSupport::PROP_PEM)->resolveIndirect(); + if (Variable::TYPE_STRING === $prop->type) { + return $prop->toString(); + } + } + + return ''; } /** diff --git a/ext/openssl/openssl_x509_read.php b/ext/openssl/openssl_x509_read.php index a9ad3d1dc6b..e5b782cbe0b 100644 --- a/ext/openssl/openssl_x509_read.php +++ b/ext/openssl/openssl_x509_read.php @@ -16,9 +16,7 @@ /** * openssl_x509_read() — parse PEM into OpenSSLCertificate (php-src ext/openssl/xp.c; #7268, #6274). * - * JIT/AOT leftover #33497: catchable argc/TypeError for non-(OpenSSLCertificate|string) args - * (peer openssl_pkey_free #33487 / openssl_x509_free #33492). Happy-path string/object → certificate - * still needs object emission (VM-only today). + * JIT/AOT: argc/TypeError (#33497); happy-path PEM/cert → OpenSSLCertificate (#34048). */ final class openssl_x509_read extends Internal { @@ -60,10 +58,7 @@ public function call(Context $context, JITVariable ...$args): Value return self::jitReturnNull($context); } - // String / OpenSSLCertificate object emission remains VM-only for thin AOT (#33497). - throw new \LogicException( - 'openssl_x509_read() is not implemented for JIT in this compiler build (issue #7268)' - ); + return JitOpensslX509Read::invoke($context, $args[0]); } /** @return non-empty-string|null Zend type label when the arg cannot be OpenSSLCertificate|string */ diff --git a/lib/JIT/Builtin/Type/Object_.php b/lib/JIT/Builtin/Type/Object_.php index 9d6645fd91c..e2193ced921 100755 --- a/lib/JIT/Builtin/Type/Object_.php +++ b/lib/JIT/Builtin/Type/Object_.php @@ -3695,6 +3695,14 @@ private function registerExternalClass(string $lcname, string $displayName): voi Variable::TYPE_STRING ); } + // OpenSSLCertificate PEM for thin AOT openssl_x509_read (#34048). + if ('opensslcertificate' === $lcname) { + $this->defineProperty( + $id, + \PHPCompiler\ext\openssl\OpensslCertificateJitSupport::PROP_PEM, + Variable::TYPE_STRING + ); + } if ('phpcompiler\vm\context' === $lcname) { $this->defineProperty($id, 'runtime', Variable::TYPE_OBJECT); $this->defineProperty($id, 'errors', Variable::TYPE_OBJECT); diff --git a/test/repro/issue_34048_openssl_x509_read_aot.php b/test/repro/issue_34048_openssl_x509_read_aot.php new file mode 100644 index 00000000000..c87b6b3d0e0 --- /dev/null +++ b/test/repro/issue_34048_openssl_x509_read_aot.php @@ -0,0 +1,27 @@ +assertFileExists($entry); $contents = (string) file_get_contents($entry); $count = bootstrap_spine_counts(self::$root)['spine']; - // Spine ratio 7755/7755 — full Phase A inventory in compiler_lib_spine_smoke (#2202). - $this->assertSame(7755, $count, 'M2 spine require_once units track Phase A inventory (#8559, #9234, #11629, #18550); coverage sync defers PregJitHelperThinAot (#24115) + NetworkServicesNameLookupThinAot (#27103)'); + // Spine ratio 7758/7761 — Phase A inventory in compiler_lib_spine_smoke (#2202, #34048). + $this->assertSame(7758, $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}';", diff --git a/test/unit/Issue34048OpensslX509ReadHappyPathAotTest.php b/test/unit/Issue34048OpensslX509ReadHappyPathAotTest.php new file mode 100644 index 00000000000..82e5762d5bb --- /dev/null +++ b/test/unit/Issue34048OpensslX509ReadHappyPathAotTest.php @@ -0,0 +1,80 @@ +assertNotFalse($code); + ob_start(); + $runtime->run($runtime->parseAndCompile($code, 'issue_34048_openssl_x509_read_aot.php')); + $out = (string) ob_get_clean(); + $this->assertSame(self::EXPECTED, $out); + } + + /** + * @group llvm + * @group aot + */ + public function testAotBakePemLiteralMatchVm(): void + { + if (!LlvmToolchain::hasLibrary(dirname(__DIR__, 2))) { + $this->markTestSkipped('LLVM 9 toolchain not available'); + } + $root = dirname(__DIR__, 2); + $src = $root.'/test/repro/issue_34048_openssl_x509_read_aot.php'; + $runtime = new Runtime(); + $code = file_get_contents($src); + $this->assertNotFalse($code); + ob_start(); + $runtime->run($runtime->parseAndCompile($code, 'issue_34048_openssl_x509_read_aot.php')); + $vmOut = (string) ob_get_clean(); + $this->assertSame(self::EXPECTED, $vmOut); + + $bin = sys_get_temp_dir().'/phpc_ossl_x509_read_hp_'.getmypid().'.bin'; + $compile = 'env PHP_COMPILER_HELPER_RUNTIME_O=0 '.escapeshellarg(PHP_BINARY).' ' + .escapeshellarg($root.'/bin/compile.php') + .' -o '.escapeshellarg($bin).' '.escapeshellarg($src).' 2>&1'; + exec($compile, $compileOut, $compileRc); + $this->assertSame(0, $compileRc, implode("\n", $compileOut)); + $this->assertFileExists($bin); + try { + $runOut = []; + exec(escapeshellarg($bin).' 2>/dev/null', $runOut, $runRc); + $this->assertSame(0, $runRc, implode("\n", $runOut)); + $this->assertSame($vmOut, implode("\n", $runOut)."\n"); + } finally { + @unlink($bin); + } + } + + public function testHappyPathNoLongerLogicExceptionOnly(): void + { + $src = (string) file_get_contents(dirname(__DIR__, 2).'/ext/openssl/openssl_x509_read.php'); + $this->assertStringContainsString('JitOpensslX509Read::invoke', $src); + $this->assertStringNotContainsString( + 'openssl_x509_read() is not implemented for JIT in this compiler build', + $src + ); + $this->assertFileDoesNotExist(dirname(__DIR__, 2).'/lib/AOT/runtime/openssl_x509_read.c'); + $jit = (string) file_get_contents(dirname(__DIR__, 2).'/ext/openssl/JitOpensslX509Read.php'); + $this->assertStringContainsString('bakeFromPemLiteral', $jit); + $this->assertStringContainsString('VmOpensslX509Native::normalizeCertificatePem', $jit); + } +}