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
8 changes: 6 additions & 2 deletions lib/JIT/Builtin/LastErrorRuntime.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace PHPCompiler\JIT\Builtin;

use PHPCompiler\JIT\BasicBlockHelper;
use PHPCompiler\JIT\Context;
use PHPCompiler\JIT\JitVmHelperLink;
use PHPCompiler\JIT\LibcExtern;
Expand All @@ -15,7 +16,8 @@
* JIT/AOT link for __phpc_last_error_* via ErrorLastJitHelper PHP (#9454, #9607, #25318).
*
* Helper compile: {@see JitVmHelperLink::ensureCompiled} (peer ExecutionLimits #25269).
* Thin LLVM bridges forward the __phpc_last_error_* ABI. php-src: ext/standard/basic_functions.c
* Thin LLVM bridges forward the __phpc_last_error_* ABI. Mid-{main} ensureLinked restores
* builder insert (#34631 / peer JitHelperAbiBridge #34621). php-src: ext/standard/basic_functions.c
*/
final class LastErrorRuntime
{
Expand Down Expand Up @@ -73,14 +75,16 @@ public static function implement(Context $context): void
return;
}

// Capture before NestedJIT/bridge emit so mid-{main} ensureLinked is safe (#34631).
$restoreBlock = BasicBlockHelper::tryGetInsertBlock($context);
self::ensureJitHelperCompiled($context);
self::ensureHashtableHelpers($context);
self::implementRecordBridge($context);
self::implementClearBridge($context);
self::implementActiveBridge($context);
self::implementHashtableBridge($context);
self::registerLinkedRuntime($context);
$context->builder->clearInsertionPosition();
BasicBlockHelper::restoreInsertBlock($context, $restoreBlock);
}

private static function implementRecordBridge(Context $context): void
Expand Down
6 changes: 5 additions & 1 deletion lib/JIT/Context.php
Original file line number Diff line number Diff line change
Expand Up @@ -2319,7 +2319,11 @@ private function ensureMinimalUserStandaloneBodies(): void
// ProgressNote / GcCollectCycles always-on removed (#34605): tryResolveProgressStaticCall /
// JitGcCollectCycles / Object_ / GcStatusRuntime already ensureLinked before lookup
// (peer #34578). Full standalone still ensureStandaloneBodies below.
Builtin\LastErrorRuntime::ensureStandaloneBodies($this);
// LastError always-on removed (#34631): JitErrorGetLast / JitTriggerErrorKernel already
// ensureLinked before lookup (peer #34621). LastErrorRuntime restores builder insert
// mid-{main}. Leftover Context NestedJIT vs Runtime ABI drift mints *.1 (#31894 / #32122).
// Full standalone still ensureStandaloneBodies below; StringTriggerError always-on still
// pulls LastError when trigger_error ABI is linked during thin init.
Builtin\SuperglobalNameRuntime::ensureLinked($this);
Builtin\EnvLocalRuntime::ensureLinked($this);
// CLI argv: NestedJIT CliArgvJitHelper during thin init (peer IncludePath #20877 / #20904)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,22 @@ public function testEnsureMinimalDropsEagerDomGcProgressAssert(): void

// Essentials for thin echo / error / argv / getenv surface stay.
// HtmlEntities / Decode / ErrorHandler / ExceptionHandler dropped in #34612 (peer this test).
// LastError dropped in #34631 (peer this test).
foreach ([
'StringHtmlspecialchars::ensureStandaloneBodies($this)',
'ObOutputRuntime::ensureLinked($this)',
'StringTriggerError::ensureStandaloneBodies($this)',
'CliArgvRuntime::ensureStandaloneBodies($this)',
'EnvLocalRuntime::ensureLinked($this)',
'SuperglobalNameRuntime::ensureLinked($this)',
'LastErrorRuntime::ensureStandaloneBodies($this)',
] as $keep) {
$this->assertStringContainsString($keep, $minimalBody, "keep {$keep} in minimal (#34605)");
}
$this->assertStringNotContainsString(
'LastErrorRuntime::ensureStandaloneBodies($this)',
$minimalBody,
'ensureMinimal must not eagerly LastErrorRuntime (#34631)'
);
foreach ([
'HtmlEntitiesJit::ensureStandaloneBodies($this)',
'StringHtmlspecialcharsDecode::ensureStandaloneBodies($this)',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,22 @@ public function testEnsureMinimalDropsEagerHtmlErrorHandler(): void
}

// Essentials for thin echo / error / argv / getenv surface stay.
// LastError dropped in #34631 (peer this test).
foreach ([
'StringHtmlspecialchars::ensureStandaloneBodies($this)',
'ObOutputRuntime::ensureLinked($this)',
'StringTriggerError::ensureStandaloneBodies($this)',
'CliArgvRuntime::ensureStandaloneBodies($this)',
'EnvLocalRuntime::ensureLinked($this)',
'SuperglobalNameRuntime::ensureLinked($this)',
'LastErrorRuntime::ensureStandaloneBodies($this)',
] as $keep) {
$this->assertStringContainsString($keep, $minimalBody, "keep {$keep} in minimal (#34612)");
}
$this->assertStringNotContainsString(
'LastErrorRuntime::ensureStandaloneBodies($this)',
$minimalBody,
'ensureMinimal must not eagerly LastErrorRuntime (#34631)'
);
}

public function testCallSitesEnsureBeforeLookup(): void
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\Test\Unit;

use PHPUnit\Framework\TestCase;

/**
* Drop Context::ensureMinimalUserStandaloneBodies always-on LastErrorRuntime (#34631 / peer #34621).
*
* Thin AOT hello-world must not eagerly NestedJIT last-error ABI; JitErrorGetLast /
* JitTriggerErrorKernel ensureLinked lazily (#32122 .1 mint class).
*/
final class ContextMinimalStandaloneLazyLastErrorRuntimeShrinkTest extends TestCase
{
public function testEnsureMinimalDropsEagerLastError(): void
{
$context = (string) file_get_contents(__DIR__.'/../../lib/JIT/Context.php');
$this->assertStringContainsString('#34631', $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(
'LastErrorRuntime::ensureStandaloneBodies($this)',
$minimalBody,
'ensureMinimalUserStandaloneBodies must not eagerly LastErrorRuntime (#34631)'
);

// Essentials for thin echo / error / argv / getenv surface stay.
foreach ([
'StringHtmlspecialchars::ensureStandaloneBodies($this)',
'ObOutputRuntime::ensureLinked($this)',
'StringTriggerError::ensureStandaloneBodies($this)',
'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 (#34631)");
}

// Full standalone still links LastError after TriggerError.
$fullPos = strpos($context, 'private function ensureFullStandaloneBodies');
$this->assertNotFalse($fullPos);
$fullBody = substr($context, $fullPos);
$this->assertStringContainsString('LastErrorRuntime::ensureStandaloneBodies($this)', $fullBody);
}

public function testCallSitesEnsureBeforeLookup(): void
{
$checks = [
'ext/standard/JitErrorGetLast.php' => 'LastErrorRuntime::ensureLinked',
'ext/standard/JitTriggerErrorKernel.php' => 'LastErrorRuntime::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 (#34631)');
}
}

public function testLastErrorRuntimeRestoresInsert(): void
{
$source = (string) file_get_contents(__DIR__.'/../../lib/JIT/Builtin/LastErrorRuntime.php');
$this->assertStringContainsString('#34631', $source);
$this->assertStringContainsString('BasicBlockHelper::tryGetInsertBlock', $source);
$this->assertStringContainsString('BasicBlockHelper::restoreInsertBlock', $source);
$this->assertStringNotContainsString(
"\$context->builder->clearInsertionPosition();\n }",
$source,
'implement() must not always clear insert (#34631)'
);
}

public function testNoNewRuntimeCForMinimalLastErrorLazy(): void
{
$runtimeDir = dirname(__DIR__, 2).'/lib/AOT/runtime';
$this->assertFileDoesNotExist(
$runtimeDir.'/last_error.c',
'must not add last_error.c for #34631 — PHP JIT bridges only'
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,24 @@ public function testEnsureMinimalDropsEagerJitReturnPending(): void
);

// Essentials for thin echo / error / argv / getenv surface stay.
// LastError dropped in #34631 (peer this test).
foreach ([
'StringHtmlspecialchars::ensureStandaloneBodies($this)',
'ObOutputRuntime::ensureLinked($this)',
'StringTriggerError::ensureStandaloneBodies($this)',
'CliArgvRuntime::ensureStandaloneBodies($this)',
'EnvLocalRuntime::ensureLinked($this)',
'SuperglobalNameRuntime::ensureLinked($this)',
'LastErrorRuntime::ensureStandaloneBodies($this)',
'ExceptionBridge::ensureStandaloneBodies($this)',
'ErrorBridge::ensureStandaloneBodies($this)',
] as $keep) {
$this->assertStringContainsString($keep, $minimalBody, "keep {$keep} in minimal (#34621)");
}
$this->assertStringNotContainsString(
'LastErrorRuntime::ensureStandaloneBodies($this)',
$minimalBody,
'ensureMinimal must not eagerly LastErrorRuntime (#34631)'
);

// Full standalone still links return-pending after TriggerError.
$fullPos = strpos($context, 'private function ensureFullStandaloneBodies');
Expand Down
Loading