From e98794b37e7890c7f1ae6d3fcdd6ae25f51c0135 Mon Sep 17 00:00:00 2001 From: PurHur Date: Wed, 26 Aug 2026 11:53:15 +0000 Subject: [PATCH] php-in-php: lazy Utf8Latin1/RewriteVars/Define/Strspn/FileGetContents/Readfile from ensureFull (#35089) Drop always-on NestedJIT of those stdlib ABIs from Context::ensureFullStandaloneBodies (peer #34578 / #35086). BootstrapCompileSmokeM3Emit now ensureLinked StringFileGetContents before __compiler_file_get_contents lookup so inventory argv still links (#15604 / #32122 .1 mint). Co-authored-by: Cursor --- lib/JIT/BootstrapCompileSmokeM3Emit.php | 4 + lib/JIT/Context.php | 15 ++-- ...lStandaloneLazyStdlibRuntimeShrinkTest.php | 85 +++++++++++++++++++ 3 files changed, 97 insertions(+), 7 deletions(-) create mode 100644 test/unit/ContextFullStandaloneLazyStdlibRuntimeShrinkTest.php diff --git a/lib/JIT/BootstrapCompileSmokeM3Emit.php b/lib/JIT/BootstrapCompileSmokeM3Emit.php index 3e7880533bf..7895aa448ea 100644 --- a/lib/JIT/BootstrapCompileSmokeM3Emit.php +++ b/lib/JIT/BootstrapCompileSmokeM3Emit.php @@ -9,6 +9,7 @@ require_once __DIR__.'/RuntimeEmitTuInit.php'; use PHPCompiler\ext\standard\JitStringSearch; +use PHPCompiler\JIT\Builtin\StringFileGetContents; use PHPCompiler\JIT\Builtin\StringGetenv; use PHPLLVM\Builder; use PHPLLVM\Value; @@ -435,6 +436,9 @@ private static function emitSourceReadOrFail( $i64 = $context->getTypeFromString('int64'); $strPtr = $context->getTypeFromString('__string__*'); + // Lazy ensureFull (#35089 / peer #34578): Context no longer NestedJITs + // __compiler_file_get_contents during full standalone init (#15604 / #32122). + StringFileGetContents::ensureLinked($context); $code = $context->builder->call( $context->lookupFunction('__compiler_file_get_contents'), $sourceFile diff --git a/lib/JIT/Context.php b/lib/JIT/Context.php index 5a7caa84ecc..343fb4225b5 100644 --- a/lib/JIT/Context.php +++ b/lib/JIT/Context.php @@ -2498,19 +2498,20 @@ private function ensureFullStandaloneBodies(): void // (#10173). Full standalone must not emit fn-static table ABI during init — // leftover Context NestedJIT vs Runtime ABI drift mints phpc_fn_static_*.1 // (#31894 / #32122). - Builtin\StringUtf8Latin1::ensureStandaloneBodies($this); - Builtin\RewriteVarsRuntime::ensureStandaloneBodies($this); - Builtin\DefineRuntime::ensureStandaloneBodies($this); + // StringUtf8Latin1 / RewriteVars / Define / Strspn / FileGetContents / Readfile + // always-on removed (#35089): JitUtf8Latin1 / JitDefine / SpnJitLowering / + // JitParseStrUserScriptCstrKernel / JitFileGetContents / readfile.php / + // RewriteVarsRuntime::emit* / BootstrapCompileSmokeM3Emit already ensureLinked + // before lookup (peer ensureMinimal #34578 / Type #34474 / #34423). Full + // standalone must not NestedJIT those ABIs during init — leftover Context + // NestedJIT vs Runtime ABI drift mints utf8_*.1 / define.1 / + // file_get_contents.1 / readfile.1 / strspn.1 (#31894 / #32122). Builtin\SuperglobalRefreshRuntime::ensureStandaloneBodies($this); // SuperglobalName always-on removed (#35035): JitSuperglobalName / JIT.php // StringSuperglobalName::ensureLinked before lookup (peer ensureMinimal #34812 / // #33235). Full standalone must not NestedJIT is_superglobal_name during init — // leftover Context NestedJIT vs Runtime ABI drift mints is_superglobal_name.1 // (#31894 / #32122). - Builtin\StringStrspn::ensureStandaloneBodies($this); - // BootstrapCompileSmokeM3Emit / inventory argv {main} calls __compiler_file_get_contents (#15604). - Builtin\StringFileGetContents::ensureStandaloneBodies($this); - Builtin\StringReadfile::ensureStandaloneBodies($this); // TokenGetAll / Highlight / Hebrev / Hebrevc always-on removed (#35035): each // ensureStandaloneBodies is a no-op — helper LLVM compiles on first lowering // (TokenGetAll::helperFunction / JitHighlight / JitHebrev). Do not re-add eager diff --git a/test/unit/ContextFullStandaloneLazyStdlibRuntimeShrinkTest.php b/test/unit/ContextFullStandaloneLazyStdlibRuntimeShrinkTest.php new file mode 100644 index 00000000000..f2679f8dbf2 --- /dev/null +++ b/test/unit/ContextFullStandaloneLazyStdlibRuntimeShrinkTest.php @@ -0,0 +1,85 @@ +assertStringContainsString('#35089', $context); + $fullPos = strpos($context, 'private function ensureFullStandaloneBodies'); + $this->assertNotFalse($fullPos); + $fullEnd = strpos($context, 'public function compileToFile', $fullPos); + $this->assertNotFalse($fullEnd); + $fullBody = substr($context, $fullPos, $fullEnd - $fullPos); + + foreach ([ + 'StringUtf8Latin1::ensureStandaloneBodies($this)', + 'RewriteVarsRuntime::ensureStandaloneBodies($this)', + 'DefineRuntime::ensureStandaloneBodies($this)', + 'StringStrspn::ensureStandaloneBodies($this)', + 'StringFileGetContents::ensureStandaloneBodies($this)', + 'StringReadfile::ensureStandaloneBodies($this)', + ] as $forbidden) { + $this->assertStringNotContainsString( + $forbidden, + $fullBody, + 'ensureFullStandaloneBodies must not eagerly '.$forbidden.' (#35089)' + ); + } + + // Still links echo / argv / refresh used by standalone main. + $this->assertStringContainsString('ValueEchoRuntime::ensureLinked($this)', $fullBody); + $this->assertStringContainsString('CliArgvRuntime::ensureStandaloneBodies($this)', $fullBody); + $this->assertStringContainsString('SuperglobalRefreshRuntime::ensureStandaloneBodies($this)', $fullBody); + } + + public function testCallSitesStillEnsureBeforeLookup(): void + { + $checks = [ + 'ext/standard/JitUtf8Latin1.php' => 'StringUtf8Latin1::ensureLinked', + 'ext/standard/JitDefine.php' => 'DefineRuntime::ensureLinked', + 'ext/standard/JitFileGetContents.php' => 'StringFileGetContents::ensureLinked', + 'ext/standard/readfile.php' => 'StringReadfile::ensureLinked', + 'ext/standard/SpnJitLowering.php' => 'StringStrspn::ensureLinked', + 'lib/JIT/Builtin/RewriteVarsRuntime.php' => 'self::ensureLinked($context)', + 'lib/JIT/BootstrapCompileSmokeM3Emit.php' => 'StringFileGetContents::ensureLinked', + ]; + foreach ($checks as $rel => $needle) { + $path = __DIR__.'/../../'.$rel; + $this->assertFileExists($path, $rel); + $source = (string) file_get_contents($path); + $this->assertStringContainsString($needle, $source, $rel.' must ensure lazily (#35089)'); + } + } + + public function testNoNewRuntimeCForFullStdlibLazy(): void + { + $runtimeDir = dirname(__DIR__, 2).'/lib/AOT/runtime'; + foreach ([ + 'file_get_contents.c', + 'readfile.c', + 'utf8_latin1.c', + 'define_runtime.c', + 'strspn.c', + 'rewrite_vars.c', + ] as $name) { + $this->assertFileDoesNotExist( + $runtimeDir.'/'.$name, + "must not add {$name} for #35089 — PHP JIT bridges only" + ); + } + } +}