From f954a00421ffd55f64f9582e90a7aeb6b3606c2f Mon Sep 17 00:00:00 2001 From: PurHur Date: Wed, 24 Jun 2026 16:52:08 +0000 Subject: [PATCH] =?UTF-8?q?Delete=20StringPhpinfoRuntimeLlvm=20=E2=80=94?= =?UTF-8?q?=20standalone=20AOT=20uses=20PhpinfoJitHelper=20(#9256)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Route AOT standalone through the same thin LLVM bridge as JIT embed, deleting the ~313-line standalone HTML LLVM quarantine. Net −313 LLVM lines. Co-authored-by: Cursor --- docs/bootstrap-inventory.md | 18 +- lib/JIT/Builtin/StringPhpinfoRuntime.php | 53 ++- lib/JIT/Builtin/StringPhpinfoRuntimeLlvm.php | 313 ------------------ .../compiler_lib_spine_smoke/main.php | 1 - test/unit/BootstrapSelfhostBundleTest.php | 1 - test/unit/PhpinfoJitRuntimeShrinkTest.php | 11 +- 6 files changed, 41 insertions(+), 356 deletions(-) delete mode 100644 lib/JIT/Builtin/StringPhpinfoRuntimeLlvm.php diff --git a/docs/bootstrap-inventory.md b/docs/bootstrap-inventory.md index ee7c2c9dc22..3d42a1e588e 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 | 3028 | -| Phase A inventory files (M2 ratio SSOT) | 3028 | +| PHP files on vm.php path | 3027 | +| Phase A inventory files (M2 ratio SSOT) | 3027 | | Phase A ratio-deferred paths | 0 | | Source constructs flagged (blockers) | 0 | -| Source constructs flagged (warnings) | 8157 | +| Source constructs flagged (warnings) | 8156 | ## Compiler CFG gaps (`lib/Compiler.php`) @@ -2261,8 +2261,7 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag | `lib/JIT/Builtin/StringParseStrJit.php` | 0 | 1 | | `lib/JIT/Builtin/StringPasswordCrypto.php` | 0 | 1 | | `lib/JIT/Builtin/StringPasswordCryptoJit.php` | 0 | 1 | -| `lib/JIT/Builtin/StringPhpinfoRuntime.php` | 0 | 2 | -| `lib/JIT/Builtin/StringPhpinfoRuntimeLlvm.php` | 0 | 2 | +| `lib/JIT/Builtin/StringPhpinfoRuntime.php` | 0 | 3 | | `lib/JIT/Builtin/StringPregMatch.php` | 0 | 1 | | `lib/JIT/Builtin/StringPregMatchJit.php` | 0 | 2 | | `lib/JIT/Builtin/StringPregQuote.php` | 0 | 1 | @@ -17661,13 +17660,8 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag ### `lib/JIT/Builtin/StringPhpinfoRuntime.php` **Warnings** (review for bootstrap subset): -- new JIT (line 160) -- 7 class method(s) - -### `lib/JIT/Builtin/StringPhpinfoRuntimeLlvm.php` - -**Warnings** (review for bootstrap subset): -- 21 class method(s) +- new JIT (line 158) +- 8 class method(s) - 1 closure(s) ### `lib/JIT/Builtin/StringPregMatch.php` diff --git a/lib/JIT/Builtin/StringPhpinfoRuntime.php b/lib/JIT/Builtin/StringPhpinfoRuntime.php index 144bf828f59..902a5ffe10f 100644 --- a/lib/JIT/Builtin/StringPhpinfoRuntime.php +++ b/lib/JIT/Builtin/StringPhpinfoRuntime.php @@ -5,16 +5,15 @@ namespace PHPCompiler\JIT\Builtin; use PHPCompiler\JIT; -use PHPCompiler\JIT\Builtin; use PHPCompiler\JIT\Context; +use PHPCompiler\JIT\NestedJitCompileScope; use PHPLLVM\Value\Function_ as LlvmFunction; /** * JIT/AOT link for __compiler_phpinfo / __compiler_phpcredits via PhpinfoJitHelper PHP (#9256). * - * JIT uses compiled {@see \PHPCompiler\ext\standard\PhpinfoJitHelper}; AOT standalone keeps - * {@see StringPhpinfoRuntimeLlvm} until VmInfo HTML compiles in native link (#9256). - * php-src: ext/standard/info.c + * JIT embed and AOT standalone compile {@see \PHPCompiler\ext\standard\PhpinfoJitHelper}; thin LLVM bridges + * forward the ABI. php-src: ext/standard/info.c */ final class StringPhpinfoRuntime { @@ -41,6 +40,11 @@ public static function ensureLinked(Context $context): void self::implement($context); } + public static function ensureStandaloneBodies(Context $context): void + { + self::implement($context); + } + public static function implement(Context $context): void { $probe = $context->module->getNamedFunction('__compiler_phpinfo'); @@ -50,13 +54,6 @@ public static function implement(Context $context): void return; } - if (Builtin::LOAD_TYPE_STANDALONE === $context->loadType) { - StringPhpinfoRuntimeLlvm::implement($context); - self::registerLinkedRuntime($context); - - return; - } - ObOutput::registerExternals($context); ObOutputRuntime::ensureLinked($context); self::ensureJitHelperCompiled($context); @@ -149,25 +146,27 @@ private static function ensureJitHelperCompiled(Context $context): void $runtime = $context->runtime; $path = \dirname(__DIR__, 3).self::HELPER_PATH; $prevSelfHostAot = \getenv('PHP_COMPILER_SELFHOST_AOT'); - if (\function_exists('putenv')) { - \putenv('PHP_COMPILER_SELFHOST_AOT=0'); - } - try { - $block = $runtime->parseAndCompile((string) \file_get_contents($path), 'PhpinfoJitHelper.php'); - if (null === $block) { - throw new \LogicException('PhpinfoJitHelper.php parseAndCompile failed (#9256)'); - } - $jit = new JIT($context); - $jit->compile($block); - } finally { + NestedJitCompileScope::run($context, static function () use ($context, $runtime, $path, $prevSelfHostAot): void { if (\function_exists('putenv')) { - if (false === $prevSelfHostAot || null === $prevSelfHostAot) { - \putenv('PHP_COMPILER_SELFHOST_AOT='); - } else { - \putenv('PHP_COMPILER_SELFHOST_AOT='.$prevSelfHostAot); + \putenv('PHP_COMPILER_SELFHOST_AOT=0'); + } + try { + $block = $runtime->parseAndCompile((string) \file_get_contents($path), 'PhpinfoJitHelper.php'); + if (null === $block) { + throw new \LogicException('PhpinfoJitHelper.php parseAndCompile failed (#9256)'); + } + $jit = new JIT($context); + $jit->compile($block); + } finally { + if (\function_exists('putenv')) { + if (false === $prevSelfHostAot || null === $prevSelfHostAot) { + \putenv('PHP_COMPILER_SELFHOST_AOT='); + } else { + \putenv('PHP_COMPILER_SELFHOST_AOT='.$prevSelfHostAot); + } } } - } + }); foreach (self::COMPILED_HELPERS as $logical) { if (!isset($context->functions[\strtolower($logical)])) { throw new \LogicException($logical.' was not compiled for JIT (#9256)'); diff --git a/lib/JIT/Builtin/StringPhpinfoRuntimeLlvm.php b/lib/JIT/Builtin/StringPhpinfoRuntimeLlvm.php deleted file mode 100644 index b35c5cd5997..00000000000 --- a/lib/JIT/Builtin/StringPhpinfoRuntimeLlvm.php +++ /dev/null @@ -1,313 +0,0 @@ -getTypeFromString('int32'); - $fnPhpinfo = self::declareIfMissing( - $context, - '__compiler_phpinfo', - $context->context->functionType($i32, false, $i32) - ); - self::implementPhpinfo($context, $fnPhpinfo); - - $voidTy = $context->getTypeFromString('void'); - $fnCredits = self::declareIfMissing( - $context, - '__compiler_phpcredits', - $context->context->functionType($voidTy, false, $i32) - ); - self::implementPhpcredits($context, $fnCredits); - } - - private static function implementPhpinfo(Context $context, LlvmFunction $fn): void - { - $entry = $fn->appendBasicBlock('pinfo_entry'); - $done = $fn->appendBasicBlock('pinfo_done'); - $context->builder->positionAtEnd($entry); - - $flags = $fn->getParam(0); - self::emitPhpinfoHtmlHeader($context); - - self::emitSectionIfSelected($context, $flags, VmInfo::INFO_GENERAL, self::emitGeneralSection(...)); - self::emitSectionIfSelected($context, $flags, VmInfo::INFO_MODULES, self::emitModulesSection(...)); - self::emitSectionIfSelected($context, $flags, VmInfo::INFO_CONFIGURATION, self::emitConfigurationSection(...)); - self::emitSectionIfSelected($context, $flags, VmInfo::INFO_LICENSE, self::emitLicenseSection(...)); - self::emitSectionIfSelected($context, $flags, VmInfo::INFO_CREDITS, static function (Context $ctx): void { - self::emitCreditsSection($ctx, VmInfo::CREDITS_GENERAL); - }); - - self::emitObEchoCstr($context, ''); - $context->builder->branch($done); - $context->builder->positionAtEnd($done); - $i32 = $context->getTypeFromString('int32'); - $context->builder->returnValue($i32->constInt(1, false)); - $context->builder->clearInsertionPosition(); - } - - private static function implementPhpcredits(Context $context, LlvmFunction $fn): void - { - $entry = $fn->appendBasicBlock('pcred_entry'); - $skip = $fn->appendBasicBlock('pcred_skip'); - $work = $fn->appendBasicBlock('pcred_work'); - $done = $fn->appendBasicBlock('pcred_done'); - $context->builder->positionAtEnd($entry); - - $flags = $fn->getParam(0); - $selected = self::emitCreditsFlagSelected($context, $flags, VmInfo::CREDITS_GENERAL); - $context->builder->branchIf($selected, $work, $skip); - - $context->builder->positionAtEnd($work); - self::emitCreditsSection($context, VmInfo::CREDITS_GENERAL); - $context->builder->branch($done); - - $context->builder->positionAtEnd($skip); - $context->builder->branch($done); - - $context->builder->positionAtEnd($done); - $context->builder->returnVoid(); - $context->builder->clearInsertionPosition(); - } - - /** - * @param callable(Context): void $emit - */ - private static function emitSectionIfSelected(Context $context, Value $flags, int $section, callable $emit): void - { - $fn = BasicBlockHelper::parentFunction($context); - $selected = self::emitInfoFlagSelected($context, $flags, $section); - $work = $fn->appendBasicBlock('pinfo_sec_'.(++self::$blockSuffix)); - $skip = $fn->appendBasicBlock('pinfo_skip_'.self::$blockSuffix); - $context->builder->branchIf($selected, $work, $skip); - $context->builder->positionAtEnd($work); - $emit($context); - $context->builder->branch($skip); - $context->builder->positionAtEnd($skip); - } - - private static function emitPhpinfoHtmlHeader(Context $context): void - { - self::emitObEchoCstr($context, ''); - self::emitObEchoCstr($context, ''); - self::emitObEchoCstr($context, 'phpinfo()
'); - } - - private static function emitGeneralSection(Context $context): void - { - $version = CompilerVersion::VERSION; - self::emitObEchoCstr($context, ''); - self::emitObEchoCstr($context, ''); - self::emitObEchoCstr($context, ''); - self::emitObEchoCstr($context, ''); - self::emitObEchoCstr($context, ''); - self::emitObEchoCstr($context, ''); - self::emitObEchoCstr($context, '

PHP Version '); - self::emitObEchoCompilerString($context, self::callCompilerPhpversion($context, null)); - self::emitObEchoCstr($context, '

System '); - foreach (['s', 'n', 'r', 'v', 'm'] as $mode) { - self::emitObEchoCompilerString($context, self::callCompilerPhpUname($context, $mode)); - self::emitObEchoCstr($context, ' '); - } - self::emitObEchoCstr($context, '
Build System '); - self::emitObEchoCompilerString($context, self::callCompilerPhpUname($context, 's')); - self::emitObEchoCstr($context, ' '); - self::emitObEchoCompilerString($context, self::callCompilerPhpUname($context, 'm')); - self::emitObEchoCstr($context, '
Server API '); - self::emitObEchoCompilerString($context, self::callCompilerPhpSapiName($context)); - self::emitObEchoCstr($context, '
PHP Version '.$version.'
Zend Engine Version '.VmInfo::ZEND_VERSION.'

'); - } - - private static function emitModulesSection(Context $context): void - { - $extensions = ModuleRegistry::getLoadedExtensions(); - sort($extensions, SORT_STRING); - self::emitObEchoCstr($context, ''); - self::emitObEchoCstr($context, ''); - foreach ($extensions as $name) { - self::emitObEchoCstr( - $context, - '' - ); - } - self::emitObEchoCstr($context, '

PHP Modules

Module Name Enabled
'.htmlspecialchars($name, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8').' enabled

