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
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ test-docker-exec:
.PHONY: test-docker-quick
test-docker-quick: test-docker-fast

.PHONY: bootstrap-inventory bootstrap-spine-phpcfg-parse-check bootstrap-profile bootstrap-aot-lint bootstrap-aot-link bootstrap-aot-link-lib bootstrap-vendor-prelink-bundles bootstrap-vendor-objects bootstrap-selfhost-probe bootstrap-selfhost-link bootstrap-selfhost-compile-smoke bootstrap-selfhost-compile-smoke-strict bootstrap-selfhost-runtime-compile-smoke bootstrap-selfhost-runtime-compile-smoke-strict bootstrap-m3-emit-tu-execute bootstrap-selfhost-compiler-driver-smoke bootstrap-selfhost-compiler-unit-probe bootstrap-selfhost-compiler-unit-probe-strict bootstrap-selfhost-jit-unit-probe bootstrap-selfhost-vm-unit-probe bootstrap-selfhost-parser-unit-probe bootstrap-selfhost-types-unit-probe bootstrap-selfhost-lib-spine-smoke bootstrap-selfhost-lib-spine-vm-smoke bootstrap-selfhost-vm-driver-execute-probe bootstrap-selfhost-helloworld bootstrap-selfhost-helloworld-compile-bin bootstrap-selfhost-cli-driver-emit bootstrap-native-compile-driver-smoke bootstrap-loop-gen1-link bootstrap-loop-gen1-full-spine-emit bootstrap-loop-probe bootstrap-loop-probe-dry bootstrap-loop-probe-dry-run bootstrap-wave-check
.PHONY: bootstrap-inventory bootstrap-spine-phpcfg-parse-check bootstrap-profile bootstrap-aot-lint bootstrap-aot-link bootstrap-aot-link-lib bootstrap-vendor-prelink-bundles bootstrap-vendor-objects bootstrap-selfhost-probe bootstrap-selfhost-link bootstrap-selfhost-compile-smoke bootstrap-selfhost-compile-smoke-strict bootstrap-selfhost-runtime-compile-smoke bootstrap-selfhost-runtime-compile-smoke-strict bootstrap-m3-emit-tu-execute bootstrap-selfhost-compiler-driver-smoke bootstrap-selfhost-compiler-unit-probe bootstrap-selfhost-compiler-unit-probe-strict bootstrap-selfhost-jit-unit-probe bootstrap-selfhost-vm-unit-probe bootstrap-selfhost-parser-unit-probe bootstrap-selfhost-types-unit-probe bootstrap-selfhost-lib-spine-smoke bootstrap-selfhost-lib-spine-vm-smoke bootstrap-selfhost-vm-driver-execute-probe bootstrap-selfhost-helloworld bootstrap-selfhost-helloworld-compile-bin bootstrap-selfhost-cli-driver-emit bootstrap-native-compile-driver-smoke bootstrap-selfhost-driver-smoke bootstrap-loop-gen1-link bootstrap-loop-gen1-full-spine-emit bootstrap-loop-probe bootstrap-loop-probe-dry bootstrap-loop-probe-dry-run bootstrap-wave-check
bootstrap-inventory:
php script/bootstrap-inventory.php
.PHONY: bootstrap-inventory-check bootstrap-inventory-regenerate
Expand Down Expand Up @@ -333,6 +333,8 @@ bootstrap-selfhost-cli-driver-emit:
./script/bootstrap-selfhost-cli-driver-emit.sh
bootstrap-native-compile-driver-smoke:
./script/bootstrap-native-compile-driver-smoke.sh
bootstrap-selfhost-driver-smoke:
./script/bootstrap-selfhost-driver-smoke.sh
bootstrap-loop-gen1-link:
BOOTSTRAP_M4_LINK_COMPILE_DRIVER=1 \
BOOTSTRAP_M4_COMPILE_DRIVER_REAL_LOWERING=1 \
Expand Down
1 change: 1 addition & 0 deletions docs/bootstrap-selfhost.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
| M3 HelloWorld wave gate | `./script/bootstrap-wave-check.sh --with-helloworld` | ✅ opt-in `BOOTSTRAP_M3_HELLOWORLD=1` |
| M3 HelloWorld strict CI gate | `BOOTSTRAP_M3_HELLOWORLD_STRICT_GATE=1 ./script/ci-local.sh` | opt-in ([#1526](https://github.com/PurHur/php-compiler/issues/1526)); runs `bootstrap-selfhost-helloworld-probe.sh` with `BOOTSTRAP_M3_HELLOWORLD_STRICT=1` + compile-driver link (default **off** until `emit_path=native` stable) |
| M5 CLI driver native emit | `make bootstrap-selfhost-cli-driver-emit` or `./script/bootstrap-selfhost-cli-driver-emit.sh` | ✅ `bin/vm.php` + `src/cli_driver.php` via M3 link-time sidecars ([#2699](https://github.com/PurHur/php-compiler/issues/2699)); requires `make bootstrap-selfhost-helloworld-compile-bin` |
| M5 bootstrap driver smoke | `make bootstrap-selfhost-driver-smoke` or `BOOTSTRAP_M5_DRIVER_GATE=1` in `ci-local.sh` llvm tail | ✅ native gen-2 compile + run (`compiler smoke`) via `build/selfhost-helloworld-compile` — no Zend on compile step ([#1521](https://github.com/PurHur/php-compiler/issues/1521)); opt-in CI gate default **off** |
| M3 compile-smoke self-host probe | `./script/bootstrap-selfhost-compile-smoke-probe.sh` | 🚧 **partial** — bundle link ✅; compile-smoke AOT **run** native ✅; native emit via `compile_smoke_m3_emit_native_entry.php` blocked at emit-TU runtime init ([#1937](https://github.com/PurHur/php-compiler/issues/1937)); `emit_path=native` when `compile_smoke_m3_emit: compile OK`; Zend fallback (`emit_path=zend partial`) otherwise — see [bootstrap-m5-fast-path.md](bootstrap-m5-fast-path.md) |
| M3 compile-smoke probe CI gate | `BOOTSTRAP_M3_COMPILE_SMOKE_PROBE_GATE=1 ./script/ci-local.sh` | default-on ([#1937](https://github.com/PurHur/php-compiler/issues/1937)); runs `bootstrap-selfhost-compile-smoke-probe.sh` (partial Zend emit + native run) |
| M3 compile-smoke strict probe | `BOOTSTRAP_M3_COMPILE_SMOKE_STRICT=1 ./script/bootstrap-selfhost-compile-smoke-probe.sh` or `make bootstrap-selfhost-compile-smoke-strict` | ✅ `emit_path=native` — strict auto-enables compile-driver link env ([#2610](https://github.com/PurHur/php-compiler/issues/2610); refuses `emit_path=zend_fallback_would_be_used`) |
Expand Down
17 changes: 17 additions & 0 deletions patches/php-types-fromdecl-junk-fragments.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
diff --git vendor/ircmaxell/php-types/lib/PHPTypes/Type.php vendor/ircmaxell/php-types/lib/PHPTypes/Type.php
index 1111111..2222222 100644
--- vendor/ircmaxell/php-types/lib/PHPTypes/Type.php
+++ vendor/ircmaxell/php-types/lib/PHPTypes/Type.php
@@ -371,6 +371,12 @@ class Type
]))->simplify();
}
$decl = self::stripTrailingDocText($decl);
+ $trimmedDecl = trim($decl);
+ // Malformed phpdoc fragments in vendor trees (north-star5 prelink; #2743, #2745).
+ if ('' === $trimmedDecl || '*' === $trimmedDecl || '*/' === $trimmedDecl
+ || str_starts_with($trimmedDecl, '*/')) {
+ return self::mixed();
+ }
if (preg_match('/^array\{/i', $decl)) {
return new self(self::TYPE_ARRAY);
}
4 changes: 4 additions & 0 deletions script/apply-patches.sh
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ patch_already_applied() {
php-types-docblock-trailing-text.patch)
grep -q "stripTrailingDocText" "$ROOT/vendor/ircmaxell/php-types/lib/PHPTypes/Type.php" 2>/dev/null
;;
php-types-fromdecl-junk-fragments.patch)
grep -q "str_starts_with(\$trimmedDecl, '\\*/')" "$ROOT/vendor/ircmaxell/php-types/lib/PHPTypes/Type.php" 2>/dev/null
;;
php-types-ns-func-call.patch)
grep -q 'function resolveOp_Expr_NsFuncCall' "$ROOT/vendor/ircmaxell/php-types/lib/PHPTypes/TypeReconstructor.php" 2>/dev/null
;;
Expand Down Expand Up @@ -443,6 +446,7 @@ if [[ -d "$ROOT/vendor/ircmaxell/php-types" ]]; then
apply_patch "$PATCH_DIR/php-types-generics-fallback.patch"
apply_patch "$PATCH_DIR/php-types-generics-list-array.patch"
apply_patch "$PATCH_DIR/php-types-docblock-trailing-text.patch"
apply_patch "$PATCH_DIR/php-types-fromdecl-junk-fragments.patch"
apply_patch "$PATCH_DIR/php-types-ns-func-call.patch"
apply_patch "$PATCH_DIR/php-types-arrow-function.patch"
apply_patch "$PATCH_DIR/php-types-magic-script-const.patch"
Expand Down
107 changes: 107 additions & 0 deletions script/bootstrap-selfhost-driver-smoke.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#!/usr/bin/env bash
# M5 bootstrap driver smoke (#1521): native helloworld compile driver compiles + runs a
# bootstrap fixture without Zend on the compile step (gen-1 emit → gen-2 run).
#
# Stage 0: Zend links build/selfhost-helloworld-compile (M3 compile-driver TU).
# Stage 1: Native driver emits test/bootstrap-aot/compiler_smoke_standalone.php → gen-2 binary.
# Stage 2: Run gen-2; expect "compiler smoke" (same as M4 loop gen-2 slice).
#
# Optional slice: compiled bin/compile.php -l echo_hello (no Zend on lint) when present.
set -euo pipefail

ROOT="$(cd "$(dirname "$0")/.." && pwd)"
# shellcheck source=php-env.sh
source "${ROOT}/script/php-env.sh"
ci_apply_llvm_memory_env

DRIVER="${ROOT}/build/selfhost-helloworld-compile"
COMPILED_COMPILE="${ROOT}/build/bin-compile-aot"
SOURCE="${ROOT}/test/bootstrap-aot/compiler_smoke_standalone.php"
GEN2_OUT="${ROOT}/build/selfhost-driver-smoke-gen2"
EXPECTED_STDOUT="compiler smoke"

if [[ -z "${PHP_COMPILER_LLVM_PATH:-}" || ! -f "${PHP_COMPILER_LLVM_PATH}/libLLVM-9.so.1" ]]; then
echo "bootstrap-selfhost-driver-smoke: LLVM 9 not found (skip)" >&2
exit 2
fi

if [[ ! -f "${SOURCE}" ]]; then
echo "bootstrap-selfhost-driver-smoke: missing ${SOURCE}" >&2
exit 1
fi

mkdir -p "${ROOT}/build"
rm -f "${GEN2_OUT}"

echo "bootstrap-selfhost-driver-smoke: stage 0 — link native M3 compile driver (Zend link only)"
export PHP_COMPILER_M3_SOURCE="${ROOT}/bin/compile.php"
export PHP_COMPILER_M3_OUT="${COMPILED_COMPILE}"
if ! ./script/bootstrap-selfhost-helloworld-compile-bin.sh >/dev/null; then
echo "bootstrap-selfhost-driver-smoke: helloworld compile-driver link failed" >&2
exit 1
fi

if [[ ! -x "${DRIVER}" ]]; then
echo "bootstrap-selfhost-driver-smoke: missing executable ${DRIVER}" >&2
exit 1
fi

echo "bootstrap-selfhost-driver-smoke: stage 1 — native gen-2 compile (no Zend on compile)"
set +e
compile_out="$(
env PHP_COMPILER_M3_COMPILE_MODE=compile \
PHP_COMPILER_M3_SOURCE="${SOURCE}" \
PHP_COMPILER_M3_OUT="${GEN2_OUT}" \
"${DRIVER}" 2>&1
)"
compile_code=$?
set -e
printf '%s\n' "${compile_out}"

if [[ "${compile_code}" -ne 0 ]]; then
echo "bootstrap-selfhost-driver-smoke: native compile failed (exit ${compile_code})" >&2
exit 1
fi

if ! grep -q 'helloworld_compile_smoke: compile OK' <<< "${compile_out}"; then
echo "bootstrap-selfhost-driver-smoke: expected helloworld_compile_smoke: compile OK" >&2
exit 1
fi

if [[ ! -x "${GEN2_OUT}" ]]; then
echo "bootstrap-selfhost-driver-smoke: missing gen-2 binary ${GEN2_OUT}" >&2
exit 1
fi

echo "bootstrap-selfhost-driver-smoke: stage 2 — run gen-2 binary"
set +e
run_out="$("${GEN2_OUT}" 2>&1)"
run_code=$?
set -e
printf '%s\n' "${run_out}"

if [[ "${run_code}" -ne 0 ]]; then
echo "bootstrap-selfhost-driver-smoke: gen-2 run failed (exit ${run_code})" >&2
exit 1
fi

if ! grep -qx "${EXPECTED_STDOUT}" <<< "${run_out}"; then
echo "bootstrap-selfhost-driver-smoke: unexpected stdout (want ${EXPECTED_STDOUT})" >&2
exit 1
fi

if [[ -x "${COMPILED_COMPILE}" ]]; then
echo "bootstrap-selfhost-driver-smoke: stage 3 — compiled bin/compile.php lint (no Zend)"
set +e
lint_out="$("${COMPILED_COMPILE}" -l "${ROOT}/test/bootstrap-aot/echo_hello.php" 2>&1)"
lint_code=$?
set -e
if [[ "${lint_code}" -ne 0 ]]; then
printf '%s\n' "${lint_out}" >&2
echo "bootstrap-selfhost-driver-smoke: compiled driver lint failed (exit ${lint_code})" >&2
exit 1
fi
fi

echo "bootstrap-selfhost-driver-smoke: emit_path=native (gen-2 compile + run)"
echo "bootstrap-selfhost-driver-smoke: OK ${DRIVER} -> ${GEN2_OUT}"
3 changes: 2 additions & 1 deletion script/bootstrap-vendor-objects.php
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@
@unlink($buildBase.'.o');
@unlink($objectAbs);

$cmd = escapeshellarg($phpBin).' '.escapeshellarg($compileBin)
$cmd = 'PHP_COMPILER_VENDOR_PRELINK=1 PHP_COMPILER_SELFHOST_AOT=0 PHP_COMPILER_KEEP_OBJECT_FILE=1 '
.escapeshellarg($phpBin).' '.escapeshellarg($compileBin)
.' -o '.escapeshellarg($buildBase).' '.escapeshellarg($bundleAbs).' 2>&1';
$output = [];
exec($cmd, $output, $code);
Expand Down
13 changes: 13 additions & 0 deletions script/ci-common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -859,6 +859,19 @@ ci_run_bootstrap_m3_strict() {
}

# M4 bootstrap-loop dry-run probe in ci-local LLVM tail (issue #2058); after M3 strict gates.
# M5 bootstrap driver: native helloworld compile driver emits + runs gen-2 without Zend on compile (#1521).
ci_run_bootstrap_m5_driver_smoke() {
if [[ "${BOOTSTRAP_M5_DRIVER_GATE:-0}" != "1" ]]; then
return 0
fi
if ! ci_llvm_ready; then
echo "bootstrap-selfhost-driver-smoke: skipped (LLVM 9 not available)"
return 0
fi
echo "bootstrap-selfhost-driver-smoke (BOOTSTRAP_M5_DRIVER_GATE=1, issue #1521)..."
"$_CI_SCRIPT_DIR/bootstrap-selfhost-driver-smoke.sh"
}

ci_run_bootstrap_m4_loop_probe() {
if [[ "${BOOTSTRAP_M4_LOOP_PROBE:-0}" != "1" ]]; then
return 0
Expand Down
1 change: 1 addition & 0 deletions script/ci-defaults.env
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export BOOTSTRAP_M3_STRICT_SYNC_GATE="${BOOTSTRAP_M3_STRICT_SYNC_GATE:-0}" # op
export M3_ALLOWLIST_SYNC_GATE="${M3_ALLOWLIST_SYNC_GATE:-1}" # default on (#1905); opt-out M3_ALLOWLIST_SYNC_GATE=0 for bulk symbol PRs
export BOOTSTRAP_M5_DOC_SYNC_GATE="${BOOTSTRAP_M5_DOC_SYNC_GATE:-1}" # default on (#1984); opt-out BOOTSTRAP_M5_DOC_SYNC_GATE=0 for doc-only iteration
export BOOTSTRAP_VENDOR_INVENTORY_SYNC_GATE="${BOOTSTRAP_VENDOR_INVENTORY_SYNC_GATE:-1}" # default on (#2040, #2030); opt-out BOOTSTRAP_VENDOR_INVENTORY_SYNC_GATE=0 for vendor-only iteration
export BOOTSTRAP_M5_DRIVER_GATE="${BOOTSTRAP_M5_DRIVER_GATE:-0}" # opt-in (#1521); native gen-2 compile+run via helloworld compile driver (bootstrap-selfhost-driver-smoke)
export BOOTSTRAP_VENDOR_PRELINK_GATE="${BOOTSTRAP_VENDOR_PRELINK_GATE:-0}" # opt-in (#1416); make bootstrap-vendor-objects when M3 vendor JIT stable
export BOOTSTRAP_VENDOR_PRELINK_SYNC_GATE="${BOOTSTRAP_VENDOR_PRELINK_SYNC_GATE:-1}" # default on; ci-fast checks bundle/manifest sync (#1416)
export BOOTSTRAP_INVENTORY_LINT_SYNC_GATE="${BOOTSTRAP_INVENTORY_LINT_SYNC_GATE:-0}" # opt-in (#2210); flip default-on after inventory lint snapshot stable
Expand Down
1 change: 1 addition & 0 deletions script/ci-local.sh
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ if ci_llvm_ready; then
ci_run_bootstrap_m3_compile_smoke_strict
ci_run_bootstrap_runtime_compile_smoke_strict
ci_run_bootstrap_m4_loop_probe
ci_run_bootstrap_m5_driver_smoke

echo "PHPUnit: JIT compliance (@group jit)..."
LLVM_JUNIT="$(mktemp "${TMPDIR:-/tmp}/llvm-jit-junit.XXXXXX.xml")"
Expand Down
53 changes: 53 additions & 0 deletions test/unit/BootstrapSelfhostDriverSmokeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

declare(strict_types=1);

namespace PHPCompiler;

use PHPUnit\Framework\TestCase;

final class BootstrapSelfhostDriverSmokeTest extends TestCase
{
private static string $root;

public static function setUpBeforeClass(): void
{
self::$root = dirname(__DIR__, 2);
}

public function testDriverSmokeScriptDocumentsStages(): void
{
$script = (string) file_get_contents(self::$root.'/script/bootstrap-selfhost-driver-smoke.sh');
$this->assertStringContainsString('bootstrap-selfhost-driver-smoke:', $script);
$this->assertStringContainsString('compiler_smoke_standalone.php', $script);
$this->assertStringContainsString('PHP_COMPILER_M3_COMPILE_MODE=compile', $script);
$this->assertStringContainsString('emit_path=native', $script);
$this->assertStringContainsString('compiler smoke', $script);
}

public function testMakefileExposesDriverSmokeTarget(): void
{
$makefile = (string) file_get_contents(self::$root.'/Makefile');
$this->assertStringContainsString('bootstrap-selfhost-driver-smoke:', $makefile);
$this->assertStringContainsString('./script/bootstrap-selfhost-driver-smoke.sh', $makefile);
}

public function testCiDefaultsDefinesM5DriverGate(): void
{
$defaults = (string) file_get_contents(self::$root.'/script/ci-defaults.env');
$this->assertStringContainsString('BOOTSTRAP_M5_DRIVER_GATE', $defaults);
}

public function testCiCommonWiresM5DriverSmoke(): void
{
$common = (string) file_get_contents(self::$root.'/script/ci-common.sh');
$this->assertStringContainsString('ci_run_bootstrap_m5_driver_smoke', $common);
$this->assertStringContainsString('bootstrap-selfhost-driver-smoke.sh', $common);
}

public function testFromDeclJunkFragmentsPatchRegistered(): void
{
$apply = (string) file_get_contents(self::$root.'/script/apply-patches.sh');
$this->assertStringContainsString('php-types-fromdecl-junk-fragments.patch', $apply);
}
}
31 changes: 31 additions & 0 deletions test/unit/PhpTypesFromDeclJunkFragmentsPatchTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace PHPCompiler;

use PHPUnit\Framework\TestCase;
use PHPTypes\Type;

final class PhpTypesFromDeclJunkFragmentsPatchTest extends TestCase
{
public function testFromDeclToleratesMalformedDocFragments(): void
{
if (!is_file(dirname(__DIR__, 2).'/vendor/ircmaxell/php-types/lib/PHPTypes/Type.php')) {
$this->markTestSkipped('vendor/ircmaxell/php-types not installed');
}

foreach (['*/', '*'] as $decl) {
$type = Type::fromDecl($decl);
$this->assertInstanceOf(Type::class, $type);
$this->assertNotSame(Type::TYPE_OBJECT, $type->type, 'decl='.$decl);
}

$this->expectException(\RuntimeException::class);
Type::fromDecl('');

$trailing = Type::fromDecl('PHPTypes\\Type The type');
$this->assertSame(Type::TYPE_OBJECT, $trailing->type);
$this->assertSame('PHPTypes\\Type', $trailing->name);
}
}