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

namespace PHPCompiler\JIT\Builtin;

use PHPCompiler\JIT\Builtin;
use PHPCompiler\JIT\BasicBlockHelper;
use PHPCompiler\JIT\Context;
use PHPLLVM;

Expand All @@ -23,9 +23,10 @@ public static function ensureLinked(Context $context): void
{
self::registerPendingGlobals($context);
self::registerDeclarations($context);
if (Builtin::LOAD_TYPE_STANDALONE !== $context->loadType) {
self::implementBodies($context);
}
// Standalone too — Context ensureMinimal no longer eagerly ErrorBridge (#34769 /
// peer #34732). Call-site ensureLinked must implement bodies or thin AOT mints
// declaration-only *.1 / link-fail (#31894 / #32122).
self::implementBodies($context);
}

public static function ensureStandaloneBodies(Context $context): void
Expand All @@ -37,6 +38,7 @@ public static function ensureStandaloneBodies(Context $context): void

public static function emitRaise(Context $context, string $message): void
{
self::ensureLinked($context);
$msgLen = $context->constantFromInteger(\strlen($message), 'size_t');
$msgCStr = $context->builder->pointerCast(
$context->constantFromString($message),
Expand All @@ -58,10 +60,17 @@ private static function implementBodies(Context $context): void
return;
}

self::registerPendingGlobals($context);
self::registerDeclarations($context);
self::implementRaiseFunction($context);
self::implementPendingHelpers($context);
// Body emission clears the insert block; restore so mid-{main} assert sites stay
// well-formed (#34769 / peer ErrorRaise #26826).
$restore = BasicBlockHelper::tryGetInsertBlock($context);
try {
self::registerPendingGlobals($context);
self::registerDeclarations($context);
self::implementRaiseFunction($context);
self::implementPendingHelpers($context);
} finally {
BasicBlockHelper::restoreInsertBlock($context, $restore);
}
}

private static function registerPendingGlobals(Context $context): void
Expand Down
13 changes: 8 additions & 5 deletions lib/JIT/Builtin/ErrorRaise.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ public static function ensureLinked(Context $context): void
{
self::registerPendingGlobals($context);
self::registerDeclarations($context);
if (Builtin::LOAD_TYPE_STANDALONE !== $context->loadType) {
self::implementBodies($context);
}
// Standalone too — Context ensureMinimal no longer eagerly ErrorBridge (#34769 /
// peer #34732). Call-site ensureLinked must implement bodies or thin AOT mints
// declaration-only *.1 / link-fail (#31894 / #32122).
self::implementBodies($context);
}

public static function ensureStandaloneBodies(Context $context): void
Expand Down Expand Up @@ -59,6 +60,7 @@ private static function implementBodies(Context $context): void

public static function emitRaise(Context $context, string $message): void
{
self::ensureLinked($context);
self::emitPendingMessage($context, $message);
}

Expand Down Expand Up @@ -304,7 +306,8 @@ public static function emitClearForStandaloneMain(Context $context): void
if (Builtin::LOAD_TYPE_STANDALONE !== $context->loadType) {
return;
}
self::registerDeclarations($context);
// Lazy bodies — ensureMinimal no longer ErrorBridge (#34769).
self::ensureLinked($context);
$context->builder->call($context->lookupFunction('phpc_jit_error_clear_pending'));
}

Expand All @@ -313,7 +316,7 @@ public static function emitAbortIfPendingForStandaloneMain(Context $context): vo
if (Builtin::LOAD_TYPE_STANDALONE !== $context->loadType) {
return;
}
self::registerDeclarations($context);
self::ensureLinked($context);
$context->builder->call($context->lookupFunction('phpc_jit_abort_if_pending_error'));
}

Expand Down
5 changes: 3 additions & 2 deletions lib/JIT/Builtin/ReadonlyRaise.php
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,8 @@ public static function emitClearForStandaloneMain(Context $context): void
if (Builtin::LOAD_TYPE_STANDALONE !== $context->loadType) {
return;
}
self::registerDeclarations($context);
// Lazy bodies — ensureMinimal no longer ErrorBridge (#34769).
self::ensureLinked($context);
$context->builder->call($context->lookupFunction('phpc_jit_clear_pending_exception'));
}