'); - } - - private static function emitConfigurationSection(Context $context): void - { - self::emitObEchoCstr($context, ''); - self::emitObEchoCstr($context, ''); - self::emitObEchoCstr($context, '

Configuration

Compiler PurHur/php-compiler

'); - } - - private static function emitLicenseSection(Context $context): void - { - self::emitObEchoCstr($context, ''); - self::emitObEchoCstr($context, ''); - self::emitObEchoCstr($context, '

PHP License

This program is free software; you can redistribute it and/or modify it under the terms of the PHP License.

'); - } - - private static function emitCreditsSection(Context $context, int $flags): void - { - unset($flags); - self::emitObEchoCstr($context, ''); - self::emitObEchoCstr($context, ''); - self::emitObEchoCstr($context, '

PHP Credits

PurHur/php-compiler — PHP-in-PHP compiler runtime

'); - } - - private static function callCompilerPhpversion(Context $context, ?string $extension): Value - { - $strPtr = $context->getTypeFromString('__string__*'); - $extArg = $strPtr->constNull(); - if (null !== $extension) { - $extArg = self::literalString($context, $extension); - } - - return $context->builder->call( - $context->lookupFunction('__compiler_phpversion'), - $extArg - ); - } - - private static function callCompilerPhpSapiName(Context $context): Value - { - return $context->builder->call($context->lookupFunction('__compiler_php_sapi_name')); - } - - private static function callCompilerPhpUname(Context $context, string $mode): Value - { - return $context->builder->call( - $context->lookupFunction('__compiler_php_uname'), - self::literalString($context, $mode) - ); - } - - private static function emitInfoFlagSelected(Context $context, Value $flags, int $section): Value - { - $i32 = $context->getTypeFromString('int32'); - $all = $context->builder->icmp(Builder::INT_EQ, $flags, $i32->constInt(-1, true)); - $masked = $context->builder->and($flags, $i32->constInt($section, false)); - $hasBit = $context->builder->icmp(Builder::INT_NE, $masked, $i32->constInt(0, false)); - - return $context->builder->or($all, $hasBit); - } - - private static function emitCreditsFlagSelected(Context $context, Value $flags, int $section): Value - { - $i32 = $context->getTypeFromString('int32'); - $all = $context->builder->icmp(Builder::INT_EQ, $flags, $i32->constInt(-1, true)); - $masked = $context->builder->and($flags, $i32->constInt($section, false)); - $hasBit = $context->builder->icmp(Builder::INT_NE, $masked, $i32->constInt(0, false)); - - return $context->builder->or($all, $hasBit); - } - - private static function emitObEchoCstr(Context $context, string $text): void - { - $i8p = $context->getTypeFromString('int8*'); - $context->builder->call( - $context->lookupFunction('__phpc_ob_echo_cstr'), - $context->builder->pointerCast($context->constantFromString($text), $i8p) - ); - } - - private static function emitObEchoCompilerString(Context $context, Value $str): void - { - $map = $context->structFieldMap['__string__'] ?? ['ref' => 0, 'length' => 1, 'value' => 2]; - $len = $context->builder->load($context->builder->structGep($str, $map['length'])); - $data = $context->builder->structGep($str, $map['value']); - $sizeT = $context->getTypeFromString('size_t'); - $context->builder->call( - $context->lookupFunction('__phpc_ob_echo_substr'), - $data, - $context->builder->zExt($len, $sizeT) - ); - } - - private static function literalString(Context $context, string $text): Value - { - $i64 = $context->getTypeFromString('int64'); - $charPtr = $context->getTypeFromString('char*'); - $cstr = $context->builder->pointerCast($context->constantFromString($text), $charPtr); - - return $context->builder->call( - $context->lookupFunction('__string__init'), - $i64->constInt(\strlen($text), false), - $cstr - ); - } - - private static function ensureObEchoSubstr(Context $context): void - { - $voidTy = $context->getTypeFromString('void'); - $i8p = $context->getTypeFromString('int8*'); - $sizeT = $context->getTypeFromString('size_t'); - self::ensureExternal( - $context, - '__phpc_ob_echo_substr', - $context->context->functionType($voidTy, false, $i8p, $sizeT) - ); - self::ensureExternal( - $context, - '__string__init', - $context->context->functionType( - $context->getTypeFromString('__string__*'), - false, - $context->getTypeFromString('int64'), - $context->getTypeFromString('char*') - ) - ); - } - - private static function declareIfMissing(Context $context, string $name, $ft): LlvmFunction - { - $probe = $context->module->getNamedFunction($name); - if (null !== $probe) { - $context->registerFunction($name, $probe); - - return $probe; - } - - $fn = $context->module->addFunction($name, $ft); - $context->registerFunction($name, $fn); - - return $fn; - } - - private static function ensureExternal(Context $context, string $name, $ft): void - { - try { - $context->lookupFunction($name); - } catch (\Throwable) { - $fn = $context->module->addFunction($name, $ft); - $context->registerFunction($name, $fn); - } - } -} diff --git a/test/selfhost/compiler_lib_spine_smoke/main.php b/test/selfhost/compiler_lib_spine_smoke/main.php index d64f6110def..34fe5eccbdd 100644 --- a/test/selfhost/compiler_lib_spine_smoke/main.php +++ b/test/selfhost/compiler_lib_spine_smoke/main.php @@ -2314,7 +2314,6 @@ require_once __DIR__.'/../../../lib/JIT/Builtin/StringPasswordCrypto.php'; require_once __DIR__.'/../../../lib/JIT/Builtin/StringPasswordCryptoJit.php'; require_once __DIR__.'/../../../lib/JIT/Builtin/StringPhpinfoRuntime.php'; -require_once __DIR__.'/../../../lib/JIT/Builtin/StringPhpinfoRuntimeLlvm.php'; require_once __DIR__.'/../../../lib/JIT/Builtin/StringPregMatch.php'; require_once __DIR__.'/../../../lib/JIT/Builtin/StringPregMatchJit.php'; require_once __DIR__.'/../../../lib/JIT/Builtin/StringPregQuote.php'; diff --git a/test/unit/BootstrapSelfhostBundleTest.php b/test/unit/BootstrapSelfhostBundleTest.php index 25c15670b2f..7fc14720e0c 100644 --- a/test/unit/BootstrapSelfhostBundleTest.php +++ b/test/unit/BootstrapSelfhostBundleTest.php @@ -14,7 +14,6 @@ final class BootstrapSelfhostBundleTest extends TestCase /** @var list */ private const LIB_SPINE_SMOKE_NEW_UNITS = [ 'ext/standard/PhpinfoJitHelper.php', - 'lib/JIT/Builtin/StringPhpinfoRuntimeLlvm.php', 'lib/JIT/JitArrayUserSetOps.php', 'lib/JIT/Builtin/CastArrayRuntime.php', 'lib/JIT/Builtin/VarFetchRuntime.php', diff --git a/test/unit/PhpinfoJitRuntimeShrinkTest.php b/test/unit/PhpinfoJitRuntimeShrinkTest.php index 8d7ac85b615..9e09dae9032 100644 --- a/test/unit/PhpinfoJitRuntimeShrinkTest.php +++ b/test/unit/PhpinfoJitRuntimeShrinkTest.php @@ -23,9 +23,9 @@ public function testStringPhpinfoRuntimeRoutesThroughPhpinfoJitHelper(): void $this->assertStringNotContainsString('emitPhpinfoHtmlHeader', $source); $this->assertStringNotContainsString('emitGeneralSection', $source); $this->assertStringNotContainsString('emitObEchoCstr', $source); + $this->assertStringNotContainsString('StringPhpinfoRuntimeLlvm', $source); $this->assertLessThan(200, \substr_count($source, "\n"), 'StringPhpinfoRuntime must be a thin bridge'); - $llvm = (string) \file_get_contents(dirname(__DIR__, 2).'/lib/JIT/Builtin/StringPhpinfoRuntimeLlvm.php'); - $this->assertStringContainsString('emitPhpinfoHtmlHeader', $llvm, 'standalone LLVM quarantined in StringPhpinfoRuntimeLlvm'); + $this->assertFileDoesNotExist(dirname(__DIR__, 2).'/lib/JIT/Builtin/StringPhpinfoRuntimeLlvm.php'); } public function testVmInfoExposesRenderPhpinfoForSharedSsot(): void @@ -40,4 +40,11 @@ public function testJitInfoRoutesThroughStringPhpinfoRuntime(): void $source = (string) \file_get_contents(dirname(__DIR__, 2).'/ext/standard/JitInfo.php'); $this->assertStringContainsString('StringPhpinfoRuntime::ensureLinked', $source); } + + public function testSpineBundleOmitsDeletedStringPhpinfoRuntimeLlvm(): void + { + $spine = (string) \file_get_contents(dirname(__DIR__, 2).'/test/selfhost/compiler_lib_spine_smoke/main.php'); + $this->assertStringNotContainsString('StringPhpinfoRuntimeLlvm.php', $spine); + $this->assertStringContainsString('PhpinfoJitHelper.php', $spine); + } }