From 727636886d4836349c75bf921d5595849ce1bcd1 Mon Sep 17 00:00:00 2001 From: PurHur Date: Tue, 25 Aug 2026 13:18:07 +0000 Subject: [PATCH] php-in-php: lazy ObOutputRuntime from ensureMinimal (#34695) Thin AOT hello-world must not NestedJIT ob_* ABI during init; ValueEchoHelper, ValueEchoRuntime, and ECHO/PRINT call sites ensureLinked before lookup (peer #34642). Co-authored-by: Cursor --- lib/JIT.php | 2 + .../ReflectionExtensionInfoRuntime.php | 1 + lib/JIT/Builtin/ScriptExit.php | 2 + lib/JIT/Builtin/StringFormat.php | 1 + lib/JIT/Builtin/ValueEchoRuntime.php | 2 + lib/JIT/Context.php | 9 +- lib/JIT/ValueEchoHelper.php | 4 + ...zyDomGcProgressAssertRuntimeShrinkTest.php | 16 +++- ...eLazyHtmlErrorHandlerRuntimeShrinkTest.php | 16 +++- ...eLazyHtmlspecialcharsRuntimeShrinkTest.php | 10 ++- ...andaloneLazyLastErrorRuntimeShrinkTest.php | 8 +- ...tandaloneLazyObOutputRuntimeShrinkTest.php | 84 +++++++++++++++++++ ...loneLazyReturnPendingRuntimeShrinkTest.php | 16 +++- ...lStandaloneLazyStdlibRuntimeShrinkTest.php | 14 +++- ...daloneLazyStringTriggerErrorShrinkTest.php | 10 ++- .../ExamplesHelloWorldAotRegressionTest.php | 10 ++- test/unit/ObOutputRuntimeShrinkTest.php | 20 ++++- 17 files changed, 196 insertions(+), 29 deletions(-) create mode 100644 test/unit/ContextMinimalStandaloneLazyObOutputRuntimeShrinkTest.php diff --git a/lib/JIT.php b/lib/JIT.php index 9cdd719d138..93bf47a3043 100644 --- a/lib/JIT.php +++ b/lib/JIT.php @@ -11009,6 +11009,8 @@ private function compileBlockInternal( case OpCode::TYPE_PRINT: JIT\JitNativeString::ensureInsertBlock($this->context); $this->context->intrinsic->builder = $this->context->builder; + // Call-site ensure — thin minimal init no longer always-on ObOutput (#34695). + JIT\Builtin\ObOutputRuntime::ensureLinked($this->context); $this->context->callSiteLine = OpCode::TYPE_ECHO === $op->type ? (int) ($op->arg2 ?? 0) : (int) ($op->arg3 ?? 0); diff --git a/lib/JIT/Builtin/ReflectionExtensionInfoRuntime.php b/lib/JIT/Builtin/ReflectionExtensionInfoRuntime.php index 637d03eb9c6..be0b2e0147c 100644 --- a/lib/JIT/Builtin/ReflectionExtensionInfoRuntime.php +++ b/lib/JIT/Builtin/ReflectionExtensionInfoRuntime.php @@ -137,6 +137,7 @@ public static function emit(Context $context, Value $nameCstr, Value $nameLen): private static function echoBakedText(Context $context, string $text): void { + ObOutputRuntime::ensureLinked($context); $i8p = $context->getTypeFromString('int8*'); $strMap = $context->structFieldMap['__string__']; $infoStr = $context->builder->load($context->constantStringFromString($text)); diff --git a/lib/JIT/Builtin/ScriptExit.php b/lib/JIT/Builtin/ScriptExit.php index 1a4afbb1ed0..d26c3d1c5e8 100644 --- a/lib/JIT/Builtin/ScriptExit.php +++ b/lib/JIT/Builtin/ScriptExit.php @@ -32,6 +32,7 @@ public static function emit(Context $context, Variable $arg): void private static function emitStatusOnly(Context $context, Variable $arg): void { + ObOutputRuntime::ensureLinked($context); switch ($arg->type) { case Variable::TYPE_NULL: // PHP 8.4+ string|int: null → E_DEPRECATED then status 0 (#29575). @@ -115,6 +116,7 @@ private static function emitStatusOnly(Context $context, Variable $arg): void private static function emitMessage(Context $context, Variable $arg): void { + ObOutputRuntime::ensureLinked($context); switch ($arg->type) { case Variable::TYPE_NULL: return; diff --git a/lib/JIT/Builtin/StringFormat.php b/lib/JIT/Builtin/StringFormat.php index a3ec3310cab..a78caa219cf 100644 --- a/lib/JIT/Builtin/StringFormat.php +++ b/lib/JIT/Builtin/StringFormat.php @@ -46,6 +46,7 @@ final class StringFormat public static function ensureLinked(Context $context): void { + ObOutputRuntime::ensureLinked($context); self::implement($context); } diff --git a/lib/JIT/Builtin/ValueEchoRuntime.php b/lib/JIT/Builtin/ValueEchoRuntime.php index 2697e378375..2901d92e631 100644 --- a/lib/JIT/Builtin/ValueEchoRuntime.php +++ b/lib/JIT/Builtin/ValueEchoRuntime.php @@ -96,6 +96,8 @@ final class ValueEchoRuntime public static function ensureLinked(Context $context): void { + // ObOutput before type bridges — Context full/minimal no longer always-on (#34695). + ObOutputRuntime::ensureLinked($context); self::implement($context); } diff --git a/lib/JIT/Context.php b/lib/JIT/Context.php index 2de477da9bc..5cc645b5184 100644 --- a/lib/JIT/Context.php +++ b/lib/JIT/Context.php @@ -2318,7 +2318,10 @@ private function ensureMinimalUserStandaloneBodies(): void // JitReturnPending always-on removed (#34621): TryCatchHelper / emitPendingReturnResume // already ensureLinked before lookup (peer #34612). JitHelperAbiBridge restores insert // mid-{main}. Leftover Context NestedJIT vs Runtime ABI drift mints *.1 (#31894 / #32122). - Builtin\ObOutputRuntime::ensureLinked($this); + // ObOutputRuntime always-on removed (#34695): ValueEchoHelper / ValueEchoRuntime / + // JIT ECHO/PRINT already ensureLinked before __phpc_ob_echo_* lookup (peer #34642). + // Leftover Context NestedJIT vs Runtime ABI drift mints *.1 (#31894 / #32122). + // Thin AOT hello-world must not NestedJIT ob_* ABI during init. // StringRandomBytes / Utf8Latin1 / RewriteVars / Define / StrContains / StatPath / // FileGetContents / MetaTags / HashCrypto / MbNumericEntity / Readfile / Bin2hex / // Addslashes / Stripslashes / FilePutContents / IniRuntime always-on removed (#34578): @@ -2368,7 +2371,9 @@ private function ensureFullStandaloneBodies(): void Builtin\AssertFail::ensureStandaloneBodies($this); Builtin\AssertOptionsRuntime::ensureStandaloneBodies($this); Builtin\JitReturnPending::ensureStandaloneBodies($this); - Builtin\ObOutputRuntime::ensureLinked($this); + // ObOutput always-on before ValueEcho removed (#34695): ValueEchoRuntime::ensureLinked + // already ObOutputRuntime::ensureLinked (peer #34642). Leftover Context NestedJIT vs + // Runtime ABI drift mints *.1 (#31894 / #32122). Builtin\ValueEchoRuntime::ensureLinked($this); Builtin\CliArgvRuntime::ensureStandaloneBodies($this); // Nested-JIT string helpers: lazy via ensureLinked during spine/thin init (#14472, #20571). diff --git a/lib/JIT/ValueEchoHelper.php b/lib/JIT/ValueEchoHelper.php index 044fe694c7c..26dd3809637 100644 --- a/lib/JIT/ValueEchoHelper.php +++ b/lib/JIT/ValueEchoHelper.php @@ -23,6 +23,8 @@ final class ValueEchoHelper public static function echoLiteral(Context $context, string $literal): void { + // Call-site ensure — Context ensureMinimal no longer always-on ObOutput (#34695 / peer #34642). + Builtin\ObOutputRuntime::ensureLinked($context); $charPtr = $context->getTypeFromString('char*'); $context->builder->call( $context->lookupFunction('__phpc_ob_echo_cstr'), @@ -42,6 +44,7 @@ public static function echoNativeLong( ?Operand $sourceOperand = null ): void { + Builtin\ObOutputRuntime::ensureLinked($context); Builtin\StringDir::ensureLinked($context); $tag = 'enl'.(string) ++self::$seq; $i64 = $context->getTypeFromString('int64'); @@ -189,6 +192,7 @@ public static function echoObjectVariable(Context $context, Variable $objectVar, public static function echoStringVariable(Context $context, Variable $stringVar): void { + Builtin\ObOutputRuntime::ensureLinked($context); $argValue = $context->helper->loadValue($stringVar); $offset = $context->structFieldIndex($argValue, 'length'); $__str__length = $context->builder->load( diff --git a/test/unit/ContextMinimalStandaloneLazyDomGcProgressAssertRuntimeShrinkTest.php b/test/unit/ContextMinimalStandaloneLazyDomGcProgressAssertRuntimeShrinkTest.php index b858d6fc68b..2cf1d23af45 100644 --- a/test/unit/ContextMinimalStandaloneLazyDomGcProgressAssertRuntimeShrinkTest.php +++ b/test/unit/ContextMinimalStandaloneLazyDomGcProgressAssertRuntimeShrinkTest.php @@ -38,12 +38,10 @@ public function testEnsureMinimalDropsEagerDomGcProgressAssert(): void ); } - // Essentials for thin echo / error / argv / getenv surface stay. + // Essentials for thin argv / getenv stay. // HtmlEntities / Decode / ErrorHandler / ExceptionHandler dropped in #34612 (peer this test). - // LastError dropped in #34631 (peer this test). + // LastError dropped in #34631; ObOutput / TriggerError in #34695 / #34641. foreach ([ - 'ObOutputRuntime::ensureLinked($this)', - 'StringTriggerError::ensureStandaloneBodies($this)', 'CliArgvRuntime::ensureStandaloneBodies($this)', 'EnvLocalRuntime::ensureLinked($this)', 'SuperglobalNameRuntime::ensureLinked($this)', @@ -55,6 +53,16 @@ public function testEnsureMinimalDropsEagerDomGcProgressAssert(): void $minimalBody, 'ensureMinimal must not eagerly LastErrorRuntime (#34631)' ); + $this->assertStringNotContainsString( + 'ObOutputRuntime::ensureLinked($this)', + $minimalBody, + 'ensureMinimal must not eagerly ObOutputRuntime (#34695)' + ); + $this->assertStringNotContainsString( + 'StringTriggerError::ensureStandaloneBodies($this)', + $minimalBody, + 'ensureMinimal must not eagerly StringTriggerError (#34641)' + ); foreach ([ 'HtmlEntitiesJit::ensureStandaloneBodies($this)', 'StringHtmlspecialcharsDecode::ensureStandaloneBodies($this)', diff --git a/test/unit/ContextMinimalStandaloneLazyHtmlErrorHandlerRuntimeShrinkTest.php b/test/unit/ContextMinimalStandaloneLazyHtmlErrorHandlerRuntimeShrinkTest.php index c7eb7ad6956..7bde387f80b 100644 --- a/test/unit/ContextMinimalStandaloneLazyHtmlErrorHandlerRuntimeShrinkTest.php +++ b/test/unit/ContextMinimalStandaloneLazyHtmlErrorHandlerRuntimeShrinkTest.php @@ -37,11 +37,9 @@ public function testEnsureMinimalDropsEagerHtmlErrorHandler(): void ); } - // Essentials for thin echo / error / argv / getenv surface stay. - // LastError dropped in #34631 (peer this test). + // Essentials for thin argv / getenv stay. + // LastError dropped in #34631; ObOutput / TriggerError in #34695 / #34641. foreach ([ - 'ObOutputRuntime::ensureLinked($this)', - 'StringTriggerError::ensureStandaloneBodies($this)', 'CliArgvRuntime::ensureStandaloneBodies($this)', 'EnvLocalRuntime::ensureLinked($this)', 'SuperglobalNameRuntime::ensureLinked($this)', @@ -53,6 +51,16 @@ public function testEnsureMinimalDropsEagerHtmlErrorHandler(): void $minimalBody, 'ensureMinimal must not eagerly LastErrorRuntime (#34631)' ); + $this->assertStringNotContainsString( + 'ObOutputRuntime::ensureLinked($this)', + $minimalBody, + 'ensureMinimal must not eagerly ObOutputRuntime (#34695)' + ); + $this->assertStringNotContainsString( + 'StringTriggerError::ensureStandaloneBodies($this)', + $minimalBody, + 'ensureMinimal must not eagerly StringTriggerError (#34641)' + ); } public function testCallSitesEnsureBeforeLookup(): void diff --git a/test/unit/ContextMinimalStandaloneLazyHtmlspecialcharsRuntimeShrinkTest.php b/test/unit/ContextMinimalStandaloneLazyHtmlspecialcharsRuntimeShrinkTest.php index a0c08149609..4a7398115ae 100644 --- a/test/unit/ContextMinimalStandaloneLazyHtmlspecialcharsRuntimeShrinkTest.php +++ b/test/unit/ContextMinimalStandaloneLazyHtmlspecialcharsRuntimeShrinkTest.php @@ -30,10 +30,8 @@ public function testEnsureMinimalDropsEagerHtmlspecialchars(): void 'ensureMinimalUserStandaloneBodies must not eagerly StringHtmlspecialchars (#34642)' ); - // Essentials for thin echo / error / argv / getenv surface stay. + // Essentials for thin argv / getenv / bridges stay (#34695 ObOutput lazy). foreach ([ - 'ObOutputRuntime::ensureLinked($this)', - 'StringTriggerError::ensureStandaloneBodies($this)', 'CliArgvRuntime::ensureStandaloneBodies($this)', 'EnvLocalRuntime::ensureLinked($this)', 'SuperglobalNameRuntime::ensureLinked($this)', @@ -42,6 +40,12 @@ public function testEnsureMinimalDropsEagerHtmlspecialchars(): void ] as $keep) { $this->assertStringContainsString($keep, $minimalBody, "keep {$keep} in minimal (#34642)"); } + + $this->assertStringNotContainsString( + 'ObOutputRuntime::ensureLinked($this)', + $minimalBody, + 'ensureMinimal must not eagerly ObOutputRuntime (#34695)' + ); } public function testCallSiteEnsuresBeforeLookup(): void diff --git a/test/unit/ContextMinimalStandaloneLazyLastErrorRuntimeShrinkTest.php b/test/unit/ContextMinimalStandaloneLazyLastErrorRuntimeShrinkTest.php index 46085ebcde9..e08f3dfddad 100644 --- a/test/unit/ContextMinimalStandaloneLazyLastErrorRuntimeShrinkTest.php +++ b/test/unit/ContextMinimalStandaloneLazyLastErrorRuntimeShrinkTest.php @@ -30,9 +30,8 @@ public function testEnsureMinimalDropsEagerLastError(): void 'ensureMinimalUserStandaloneBodies must not eagerly LastErrorRuntime (#34631)' ); - // Essentials for thin echo / error / argv / getenv surface stay. + // Essentials for thin argv / getenv / bridges stay (#34695 ObOutput lazy). foreach ([ - 'ObOutputRuntime::ensureLinked($this)', 'CliArgvRuntime::ensureStandaloneBodies($this)', 'EnvLocalRuntime::ensureLinked($this)', 'SuperglobalNameRuntime::ensureLinked($this)', @@ -47,6 +46,11 @@ public function testEnsureMinimalDropsEagerLastError(): void $minimalBody, 'ensureMinimal must not eagerly StringTriggerError (#34641)' ); + $this->assertStringNotContainsString( + 'ObOutputRuntime::ensureLinked($this)', + $minimalBody, + 'ensureMinimal must not eagerly ObOutputRuntime (#34695)' + ); // Full standalone still links LastError after TriggerError. $fullPos = strpos($context, 'private function ensureFullStandaloneBodies'); diff --git a/test/unit/ContextMinimalStandaloneLazyObOutputRuntimeShrinkTest.php b/test/unit/ContextMinimalStandaloneLazyObOutputRuntimeShrinkTest.php new file mode 100644 index 00000000000..11899f3d516 --- /dev/null +++ b/test/unit/ContextMinimalStandaloneLazyObOutputRuntimeShrinkTest.php @@ -0,0 +1,84 @@ +assertStringContainsString('#34695', $context); + $minimalPos = strpos($context, 'private function ensureMinimalUserStandaloneBodies'); + $this->assertNotFalse($minimalPos); + $minimalEnd = strpos($context, 'private function ensureBootstrapAotStandaloneBodies', $minimalPos); + $this->assertNotFalse($minimalEnd); + $minimalBody = substr($context, $minimalPos, $minimalEnd - $minimalPos); + + $this->assertStringNotContainsString( + 'ObOutputRuntime::ensureLinked($this)', + $minimalBody, + 'ensureMinimalUserStandaloneBodies must not eagerly ObOutputRuntime (#34695)' + ); + + // Essentials for thin argv / getenv / bridges stay. + foreach ([ + 'CliArgvRuntime::ensureStandaloneBodies($this)', + 'EnvLocalRuntime::ensureLinked($this)', + 'SuperglobalNameRuntime::ensureLinked($this)', + 'ExceptionBridge::ensureStandaloneBodies($this)', + 'ErrorBridge::ensureStandaloneBodies($this)', + ] as $keep) { + $this->assertStringContainsString($keep, $minimalBody, "keep {$keep} in minimal (#34695)"); + } + + // Full standalone: ObOutput before ValueEcho dropped; ValueEchoRuntime::ensureLinked + // pulls ObOutput (peer #34642). + $fullPos = strpos($context, 'private function ensureFullStandaloneBodies'); + $this->assertNotFalse($fullPos); + $fullSlice = substr($context, $fullPos, 2500); + $this->assertStringNotContainsString( + "Builtin\\ObOutputRuntime::ensureLinked(\$this);\n Builtin\\ValueEchoRuntime::ensureLinked(\$this)", + $fullSlice, + 'ensureFull must not always-on ObOutput immediately before ValueEcho (#34695)' + ); + $this->assertStringContainsString('ValueEchoRuntime::ensureLinked($this)', $fullSlice); + } + + public function testCallSitesEnsureBeforeLookup(): void + { + $checks = [ + 'lib/JIT/ValueEchoHelper.php' => 'ObOutputRuntime::ensureLinked', + 'lib/JIT/Builtin/ValueEchoRuntime.php' => 'ObOutputRuntime::ensureLinked', + 'lib/JIT.php' => 'ObOutputRuntime::ensureLinked($this->context)', + 'lib/JIT/Builtin/StringFormat.php' => 'ObOutputRuntime::ensureLinked($context)', + 'lib/JIT/Builtin/ScriptExit.php' => 'ObOutputRuntime::ensureLinked($context)', + ]; + 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 (#34695)'); + } + } + + public function testNoNewRuntimeCForMinimalObOutputLazy(): void + { + $runtimeDir = dirname(__DIR__, 2).'/lib/AOT/runtime'; + $this->assertFileDoesNotExist( + $runtimeDir.'/ob_output.c', + 'must not add ob_output.c for #34695 — PHP JIT bridges only' + ); + } +} diff --git a/test/unit/ContextMinimalStandaloneLazyReturnPendingRuntimeShrinkTest.php b/test/unit/ContextMinimalStandaloneLazyReturnPendingRuntimeShrinkTest.php index 217a15a4e23..960cbcbe93d 100644 --- a/test/unit/ContextMinimalStandaloneLazyReturnPendingRuntimeShrinkTest.php +++ b/test/unit/ContextMinimalStandaloneLazyReturnPendingRuntimeShrinkTest.php @@ -30,11 +30,9 @@ public function testEnsureMinimalDropsEagerJitReturnPending(): void 'ensureMinimalUserStandaloneBodies must not eagerly JitReturnPending (#34621)' ); - // Essentials for thin echo / error / argv / getenv surface stay. - // LastError dropped in #34631 (peer this test). + // Essentials for thin argv / getenv / bridges stay. + // LastError dropped in #34631; ObOutput / TriggerError in #34695 / #34641. foreach ([ - 'ObOutputRuntime::ensureLinked($this)', - 'StringTriggerError::ensureStandaloneBodies($this)', 'CliArgvRuntime::ensureStandaloneBodies($this)', 'EnvLocalRuntime::ensureLinked($this)', 'SuperglobalNameRuntime::ensureLinked($this)', @@ -48,6 +46,16 @@ public function testEnsureMinimalDropsEagerJitReturnPending(): void $minimalBody, 'ensureMinimal must not eagerly LastErrorRuntime (#34631)' ); + $this->assertStringNotContainsString( + 'ObOutputRuntime::ensureLinked($this)', + $minimalBody, + 'ensureMinimal must not eagerly ObOutputRuntime (#34695)' + ); + $this->assertStringNotContainsString( + 'StringTriggerError::ensureStandaloneBodies($this)', + $minimalBody, + 'ensureMinimal must not eagerly StringTriggerError (#34641)' + ); // Full standalone still links return-pending after TriggerError. $fullPos = strpos($context, 'private function ensureFullStandaloneBodies'); diff --git a/test/unit/ContextMinimalStandaloneLazyStdlibRuntimeShrinkTest.php b/test/unit/ContextMinimalStandaloneLazyStdlibRuntimeShrinkTest.php index 4f730805836..52c8ef6dce8 100644 --- a/test/unit/ContextMinimalStandaloneLazyStdlibRuntimeShrinkTest.php +++ b/test/unit/ContextMinimalStandaloneLazyStdlibRuntimeShrinkTest.php @@ -49,16 +49,24 @@ public function testEnsureMinimalDropsEagerStdlibBatch(): void ); } - // Essentials for thin echo / error / argv / getenv surface stay. + // Essentials for thin argv / getenv stay (#34695 ObOutput / #34641 TriggerError lazy). foreach ([ - 'ObOutputRuntime::ensureLinked($this)', - 'StringTriggerError::ensureStandaloneBodies($this)', 'CliArgvRuntime::ensureStandaloneBodies($this)', 'EnvLocalRuntime::ensureLinked($this)', 'SuperglobalNameRuntime::ensureLinked($this)', ] as $keep) { $this->assertStringContainsString($keep, $minimalBody, "keep {$keep} in minimal (#34578)"); } + $this->assertStringNotContainsString( + 'ObOutputRuntime::ensureLinked($this)', + $minimalBody, + 'ensureMinimal must not eagerly ObOutputRuntime (#34695)' + ); + $this->assertStringNotContainsString( + 'StringTriggerError::ensureStandaloneBodies($this)', + $minimalBody, + 'ensureMinimal must not eagerly StringTriggerError (#34641)' + ); } public function testCallSitesEnsureBeforeLookup(): void diff --git a/test/unit/ContextMinimalStandaloneLazyStringTriggerErrorShrinkTest.php b/test/unit/ContextMinimalStandaloneLazyStringTriggerErrorShrinkTest.php index 2e266f6bbe0..6cadd57d36f 100644 --- a/test/unit/ContextMinimalStandaloneLazyStringTriggerErrorShrinkTest.php +++ b/test/unit/ContextMinimalStandaloneLazyStringTriggerErrorShrinkTest.php @@ -30,10 +30,8 @@ public function testEnsureMinimalDropsEagerStringTriggerError(): void 'ensureMinimalUserStandaloneBodies must not eagerly StringTriggerError (#34641)' ); - // Essentials for thin echo / argv / getenv / bridges stay. + // Essentials for thin argv / getenv / bridges stay (#34695 ObOutput lazy). foreach ([ - 'StringHtmlspecialchars::ensureStandaloneBodies($this)', - 'ObOutputRuntime::ensureLinked($this)', 'CliArgvRuntime::ensureStandaloneBodies($this)', 'EnvLocalRuntime::ensureLinked($this)', 'SuperglobalNameRuntime::ensureLinked($this)', @@ -43,6 +41,12 @@ public function testEnsureMinimalDropsEagerStringTriggerError(): void $this->assertStringContainsString($keep, $minimalBody, "keep {$keep} in minimal (#34641)"); } + $this->assertStringNotContainsString( + 'ObOutputRuntime::ensureLinked($this)', + $minimalBody, + 'ensureMinimal must not eagerly ObOutputRuntime (#34695)' + ); + // Full standalone still links StringTriggerError before AssertFail / LastError. $fullPos = strpos($context, 'private function ensureFullStandaloneBodies'); $this->assertNotFalse($fullPos); diff --git a/test/unit/ExamplesHelloWorldAotRegressionTest.php b/test/unit/ExamplesHelloWorldAotRegressionTest.php index b816cd2a18f..d9330b06355 100644 --- a/test/unit/ExamplesHelloWorldAotRegressionTest.php +++ b/test/unit/ExamplesHelloWorldAotRegressionTest.php @@ -24,9 +24,10 @@ public function testContextMinimalUserStandaloneBodiesDefersNestedJit(): void $this->assertStringContainsString('ensureUserScriptRefreshPrerequisites', $refresh); $this->assertStringContainsString('ensureUserScriptRefreshEmit', $refresh); $this->assertStringContainsString('JitSuperglobalRefreshKernel::implement', $refresh); - // StringHtmlspecialchars lazy (#34642); HtmlspecialcharsDecode / HtmlEntities / - // ErrorHandler / ExceptionHandler lazy (#34612). + // StringHtmlspecialchars lazy (#34642); ObOutput lazy (#34695); HtmlspecialcharsDecode / + // HtmlEntities / ErrorHandler / ExceptionHandler lazy (#34612). $this->assertStringContainsString('#34642', $source); + $this->assertStringContainsString('#34695', $source); $this->assertStringContainsString('#34612', $source); $minimalPos = strpos($source, 'private function ensureMinimalUserStandaloneBodies'); $this->assertNotFalse($minimalPos); @@ -38,6 +39,11 @@ public function testContextMinimalUserStandaloneBodiesDefersNestedJit(): void $minimalBody, 'thin hello-world must not eagerly NestedJIT htmlspecialchars (#34642)' ); + $this->assertStringNotContainsString( + 'ObOutputRuntime::ensureLinked($this)', + $minimalBody, + 'thin hello-world must not eagerly NestedJIT ObOutput (#34695)' + ); $this->assertStringNotContainsString('StringHtmlspecialcharsStandaloneLlvm', $source); $this->assertStringNotContainsString('SuperglobalRefreshUserScriptLlvm', $refresh); $userScript = (string) file_get_contents(dirname(__DIR__, 2).'/ext/standard/JitSuperglobalRefreshKernel.php'); diff --git a/test/unit/ObOutputRuntimeShrinkTest.php b/test/unit/ObOutputRuntimeShrinkTest.php index 5ed93726143..ab2eb63e6c9 100644 --- a/test/unit/ObOutputRuntimeShrinkTest.php +++ b/test/unit/ObOutputRuntimeShrinkTest.php @@ -75,10 +75,26 @@ public function testRuntimeOwnerDeclaresObAbiModuleLocally(): void ); } - public function testContextStillEnsureLinksObOutputForStandalone(): void + public function testContextDropsAlwaysOnObOutputForMinimalStandalone(): void { $ctx = (string) file_get_contents(__DIR__.'/../../lib/JIT/Context.php'); - $this->assertStringContainsString('ObOutputRuntime::ensureLinked($this)', $ctx); + $this->assertStringContainsString('#34695', $ctx); + $minimalPos = strpos($ctx, 'private function ensureMinimalUserStandaloneBodies'); + $this->assertNotFalse($minimalPos); + $minimalEnd = strpos($ctx, 'private function ensureBootstrapAotStandaloneBodies', $minimalPos); + $this->assertNotFalse($minimalEnd); + $minimalBody = substr($ctx, $minimalPos, $minimalEnd - $minimalPos); + $this->assertStringNotContainsString( + 'ObOutputRuntime::ensureLinked($this)', + $minimalBody, + 'ensureMinimal must not eagerly ObOutputRuntime (#34695)' + ); + $helper = (string) file_get_contents(__DIR__.'/../../lib/JIT/ValueEchoHelper.php'); + $this->assertStringContainsString( + 'ObOutputRuntime::ensureLinked($context)', + $helper, + 'ValueEchoHelper must ensureLinked before __phpc_ob_echo_* (#34695)' + ); } public function testNoRuntimeCForObOutputAbi(): void