Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ Matrix details: [docs/local-ci-matrix.md](docs/local-ci-matrix.md).
|-----------|----------------|--------|
| **M0 — Bundled subset runs** | ~**109** literal `require_once` units in `test/selfhost/compiler_minimal/main.php` compile+link under AOT; native binary prints `compiler_minimal bundle OK` | ✅ ([#557](https://github.com/PurHur/php-compiler/issues/557), [#913](https://github.com/PurHur/php-compiler/issues/913)) |
| **M1 — Compiler-shaped bundle** | Same bundle **lints** as one translation unit; **compile-smoke** links a tiny fixture and runs AOT echo (`compiler smoke`); driver smoke bundles `bin/compile.php`-adjacent units | ✅ ([#1025](https://github.com/PurHur/php-compiler/issues/1025)) |
| **M2 — Full top-level `lib/` + spine** | All **14** top-level `lib/*.php` lint ✅; **`compiler_lib_spine_smoke`** (**661** / **657** inventory units; 1 deferred) native link ✅; grow toward full `bin/vm.php` path | 🚧 100% inventory coverage (cli shim substitutes) |
| **M2 — Full top-level `lib/` + spine** | All **14** top-level `lib/*.php` lint ✅; **`compiler_lib_spine_smoke`** native link ✅ with real **`bin/vm.php`** (#2134); grow toward full inventory | 🚧 HashTable ratio-deferred |
| **M3 — Native compiles PHP** | Self-host bundle links; HelloWorld AOT **runs** natively; **compile emit still Zend fallback** | 🚧 partial |
| **M4 — Bootstrap loop** | Native toolchain rebuilds the **next** compiler sources | ⬜ |
| **M5 — Full self-host** | Real `bin/vm.php` / `bin/compile.php` on full inventory; **no Zend bootstrap** | ⬜ **north star** ([#1492](https://github.com/PurHur/php-compiler/issues/1492)) |
Expand Down
9 changes: 7 additions & 2 deletions bin/vm.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,10 @@ function run(string $filename, string $code, array $options): void
}
}

require_once __DIR__.'/../src/cli.php';
require_once __DIR__.'/../src/cli_driver.php';
if (
!(defined('PHP_COMPILER_LIB_SPINE_SMOKE') && PHP_COMPILER_LIB_SPINE_SMOKE)
&& !(\function_exists('php_compiler_cli_should_skip_entry_driver') && php_compiler_cli_should_skip_entry_driver())
) {
require_once __DIR__.'/../src/cli.php';
require_once __DIR__.'/../src/cli_driver.php';
}
5 changes: 2 additions & 3 deletions docs/bootstrap-inventory.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@ Regenerate: `php script/bootstrap-inventory.php`
| Metric | Count |
|--------|------:|
| PHP files on vm.php path | 712 |
| Phase A inventory files (M2 ratio SSOT) | 710 |
| Phase A ratio-deferred paths | 2 |
| Phase A inventory files (M2 ratio SSOT) | 711 |
| Phase A ratio-deferred paths | 1 |
| Source constructs flagged (blockers) | 0 |
| Source constructs flagged (warnings) | 1837 |

Phase A ratio-deferred (still inventoried; excluded from M2 spine ratio denominator only — [#2543](https://github.com/PurHur/php-compiler/issues/2543)):

- `bin/vm.php` — spine substitute: test/bootstrap-aot/vm_run_smoke.php
- `lib/VM/HashTable.php` — spine bundles lib/JIT/Builtin/Type/HashTable.php via ArrayIterator

Included on Phase A path and in `compiler_lib_spine_smoke` (not ratio-deferred): `lib/JIT/Builtin/StringPregMatch.php`, `lib/AOT/Linker.php` (external `clang` / `shell_exec` native floor).
Expand Down
6 changes: 3 additions & 3 deletions docs/bootstrap-selfhost.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Self-host bootstrap roadmap

**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:** **661** / **657** (`php script/bootstrap-spine-count.php`; 1 deferred native-link [#2126](https://github.com/PurHur/php-compiler/issues/2126)). **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) · 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:** **661** units with real **`bin/vm.php`** ([#2134](https://github.com/PurHur/php-compiler/issues/2134); `php script/bootstrap-spine-count.php`). **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) · 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

Expand Down Expand Up @@ -31,7 +31,7 @@
| Wave gate in full CI | `./script/ci-local.sh` (LLVM tail) | ✅ default-on when LLVM 9 present; `BOOTSTRAP_WAVE_CHECK=0` to skip; `./script/bootstrap-wave-check.sh --fail-fast` |
| Self-host native link | `./script/bootstrap-selfhost-link.sh` | ✅ `build/selfhost` prints `compiler_minimal bundle OK` ([#557](https://github.com/PurHur/php-compiler/issues/557), [#913](https://github.com/PurHur/php-compiler/issues/913)) |
| M2 lib spine smoke lint | `php bin/compile.php -l test/selfhost/compiler_lib_spine_smoke/main.php` | ✅ **661/657** units ([#1492](https://github.com/PurHur/php-compiler/issues/1492), [#2001](https://github.com/PurHur/php-compiler/issues/2001), [#2126](https://github.com/PurHur/php-compiler/issues/2126))
| M2 spine coverage drift | `php script/check-selfhost-spine-coverage-sync.php` | ✅ 661/657 in spine; **1** deferred (native-link [#2201](https://github.com/PurHur/php-compiler/issues/2201)); `SELFHOST_SPINE_COVERAGE_SYNC_GATE=1` ([#1945](https://github.com/PurHur/php-compiler/issues/1945))
| M2 spine coverage drift | `php script/check-selfhost-spine-coverage-sync.php` | ✅ 661 inventory units in spine; `bin/vm.php` promoted (#2134); `SELFHOST_SPINE_COVERAGE_SYNC_GATE=1` ([#1945](https://github.com/PurHur/php-compiler/issues/1945))
| M2 lib spine smoke native run | `./script/bootstrap-selfhost-lib-spine-smoke-link.sh` or `BOOTSTRAP_LIB_SPINE_SMOKE=1 make bootstrap-selfhost-lib-spine-smoke` | ✅ `build/selfhost-lib-spine-smoke` prints `compiler_lib_spine_smoke bundle OK` |
| M2 lib spine VM `-r` smoke | `./script/bootstrap-selfhost-lib-spine-vm-smoke.sh` or `BOOTSTRAP_LIB_SPINE_VM_SMOKE=1 make bootstrap-selfhost-lib-spine-vm-smoke` | ✅ same binary + `PHP_COMPILER_VM_SPINE_SMOKE=1` prints `vm-spine-ok` ([#1846](https://github.com/PurHur/php-compiler/issues/1846); `ci-local.sh` default `BOOTSTRAP_LIB_SPINE_VM_SMOKE_GATE=1` ([#1867](https://github.com/PurHur/php-compiler/issues/1867)); set `0` to skip) |
| M3 HelloWorld self-host probe lint | `php bin/compile.php -l test/selfhost/compiler_helloworld_smoke/main.php` | ✅ `compiler_compile_smoke` spine + `helloworld_compile_smoke` driver (linkable) |
Expand Down Expand Up @@ -212,7 +212,7 @@ Extends `compiler_minimal` with remaining vm.php-path `lib/` units that pass bun
| `lib/JIT/Builtin/Type.php`, `lib/JIT/Builtin/Type/String_.php` | JIT builtin type hierarchy toward full stdlib lowering |
| `lib/Doctor.php` | compile-time diagnostics helper |
| `lib/Cli/InvokeCwd.php`, `lib/Cli/PhpcBuild.php`, `lib/Cli/PhpcInit.php`, `lib/Cli/PhpcRun.php` | `phpc` CLI spine toward `bin/compile.php` / `phpc run` |
| `test/bootstrap-aot/vm_run_smoke.php` | Bundleable `bin/vm.php` run() subset; full entry deferred until M4 (`src/cli.php`) |
| `bin/vm.php` | Real `require_once` in `compiler_lib_spine_smoke` (#2134); cli argv via `cli_spine_shim.php` |
| `lib/Web/CgiAotDriver.php`, `lib/Web/CgiDriver.php`, `lib/Web/ProjectDeploy.php` | CGI / deploy drivers on vm.php path |
| `ext/standard/JitAddslashes.php`, `JitBase64Encode.php`, `JitBin2hex.php`, `JitChunkSplit.php`, `JitCrc32.php`, `JitExplode.php`, `JitChmod.php`, `JitCopy.php`, `JitDate.php`, `JitImplode.php`, `JitNl2br.php`, `JitPregQuote.php`, `JitQuotemeta.php`, `JitStrRot13.php`, `JitSessionId.php`, `JitSessionName.php`, `ext/standard/Module.php` | stdlib JIT leaf modules toward full inventory |

Expand Down
2 changes: 1 addition & 1 deletion docs/roadmap-wave3.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:** **661/657** inventory (`compiler_lib_spine_smoke` native link ✅; 1 deferred native-link [#2126](https://github.com/PurHur/php-compiler/issues/2126); [#1492](https://github.com/PurHur/php-compiler/issues/1492), M2 batches [#1419](https://github.com/PurHur/php-compiler/issues/1419), [#1497](https://github.com/PurHur/php-compiler/issues/1497)). Target doc: [self-host-target.md](self-host-target.md)
**M2 spine:** **661** inventory units (`compiler_lib_spine_smoke` native link ✅ with **`bin/vm.php`** [#2134](https://github.com/PurHur/php-compiler/issues/2134); [#1492](https://github.com/PurHur/php-compiler/issues/1492), M2 batches [#1419](https://github.com/PurHur/php-compiler/issues/1419), [#1497](https://github.com/PurHur/php-compiler/issues/1497)). Target doc: [self-host-target.md](self-host-target.md)

## Language (#1354–#1366)

Expand Down
6 changes: 3 additions & 3 deletions docs/self-host-target.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ That is **M5**. Everything below is the honest path from today’s bootstrap to
|-------|-------|--------|
| **Bootstrap driver** | Zend runs `php bin/compile.php` | Compiled `bin/compile.php` |
| **Bundle size** | **661** curated `require_once` in spine smoke (108 minimal overlap + **553** M2-only) | **657** inventory files |
| **Inventory coverage** | **661/657** in spine smoke (~93%; some paths deferred [#2126](https://github.com/PurHur/php-compiler/issues/2126)) | **100%**
| **Inventory coverage** | **661/712** in spine smoke with real **`bin/vm.php`** ([#2134](https://github.com/PurHur/php-compiler/issues/2134)) | **100%**
| **HelloWorld** | Native **run** ✅; **emit** still Zend fallback (strict gate 🚧) | Native compile + emit |
| **Bootstrap loop (M4)** | Gen-1 link + gen-2 Zend partial | Native gen-2 emit + full tree rebuild |
| **Vendor** | `composer install` + patches on host | Prelinked artifacts only |
Expand Down Expand Up @@ -63,7 +63,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 | ✅ **661/657** units (link) | **~93%** |
| **M2** | Spine grows toward full `bin/vm.php` inventory | ✅ **661** units (link; **`bin/vm.php`** [#2134](https://github.com/PurHur/php-compiler/issues/2134)) | **~93%** |
| **M3** | Self-host binary **compiles external PHP** (HelloWorld) without Zend emit | 🚧 partial (run ✅, emit 🚧) | **~35%** |

**M3 unit probe presenter** ([#2360](https://github.com/PurHur/php-compiler/issues/2360)): `make north-star3-verify` runs `008-SelfHostProbe` plus optional `bootstrap-selfhost-{compiler,jit,vm,parser,types}-unit-probe.sh` when LLVM 9 and probe scripts are present (parser step [#2418](https://github.com/PurHur/php-compiler/issues/2418), PHPTypes step [#2434](https://github.com/PurHur/php-compiler/issues/2434)). **Parser unit probe** ([#2409](https://github.com/PurHur/php-compiler/issues/2409)): `make bootstrap-selfhost-parser-unit-probe` — CFG front-end (`Runtime` + `lib/Compiler.php` bundle); CI gate ([#2417](https://github.com/PurHur/php-compiler/issues/2417)) opt-in in `ci-local.sh`. **PHPTypes unit probe** ([#2430](https://github.com/PurHur/php-compiler/issues/2430)): `make bootstrap-selfhost-types-unit-probe` — `lib/JIT.php` / `JIT\Builtin\Type` external-class constant seeds; Zend smoke for `Type::TYPE_*` + union/intersection `fromTypeDecl`; `BOOTSTRAP_PHPTYPES_UNIT_PROBE_GATE=1` default-on in `ci-local.sh` ([#2433](https://github.com/PurHur/php-compiler/issues/2433), [#2436](https://github.com/PurHur/php-compiler/issues/2436)). **VM unit probe** ([#2354](https://github.com/PurHur/php-compiler/issues/2354)): `make bootstrap-selfhost-vm-unit-probe` / `BOOTSTRAP_VM_UNIT_PROBE_GATE=1` in `ci-local.sh` llvm tail. Compiler/JIT unit probes: [#2216](https://github.com/PurHur/php-compiler/issues/2216), [#2332](https://github.com/PurHur/php-compiler/issues/2332).
Expand All @@ -76,7 +76,7 @@ That is **M5**. Everything below is the honest path from today’s bootstrap to

| Indicator | Formula | May 2026 |
|-----------|---------|----------|
| **M2 spine progress** | `require_once` units in `compiler_lib_spine_smoke` ÷ Phase A inventory file count | **661 / 657** (1 deferred [#2126](https://github.com/PurHur/php-compiler/issues/2126)) |
| **M2 spine progress** | `require_once` units in `compiler_lib_spine_smoke` ÷ Phase A inventory file count | **661 / 712** (`bin/vm.php` promoted [#2134](https://github.com/PurHur/php-compiler/issues/2134)) |
| **Public “Self-host” row** | Same M2 ratio until M3–M5 gates add weight ([`development-status.md`](pages/development-status.md)) | **~58%** |
| **Composite (internal)** | Milestone weights in table above (M0–M1 = 100%, M2 = spine %, M3–M5 = gate %) | **~52%** |

Expand Down
43 changes: 43 additions & 0 deletions lib/JIT/IncludeHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ public static function compileLiteral(
'include/require must use a compile-time literal path for JIT/AOT (issue #54)'
);
}
if (self::shouldSkipSelfHostSpineCliInclude($path)) {
self::emitSkippedSelfHostSpineCliInclude($jit, $callerBlock, $resultOperand);

return;
}
self::compileIncludedFile($jit, $func, $callerBlock, $path, $resultOperand);
}

Expand Down Expand Up @@ -662,4 +667,42 @@ private static function resolveLiteralPath(

return null;
}

/**
* Skip argv/cli driver includes when bundling bin/vm.php in compiler_lib_spine_smoke (#2134).
* cli_spine_shim.php provides php_compiler_cli_should_skip_entry_driver() at runtime; this
* avoids compiling vendor/autoload Expr_Closure during self-host AOT link.
*/
private static function shouldSkipSelfHostSpineCliInclude(string $path): bool
{
$flag = getenv('PHP_COMPILER_SELFHOST_AOT');
if ('1' !== $flag && 'true' !== strtolower((string) $flag)) {
return false;
}
$normalized = str_replace('\\', '/', $path);

return str_ends_with($normalized, '/src/cli.php')
|| str_ends_with($normalized, '/src/cli_driver.php')
|| str_ends_with($normalized, '/vendor/autoload.php');
}

private static function emitSkippedSelfHostSpineCliInclude(
JIT $jit,
Block $callerBlock,
?Operand $resultOperand
): void {
if (null === $resultOperand) {
return;
}
$jit->assignOperand(
$resultOperand,
new Variable(
$jit->context,
Variable::TYPE_NATIVE_LONG,
Variable::KIND_VALUE,
$jit->context->constantFromInteger(1)
),
true
);
}
}
1 change: 0 additions & 1 deletion script/bootstrap-phase-a-deferred.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
function bootstrap_phase_a_ratio_deferred(): array
{
return [
'bin/vm.php' => 'spine substitute: test/bootstrap-aot/vm_run_smoke.php',
'lib/VM/HashTable.php' => 'spine bundles lib/JIT/Builtin/Type/HashTable.php via ArrayIterator',
];
}
Expand Down
4 changes: 1 addition & 3 deletions script/bootstrap-spine-deferred-lib.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,5 @@
*/
function bootstrap_spine_native_link_deferred(): array
{
return [
'bin/vm.php',
];
return [];
}
1 change: 0 additions & 1 deletion script/check-selfhost-spine-coverage-sync.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@

/** Inventory paths covered by spine substitutes (not literal require_once) — issue #1423, #1945. */
$spineSubstitutes = [
'bin/vm.php' => 'test/bootstrap-aot/vm_run_smoke.php',
'src/cli.php' => 'test/bootstrap-aot/cli_spine_shim.php',
'src/cli_driver.php' => 'test/bootstrap-aot/cli_spine_shim.php',
'src/llvm-env.php' => 'test/bootstrap-aot/llvm_env_spine_shim.php',
Expand Down
5 changes: 4 additions & 1 deletion test/selfhost/compiler_lib_spine_smoke/main.php
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,10 @@
require_once __DIR__.'/../../../ext/types/strlen.php';
require_once __DIR__.'/../../../src/tokenizer-compat.php';
require_once __DIR__.'/../../../test/bootstrap-aot/cli_spine_shim.php';
require_once __DIR__.'/../../../test/bootstrap-aot/vm_run_smoke.php';
if (!defined('PHP_COMPILER_LIB_SPINE_SMOKE')) {
define('PHP_COMPILER_LIB_SPINE_SMOKE', true);
}
require_once __DIR__.'/../../../bin/vm.php';
require_once __DIR__.'/../../../src/yay-php8-compat.php';
require_once __DIR__.'/../../../test/bootstrap-aot/llvm_env_spine_shim.php';
require_once __DIR__.'/../../../ext/standard/JitArrayIsList.php';
Expand Down
5 changes: 3 additions & 2 deletions test/unit/BootstrapLibSpineVmSmokeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@ public function testVmSpineSmokeScriptDocumentsEnvAndArtifact(): void
$this->assertStringContainsString('bootstrap-selfhost-lib-spine-smoke-link.sh', $script);
}

public function testSpineEntryBundlesVmRunSmokeDispatch(): void
public function testSpineEntryBundlesBinVmPhp(): void
{
$entry = (string) file_get_contents(self::$root.'/test/selfhost/compiler_lib_spine_smoke/main.php');
$this->assertStringContainsString('vm_run_smoke.php', $entry);
$this->assertStringContainsString('bin/vm.php', $entry);
$this->assertStringContainsString('PHP_COMPILER_LIB_SPINE_SMOKE', $entry);
$this->assertStringContainsString('PHP_COMPILER_VM_SPINE_SMOKE', $entry);
$this->assertStringContainsString('vm-spine-ok', $entry);
$this->assertStringContainsString('bootstrap-selfhost-lib-spine-vm-smoke', $entry);
Expand Down
4 changes: 2 additions & 2 deletions test/unit/BootstrapSelfhostBundleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ final class BootstrapSelfhostBundleTest extends TestCase
'ext/standard/JitTraitExists.php',
'ext/standard/Module.php',
'lib/Lint/SwitchDetector.php',
'test/bootstrap-aot/vm_run_smoke.php',
'bin/vm.php',
'ext/standard/VmCrc32.php',
'ext/standard/VmDate.php',
'ext/standard/VmErrorHandler.php',
Expand Down Expand Up @@ -375,7 +375,7 @@ public function testCompilerLibSpineSmokeBundleUnitCountAndKeyUnits(): void
$this->assertFileExists($entry);
$contents = (string) file_get_contents($entry);
$count = substr_count($contents, 'require_once __DIR__');
$this->assertSame(661, $count, 'M2 spine 661/657 inventory (1 deferred native-link #2201)');
$this->assertSame(661, $count, 'M2 spine 661 inventory units (bin/vm.php promoted #2134)');
foreach (self::LIB_SPINE_SMOKE_NEW_UNITS as $unit) {
$this->assertStringContainsString(
"require_once __DIR__.'/../../../{$unit}';",
Expand Down
Loading