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
20 changes: 17 additions & 3 deletions lib/JIT/Builtin/Refcount.php
Original file line number Diff line number Diff line change
Expand Up @@ -172,15 +172,28 @@ public function register(): void {
}

public function implement(): void {
\PHPCompiler\JIT\Builtin\WeakRefRuntime::ensureLinked($this->context);
\PHPCompiler\JIT\Builtin\WeakRefNative::registerDeclarations($this->context);
\PHPCompiler\JIT\Builtin\GcCollectCyclesRuntime::ensureDeclarations($this->context);
// WeakRef / GC delref always-on ensureLinked removed (#35802): only
// implementDelref lookupFunction phpc_weakref_clear_object_typed /
// phpc_gc_unregister / phpc_destruct_* — call ensureDelrefHelperAbis there
// (peer #35751 HashTable lazy strtol, #35626 strcoll). Thin hello-world must
// not NestedJIT weakref/gc ABIs during Refcount init — leftover NestedJIT vs
// Runtime ABI drift mints phpc_weakref_*.1 / phpc_gc_*.1 (#31894 / #32122).
$this->implementInit();
$this->implementAddref();
$this->implementDelref();
$this->implementSeparate();
}

/**
* WeakReference clear + GC unregister + deferred-destruct probes — delref only (#35802).
*/
private function ensureDelrefHelperAbis(): void
{
\PHPCompiler\JIT\Builtin\WeakRefRuntime::ensureLinked($this->context);
\PHPCompiler\JIT\Builtin\WeakRefNative::registerDeclarations($this->context);
\PHPCompiler\JIT\Builtin\GcCollectCyclesRuntime::ensureDeclarations($this->context);
}

private function implementInit(): void {
// insertValue returns a new aggregate — must store it (#24226: prior codegen
// discarded the SSA value, so refcount/typeinfo never hit memory).
Expand Down Expand Up @@ -254,6 +267,7 @@ private function implementAddref(): void {
}

private function implementDelref(): void {
$this->ensureDelrefHelperAbis();
$fn___8f14e45fceea167a5a36dedd4bea2543 = $this->context->lookupFunction('__ref__delref');
$block___8f14e45fceea167a5a36dedd4bea2543 = $fn___8f14e45fceea167a5a36dedd4bea2543->appendBasicBlock('main');
$this->context->builder->positionAtEnd($block___8f14e45fceea167a5a36dedd4bea2543);
Expand Down
14 changes: 12 additions & 2 deletions lib/JIT/Builtin/Refcount.pre
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,23 @@ class Refcount extends Builtin {
}

public function implement(): void {
\PHPCompiler\JIT\Builtin\WeakRefRuntime::ensureLinked($this->context);
\PHPCompiler\JIT\Builtin\WeakRefNative::registerDeclarations($this->context);
// WeakRef / GC delref always-on ensureLinked removed (#35802): only
// implementDelref emits phpc_weakref_clear_object_typed / phpc_gc_unregister /
// phpc_destruct_* — call ensureDelrefHelperAbis there (peer #35751).
$this->implementInit();
$this->implementAddref();
$this->implementDelref();
$this->implementSeparate();
}

/** WeakReference clear + GC unregister + deferred-destruct probes — delref only (#35802). */
private function ensureDelrefHelperAbis(): void
{
\PHPCompiler\JIT\Builtin\WeakRefRuntime::ensureLinked($this->context);
\PHPCompiler\JIT\Builtin\WeakRefNative::registerDeclarations($this->context);
\PHPCompiler\JIT\Builtin\GcCollectCyclesRuntime::ensureDeclarations($this->context);
}

private function implementInit(): void {
// NOTE: compile{} expands `$ref.refcount = …` to insertValue without store.
// The generated Refcount.php hand-stores the aggregate (#24226). Re-run the
Expand Down Expand Up @@ -101,6 +110,7 @@ class Refcount extends Builtin {
}

private function implementDelref(): void {
$this->ensureDelrefHelperAbis();
compile {
function __ref__delref($refVirtual) {
$isNull = $refVirtual == null;
Expand Down
87 changes: 87 additions & 0 deletions test/unit/RefcountLazyWeakRefRuntimeShrinkTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\Test\Unit;

use PHPUnit\Framework\TestCase;

/**
* Drop Refcount::implement always-on WeakRef/GC NestedJIT (#35802 / peer #35751).
*
* Thin hello-world AOT must not NestedJIT weakref/gc ABIs during Refcount init —
* leftover NestedJIT vs Runtime ABI drift mints phpc_weakref_*.1 / phpc_gc_*.1
* (#31894 / #32122).
*/
final class RefcountLazyWeakRefRuntimeShrinkTest extends TestCase
{
public function testRefcountImplementDropsEagerWeakRefGcEnsureLinked(): void
{
$source = (string) file_get_contents(__DIR__.'/../../lib/JIT/Builtin/Refcount.php');
$this->assertStringContainsString('#35802', $source);
$pos = strpos($source, 'public function implement(): void');
$this->assertNotFalse($pos);
$next = strpos($source, 'private function ensureDelrefHelperAbis', $pos);
$this->assertNotFalse($next);
$body = substr($source, $pos, $next - $pos);
foreach ([
'WeakRefRuntime::ensureLinked',
'WeakRefNative::registerDeclarations',
'GcCollectCyclesRuntime::ensureDeclarations',
] as $forbidden) {
$this->assertStringNotContainsString(
$forbidden,
$body,
'Refcount::implement must not eagerly '.$forbidden.' (#35802)'
);
}
}

public function testImplementDelrefEnsuresWeakRefGcBeforeLookup(): void
{
$source = (string) file_get_contents(__DIR__.'/../../lib/JIT/Builtin/Refcount.php');
$fnPos = strpos($source, 'private function implementDelref(): void');
$this->assertNotFalse($fnPos);
$nextFn = strpos($source, 'private function implementSeparate(): void', $fnPos);
$this->assertNotFalse($nextFn);
$chunk = substr($source, $fnPos, $nextFn - $fnPos);
$this->assertStringContainsString(
'ensureDelrefHelperAbis',
$chunk,
'implementDelref must ensureDelrefHelperAbis before lookup (#35802)'
);
$ensurePos = strpos($chunk, 'ensureDelrefHelperAbis');
$lookupPos = strpos($chunk, "lookupFunction('phpc_weakref_clear_object_typed')");
$this->assertNotFalse($ensurePos);
$this->assertNotFalse($lookupPos);
$this->assertLessThan($lookupPos, $ensurePos);
}

public function testRefcountPreMatchesLazyDelrefPattern(): void
{
$source = (string) file_get_contents(__DIR__.'/../../lib/JIT/Builtin/Refcount.pre');
$this->assertStringContainsString('#35802', $source);
$this->assertStringContainsString('ensureDelrefHelperAbis', $source);
$pos = strpos($source, 'public function implement(): void');
$this->assertNotFalse($pos);
$next = strpos($source, 'private function ensureDelrefHelperAbis', $pos);
$this->assertNotFalse($next);
$body = substr($source, $pos, $next - $pos);
$this->assertStringNotContainsString('WeakRefRuntime::ensureLinked', $body);
}

public function testNoNewRuntimeCForLazyWeakRefAbis(): void
{
$runtimeDir = dirname(__DIR__, 2).'/lib/AOT/runtime';
foreach ([
'weakref.c',
'phpc_weakref.c',
'gc_unregister.c',
] as $name) {
$this->assertFileDoesNotExist(
$runtimeDir.'/'.$name,
'must not add '.$name.' for #35802 — PHP JIT bridges only'
);
}
}
}
Loading