Expand All @@ -449,7 +450,7 @@ public static function emitAbortIfPendingForStandaloneMain(Context $context): vo
if (Builtin::LOAD_TYPE_STANDALONE !== $context->loadType) {
return;
}
self::registerDeclarations($context);
self::ensureLinked($context);
$context->builder->call($context->lookupFunction('phpc_jit_abort_if_pending_logic_exception'));
}

Expand Down
6 changes: 5 additions & 1 deletion lib/JIT/Context.php
Original file line number Diff line number Diff line change
Expand Up @@ -2302,8 +2302,12 @@ private function ensureMinimalUserStandaloneBodies(): void
// bodies before lookup (peer #34695). Thin hello-world must not NestedJIT TypeErrorRaise
// / JitThrow during init — thin {main} skips ExceptionBridge clear/abort anyway.
// Leftover Context NestedJIT vs Runtime ABI drift mints *.1 (#31894 / #32122).
// ErrorBridge always-on removed (#34769): ErrorRaise / AssertionErrorRaise /
// ReadonlyRaise ensureLinked + emitClear/emitAbort/emitRaise already implement
// standalone bodies before lookup (peer #34732). Thin hello-world must not NestedJIT
// pending-Error ABI during init — thin {main} skips ErrorBridge clear/abort when unused.
// Leftover Context NestedJIT vs Runtime ABI drift mints *.1 (#31894 / #32122).
// Full standalone still ensureStandaloneBodies below.
ErrorBridge::ensureStandaloneBodies($this);
// ErrorHandler / ExceptionHandler always-on removed (#34612): JitErrorHandler /
// JitTriggerErrorKernel / JitExceptionHandler / TryCatchHelper already ensureLinked
// before lookup (peer #34605). implement() paths restore builder insert mid-{main}.
Expand Down
2 changes: 2 additions & 0 deletions lib/JIT/ErrorBridge.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
*
* Replaces lib/AOT/runtime/phpc_error_raise.c — LLVM bodies live in {@see ErrorRaise};
* readonly property guards use {@see ReadonlyBridge} (#5374).
* Standalone bodies are lazy via ensureLinked at call sites (#34769); Context
* ensureMinimal no longer eagerly NestedJITs this ABI.
*/
final class ErrorBridge
{
Expand Down
156 changes: 156 additions & 0 deletions test/unit/ContextMinimalStandaloneLazyErrorBridgeRuntimeShrinkTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\Test\Unit;

use PHPUnit\Framework\TestCase;

/**
* Drop Context::ensureMinimalUserStandaloneBodies always-on ErrorBridge (#34769 / peer #34732).
*
* Thin AOT hello-world must not eagerly NestedJIT ErrorRaise / AssertionErrorRaise /
* ReadonlyRaise ABI; call-site ensureLinked implements standalone bodies (#32122 .1 mint class).
*/
final class ContextMinimalStandaloneLazyErrorBridgeRuntimeShrinkTest extends TestCase
{
public function testEnsureMinimalDropsEagerErrorBridge(): void
{
$context = (string) file_get_contents(__DIR__.'/../../lib/JIT/Context.php');
$this->assertStringContainsString('#34769', $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(
'ErrorBridge::ensureStandaloneBodies($this)',
$minimalBody,
'ensureMinimalUserStandaloneBodies must not eagerly ErrorBridge (#34769)'
);

// Essentials for thin argv / getenv stay.
foreach ([
'CliArgvRuntime::ensureStandaloneBodies($this)',
'EnvLocalRuntime::ensureLinked($this)',
'SuperglobalNameRuntime::ensureLinked($this)',
] as $keep) {
$this->assertStringContainsString($keep, $minimalBody, "keep {$keep} in minimal (#34769)");
}

// ensureFull still eagerly ErrorBridge (full AOT fixture surface).
$fullPos = strpos($context, 'private function ensureFullStandaloneBodies');
$this->assertNotFalse($fullPos);
$fullEnd = strpos($context, 'private function ', $fullPos + 1);
$fullHead = false === $fullEnd
? substr($context, $fullPos, 2500)
: substr($context, $fullPos, min(2500, $fullEnd - $fullPos));
$this->assertStringContainsString(
'ErrorBridge::ensureStandaloneBodies($this)',
$fullHead,
'ensureFullStandaloneBodies still ensures ErrorBridge (#34769)'
);
}

public function testErrorRaiseEnsureLinkedImplementsStandaloneBodies(): void
{
$source = (string) file_get_contents(__DIR__.'/../../lib/JIT/Builtin/ErrorRaise.php');
$this->assertStringContainsString('#34769', $source);
$pos = strpos($source, 'public static function ensureLinked');
$this->assertNotFalse($pos);
$next = strpos($source, 'public static function ensureStandaloneBodies', $pos + 10);
$this->assertNotFalse($next);
$body = substr($source, $pos, $next - $pos);
$this->assertStringContainsString('self::implementBodies($context)', $body);
$this->assertStringNotContainsString(
'LOAD_TYPE_STANDALONE !== $context->loadType',
$body,
'ensureLinked must implement bodies for STANDALONE too (#34769)'
);
$this->assertStringContainsString(
'BasicBlockHelper::tryGetInsertBlock',
$source,
'implementBodies must restore insert block mid-{main} (#34769)'
);
}

public function testAssertionErrorRaiseEnsureLinkedImplementsStandaloneBodies(): void
{
$source = (string) file_get_contents(__DIR__.'/../../lib/JIT/Builtin/AssertionErrorRaise.php');
$this->assertStringContainsString('#34769', $source);
$pos = strpos($source, 'public static function ensureLinked');
$this->assertNotFalse($pos);
$next = strpos($source, 'public static function ensureStandaloneBodies', $pos + 10);
$this->assertNotFalse($next);
$body = substr($source, $pos, $next - $pos);
$this->assertStringContainsString('self::implementBodies($context)', $body);
$this->assertStringNotContainsString(
'LOAD_TYPE_STANDALONE !== $context->loadType',
$body,
'ensureLinked must implement bodies for STANDALONE too (#34769)'
);
$this->assertStringContainsString(
'BasicBlockHelper::tryGetInsertBlock',
$source,
'implementBodies must restore insert block mid-{main} (#34769)'
);
}

public function testEmitClearAndAbortEnsureBeforeLookup(): void
{
foreach ([
__DIR__.'/../../lib/JIT/Builtin/ErrorRaise.php',
__DIR__.'/../../lib/JIT/Builtin/ReadonlyRaise.php',
] as $path) {
$source = (string) file_get_contents($path);
foreach (['emitClearForStandaloneMain', 'emitAbortIfPendingForStandaloneMain'] as $method) {
$pos = strpos($source, 'public static function '.$method);
$this->assertNotFalse($pos, $path.' '.$method);
$next = strpos($source, 'public static function ', $pos + 10);
$body = false === $next
? substr($source, $pos)
: substr($source, $pos, $next - $pos);
$this->assertStringContainsString(
'self::ensureLinked($context)',
$body,
basename($path).'::'.$method.' must ensureLinked before lookup (#34769)'
);
}
}
}

public function testEmitRaiseEnsuresBeforeLookup(): void
{
foreach ([
__DIR__.'/../../lib/JIT/Builtin/ErrorRaise.php',
__DIR__.'/../../lib/JIT/Builtin/AssertionErrorRaise.php',
] as $path) {
$source = (string) file_get_contents($path);
$pos = strpos($source, 'public static function emitRaise');
$this->assertNotFalse($pos, $path);
$next = strpos($source, 'public static function ', $pos + 10);
$body = false === $next
? substr($source, $pos)
: substr($source, $pos, $next - $pos);
$this->assertStringContainsString(
'self::ensureLinked($context)',
$body,
basename($path).'::emitRaise must ensureLinked (#34769)'
);
}
}

public function testNoNewRuntimeCForMinimalErrorBridgeLazy(): void
{
$runtimeDir = dirname(__DIR__, 2).'/lib/AOT/runtime';
$this->assertFileDoesNotExist(
$runtimeDir.'/error_bridge.c',
'must not add error_bridge.c for #34769 — PHP JIT bridges only'
);
$this->assertFileDoesNotExist(
$runtimeDir.'/phpc_error_raise.c',
'must not re-add phpc_error_raise.c for #34769'
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,19 @@ public function testEnsureMinimalDropsEagerExceptionBridge(): void
'ensureMinimalUserStandaloneBodies must not eagerly ExceptionBridge (#34732)'
);

// Essentials for thin argv / getenv / Error pending stay.
// Essentials for thin argv / getenv stay (#34769 dropped ErrorBridge).
foreach ([
'CliArgvRuntime::ensureStandaloneBodies($this)',
'EnvLocalRuntime::ensureLinked($this)',
'SuperglobalNameRuntime::ensureLinked($this)',
'ErrorBridge::ensureStandaloneBodies($this)',
] as $keep) {
$this->assertStringContainsString($keep, $minimalBody, "keep {$keep} in minimal (#34732)");
$this->assertStringContainsString($keep, $minimalBody, "keep {$keep} in minimal (#34769)");
}
$this->assertStringNotContainsString(
'ErrorBridge::ensureStandaloneBodies($this)',
$minimalBody,
'ensureMinimal must not eagerly ErrorBridge (#34769)'
);

// ensureFull still eagerly ExceptionBridge (full AOT fixture surface).
$fullPos = strpos($context, 'private function ensureFullStandaloneBodies');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,14 @@ public function testEnsureMinimalDropsEagerHtmlspecialchars(): void
'CliArgvRuntime::ensureStandaloneBodies($this)',
'EnvLocalRuntime::ensureLinked($this)',
'SuperglobalNameRuntime::ensureLinked($this)',
'ErrorBridge::ensureStandaloneBodies($this)',
] as $keep) {
$this->assertStringContainsString($keep, $minimalBody, "keep {$keep} in minimal (#34732)");
$this->assertStringContainsString($keep, $minimalBody, "keep {$keep} in minimal (#34769)");
}
$this->assertStringNotContainsString(
'ErrorBridge::ensureStandaloneBodies($this)',
$minimalBody,
'ensureMinimal must not eagerly ErrorBridge (#34769)'
);
$this->assertStringNotContainsString(
'ExceptionBridge::ensureStandaloneBodies($this)',
$minimalBody,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,14 @@ public function testEnsureMinimalDropsEagerLastError(): void
'CliArgvRuntime::ensureStandaloneBodies($this)',
'EnvLocalRuntime::ensureLinked($this)',
'SuperglobalNameRuntime::ensureLinked($this)',
'ErrorBridge::ensureStandaloneBodies($this)',
] as $keep) {
$this->assertStringContainsString($keep, $minimalBody, "keep {$keep} in minimal (#34732)");
$this->assertStringContainsString($keep, $minimalBody, "keep {$keep} in minimal (#34769)");
}
$this->assertStringNotContainsString(
'ErrorBridge::ensureStandaloneBodies($this)',
$minimalBody,
'ensureMinimal must not eagerly ErrorBridge (#34769)'
);
$this->assertStringNotContainsString(
'ExceptionBridge::ensureStandaloneBodies($this)',
$minimalBody,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,14 @@ public function testEnsureMinimalDropsEagerObOutput(): void
'CliArgvRuntime::ensureStandaloneBodies($this)',
'EnvLocalRuntime::ensureLinked($this)',
'SuperglobalNameRuntime::ensureLinked($this)',
'ErrorBridge::ensureStandaloneBodies($this)',
] as $keep) {
$this->assertStringContainsString($keep, $minimalBody, "keep {$keep} in minimal (#34732)");
$this->assertStringContainsString($keep, $minimalBody, "keep {$keep} in minimal (#34769)");
}
$this->assertStringNotContainsString(
'ErrorBridge::ensureStandaloneBodies($this)',
$minimalBody,
'ensureMinimal must not eagerly ErrorBridge (#34769)'
);
$this->assertStringNotContainsString(
'ExceptionBridge::ensureStandaloneBodies($this)',
$minimalBody,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,14 @@ public function testEnsureMinimalDropsEagerJitReturnPending(): void
'CliArgvRuntime::ensureStandaloneBodies($this)',
'EnvLocalRuntime::ensureLinked($this)',
'SuperglobalNameRuntime::ensureLinked($this)',
'ErrorBridge::ensureStandaloneBodies($this)',
] as $keep) {
$this->assertStringContainsString($keep, $minimalBody, "keep {$keep} in minimal (#34732)");
$this->assertStringContainsString($keep, $minimalBody, "keep {$keep} in minimal (#34769)");
}
$this->assertStringNotContainsString(
'ErrorBridge::ensureStandaloneBodies($this)',
$minimalBody,
'ensureMinimal must not eagerly ErrorBridge (#34769)'
);
$this->assertStringNotContainsString(
'ExceptionBridge::ensureStandaloneBodies($this)',
$minimalBody,
Expand Down
Loading
Loading