diff --git a/Makefile b/Makefile index 09b3f4bba71..eb9a89d1850 100755 --- a/Makefile +++ b/Makefile @@ -238,7 +238,7 @@ test-docker-exec: .PHONY: test-docker-quick test-docker-quick: test-docker-fast -.PHONY: bootstrap-inventory bootstrap-profile bootstrap-aot-lint bootstrap-aot-link bootstrap-aot-link-lib bootstrap-selfhost-probe bootstrap-selfhost-link bootstrap-selfhost-compile-smoke bootstrap-selfhost-runtime-compile-smoke bootstrap-selfhost-compiler-driver-smoke bootstrap-selfhost-jit-unit-probe bootstrap-selfhost-vm-unit-probe bootstrap-selfhost-lib-spine-smoke bootstrap-selfhost-lib-spine-vm-smoke bootstrap-selfhost-helloworld bootstrap-loop-gen1-link bootstrap-loop-probe bootstrap-loop-probe-dry bootstrap-loop-probe-dry-run bootstrap-wave-check +.PHONY: bootstrap-inventory bootstrap-profile bootstrap-aot-lint bootstrap-aot-link bootstrap-aot-link-lib bootstrap-selfhost-probe bootstrap-selfhost-link bootstrap-selfhost-compile-smoke bootstrap-selfhost-runtime-compile-smoke bootstrap-selfhost-compiler-driver-smoke bootstrap-selfhost-jit-unit-probe bootstrap-selfhost-vm-unit-probe bootstrap-selfhost-parser-unit-probe bootstrap-selfhost-lib-spine-smoke bootstrap-selfhost-lib-spine-vm-smoke bootstrap-selfhost-helloworld bootstrap-loop-gen1-link bootstrap-loop-probe bootstrap-loop-probe-dry bootstrap-loop-probe-dry-run bootstrap-wave-check bootstrap-inventory: php script/bootstrap-inventory.php bootstrap-profile: bootstrap-inventory @@ -265,6 +265,8 @@ bootstrap-selfhost-jit-unit-probe: ./script/bootstrap-selfhost-jit-unit-probe.sh bootstrap-selfhost-vm-unit-probe: ./script/bootstrap-selfhost-vm-unit-probe.sh +bootstrap-selfhost-parser-unit-probe: + ./script/bootstrap-selfhost-parser-unit-probe.sh bootstrap-selfhost-lib-spine-smoke: ./script/bootstrap-selfhost-lib-spine-smoke-link.sh bootstrap-selfhost-lib-spine-vm-smoke: diff --git a/docs/bootstrap-selfhost.md b/docs/bootstrap-selfhost.md index 505c1e525a5..68337008dbb 100644 --- a/docs/bootstrap-selfhost.md +++ b/docs/bootstrap-selfhost.md @@ -20,6 +20,8 @@ | JIT unit probe native link | `./script/bootstrap-selfhost-jit-unit-probe.sh` or `make bootstrap-selfhost-jit-unit-probe` | ✅ `build/selfhost-jit-unit-probe` prints `jit_unit_probe bundle OK`; `BOOTSTRAP_JIT_UNIT_PROBE_GATE=1` opt-in in `ci-local.sh` llvm tail ([#2361](https://github.com/PurHur/php-compiler/issues/2361)) | | VM unit probe lint | `php bin/compile.php -l test/selfhost/vm_unit_probe/main.php` | ✅ `compiler_minimal`-scale bundle + `lib/VM.php` + `vm_unit_probe_run.php` ([#2354](https://github.com/PurHur/php-compiler/issues/2354)) | | VM unit probe native link | `./script/bootstrap-selfhost-vm-unit-probe.sh` or `make bootstrap-selfhost-vm-unit-probe` | ✅ `build/selfhost-vm-unit-probe` prints `vm_unit_probe bundle OK` (link-only; VM `echo` run via `vm_unit_probe_run.php` deferred — native init); `BOOTSTRAP_VM_UNIT_PROBE_GATE=1` opt-in in `ci-local.sh` llvm tail ([#2368](https://github.com/PurHur/php-compiler/issues/2368)) | +| Parser unit probe lint | `php bin/compile.php -l test/selfhost/parser_unit_probe/main.php` | ✅ `compiler_minimal`-scale bundle + `lib/Runtime.php` + `parser_unit_probe_parse.php` ([#2409](https://github.com/PurHur/php-compiler/issues/2409)) | +| Parser unit probe native link | `./script/bootstrap-selfhost-parser-unit-probe.sh` or `make bootstrap-selfhost-parser-unit-probe` | ✅ `build/selfhost-parser-unit-probe` prints `parser_unit_probe bundle OK` (link-only; `Runtime::parse` on fixture under Zend via PHPUnit); CI gate opt-in ([#2417](https://github.com/PurHur/php-compiler/issues/2417)) | | Compiler compile smoke AOT echo run | `./script/bootstrap-selfhost-compile-smoke-run.sh` or `make bootstrap-selfhost-compile-smoke-run` | ✅ `build/selfhost-compile-smoke-echo` prints `compiler smoke` from `test/bootstrap-aot/compiler_smoke_standalone.php` (wave 7A; included in `--with-compile-smoke`) | | Wave gate (lint + probe) | `./script/bootstrap-wave-check.sh` | ✅ selfhost-lint → aot-lint → probe; prints `NEXT_LOWER` | | Self-host compile probe | `make bootstrap-selfhost-probe` | ✅ `-l` + `-o build/selfhost` ([#816](https://github.com/PurHur/php-compiler/issues/816), [#827](https://github.com/PurHur/php-compiler/issues/827), [#913](https://github.com/PurHur/php-compiler/issues/913)) | diff --git a/docs/self-host-target.md b/docs/self-host-target.md index 4a916cd1abf..3d3d6429411 100644 --- a/docs/self-host-target.md +++ b/docs/self-host-target.md @@ -66,7 +66,7 @@ That is **M5**. Everything below is the honest path from today’s bootstrap to | **M2** | Spine grows toward full `bin/vm.php` inventory | ✅ **655/657** units (link) | **~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}-unit-probe.sh` when LLVM 9 and probe scripts are present. **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). +**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}-unit-probe.sh` when LLVM 9 and probe scripts are present. **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); `north-star3-verify` step ([#2418](https://github.com/PurHur/php-compiler/issues/2418)) and CI gate ([#2417](https://github.com/PurHur/php-compiler/issues/2417)) follow. **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). | **M4** | Self-host binary **rebuilds** the next compiler tree | ⬜ | 0% | | **M5** | Full self-host; Zend retired from loop | ⬜ north star | 0% | diff --git a/lib/Doctor.php b/lib/Doctor.php index 5cb97b01a12..2df85efb902 100644 --- a/lib/Doctor.php +++ b/lib/Doctor.php @@ -206,7 +206,8 @@ public static function runSelfhost(string $repoRoot): int fwrite(STDOUT, " make bootstrap-selfhost-jit-unit-probe\n"); fwrite(STDOUT, ' BOOTSTRAP_JIT_UNIT_PROBE_GATE='.(self::gateEnabled('BOOTSTRAP_JIT_UNIT_PROBE_GATE', $jitUnitProbeDefault) ? '1' : '0')." (default {$jitUnitProbeDefault}) — ci-local LLVM tail ([#2332](https://github.com/PurHur/php-compiler/issues/2332), [#2361](https://github.com/PurHur/php-compiler/issues/2361))\n"); fwrite(STDOUT, " make bootstrap-selfhost-vm-unit-probe\n"); - fwrite(STDOUT, ' BOOTSTRAP_VM_UNIT_PROBE_GATE='.(self::gateEnabled('BOOTSTRAP_VM_UNIT_PROBE_GATE', $vmUnitProbeDefault) ? '1' : '0')." (default {$vmUnitProbeDefault}) — ci-local LLVM tail ([#2354](https://github.com/PurHur/php-compiler/issues/2354), [#2368](https://github.com/PurHur/php-compiler/issues/2368))\n\n"); + fwrite(STDOUT, ' BOOTSTRAP_VM_UNIT_PROBE_GATE='.(self::gateEnabled('BOOTSTRAP_VM_UNIT_PROBE_GATE', $vmUnitProbeDefault) ? '1' : '0')." (default {$vmUnitProbeDefault}) — ci-local LLVM tail ([#2354](https://github.com/PurHur/php-compiler/issues/2354), [#2368](https://github.com/PurHur/php-compiler/issues/2368))\n"); + fwrite(STDOUT, " make bootstrap-selfhost-parser-unit-probe (#2409 CFG parse front-end)\n\n"); fwrite(STDOUT, "3. M3 emit (partial vs strict)\n"); fwrite(STDOUT, " BOOTSTRAP_M3_HELLOWORLD_STRICT_GATE=".(self::gateEnabled('BOOTSTRAP_M3_HELLOWORLD_STRICT_GATE', $m3HelloStrictDefault) ? '1' : '0')." (default {$m3HelloStrictDefault}) — ci-local LLVM tail\n"); @@ -483,6 +484,7 @@ private static function printSelfHostPresenterSection(string $repoRoot): void : 'opt-in BOOTSTRAP_VM_UNIT_PROBE_GATE=1 for lib/VM.php native link (#2354, #2368)'; fwrite(STDOUT, " M3 VM probe make bootstrap-selfhost-vm-unit-probe\n"); fwrite(STDOUT, " {$vmUnitProbeDetail}\n"); + fwrite(STDOUT, " M3 parser probe make bootstrap-selfhost-parser-unit-probe (#2409)\n"); $loopProbeGate = getenv('BOOTSTRAP_LOOP_PROBE_GATE'); $loopProbeOn = false !== $loopProbeGate && '1' === $loopProbeGate; $m4LoopProbeGate = getenv('BOOTSTRAP_M4_LOOP_PROBE'); diff --git a/script/bootstrap-selfhost-parser-unit-probe.sh b/script/bootstrap-selfhost-parser-unit-probe.sh new file mode 100755 index 00000000000..a1792f9a98a --- /dev/null +++ b/script/bootstrap-selfhost-parser-unit-probe.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# M3 parser unit probe: CFG front-end bundle native link + run (issue #2409). +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +ENTRY="${ROOT}/test/selfhost/parser_unit_probe/main.php" +OUT="${ROOT}/build/selfhost-parser-unit-probe" + +# shellcheck source=php-env.sh +source "$(dirname "$0")/php-env.sh" +ci_apply_llvm_memory_env + +if [[ ! -f "${ENTRY}" ]]; then + echo "bootstrap-selfhost-parser-unit-probe: missing ${ENTRY}" >&2 + exit 1 +fi + +if [[ -z "${PHP_COMPILER_LLVM_PATH:-}" || ! -f "${PHP_COMPILER_LLVM_PATH}/libLLVM-9.so.1" ]]; then + echo "bootstrap-selfhost-parser-unit-probe: LLVM 9 not found (skip)" >&2 + exit 2 +fi + +mkdir -p "${ROOT}/build" +export PHP_COMPILER_SELFHOST_AOT=1 +export PHP_COMPILER_JIT_PROGRESS_FILE="${ROOT}/build/.last-jit-func-parser-unit-probe" +rm -f "${OUT}" "${PHP_COMPILER_JIT_PROGRESS_FILE}" + +if ! php "${ROOT}/bin/compile.php" -o "${OUT}" "${ENTRY}" 2>&1; then + echo "bootstrap-selfhost-parser-unit-probe: compile failed (progress gate; see stderr above)" >&2 + exit 1 +fi +test -x "${OUT}" + +bundle_out="$("${OUT}")" +if ! grep -q 'parser_unit_probe bundle OK' <<< "${bundle_out}"; then + echo "bootstrap-selfhost-parser-unit-probe: unexpected link stdout (want parser_unit_probe bundle OK)" >&2 + printf '%s\n' "${bundle_out}" >&2 + exit 1 +fi + +echo "bootstrap-selfhost-parser-unit-probe: OK ${OUT}" diff --git a/test/selfhost/parser_unit_probe/fixture.php b/test/selfhost/parser_unit_probe/fixture.php new file mode 100644 index 00000000000..35dae54c306 --- /dev/null +++ b/test/selfhost/parser_unit_probe/fixture.php @@ -0,0 +1,20 @@ +parse(parser_unit_probe_fixture_source(), parser_unit_probe_fixture_path()); + if (!$script instanceof \PHPCfg\Script) { + return 'parser_unit_probe parse FAIL'; + } + + return 'parser_unit_probe parse OK'; +} diff --git a/test/unit/BootstrapParserUnitProbeTest.php b/test/unit/BootstrapParserUnitProbeTest.php new file mode 100644 index 00000000000..ca7b5b734c4 --- /dev/null +++ b/test/unit/BootstrapParserUnitProbeTest.php @@ -0,0 +1,87 @@ +markTestSkipped('LLVM 9 not available for parser unit probe native link test.'); + } + + $script = self::$root.'/script/bootstrap-selfhost-parser-unit-probe.sh'; + $this->assertFileExists($script); + + $prefix = LlvmToolchain::envPrefix(self::$root); + $cmd = implode(' ', array_map('escapeshellarg', [...$prefix, 'bash', $script])).' 2>&1'; + exec($cmd, $lines, $exitCode); + + $out = implode("\n", $lines); + $this->assertSame(0, $exitCode, $out); + $this->assertStringContainsString('bootstrap-selfhost-parser-unit-probe: OK', $out); + $binary = self::$root.'/build/selfhost-parser-unit-probe'; + $this->assertTrue(is_executable($binary), $binary); + $runOut = shell_exec($binary); + $this->assertIsString($runOut); + $this->assertStringContainsString('parser_unit_probe bundle OK', $runOut); + } + + public function testParserUnitProbeLintPasses(): void + { + $entry = self::$root.'/test/selfhost/parser_unit_probe/main.php'; + $this->assertFileExists($entry); + $cmd = 'php '.escapeshellarg(self::$root.'/bin/compile.php').' -l '.escapeshellarg($entry).' 2>&1'; + exec($cmd, $lines, $exitCode); + $this->assertSame(0, $exitCode, implode("\n", $lines)); + } + + public function testParserFixtureParsesUnderZend(): void + { + require_once self::$root.'/test/selfhost/parser_unit_probe/parser_unit_probe_parse.php'; + $result = parser_unit_probe_parse_smoke(); + $this->assertSame('parser_unit_probe parse OK', $result); + } + + public function testParserUnitProbeEntryDocumentsParserSliceAndProbe(): void + { + $entry = (string) file_get_contents(self::$root.'/test/selfhost/parser_unit_probe/main.php'); + $this->assertStringContainsString('lib/Compiler.php', $entry); + $this->assertStringContainsString('lib/Runtime.php', $entry); + $this->assertStringContainsString('parser_unit_probe bundle OK', $entry); + $this->assertStringContainsString('bootstrap-selfhost-parser-unit-probe.sh', $entry); + $parseHelper = (string) file_get_contents(self::$root.'/test/selfhost/parser_unit_probe/parser_unit_probe_parse.php'); + $this->assertStringContainsString('parser_unit_probe_parse_smoke', $parseHelper); + $this->assertStringContainsString('fixture.php', $parseHelper); + } + + public function testProbeScriptDocumentsGateAndArtifact(): void + { + $script = (string) file_get_contents(self::$root.'/script/bootstrap-selfhost-parser-unit-probe.sh'); + $this->assertStringContainsString('PHP_COMPILER_SELFHOST_AOT=1', $script); + $this->assertStringContainsString('selfhost-parser-unit-probe', $script); + $this->assertStringContainsString('parser_unit_probe bundle OK', $script); + } + + public function testMakefileDefinesParserUnitProbeTarget(): void + { + $makefile = (string) file_get_contents(self::$root.'/Makefile'); + $this->assertStringContainsString('bootstrap-selfhost-parser-unit-probe:', $makefile); + $this->assertStringContainsString('bootstrap-selfhost-parser-unit-probe.sh', $makefile); + } +}