Repository navigation
php-in-php: phpc_gc.c shutdown destructors — GC cycle collection in lib/VM/Gc.php (Zend/zend_gc.c parity) #6519
Copy link
Copy link
Closed
Labels
area:compilerCompiler / CFG / JITCompiler / CFG / JITarea:vmVirtual machineVirtual machineenhancementNew feature or requestNew feature or requestimplementation-readySpec complete: repro, php-src ref, done-when — safe for workers to claimSpec complete: repro, php-src ref, done-when — safe for workers to claimphase-0:FoundationPhase 0 – foundation & DevExPhase 0 – foundation & DevExphase-2:languagePhase 2 – language featuresPhase 2 – language features
Description
Category
php-in-php | runtime
Problem
Cycle collection and shutdown __destruct ordering still live partly in lib/AOT/runtime/phpc_gc.c (~400+ lines). Zend implements this in Zend/zend_gc.c; this repo already has lib/VM/Gc.php and gc_collect_cycles() in ext/standard/, but AOT/JIT paths call C helpers for:
- deferred destructor invocation on cyclic graphs (Stdlib: gc_disable/gc_enable/gc_enabled/gc_collect_cycles — JIT/AOT (ext/standard + Zend/zend_gc.c) #4023, Language: User __destruct() — JIT/AOT invoke on object release (phase 2 of #3144) #4013)
- shutdown pass ordering vs refcount-zero immediate destruct
Self-host (#1492) requires compiled lib/ to run GC semantics without growing runtime/*.c.
php-src reference
- php/php-src
Zend/zend_gc.c—gc_collect_cycles,gc_possible_root - php/php-src
Zend/zend_execute.c— shutdown destructor pass - Existing compliance:
test/compliance/cases/runtime/gc_collect_cycles.phpt
Repro (behavior gap today)
<?php
class Node {
public ?Node $next = null;
public function __destruct() { echo "dtor\n"; }
}
$a = new Node();
$b = new Node();
$a->next = $b;
$b->next = $a;
unset($a, $b);
gc_collect_cycles();
// Zend: prints dtor (possibly twice depending on cycle handling)./script/docker-exec.sh -- bash -lc 'source script/php-env.sh
php repro_gc_cycle_destruct.php
php bin/vm.php repro_gc_cycle_destruct.php
# Compare output; AOT-linked binary must match VM (no missing dtor)
'Also audit symbols: nm lib/AOT/runtime/*.o | grep phpc_gc — any call from compiled PHP builtins should route through VM PHP helpers after migration.
Scope (PHP-in-PHP first)
| Path | Work |
|---|---|
lib/VM/Gc.php |
Port cycle mark/sweep + destructor queue from C |
ext/standard/gc_collect_cycles.php |
Single entry; delete duplicate C paths |
lib/AOT/runtime/phpc_gc.c |
Delete or shrink to thin ABI trampoline |
| JIT/AOT | Lower gc_collect_cycles() to PHP helper or shared runtime symbol |
| Tests | Extend gc_collect_cycles.phpt; add cyclic destructor PHPT |
Done when
- Repro destructor output matches Zend on VM and AOT-linked driver
- Measurable lines removed from
lib/AOT/runtime/phpc_gc.c(target: delete file or <50 line ABI) -
./script/ci-fast.sh --filter gc_collect_cyclesgreen -
php script/bootstrap-inventory.php --checkstill green
Verification
./script/docker-exec.sh -- bash -lc 'source script/php-env.sh && vendor/bin/phpunit --filter gc_collect_cycles'
make bootstrap-selfhost-linkRelated
- Stdlib: gc_disable/gc_enable/gc_enabled/gc_collect_cycles — JIT/AOT (ext/standard + Zend/zend_gc.c) #4023 GC JIT/AOT · php-in-php: WeakReference/WeakMap — delete phpc_weakref.c (~156 lines), GC weak refs in lib/VM #5303 WeakRef C deletion · Epic: Self-host critical path — compiler compiles itself (M3→M5) #1492 M5
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
area:compilerCompiler / CFG / JITCompiler / CFG / JITarea:vmVirtual machineVirtual machineenhancementNew feature or requestNew feature or requestimplementation-readySpec complete: repro, php-src ref, done-when — safe for workers to claimSpec complete: repro, php-src ref, done-when — safe for workers to claimphase-0:FoundationPhase 0 – foundation & DevExPhase 0 – foundation & DevExphase-2:languagePhase 2 – language featuresPhase 2 – language features
Activity
PurHur commentedon Jun 8, 2026
claim: PHP Runtime → PHP — starting this run (#6519: invoke __destruct during gc_collect_cycles for cyclic graphs in CycleCollector, add compliance PHPT).
VM: invoke __destruct during gc_collect_cycles on cyclic graphs (#6519)…
PurHur commentedon Jun 8, 2026
Merged via #7673.
PHP path:
CycleCollector::collect()now callsObjectLifetime::invokeDestructorBeforeGcRelease()beforeObjectRegistry::release()— matches Zend cyclic-graph destructor ordering (zend_gc.c).C shrink:
phpc_gc.cwas already deleted (#5315); no new C added.Verification (green):
```bash
./script/docker-exec.sh -- bash -lc 'source script/php-env.sh && vendor/bin/phpunit --filter "GcCollectCyclesDestructTest|gc_collect_cycles_destruct"'
OK (2 tests, 2 assertions)
```