From ee6445febbc577c77380e8c6d05bd7acb9316316 Mon Sep 17 00:00:00 2001
From: PurHur
Date: Sun, 19 Jul 2026 01:40:49 +0000
Subject: [PATCH 1/3] Stdlib: IntlBreakIterator
preceding/following/isBoundary/getLocale (#20771)
Wire random-access boundary APIs and locale/error getters on the existing
ICU/fallback boundaries state so PROFILE=8.4 matches php-src breakiterator.
Co-authored-by: Cursor
---
docs/bootstrap-inventory.md | 328 +++++++++---------
ext/intl/VmBreakIterator.php | 270 ++++++++++++++
test/compliance/JITTest.php | 8 +-
test/compliance/VMTest.php | 3 +-
.../breakiterator_preceding_following.php | 17 +
.../breakiterator_preceding_following.phpt | 24 ++
.../issue_20771_breakiterator_preceding.php | 17 +
test/unit/IntlModuleTest.php | 26 ++
8 files changed, 533 insertions(+), 160 deletions(-)
create mode 100644 test/compliance/cases/intl/breakiterator_preceding_following.php
create mode 100644 test/compliance/cases/intl/breakiterator_preceding_following.phpt
create mode 100644 test/repro/issue_20771_breakiterator_preceding.php
diff --git a/docs/bootstrap-inventory.md b/docs/bootstrap-inventory.md
index b7ec77fa752..6be6953ab21 100644
--- a/docs/bootstrap-inventory.md
+++ b/docs/bootstrap-inventory.md
@@ -8,11 +8,11 @@ Regenerate: `php script/bootstrap-inventory.php`
| Metric | Count |
|--------|------:|
-| PHP files on vm.php path | 5830 |
-| Phase A inventory files (M2 ratio SSOT) | 5830 |
+| PHP files on vm.php path | 5831 |
+| Phase A inventory files (M2 ratio SSOT) | 5831 |
| Phase A ratio-deferred paths | 0 |
| Source constructs flagged (blockers) | 0 |
-| Source constructs flagged (warnings) | 17362 |
+| Source constructs flagged (warnings) | 17374 |
## Compiler CFG gaps (`lib/Compiler.php`)
@@ -830,7 +830,7 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
| `ext/intl/NormalizerIsNormalized.php` | 0 | 2 |
| `ext/intl/NormalizerNormalize.php` | 0 | 2 |
| `ext/intl/UnicodeCanonical.php` | 0 | 1 |
-| `ext/intl/VmBreakIterator.php` | 0 | 31 |
+| `ext/intl/VmBreakIterator.php` | 0 | 43 |
| `ext/intl/VmCollator.php` | 0 | 55 |
| `ext/intl/VmGrapheme.php` | 0 | 1 |
| `ext/intl/VmIdn.php` | 0 | 5 |
@@ -8481,9 +8481,9 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
- new DOMException (line 9459)
- new DOMException (line 9462)
- new DOMException (line 9491)
-- new Error (line 10459)
-- new Error (line 10463)
-- 427 class method(s)
+- new Error (line 10402)
+- new Error (line 10406)
+- 426 class method(s)
- 2 closure(s)
### `ext/dom/VmDomCollectionDimension.php`
@@ -11435,37 +11435,49 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
### `ext/intl/VmBreakIterator.php`
**Warnings** (review for bootstrap subset):
-- new Variable (line 74)
-- new ClassEntry (line 77)
-- new ClassProperty (line 81)
-- new ClassEntry (line 86)
-- new ClassProperty (line 90)
-- new ClassEntry (line 95)
-- new ClassProperty (line 97)
-- new PartsIteratorCurrent (line 99)
-- new PartsIteratorKey (line 100)
-- new PartsIteratorNext (line 101)
-- new PartsIteratorRewind (line 102)
-- new PartsIteratorValid (line 103)
-- new Variable (line 116)
-- new BreakIteratorCreateWordInstance (line 126)
-- new BreakIteratorCreateCharacterInstance (line 127)
-- new BreakIteratorCreateLineInstance (line 128)
-- new BreakIteratorCreateSentenceInstance (line 129)
-- new BreakIteratorCreateTitleInstance (line 130)
-- new BreakIteratorSetText (line 142)
-- new BreakIteratorGetText (line 143)
-- new BreakIteratorFirst (line 144)
-- new BreakIteratorLast (line 145)
-- new BreakIteratorNext (line 146)
-- new BreakIteratorPrevious (line 147)
-- new BreakIteratorCurrent (line 148)
-- new BreakIteratorGetPartsIterator (line 149)
-- new ObjectEntry (line 164)
-- new ObjectEntry (line 322)
-- new ArgumentCountError (line 590)
-- new ArgumentCountError (line 642)
-- 50 class method(s)
+- new Variable (line 78)
+- new ClassEntry (line 81)
+- new ClassProperty (line 85)
+- new ClassEntry (line 90)
+- new ClassProperty (line 94)
+- new ClassEntry (line 99)
+- new ClassProperty (line 101)
+- new PartsIteratorCurrent (line 103)
+- new PartsIteratorKey (line 104)
+- new PartsIteratorNext (line 105)
+- new PartsIteratorRewind (line 106)
+- new PartsIteratorValid (line 107)
+- new Variable (line 120)
+- new BreakIteratorCreateWordInstance (line 130)
+- new BreakIteratorCreateCharacterInstance (line 131)
+- new BreakIteratorCreateLineInstance (line 132)
+- new BreakIteratorCreateSentenceInstance (line 133)
+- new BreakIteratorCreateTitleInstance (line 134)
+- new BreakIteratorSetText (line 146)
+- new BreakIteratorGetText (line 147)
+- new BreakIteratorFirst (line 148)
+- new BreakIteratorLast (line 149)
+- new BreakIteratorNext (line 150)
+- new BreakIteratorPrevious (line 151)
+- new BreakIteratorCurrent (line 152)
+- new BreakIteratorPreceding (line 153)
+- new BreakIteratorFollowing (line 154)
+- new BreakIteratorIsBoundary (line 155)
+- new BreakIteratorGetLocale (line 156)
+- new BreakIteratorGetErrorCode (line 157)
+- new BreakIteratorGetErrorMessage (line 158)
+- new BreakIteratorGetPartsIterator (line 159)
+- new ObjectEntry (line 174)
+- new ObjectEntry (line 446)
+- new ArgumentCountError (line 714)
+- new ArgumentCountError (line 766)
+- new ArgumentCountError (line 865)
+- new ArgumentCountError (line 885)
+- new ArgumentCountError (line 905)
+- new ArgumentCountError (line 925)
+- new ArgumentCountError (line 946)
+- new ArgumentCountError (line 965)
+- 65 class method(s)
### `ext/intl/VmCollator.php`
@@ -41620,111 +41632,111 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
- new Variable (line 9115)
- new Variable (line 9122)
- new Variable (line 9139)
-- new VM\NativeFiberStackOverflow (line 9953)
-- new VM\BuiltinCallbackCatchRedirect (line 10004)
-- new VM\BuiltinCallbackCatchRedirect (line 10022)
-- new Variable (line 10125)
-- new Variable (line 10233)
-- new Variable (line 10366)
-- new ScriptExit (line 10522)
-- new Exception (line 10539)
-- new ScriptExit (line 10547)
-- new Error (line 10810)
-- new VM\PropertyHookRefWriteSignal (line 10858)
-- new Variable (line 10882)
-- new VM\PropertyHookRefWriteSignal (line 10887)
-- new VM\PropertyHookFiberSuspendSignal (line 10890)
-- new VM\PropertyHookRefWriteSignal (line 11012)
-- new Variable (line 11029)
-- new VM\PropertyHookRefWriteSignal (line 11043)
-- new VM\PropertyHookRefWriteSignal (line 11055)
-- new Variable (line 11286)
-- new Variable (line 11309)
-- new Variable (line 11319)
-- new Variable (line 11329)
-- new VM\PropertyHookRefWriteSignal (line 11335)
-- new VM\PropertyHookRefWriteSignal (line 11343)
-- new VM\PropertyHookRefWriteSignal (line 11346)
-- new Variable (line 11358)
-- new Variable (line 11372)
-- new VM\PropertyHookRefWriteSignal (line 11378)
-- new Variable (line 11409)
-- new VM\PropertyHookRefWriteSignal (line 11414)
-- new VM\PropertyHookFiberSuspendSignal (line 11417)
-- new Error (line 11916)
-- new Error (line 11926)
-- new Error (line 11936)
-- new Error (line 11946)
-- new ClassEntry (line 12716)
-- new Variable (line 12717)
-- new VM\ClassProperty (line 12718)
-- new ObjectEntry (line 12721)
-- new Variable (line 12724)
-- new Variable (line 12805)
-- new Error (line 12891)
-- new Variable (line 12983)
-- new VM\GeneratorUncaughtThrow (line 12985)
-- new Error (line 13054)
-- new Variable (line 13099)
-- new VM\GeneratorUncaughtThrow (line 13113)
-- new Variable (line 13202)
-- new VM\GeneratorUncaughtThrow (line 13222)
-- new Variable (line 13290)
-- new Variable (line 13292)
-- new Variable (line 13296)
-- new Variable (line 13426)
-- new Variable (line 13468)
-- new Variable (line 13639)
-- new Variable (line 13655)
-- new Variable (line 13700)
-- new Variable (line 13841)
-- new Variable (line 13915)
-- new Variable (line 14079)
-- new VM\PropertyIsInitializedHandler (line 14088)
-- new Error (line 14203)
-- new VM\EnumFromHandler (line 14228)
-- new CompileError (line 14954)
-- new VM\ClassProperty (line 15119)
-- new Variable (line 15427)
-- new Variable (line 15622)
-- new Variable (line 15624)
-- new ClassEntry (line 15667)
-- new Func\PHP (line 15674)
-- new VM\ClassProperty (line 15802)
-- new Func\PHP (line 15949)
-- new Variable (line 16025)
-- new Variable (line 16032)
-- new Variable (line 16038)
-- new Variable (line 16075)
-- new Variable (line 16104)
-- new Variable (line 16289)
-- new Variable (line 16335)
-- new VM\ClassProperty (line 16400)
-- new Error (line 16446)
-- new Error (line 16481)
-- new Error (line 16484)
-- new Error (line 16487)
-- new Error (line 16490)
-- new ObjectEntry (line 16492)
-- new Error (line 16505)
-- new Error (line 16508)
-- new Error (line 16511)
+- new VM\NativeFiberStackOverflow (line 9972)
+- new VM\BuiltinCallbackCatchRedirect (line 10023)
+- new VM\BuiltinCallbackCatchRedirect (line 10041)
+- new Variable (line 10144)
+- new Variable (line 10252)
+- new Variable (line 10385)
+- new ScriptExit (line 10541)
+- new Exception (line 10558)
+- new ScriptExit (line 10566)
+- new Error (line 10829)
+- new VM\PropertyHookRefWriteSignal (line 10877)
+- new Variable (line 10901)
+- new VM\PropertyHookRefWriteSignal (line 10906)
+- new VM\PropertyHookFiberSuspendSignal (line 10909)
+- new VM\PropertyHookRefWriteSignal (line 11031)
+- new Variable (line 11048)
+- new VM\PropertyHookRefWriteSignal (line 11062)
+- new VM\PropertyHookRefWriteSignal (line 11074)
+- new Variable (line 11305)
+- new Variable (line 11328)
+- new Variable (line 11338)
+- new Variable (line 11348)
+- new VM\PropertyHookRefWriteSignal (line 11354)
+- new VM\PropertyHookRefWriteSignal (line 11362)
+- new VM\PropertyHookRefWriteSignal (line 11365)
+- new Variable (line 11377)
+- new Variable (line 11391)
+- new VM\PropertyHookRefWriteSignal (line 11397)
+- new Variable (line 11428)
+- new VM\PropertyHookRefWriteSignal (line 11433)
+- new VM\PropertyHookFiberSuspendSignal (line 11436)
+- new Error (line 11935)
+- new Error (line 11945)
+- new Error (line 11955)
+- new Error (line 11965)
+- new ClassEntry (line 12735)
+- new Variable (line 12736)
+- new VM\ClassProperty (line 12737)
+- new ObjectEntry (line 12740)
+- new Variable (line 12743)
+- new Variable (line 12824)
+- new Error (line 12910)
+- new Variable (line 13002)
+- new VM\GeneratorUncaughtThrow (line 13004)
+- new Error (line 13073)
+- new Variable (line 13118)
+- new VM\GeneratorUncaughtThrow (line 13132)
+- new Variable (line 13221)
+- new VM\GeneratorUncaughtThrow (line 13241)
+- new Variable (line 13309)
+- new Variable (line 13311)
+- new Variable (line 13315)
+- new Variable (line 13445)
+- new Variable (line 13487)
+- new Variable (line 13658)
+- new Variable (line 13674)
+- new Variable (line 13719)
+- new Variable (line 13860)
+- new Variable (line 13934)
+- new Variable (line 14098)
+- new VM\PropertyIsInitializedHandler (line 14107)
+- new Error (line 14222)
+- new VM\EnumFromHandler (line 14247)
+- new CompileError (line 14973)
+- new VM\ClassProperty (line 15138)
+- new Variable (line 15446)
+- new Variable (line 15641)
+- new Variable (line 15643)
+- new ClassEntry (line 15686)
+- new Func\PHP (line 15693)
+- new VM\ClassProperty (line 15821)
+- new Func\PHP (line 15968)
+- new Variable (line 16044)
+- new Variable (line 16051)
+- new Variable (line 16057)
+- new Variable (line 16094)
+- new Variable (line 16123)
+- new Variable (line 16308)
+- new Variable (line 16354)
+- new VM\ClassProperty (line 16419)
+- new Error (line 16465)
+- new Error (line 16500)
+- new Error (line 16503)
+- new Error (line 16506)
+- new Error (line 16509)
+- new ObjectEntry (line 16511)
+- new Error (line 16524)
+- new Error (line 16527)
- new Error (line 16530)
-- new ObjectEntry (line 16534)
-- new Variable (line 16536)
-- new Variable (line 16550)
-- new Variable (line 16577)
-- new Variable (line 16590)
-- new Error (line 16720)
-- new Error (line 16725)
-- new VM\ObjectEntry (line 16729)
-- new Variable (line 16873)
-- new Variable (line 16891)
-- new NoDiscardMetadata (line 17060)
-- new Variable (line 17229)
-- new Variable (line 17231)
-- new Variable (line 17331)
-- 488 class method(s)
+- new Error (line 16549)
+- new ObjectEntry (line 16553)
+- new Variable (line 16555)
+- new Variable (line 16569)
+- new Variable (line 16596)
+- new Variable (line 16609)
+- new Error (line 16739)
+- new Error (line 16744)
+- new VM\ObjectEntry (line 16748)
+- new Variable (line 16892)
+- new Variable (line 16910)
+- new NoDiscardMetadata (line 17079)
+- new Variable (line 17248)
+- new Variable (line 17250)
+- new Variable (line 17350)
+- 489 class method(s)
- 25 closure(s)
### `lib/VM/AbstractPropertyHookCheck.php`
@@ -44316,10 +44328,10 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
### `lib/VM/BuiltinExceptionSupport.php`
**Warnings** (review for bootstrap subset):
-- new ObjectEntry (line 544)
-- new Variable (line 548)
-- new ObjectEntry (line 564)
-- new Variable (line 568)
+- new ObjectEntry (line 554)
+- new Variable (line 558)
+- new ObjectEntry (line 574)
+- new Variable (line 578)
- 37 class method(s)
### `lib/VM/BuiltinExecute.php`
@@ -44754,18 +44766,18 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
### `lib/VM/ExceptionSupport.php`
**Warnings** (review for bootstrap subset):
-- new ReflectionObject (line 364)
-- new ScriptExit (line 386)
-- new ScriptExit (line 416)
-- new ErrorException (line 572)
-- new SoapFault (line 602)
-- new Error (line 615)
-- new FiberStackOverflow (line 618)
-- new Error (line 620)
-- new Error (line 623)
-- new Exception (line 625)
-- new Exception (line 647)
-- new Error (line 655)
+- new ReflectionObject (line 365)
+- new ScriptExit (line 387)
+- new ScriptExit (line 417)
+- new ErrorException (line 573)
+- new SoapFault (line 603)
+- new Error (line 616)
+- new FiberStackOverflow (line 619)
+- new Error (line 621)
+- new Error (line 624)
+- new Exception (line 626)
+- new Exception (line 648)
+- new Error (line 656)
- 26 class method(s)
### `lib/VM/ExceptionTrace.php`
diff --git a/ext/intl/VmBreakIterator.php b/ext/intl/VmBreakIterator.php
index 957c70b886b..4b1ff37c92e 100644
--- a/ext/intl/VmBreakIterator.php
+++ b/ext/intl/VmBreakIterator.php
@@ -11,6 +11,7 @@
use PHPCompiler\VM\Context;
use PHPCompiler\VM\ObjectEntry;
use PHPCompiler\VM\Variable;
+use PHPCompiler\VM\ReflectionSupport;
use PHPCfg\Func as CfgFunc;
/**
@@ -29,6 +30,9 @@ final class VmBreakIterator
private const UBRK_WORD = 1;
private const UBRK_LINE = 2;
private const UBRK_SENTENCE = 3;
+ /** ULOC_ACTUAL_LOCALE / ULOC_VALID_LOCALE — php-src Locale::ACTUAL_LOCALE / VALID_LOCALE */
+ private const ULOC_ACTUAL_LOCALE = 0;
+ private const ULOC_VALID_LOCALE = 1;
private const PROP_HANDLE = '__breakiterator_id';
/** @var array> */
@@ -146,6 +150,12 @@ private static function installInstanceMethods(ClassEntry $entry, int $vis): voi
'next' => [new BreakIteratorNext(), 'next'],
'previous' => [new BreakIteratorPrevious(), 'previous'],
'current' => [new BreakIteratorCurrent(), 'current'],
+ 'preceding' => [new BreakIteratorPreceding(), 'preceding'],
+ 'following' => [new BreakIteratorFollowing(), 'following'],
+ 'isboundary' => [new BreakIteratorIsBoundary(), 'isBoundary'],
+ 'getlocale' => [new BreakIteratorGetLocale(), 'getLocale'],
+ 'geterrorcode' => [new BreakIteratorGetErrorCode(), 'getErrorCode'],
+ 'geterrormessage' => [new BreakIteratorGetErrorMessage(), 'getErrorMessage'],
'getpartsiterator' => [new BreakIteratorGetPartsIterator(), 'getPartsIterator'],
];
foreach ($methods as $lc => [$handler, $name]) {
@@ -172,8 +182,11 @@ public static function createInstance(Context $ctx, int $type, ?string $locale):
'boundaries' => [0],
'parts' => null,
'index' => 0,
+ 'errorCode' => IntlError::U_ZERO_ERROR,
+ 'errorMessage' => 'U_ZERO_ERROR',
];
$obj->constructed = true;
+ self::clearObjectError($obj);
IntlError::clear();
return $obj;
@@ -216,6 +229,7 @@ public static function setText(ObjectEntry $obj, string $text): bool
$st['text'] = $text;
$st['boundaries'] = self::computeBoundaries((int) $st['type'], (string) $st['locale'], $text);
$st['pos'] = $st['boundaries'][0] ?? 0;
+ self::clearObjectError($obj);
IntlError::clear();
return true;
@@ -261,11 +275,15 @@ public static function nextPos(ObjectEntry $obj, ?int $offset = null): int
foreach ($bounds as $b) {
if ($b > $offset) {
$st['pos'] = $b;
+ self::clearObjectError($obj);
+ IntlError::clear();
return (int) $b;
}
}
$st['pos'] = self::DONE;
+ self::clearObjectError($obj);
+ IntlError::clear();
return self::DONE;
}
@@ -299,6 +317,112 @@ public static function previousPos(ObjectEntry $obj): int
return $prev;
}
+ /**
+ * preceding($offset) — largest boundary strictly before $offset (ICU ubrk_preceding; #20771).
+ */
+ public static function preceding(ObjectEntry $obj, int $offset): int
+ {
+ $st = &self::stateRef($obj);
+ $prev = self::DONE;
+ foreach ($st['boundaries'] as $b) {
+ $b = (int) $b;
+ if ($b >= $offset) {
+ break;
+ }
+ $prev = $b;
+ }
+ $st['pos'] = $prev;
+ self::clearObjectError($obj);
+ IntlError::clear();
+
+ return $prev;
+ }
+
+ /**
+ * following($offset) — first boundary strictly after $offset (ICU ubrk_following; #20771).
+ */
+ public static function following(ObjectEntry $obj, int $offset): int
+ {
+ return self::nextPos($obj, $offset);
+ }
+
+ /**
+ * isBoundary($offset) — whether $offset is a break; advances to first boundary at/after offset
+ * (ICU ubrk_isBoundary; #20771).
+ */
+ public static function isBoundary(ObjectEntry $obj, int $offset): bool
+ {
+ $st = &self::stateRef($obj);
+ $bounds = $st['boundaries'];
+ $is = \in_array($offset, $bounds, true);
+ $atOrAfter = self::DONE;
+ foreach ($bounds as $b) {
+ $b = (int) $b;
+ if ($b >= $offset) {
+ $atOrAfter = $b;
+ break;
+ }
+ }
+ $st['pos'] = $atOrAfter;
+ self::clearObjectError($obj);
+ IntlError::clear();
+
+ return $is;
+ }
+
+ /**
+ * getLocale($type) — ULOC_ACTUAL_LOCALE / ULOC_VALID_LOCALE (php-src breakiterator_get_locale; #20771).
+ *
+ * Without a live UBreakIterator handle, VALID returns the factory locale and ACTUAL is ''
+ * (matches Zend ICU for createWordInstance('en_US')).
+ *
+ * @return string|false
+ */
+ public static function getLocale(ObjectEntry $obj, int $type)
+ {
+ $st = self::stateRef($obj);
+ self::clearObjectError($obj);
+ IntlError::clear();
+ if (self::ULOC_ACTUAL_LOCALE === $type) {
+ return '';
+ }
+ if (self::ULOC_VALID_LOCALE === $type) {
+ return (string) $st['locale'];
+ }
+ self::fail($obj, 'breakiterator_get_locale: bad type: U_ILLEGAL_ARGUMENT_ERROR');
+
+ return false;
+ }
+
+ public static function getErrorCode(ObjectEntry $obj): int
+ {
+ $st = self::stateRef($obj);
+
+ return (int) ($st['errorCode'] ?? IntlError::U_ZERO_ERROR);
+ }
+
+ public static function getErrorMessage(ObjectEntry $obj): string
+ {
+ $st = self::stateRef($obj);
+
+ return (string) ($st['errorMessage'] ?? 'U_ZERO_ERROR');
+ }
+
+ private static function clearObjectError(ObjectEntry $obj): void
+ {
+ $st = &self::stateRef($obj);
+ $st['errorCode'] = IntlError::U_ZERO_ERROR;
+ $st['errorMessage'] = 'U_ZERO_ERROR';
+ }
+
+ private static function fail(ObjectEntry $obj, string $message): void
+ {
+ IntlError::set(IntlError::U_ILLEGAL_ARGUMENT_ERROR, $message);
+ $st = &self::stateRef($obj);
+ $st['errorCode'] = IntlError::U_ILLEGAL_ARGUMENT_ERROR;
+ $st['errorMessage'] = $message;
+ }
+
/** @return list */
public static function parts(ObjectEntry $obj): array
{
@@ -731,6 +855,152 @@ public function execute(Frame $frame): void
}
}
+final class BreakIteratorPreceding extends VmClassMethod
+{
+ public function __construct() { parent::__construct('preceding'); }
+ public function execute(Frame $frame): void
+ {
+ $argc = \count($frame->calledArgs);
+ if ($argc !== 2) {
+ throw new \ArgumentCountError(sprintf(
+ 'IntlBreakIterator::preceding() expects exactly 1 argument, %d given',
+ max(0, $argc - 1)
+ ));
+ }
+ $obj = VmBreakIterator::requireBreakIterator($frame, $frame->calledArgs[0]);
+ $offset = BreakIteratorOffsetArg::coerce($frame->calledArgs[1], 'IntlBreakIterator::preceding');
+ if (null !== $frame->returnVar) {
+ $frame->returnVar->int(VmBreakIterator::preceding($obj, $offset));
+ }
+ }
+}
+
+final class BreakIteratorFollowing extends VmClassMethod
+{
+ public function __construct() { parent::__construct('following'); }
+ public function execute(Frame $frame): void
+ {
+ $argc = \count($frame->calledArgs);
+ if ($argc !== 2) {
+ throw new \ArgumentCountError(sprintf(
+ 'IntlBreakIterator::following() expects exactly 1 argument, %d given',
+ max(0, $argc - 1)
+ ));
+ }
+ $obj = VmBreakIterator::requireBreakIterator($frame, $frame->calledArgs[0]);
+ $offset = BreakIteratorOffsetArg::coerce($frame->calledArgs[1], 'IntlBreakIterator::following');
+ if (null !== $frame->returnVar) {
+ $frame->returnVar->int(VmBreakIterator::following($obj, $offset));
+ }
+ }
+}
+
+final class BreakIteratorIsBoundary extends VmClassMethod
+{
+ public function __construct() { parent::__construct('isBoundary'); }
+ public function execute(Frame $frame): void
+ {
+ $argc = \count($frame->calledArgs);
+ if ($argc !== 2) {
+ throw new \ArgumentCountError(sprintf(
+ 'IntlBreakIterator::isBoundary() expects exactly 1 argument, %d given',
+ max(0, $argc - 1)
+ ));
+ }
+ $obj = VmBreakIterator::requireBreakIterator($frame, $frame->calledArgs[0]);
+ $offset = BreakIteratorOffsetArg::coerce($frame->calledArgs[1], 'IntlBreakIterator::isBoundary');
+ if (null !== $frame->returnVar) {
+ $frame->returnVar->bool(VmBreakIterator::isBoundary($obj, $offset));
+ }
+ }
+}
+
+final class BreakIteratorGetLocale extends VmClassMethod
+{
+ public function __construct() { parent::__construct('getLocale'); }
+ public function execute(Frame $frame): void
+ {
+ $argc = \count($frame->calledArgs);
+ if ($argc !== 2) {
+ throw new \ArgumentCountError(sprintf(
+ 'IntlBreakIterator::getLocale() expects exactly 1 argument, %d given',
+ max(0, $argc - 1)
+ ));
+ }
+ $obj = VmBreakIterator::requireBreakIterator($frame, $frame->calledArgs[0]);
+ $type = BreakIteratorOffsetArg::coerce($frame->calledArgs[1], 'IntlBreakIterator::getLocale', 'type');
+ $result = VmBreakIterator::getLocale($obj, $type);
+ if (null !== $frame->returnVar) {
+ false === $result ? $frame->returnVar->bool(false) : $frame->returnVar->string($result);
+ }
+ }
+}
+
+final class BreakIteratorGetErrorCode extends VmClassMethod
+{
+ public function __construct() { parent::__construct('getErrorCode'); }
+ public function execute(Frame $frame): void
+ {
+ $argc = \count($frame->calledArgs);
+ if ($argc !== 1) {
+ throw new \ArgumentCountError(sprintf(
+ 'IntlBreakIterator::getErrorCode() expects exactly 0 arguments, %d given',
+ max(0, $argc - 1)
+ ));
+ }
+ $obj = VmBreakIterator::requireBreakIterator($frame, $frame->calledArgs[0]);
+ if (null !== $frame->returnVar) {
+ $frame->returnVar->int(VmBreakIterator::getErrorCode($obj));
+ }
+ }
+}
+
+final class BreakIteratorGetErrorMessage extends VmClassMethod
+{
+ public function __construct() { parent::__construct('getErrorMessage'); }
+ public function execute(Frame $frame): void
+ {
+ $argc = \count($frame->calledArgs);
+ if ($argc !== 1) {
+ throw new \ArgumentCountError(sprintf(
+ 'IntlBreakIterator::getErrorMessage() expects exactly 0 arguments, %d given',
+ max(0, $argc - 1)
+ ));
+ }
+ $obj = VmBreakIterator::requireBreakIterator($frame, $frame->calledArgs[0]);
+ if (null !== $frame->returnVar) {
+ $frame->returnVar->string(VmBreakIterator::getErrorMessage($obj));
+ }
+ }
+}
+
+/** Coerce int offset / locale-type args for BreakIterator (#20771). */
+final class BreakIteratorOffsetArg
+{
+ public static function coerce(Variable $arg, string $method, string $param = 'offset'): int
+ {
+ $arg = $arg->resolveIndirect();
+ if (Variable::TYPE_INTEGER === $arg->type) {
+ return $arg->toInt();
+ }
+ if (Variable::TYPE_FLOAT === $arg->type) {
+ return (int) $arg->toFloat();
+ }
+ if (Variable::TYPE_BOOLEAN === $arg->type) {
+ return $arg->toBool() ? 1 : 0;
+ }
+ if (Variable::TYPE_STRING === $arg->type && is_numeric($arg->toString())) {
+ return (int) $arg->toString();
+ }
+ throw new \TypeError(sprintf(
+ '%s(): Argument #1 ($%s) must be of type int, %s given',
+ $method,
+ $param,
+ ReflectionSupport::valueTypeLabelPublic($arg)
+ ));
+ }
+}
+
final class BreakIteratorGetPartsIterator extends VmClassMethod
{
public function __construct() { parent::__construct('getPartsIterator'); }
diff --git a/test/compliance/JITTest.php b/test/compliance/JITTest.php
index 57c1ea6488a..8be64a62779 100755
--- a/test/compliance/JITTest.php
+++ b/test/compliance/JITTest.php
@@ -641,7 +641,8 @@ public static function providePHPTests(): \Generator
|| str_contains($name, 'intl_skeleton')
|| str_contains($name, 'intl_char')
|| str_contains($name, 'intl_uconverter')
- || str_contains($name, 'collator_'))
+ || str_contains($name, 'collator_')
+ || str_contains($name, 'breakiterator'))
&& !str_contains($name, 'intl_phantom')) {
continue;
}
@@ -1395,6 +1396,11 @@ public static function providePHPTests(): \Generator
if (str_contains($name, 'resourcebundle_locales_errors')) {
continue;
}
+ // IntlBreakIterator preceding/following: VM + bin/jit.php repro green (#20771);
+ // MCJIT PHPT harness hits WeakRefNativeOpsJit::nullSlot getValue() abort (same as above).
+ if (str_contains($name, 'breakiterator_preceding_following')) {
+ continue;
+ }
// Phar instance API: VM green (#20628); jit.php hits MathBaseConvertRuntime::constFloat
// (hexdec/WeakRef bootstrap) same as curl_share_init_persistent.
if (str_contains($name, 'phar_instance_api')) {
diff --git a/test/compliance/VMTest.php b/test/compliance/VMTest.php
index abacaa02d47..4f524c38d49 100755
--- a/test/compliance/VMTest.php
+++ b/test/compliance/VMTest.php
@@ -526,7 +526,8 @@ public static function providePHPTests(): \Generator
|| str_contains($name, 'intl_skeleton')
|| str_contains($name, 'intl_char')
|| str_contains($name, 'intl_uconverter')
- || str_contains($name, 'collator_'))
+ || str_contains($name, 'collator_')
+ || str_contains($name, 'breakiterator'))
&& !str_contains($name, 'intl_phantom')) {
continue;
}
diff --git a/test/compliance/cases/intl/breakiterator_preceding_following.php b/test/compliance/cases/intl/breakiterator_preceding_following.php
new file mode 100644
index 00000000000..2304f5380e4
--- /dev/null
+++ b/test/compliance/cases/intl/breakiterator_preceding_following.php
@@ -0,0 +1,17 @@
+setText('Hello world');
+echo 'preceding=', method_exists($bi, 'preceding') ? '1' : '0', "\n";
+echo 'following=', method_exists($bi, 'following') ? '1' : '0', "\n";
+echo 'isBoundary=', method_exists($bi, 'isBoundary') ? '1' : '0', "\n";
+echo 'getLocale=', method_exists($bi, 'getLocale') ? '1' : '0', "\n";
+echo 'preceding6=', $bi->preceding(6), "\n";
+echo 'cur=', $bi->current(), "\n";
+echo 'following6=', $bi->following(6), "\n";
+echo 'b5=', (int) $bi->isBoundary(5), "\n";
+echo 'b6=', (int) $bi->isBoundary(6), "\n";
+echo 'b7=', (int) $bi->isBoundary(7), "\n";
+echo 'actual=', var_export($bi->getLocale(0), true), "\n";
+echo 'valid=', var_export($bi->getLocale(1), true), "\n";
+echo 'err=', $bi->getErrorCode(), ':', $bi->getErrorMessage(), "\n";
diff --git a/test/compliance/cases/intl/breakiterator_preceding_following.phpt b/test/compliance/cases/intl/breakiterator_preceding_following.phpt
new file mode 100644
index 00000000000..9f25d52ac8c
--- /dev/null
+++ b/test/compliance/cases/intl/breakiterator_preceding_following.phpt
@@ -0,0 +1,24 @@
+--TEST--
+IntlBreakIterator preceding/following/isBoundary/getLocale (#20771)
+--SKIPIF--
+
+--RUNFILE--
+breakiterator_preceding_following.php
+--EXPECT--
+preceding=1
+following=1
+isBoundary=1
+getLocale=1
+preceding6=5
+cur=5
+following6=11
+b5=1
+b6=1
+b7=0
+actual=''
+valid='en_US'
+err=0:U_ZERO_ERROR
diff --git a/test/repro/issue_20771_breakiterator_preceding.php b/test/repro/issue_20771_breakiterator_preceding.php
new file mode 100644
index 00000000000..784c0c19a73
--- /dev/null
+++ b/test/repro/issue_20771_breakiterator_preceding.php
@@ -0,0 +1,17 @@
+setText('Hello world');
+foreach (['preceding', 'following', 'isBoundary', 'getLocale', 'getErrorCode', 'getErrorMessage'] as $m) {
+ echo $m, '=', method_exists($bi, $m) ? '1' : '0', "\n";
+}
+echo 'preceding6=', $bi->preceding(6), "\n";
+echo 'current_after_preceding=', $bi->current(), "\n";
+echo 'following6=', $bi->following(6), "\n";
+echo 'isBoundary5=', (int) $bi->isBoundary(5), "\n";
+echo 'isBoundary6=', (int) $bi->isBoundary(6), "\n";
+echo 'isBoundary7=', (int) $bi->isBoundary(7), "\n";
+// ULOC_ACTUAL_LOCALE=0 / ULOC_VALID_LOCALE=1 (Locale::ACTUAL_LOCALE / VALID_LOCALE)
+echo 'locale_actual=', var_export($bi->getLocale(0), true), "\n";
+echo 'locale_valid=', var_export($bi->getLocale(1), true), "\n";
+echo 'err=', $bi->getErrorCode(), ':', $bi->getErrorMessage(), "\n";
diff --git a/test/unit/IntlModuleTest.php b/test/unit/IntlModuleTest.php
index 6b47ba93427..cbbd8faf161 100644
--- a/test/unit/IntlModuleTest.php
+++ b/test/unit/IntlModuleTest.php
@@ -222,4 +222,30 @@ public function test_breakiterator_word_parts_via_forced_registration(): void
ob_get_clean()
);
}
+
+ public function test_breakiterator_preceding_following_locale_via_forced_registration(): void
+ {
+ $runtime = new Runtime();
+ \PHPCompiler\ext\intl\BuiltinClasses::registerBreakIterator($runtime->vmContext);
+ $code = <<<'PHP'
+setText('Hello world');
+echo (int) method_exists($bi, 'preceding'), "\n";
+echo $bi->preceding(6), "\n";
+echo $bi->current(), "\n";
+echo $bi->following(6), "\n";
+echo (int) $bi->isBoundary(5), (int) $bi->isBoundary(6), (int) $bi->isBoundary(7), "\n";
+echo var_export($bi->getLocale(0), true), "\n";
+echo var_export($bi->getLocale(1), true), "\n";
+echo $bi->getErrorCode(), ':', $bi->getErrorMessage(), "\n";
+PHP;
+ $block = $runtime->parseAndCompile($code, 'intl_breakiterator_preceding.php');
+ ob_start();
+ $runtime->run($block);
+ self::assertSame(
+ "1\n5\n5\n11\n110\n''\n'en_US'\n0:U_ZERO_ERROR\n",
+ ob_get_clean()
+ );
+ }
}
From d026692f07e6cc1418fb34fd8e18239caf439787 Mon Sep 17 00:00:00 2001
From: PurHur
Date: Sun, 19 Jul 2026 01:49:21 +0000
Subject: [PATCH 2/3] Docs: sync spine footnotes + inventory after #20776
rebase
ci-fast auto-heal for 5831/5831 footnotes and VmDom construct-flag refresh.
Co-authored-by: Cursor
---
README.md | 8 ++++----
docs/bootstrap-inventory.md | 6 +++---
docs/bootstrap-profile.json | 8 ++++++--
docs/bootstrap-selfhost.md | 6 +++---
docs/pages/development-status.md | 12 ++++++------
docs/pages/index.html | 10 +++++-----
docs/roadmap-wave3.md | 6 +++---
docs/self-host-target.md | 8 ++++----
test/unit/BootstrapSelfhostBundleTest.php | 2 +-
9 files changed, 35 insertions(+), 31 deletions(-)
diff --git a/README.md b/README.md
index 8a8f38e0fec..5b9b3e139b9 100755
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@
> **Stable line (2026)** — First maintained **stable** release **[v1.0.0](https://github.com/PurHur/php-compiler/releases/tag/v1.0.0)**; **v1.1.0** prep adds M5 fast-path stability, enum/property-hook parity, `preg_match` JIT, `spl_autoload*`, and php-in-PHP JIT helpers. Demo-ready VM + AOT for a **web-capable PHP subset**, reference examples **000–009**, and an experimental **self-host** path. Not full Zend PHP compatibility — see [what’s missing](https://purhur.github.io/php-compiler/docs/pages/missing-implementation.html).
-**Snapshot (Jul 2026, `master` — v1.1.0 prep):** VM + AOT for shipped examples ✅ · examples web smoke ✅ · self-host spine **5809** / **5809** · **852** builtins · M5 fast + strict ✅ · VM probe ~**20ms**
+**Snapshot (Jul 2026, `master` — v1.1.0 prep):** VM + AOT for shipped examples ✅ · examples web smoke ✅ · self-host spine **5831** / **5831** · **852** builtins · M5 fast + strict ✅ · VM probe ~**20ms**
---
@@ -23,7 +23,7 @@
| **AOT (`phpc build`)** | ✅ For curated subset | Standalone binaries for examples **000–009** and small CGI apps; not arbitrary Composer stacks |
| **JIT (`bin/jit.php`)** | 🚧 Partial | LLVM IR for many constructs; **MCJIT execute** still flaky ([#98](https://github.com/PurHur/php-compiler/issues/98)); EH scripts VM-fallback ([#2114](https://github.com/PurHur/php-compiler/issues/2114)) |
| **Language wave 3** | ✅ Closed batch | **12/12** language + **13/13** stdlib tracker items ([#1380](https://github.com/PurHur/php-compiler/issues/1380)); closures, try/catch, generators (VM), `parent::class`, backed enums (VM), intersection AOT checks |
-| **Self-host north star** | ✅ ~90% | M5 fast gate green; spine **5809** / **5809**; vendor prelink **3/3** ([#1492](https://github.com/PurHur/php-compiler/issues/1492)) |
+| **Self-host north star** | ✅ ~90% | M5 fast gate green; spine **5831** / **5831**; vendor prelink **3/3** ([#1492](https://github.com/PurHur/php-compiler/issues/1492)) |
### What you can rely on today
@@ -40,7 +40,7 @@ Counts from `php script/bootstrap-spine-count.php` (literal `require_once` in `c
| Milestone | Status | What it means |
|-----------|--------|----------------|
| **M0–M1** | ✅ | `compiler_minimal` + compile-smoke bundles link and run natively |
-| **M2** | ✅ **5809** / **5809** | Full Phase A inventory in spine smoke; native link + lint ✅ |
+| **M2** | ✅ **5831** / **5831** | Full Phase A inventory in spine smoke; native link + lint ✅ |
| **M3** | ✅ | HelloWorld strict native ✅; inventory argv `bin/compile.php` ✅ |
| **M4** | ✅ | `make bootstrap-loop-probe` full ladder ✅ (gen-1→gen-2→gen-3 + full-revision) |
| **M5** | ✅ | `make north-star5-verify-fast` (daily); `--strict` pre-merge ✅; vendor **3/3** ✅; gen-0 sidecars refreshed |
@@ -259,7 +259,7 @@ Full matrices (auto-generated): [`docs/capabilities.md`](docs/capabilities.md) (
**Self-host (experimental, not “stable app” scope)**
-See [Current implementation status](#current-implementation-status-june-2026) for the full M0–M5 ladder. Summary: M0–M5 bootstrap gates ✅; spine **5809** / **5809**; M3 strict native + inventory argv ✅; M4 full `bootstrap-loop-probe` ✅; M5 **`north-star5-verify-fast`** (daily) + **`--strict`** pre-merge ✅ ([#1492](https://github.com/PurHur/php-compiler/issues/1492), [#8559](https://github.com/PurHur/php-compiler/issues/8559)). Recent: native spine bundle probe, fast VM execute smoke ([#2201](https://github.com/PurHur/php-compiler/issues/2201)), `GeneratorYieldSourceMarker` spine unit ([#10356](https://github.com/PurHur/php-compiler/pull/10356)).
+See [Current implementation status](#current-implementation-status-june-2026) for the full M0–M5 ladder. Summary: M0–M5 bootstrap gates ✅; spine **5831** / **5831**; M3 strict native + inventory argv ✅; M4 full `bootstrap-loop-probe` ✅; M5 **`north-star5-verify-fast`** (daily) + **`--strict`** pre-merge ✅ ([#1492](https://github.com/PurHur/php-compiler/issues/1492), [#8559](https://github.com/PurHur/php-compiler/issues/8559)). Recent: native spine bundle probe, fast VM execute smoke ([#2201](https://github.com/PurHur/php-compiler/issues/2201)), `GeneratorYieldSourceMarker` spine unit ([#10356](https://github.com/PurHur/php-compiler/pull/10356)).
**What we do not target in v1.x**
diff --git a/docs/bootstrap-inventory.md b/docs/bootstrap-inventory.md
index 6be6953ab21..0e148b03a3d 100644
--- a/docs/bootstrap-inventory.md
+++ b/docs/bootstrap-inventory.md
@@ -8481,9 +8481,9 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
- new DOMException (line 9459)
- new DOMException (line 9462)
- new DOMException (line 9491)
-- new Error (line 10402)
-- new Error (line 10406)
-- 426 class method(s)
+- new Error (line 10459)
+- new Error (line 10463)
+- 427 class method(s)
- 2 closure(s)
### `ext/dom/VmDomCollectionDimension.php`
diff --git a/docs/bootstrap-profile.json b/docs/bootstrap-profile.json
index ddc002fda3f..faa534cb30f 100644
--- a/docs/bootstrap-profile.json
+++ b/docs/bootstrap-profile.json
@@ -893,6 +893,10 @@
"ext/intl/normalizer_get_raw_decomposition.php",
"ext/intl/normalizer_is_normalized.php",
"ext/intl/normalizer_normalize.php",
+ "ext/intl/numfmt_create.php",
+ "ext/intl/numfmt_format.php",
+ "ext/intl/numfmt_format_currency.php",
+ "ext/intl/numfmt_parse.php",
"ext/intl/transliterator_create.php",
"ext/intl/transliterator_create_from_rules.php",
"ext/intl/transliterator_create_inverse.php",
@@ -6060,9 +6064,9 @@
"test/bootstrap-aot/lib_opcode/main.php"
],
"totals": {
- "inventory_files": 5827,
+ "inventory_files": 5831,
"excluded": 0,
- "eligible": 5827,
+ "eligible": 5831,
"aot_lint_targets": 113,
"aot_link_targets": 100,
"aot_link_lib_targets": 1
diff --git a/docs/bootstrap-selfhost.md b/docs/bootstrap-selfhost.md
index 247bcd9a809..9bb3e7f98bd 100644
--- a/docs/bootstrap-selfhost.md
+++ b/docs/bootstrap-selfhost.md
@@ -2,7 +2,7 @@
**Gen-0 without Zend:** `BOOTSTRAP_M5_NO_ZEND=1 make bootstrap-selfhost-link` installs `prelinked/bootstrap-gen0/bin-compile-aot` and links `compiler_minimal` without `php bin/compile.php` ([#3053](https://github.com/PurHur/php-compiler/issues/3053)). **M5 lib spine compile:** `BOOTSTRAP_NO_ZEND_FALLBACK=1 make bootstrap-selfhost-lib-spine-smoke` (default in link script) refuses host `php bin/compile.php` on the spine emit path ([#8716](https://github.com/PurHur/php-compiler/issues/8716)). **Contributor workflow:** [bootstrap-dev-workflow.md](bootstrap-dev-workflow.md) (tiered gen-1+ path, spine checklist, CI).
-**Project north star:** The **compiler fully compiles itself** — native AOT from `lib/` (no `vendor/` at cold boot), then compiles PHP and rebuilds the next compiler revision without Zend. **M2 spine:** **5809** / **5809** Phase A inventory (`php script/bootstrap-spine-count.php`; `check-selfhost-spine-coverage-sync.php`). **M5 daily gate:** `make north-star5-verify-fast` (~1–2 min) ✅; **`--strict`** (~1h) pre-merge only. Committed `prelinked/bootstrap-gen0/` sidecars + vendor **3/3** cold boot. **Hot loop:** VM driver execute probe ~**20ms**; full spine relink only with `BOOTSTRAP_VM_DRIVER_EXECUTE_PROBE_FULL_LINK=1` ([#2201](https://github.com/PurHur/php-compiler/issues/2201)). **Living tracker:** [#1492](https://github.com/PurHur/php-compiler/issues/1492) (was [#1056](https://github.com/PurHur/php-compiler/issues/1056)) · **re-root doc:** [self-host-target.md](self-host-target.md) · **generation ladder:** [bootstrap-generations.md](bootstrap-generations.md) · **M5 fast path:** [bootstrap-m5-fast-path.md](bootstrap-m5-fast-path.md) · public status: [development-status § North star](https://purhur.github.io/php-compiler/development-status.html#north-star-self-host). Parent tracking: [#78](https://github.com/PurHur/php-compiler/issues/78) (roadmap), [#212](https://github.com/PurHur/php-compiler/issues/212) (closed umbrella).
+**Project north star:** The **compiler fully compiles itself** — native AOT from `lib/` (no `vendor/` at cold boot), then compiles PHP and rebuilds the next compiler revision without Zend. **M2 spine:** **5831** / **5831** Phase A inventory (`php script/bootstrap-spine-count.php`; `check-selfhost-spine-coverage-sync.php`). **M5 daily gate:** `make north-star5-verify-fast` (~1–2 min) ✅; **`--strict`** (~1h) pre-merge only. Committed `prelinked/bootstrap-gen0/` sidecars + vendor **3/3** cold boot. **Hot loop:** VM driver execute probe ~**20ms**; full spine relink only with `BOOTSTRAP_VM_DRIVER_EXECUTE_PROBE_FULL_LINK=1` ([#2201](https://github.com/PurHur/php-compiler/issues/2201)). **Living tracker:** [#1492](https://github.com/PurHur/php-compiler/issues/1492) (was [#1056](https://github.com/PurHur/php-compiler/issues/1056)) · **re-root doc:** [self-host-target.md](self-host-target.md) · **generation ladder:** [bootstrap-generations.md](bootstrap-generations.md) · **M5 fast path:** [bootstrap-m5-fast-path.md](bootstrap-m5-fast-path.md) · public status: [development-status § North star](https://purhur.github.io/php-compiler/development-status.html#north-star-self-host). Parent tracking: [#78](https://github.com/PurHur/php-compiler/issues/78) (roadmap), [#212](https://github.com/PurHur/php-compiler/issues/212) (closed umbrella).
## Current gates
@@ -10,9 +10,9 @@
|------|---------|--------|
| Phase A inventory | `make bootstrap-inventory-check` | ✅ vm.php-path inventory; **0** source blockers; M2 ratio SSOT: `Phase A inventory files` row in `docs/bootstrap-inventory.md` (no ratio-deferred paths — [#2543](https://github.com/PurHur/php-compiler/issues/2543)); `lib/JIT/Builtin/StringPregMatch.php` and `lib/AOT/Linker.php` **included** in spine |
| Spine PHPCfg parse | `php script/bootstrap-spine-php-cfg-parse-check.php` (`--minimal` for M0 bundle) | ✅ no unsupported php-cfg expr/stmt on spine ([#2575](https://github.com/PurHur/php-compiler/issues/2575)); `BOOTSTRAP_SPINE_PHPCFG_PARSE_GATE=1` in `ci-fast.sh` |
-| Phase B lib AOT lint | `php bin/compile.php -l lib/*.php` (with `script/php-env.sh`) | ✅ **5809/5809** top-level `lib/*.php` units ([#534](https://github.com/PurHur/php-compiler/pull/534)) |
+| Phase B lib AOT lint | `php bin/compile.php -l lib/*.php` (with `script/php-env.sh`) | ✅ **5831/5831** top-level `lib/*.php` units ([#534](https://github.com/PurHur/php-compiler/pull/534)) |
| Phase B fixture lint | `php script/bootstrap-aot-lint.php` | ✅ **13** procedural targets under `test/bootstrap-aot/` + `examples/000-HelloWorld` |
-| Phase C native run | `make bootstrap-aot-link` or `./script/bootstrap-aot-link.sh` | ✅ **5809/5809** link targets OK |
+| Phase C native run | `make bootstrap-aot-link` or `./script/bootstrap-aot-link.sh` | ✅ **5831/5831** link targets OK |
| Phase D `lib/` link | `make bootstrap-aot-link-lib` or `./script/bootstrap-aot-link-lib.sh` | ✅ `test/bootstrap-aot/lib_opcode/main.php` bundles `lib/OpCode.php` ([#540](https://github.com/PurHur/php-compiler/issues/540)) |
| Bundled `lib/Compiler.php` lint | `./script/bootstrap-selfhost-lint.sh` | ✅ `test/selfhost/compiler_minimal/main.php` + literal `require_once` units toward `bin/vm.php` (no `vendor/`) ([#559](https://github.com/PurHur/php-compiler/issues/559)) |
| Compiler compile smoke lint | `php bin/compile.php -l test/selfhost/compiler_compile_smoke/main.php` | ✅ `compiler_minimal` bundle + literal `require_once` of `test/bootstrap-aot/compiler_smoke.php` (named function CFG) |
diff --git a/docs/pages/development-status.md b/docs/pages/development-status.md
index 8eaa206c4fe..a438e423d72 100644
--- a/docs/pages/development-status.md
+++ b/docs/pages/development-status.md
@@ -14,8 +14,8 @@ permalink: /development-status.html
| **What it is** | PHP → CFG → VM / LLVM JIT → AOT native binaries |
| **North star** | Compiler compiles itself without Zend ([#1492](https://github.com/PurHur/php-compiler/issues/1492)) |
| **v1.1.0 theme** | M5 fast-path stability; enum/property hooks; `preg_match` JIT; `spl_autoload*`; php-in-PHP JIT helpers ([#78](https://github.com/PurHur/php-compiler/issues/78)) |
-| **Wave 3** | Language **5809/5809** · Stdlib **5809/5809** on master ([#1380](https://github.com/PurHur/php-compiler/issues/1380)) |
-| **Spine SSOT** | `php script/bootstrap-spine-count.php` → **5809** / **5809** |
+| **Wave 3** | Language **5831/5831** · Stdlib **5831/5831** on master ([#1380](https://github.com/PurHur/php-compiler/issues/1380)) |
+| **Spine SSOT** | `php script/bootstrap-spine-count.php` → **5831** / **5831** |
| **Builtin matrix** | **852** functions ([`docs/capabilities.md`](https://github.com/PurHur/php-compiler/blob/master/docs/capabilities.md)) |
| **Try it** | [`docs/GETTING-STARTED.md`](https://github.com/PurHur/php-compiler/blob/master/docs/GETTING-STARTED.md) |
@@ -33,7 +33,7 @@ permalink: /development-status.html
| M5 spine runtime + bootstrap | `fix/spine-aot-jit-blockers` | Native bundle-OK probe; inventory argv spine-lint fallback; gen-0 sidecars refreshed ([#8559](https://github.com/PurHur/php-compiler/issues/8559)) |
| VM driver execute probe | [9493e806d](https://github.com/PurHur/php-compiler/commit/9493e806d) | **~20ms** feedback loop — no full relink on stale SHA; `BOOTSTRAP_VM_DRIVER_EXECUTE_PROBE_FULL_LINK=1` for rebuild ([#2201](https://github.com/PurHur/php-compiler/issues/2201)) |
| M5 presenter | `make north-star5-verify-fast` | Daily PR gate (~1–2 min); `--strict` (~1h) pre-merge only ([#1492](https://github.com/PurHur/php-compiler/issues/1492)) |
-| Gen-0 refresh | [a8cffaa0e](https://github.com/PurHur/php-compiler/commit/a8cffaa0e) | Spine runtime probe + gen-0 sidecars (**5809/5809**); inventory argv spine-lint fallback ([#8559](https://github.com/PurHur/php-compiler/issues/8559)) |
+| Gen-0 refresh | [a8cffaa0e](https://github.com/PurHur/php-compiler/commit/a8cffaa0e) | Spine runtime probe + gen-0 sidecars (**5831/5831**); inventory argv spine-lint fallback ([#8559](https://github.com/PurHur/php-compiler/issues/8559)) |
| Parallel compile jobs | [#10347](https://github.com/PurHur/php-compiler/pull/10347) | `PHP_COMPILER_COMPILE_JOBS` for vendor prelink + M3 sidecar warmup |
| Spine coverage | [#10356](https://github.com/PurHur/php-compiler/pull/10356) | `GeneratorYieldSourceMarker.php` in spine; inventory **3276** Phase A files |
| v1.1.0 docs sync | [#10369](https://github.com/PurHur/php-compiler/issues/10369) | README, development-status, examples README, capability matrix (**852** builtins) |
@@ -50,7 +50,7 @@ permalink: /development-status.html
### Still open (high signal)
- **MCJIT execute** — `bin/jit.php -r` SIGSEGV ([#98](https://github.com/PurHur/php-compiler/issues/98))
-- **Literal spine ratio** — **5809/5809** ✅ (Jul 2026)
+- **Literal spine ratio** — **5831/5831** ✅ (Jul 2026)
- **Compile-spine stub retirement** — shrink `PHP_COMPILER_SELFHOST_AOT` on M3 allowlist ([#1402](https://github.com/PurHur/php-compiler/issues/1402))
- **007-ThrowsWeb AOT execute** — invalid POST segfault at runtime (link OK; slice `EXAMPLES_AOT_SMOKE_ONLY=007`)
- **LLVM 14+ upgrade** — experimental `script/install-llvm14.sh` ([#174](https://github.com/PurHur/php-compiler/issues/174))
@@ -62,7 +62,7 @@ permalink: /development-status.html
- **`phpc` CLI** — `run`, `serve`, `build`, `deploy`, `lint`, `test`, `init`, `doctor`
- **Examples 000–009** — VM and AOT link/execute for the curated web subset
- **Self-host M0** — `compiler_minimal bundle OK` ✅
-- **Self-host M2** — spine **5809/5809** ✅; native link + lint ✅
+- **Self-host M2** — spine **5831/5831** ✅; native link + lint ✅
- **Self-host M3** — HelloWorld strict `emit_path=native` ✅ ([#1493](https://github.com/PurHur/php-compiler/issues/1493)); inventory argv `bin/compile.php` ✅ ([#3024](https://github.com/PurHur/php-compiler/issues/3024) closed); compile-smoke strict native ✅ ([#1937](https://github.com/PurHur/php-compiler/issues/1937))
- **Self-host M4** — `make bootstrap-loop-probe` full ladder ✅; gen-2→gen-3 full-spine recompile ✅
- **Self-host M5** — vendor prelink **3/3** ✅; **`make north-star5-verify-fast`** daily ✅; `--strict` pre-merge; gen-0 refreshed; VM probe ~**20ms**
@@ -92,7 +92,7 @@ See [`docs/bootstrap-selfhost.md`](https://github.com/PurHur/php-compiler/blob/m
|-----------|--------|
| **M0** — Small `lib/` bundle runs | ✅ |
| **M1** — Compiler-shaped bundle + compile-smoke | ✅ |
-| **M2** — Spine toward full inventory | ✅ **5809** / **5809** |
+| **M2** — Spine toward full inventory | ✅ **5831** / **5831** |
| **M3** — Native compiles PHP (no Zend emit) | ✅ Smoke + inventory argv driver strict native |
| **M4** — Bootstrap loop (next revision) | ✅ `bootstrap-loop-probe` full ladder |
| **M5** — Full self-host, no `vendor/` cold boot | ✅ Presenter strict + compiled-only empty `build/` cold boot ([#3053](https://github.com/PurHur/php-compiler/issues/3053)) |
diff --git a/docs/pages/index.html b/docs/pages/index.html
index 7861e7f9d27..1932faa990b 100644
--- a/docs/pages/index.html
+++ b/docs/pages/index.html
@@ -70,7 +70,7 @@ A compiler for PHP in PHP that compiles itself
VM + JIT + AOT
Closures · try/catch
321 builtins
- Spine **5809** / **5809**
+ Spine **5831** / **5831**
M5 strict ✅
M3 strict emit
MCJIT execute
@@ -391,7 +391,7 @@ Self-host progress
fix/spine-aot-jit-blockers @ a8cffaa0e (15 Jun 2026, LLVM 9).
- M2 spine SSOT: php script/bootstrap-spine-count.php → **5809** / **5809** Phase A inventory (literal coverage ✅).
+ M2 spine SSOT: php script/bootstrap-spine-count.php → **5831** / **5831** Phase A inventory (literal coverage ✅).
M4: make bootstrap-loop-probe full ladder ✅.
M5: make north-star5-verify-fast ✅ daily; --strict pre-merge; VM driver probe ~20ms in CI loops.
Remaining: MCJIT execute ([#98](https://github.com/PurHur/php-compiler/issues/98)); honest PHP main() in full spine AOT (native bundle-OK probe is bootstrap smoke).
@@ -416,7 +416,7 @@
M0–M1
✓
M2
- Spine **5809** / **5809** Phase A inventory — literal coverage ✅; native link + lint ✅
+
Spine **5831** / **5831** Phase A inventory — literal coverage ✅; native link + lint ✅
(#8559).
@@ -437,7 +437,7 @@ M4
✓
M5
Vendor prelink 3/3 ✅; committed .o cold boot ✅;
- north-star5-verify-fast ✅ daily; --strict pre-merge; spine **5809** / **5809**; prelinked gen-0 refreshed;
+ north-star5-verify-fast ✅ daily; --strict pre-merge; spine **5831** / **5831**; prelinked gen-0 refreshed;
fast VM execute probe (~20ms); compiled-only cold boot via BOOTSTRAP_M5_NO_ZEND=1 ✅
(#3053,
#8559,
@@ -494,7 +494,7 @@
Get involved
PHP compare ·
Getting started
-
+
diff --git a/docs/roadmap-wave3.md b/docs/roadmap-wave3.md
index e85d2115f60..b754f95b413 100644
--- a/docs/roadmap-wave3.md
+++ b/docs/roadmap-wave3.md
@@ -1,6 +1,6 @@
# Roadmap wave 3 tracker (#1354–#1379)
-> **Wave 3 complete on master (May 2026):** language **5809/5809** + stdlib **5809/5809** ([#1380](https://github.com/PurHur/php-compiler/issues/1380)). Phase-2 / JIT-only deferrals: [#1936](https://github.com/PurHur/php-compiler/issues/1936) (attributes reflection), [#1776](https://github.com/PurHur/php-compiler/issues/1776) (stdlib JIT audit), [#1238](https://github.com/PurHur/php-compiler/issues/1238).
+> **Wave 3 complete on master (May 2026):** language **5831/5831** + stdlib **5831/5831** ([#1380](https://github.com/PurHur/php-compiler/issues/1380)). Phase-2 / JIT-only deferrals: [#1936](https://github.com/PurHur/php-compiler/issues/1936) (attributes reflection), [#1776](https://github.com/PurHur/php-compiler/issues/1776) (stdlib JIT audit), [#1238](https://github.com/PurHur/php-compiler/issues/1238).
Living status for the **25 issues** filed May 2026 toward full PHP language + stdlib coverage. Umbrella: [#1380](https://github.com/PurHur/php-compiler/issues/1380). North stars: [#1044](https://github.com/PurHur/php-compiler/issues/1044), [#1492](https://github.com/PurHur/php-compiler/issues/1492) (self-host; was [#1056](https://github.com/PurHur/php-compiler/issues/1056)).
@@ -19,7 +19,7 @@ Regenerate capability truth: `php script/capability-matrix.php`, `php script/cap
Related merges outside this wave: `goto` ([#1228](https://github.com/PurHur/php-compiler/issues/1228) / [#1333](https://github.com/PurHur/php-compiler/pull/1333)), anonymous classes ([#1233](https://github.com/PurHur/php-compiler/issues/1233) / [#1386](https://github.com/PurHur/php-compiler/pull/1386)).
-**M2 spine:** **5809** / **5809** (`php script/bootstrap-spine-count.php`) — full Phase A inventory in `compiler_lib_spine_smoke`; coverage sync ✅ (`check-selfhost-spine-coverage-sync.php`). Native spine **link** + **lint** ✅ ([#2134](https://github.com/PurHur/php-compiler/issues/2134), [#8559](https://github.com/PurHur/php-compiler/issues/8559)). **M5 daily gate:** `make north-star5-verify-fast` + VM probe ~20ms ([#2201](https://github.com/PurHur/php-compiler/issues/2201)); `--strict` pre-merge only. M4 gen-2→gen-3 recompile ✅. Target doc: [self-host-target.md](self-host-target.md)
+**M2 spine:** **5831** / **5831** (`php script/bootstrap-spine-count.php`) — full Phase A inventory in `compiler_lib_spine_smoke`; coverage sync ✅ (`check-selfhost-spine-coverage-sync.php`). Native spine **link** + **lint** ✅ ([#2134](https://github.com/PurHur/php-compiler/issues/2134), [#8559](https://github.com/PurHur/php-compiler/issues/8559)). **M5 daily gate:** `make north-star5-verify-fast` + VM probe ~20ms ([#2201](https://github.com/PurHur/php-compiler/issues/2201)); `--strict` pre-merge only. M4 gen-2→gen-3 recompile ✅. Target doc: [self-host-target.md](self-host-target.md)
## Language (#1354–#1366)
@@ -69,4 +69,4 @@ Related merges outside this wave: `goto` ([#1228](https://github.com/PurHur/php-
---
-**Wave 3 close-out (May 2026):** language **5809/5809**, stdlib **5809/5809** on master. Do not reopen [#1354](https://github.com/PurHur/php-compiler/issues/1354)–[#1379](https://github.com/PurHur/php-compiler/issues/1379) for phase-1 gaps — use phase-2 trackers [#1936](https://github.com/PurHur/php-compiler/issues/1936) (attributes reflection), [#1776](https://github.com/PurHur/php-compiler/issues/1776) (stdlib JIT audit), [#1238](https://github.com/PurHur/php-compiler/issues/1238).
+**Wave 3 close-out (May 2026):** language **5831/5831**, stdlib **5831/5831** on master. Do not reopen [#1354](https://github.com/PurHur/php-compiler/issues/1354)–[#1379](https://github.com/PurHur/php-compiler/issues/1379) for phase-1 gaps — use phase-2 trackers [#1936](https://github.com/PurHur/php-compiler/issues/1936) (attributes reflection), [#1776](https://github.com/PurHur/php-compiler/issues/1776) (stdlib JIT audit), [#1238](https://github.com/PurHur/php-compiler/issues/1238).
diff --git a/docs/self-host-target.md b/docs/self-host-target.md
index 5ad18dc2815..44d3804ce74 100644
--- a/docs/self-host-target.md
+++ b/docs/self-host-target.md
@@ -35,7 +35,7 @@ That is **M5**. Everything below is the honest path from today’s bootstrap to
|-------|-------|--------|
| **Bootstrap driver** | Prelinked gen-0 refreshed via honest inventory argv emit; native `build/bin-compile-aot-inventory` for M4/M5 | Compiled `bin/compile.php` only |
| **Bundle size** | **2643** literal Phase A inventory in spine smoke | Full vm.php closure |
-| **Inventory coverage** | **5809** / **5809** ✅ | Full closure |
+| **Inventory coverage** | **5831** / **5831** ✅ | Full closure |
| **HelloWorld** | Strict probe **emit_path=native** ✅ | Native compile for arbitrary PHP |
| **Bootstrap loop (M4)** | `make bootstrap-loop-probe` full ladder ✅ — gen-1→gen-2, gen-2→gen-3 full spine, full-revision argv | Native full revision rebuild |
| **Vendor** | **3/3** vendor `object_ok`; committed `.o` cold boot without `vendor/` ✅; `make north-star5-verify-fast` daily; `--strict` pre-merge ✅ | No Zend `vendor/autoload.php` at bootstrap |
@@ -56,7 +56,7 @@ That is **M5**. Everything below is the honest path from today’s bootstrap to
| M4 `make bootstrap-selfhost-full-revision-probe` | ✅ gen-2 inventory argv → gen-3 + fixture smoke ([#2880](https://github.com/PurHur/php-compiler/issues/2880)) |
| M4 `make bootstrap-loop-gen2-recompile-spine` | ✅ gen-2→gen-3 full spine native argv |
| M4 `make bootstrap-loop-probe` | ✅ full ladder ([#1498](https://github.com/PurHur/php-compiler/issues/1498)) |
-| `make bootstrap-aot-link` | ✅ **5809/5809** |
+| `make bootstrap-aot-link` | ✅ **5831/5831** |
| `make bootstrap-inventory-check` | ✅ **2643** Phase A files, **0** source blockers |
| `make north-star5-verify-fast` | ✅ daily M5 PR gate (~1–2 min); `ARGS=--strict` pre-merge (~1h) |
@@ -68,7 +68,7 @@ That is **M5**. Everything below is the honest path from today’s bootstrap to
|-----------|----------------|--------|-----|
| **M0** | AOT can link a **small** honest `lib/` subset | ✅ | 100% |
| **M1** | Bundle is **compiler-shaped** (lint + compile-smoke) | ✅ | 100% |
-| **M2** | Spine grows toward full `bin/vm.php` inventory | ✅ **5809** / **5809** | **100%** |
+| **M2** | Spine grows toward full `bin/vm.php` inventory | ✅ **5831** / **5831** | **100%** |
| **M3** | Self-host binary **compiles external PHP** (HelloWorld) without Zend emit | ✅ strict **native** + inventory argv | **~85%** |
| **M4** | Self-host binary **rebuilds** the next compiler tree | ✅ full `bootstrap-loop-probe` ladder | **~90%** |
| **M5** | Full self-host; Zend retired from loop | ✅ `north-star5-verify-fast` daily + `--strict` pre-merge; `BOOTSTRAP_M5_NO_ZEND=1` empty `build/` ([#3053](https://github.com/PurHur/php-compiler/issues/3053)) | **~90%** |
@@ -79,7 +79,7 @@ That is **M5**. Everything below is the honest path from today’s bootstrap to
| Indicator | Formula | Jun 2026 |
|-----------|---------|----------|
-| **M2 spine progress** | `require_once` units in `compiler_lib_spine_smoke` ÷ Phase A inventory file count | **5809** / **5809** (`php script/bootstrap-spine-count.php`) |
+| **M2 spine progress** | `require_once` units in `compiler_lib_spine_smoke` ÷ Phase A inventory file count | **5831** / **5831** (`php script/bootstrap-spine-count.php`) |
| **Public “Self-host” row** | Same M2 ratio until M3–M5 gates add weight ([`development-status.md`](pages/development-status.md)) | **~97%** |
| **M5 vendor prelink** | `object_ok` packages ÷ 3 | **3 / 3** (cfg, types, llvm) |
| **Composite (internal)** | Milestone weights in table above (M0–M1 = 100%, M2 = spine %, M3–M5 = gate %) | **~90%** |
diff --git a/test/unit/BootstrapSelfhostBundleTest.php b/test/unit/BootstrapSelfhostBundleTest.php
index 677b65ee649..44b8d1f85b6 100644
--- a/test/unit/BootstrapSelfhostBundleTest.php
+++ b/test/unit/BootstrapSelfhostBundleTest.php
@@ -526,7 +526,7 @@ public function testCompilerLibSpineSmokeBundleUnitCountAndKeyUnits(): void
$this->assertFileExists($entry);
$contents = (string) file_get_contents($entry);
$count = bootstrap_spine_counts(self::$root)['spine'];
- $this->assertSame(5809, $count, 'M2 spine require_once units track Phase A inventory (#8559, #9234, #11629, #18550)');
+ $this->assertSame(5831, $count, 'M2 spine require_once units track Phase A inventory (#8559, #9234, #11629, #18550)');
foreach (self::LIB_SPINE_SMOKE_NEW_UNITS as $unit) {
$this->assertStringContainsString(
"require_once __DIR__.'/../../../{$unit}';",
From 33cdd0e75eba6ac245a04c3d2b402c114221b6b4 Mon Sep 17 00:00:00 2001
From: PurHur
Date: Sun, 19 Jul 2026 01:53:29 +0000
Subject: [PATCH 3/3] Docs: refresh bootstrap-inventory after rebase
Regenerate construct flags so VmBreakIterator preceding APIs are listed.
Co-authored-by: Cursor
---
docs/bootstrap-inventory.md | 244 ++++++++++++++++++------------------
1 file changed, 122 insertions(+), 122 deletions(-)
diff --git a/docs/bootstrap-inventory.md b/docs/bootstrap-inventory.md
index 0e148b03a3d..0427245e682 100644
--- a/docs/bootstrap-inventory.md
+++ b/docs/bootstrap-inventory.md
@@ -8,8 +8,8 @@ Regenerate: `php script/bootstrap-inventory.php`
| Metric | Count |
|--------|------:|
-| PHP files on vm.php path | 5831 |
-| Phase A inventory files (M2 ratio SSOT) | 5831 |
+| PHP files on vm.php path | 5830 |
+| Phase A inventory files (M2 ratio SSOT) | 5830 |
| Phase A ratio-deferred paths | 0 |
| Source constructs flagged (blockers) | 0 |
| Source constructs flagged (warnings) | 17374 |
@@ -41632,111 +41632,111 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
- new Variable (line 9115)
- new Variable (line 9122)
- new Variable (line 9139)
-- new VM\NativeFiberStackOverflow (line 9972)
-- new VM\BuiltinCallbackCatchRedirect (line 10023)
-- new VM\BuiltinCallbackCatchRedirect (line 10041)
-- new Variable (line 10144)
-- new Variable (line 10252)
-- new Variable (line 10385)
-- new ScriptExit (line 10541)
-- new Exception (line 10558)
-- new ScriptExit (line 10566)
-- new Error (line 10829)
-- new VM\PropertyHookRefWriteSignal (line 10877)
-- new Variable (line 10901)
-- new VM\PropertyHookRefWriteSignal (line 10906)
-- new VM\PropertyHookFiberSuspendSignal (line 10909)
-- new VM\PropertyHookRefWriteSignal (line 11031)
-- new Variable (line 11048)
-- new VM\PropertyHookRefWriteSignal (line 11062)
-- new VM\PropertyHookRefWriteSignal (line 11074)
-- new Variable (line 11305)
-- new Variable (line 11328)
-- new Variable (line 11338)
-- new Variable (line 11348)
-- new VM\PropertyHookRefWriteSignal (line 11354)
-- new VM\PropertyHookRefWriteSignal (line 11362)
-- new VM\PropertyHookRefWriteSignal (line 11365)
-- new Variable (line 11377)
-- new Variable (line 11391)
-- new VM\PropertyHookRefWriteSignal (line 11397)
-- new Variable (line 11428)
-- new VM\PropertyHookRefWriteSignal (line 11433)
-- new VM\PropertyHookFiberSuspendSignal (line 11436)
-- new Error (line 11935)
-- new Error (line 11945)
-- new Error (line 11955)
-- new Error (line 11965)
-- new ClassEntry (line 12735)
-- new Variable (line 12736)
-- new VM\ClassProperty (line 12737)
-- new ObjectEntry (line 12740)
-- new Variable (line 12743)
-- new Variable (line 12824)
-- new Error (line 12910)
-- new Variable (line 13002)
-- new VM\GeneratorUncaughtThrow (line 13004)
-- new Error (line 13073)
-- new Variable (line 13118)
-- new VM\GeneratorUncaughtThrow (line 13132)
-- new Variable (line 13221)
-- new VM\GeneratorUncaughtThrow (line 13241)
-- new Variable (line 13309)
-- new Variable (line 13311)
-- new Variable (line 13315)
-- new Variable (line 13445)
-- new Variable (line 13487)
-- new Variable (line 13658)
-- new Variable (line 13674)
-- new Variable (line 13719)
-- new Variable (line 13860)
-- new Variable (line 13934)
-- new Variable (line 14098)
-- new VM\PropertyIsInitializedHandler (line 14107)
-- new Error (line 14222)
-- new VM\EnumFromHandler (line 14247)
-- new CompileError (line 14973)
-- new VM\ClassProperty (line 15138)
-- new Variable (line 15446)
-- new Variable (line 15641)
-- new Variable (line 15643)
-- new ClassEntry (line 15686)
-- new Func\PHP (line 15693)
-- new VM\ClassProperty (line 15821)
-- new Func\PHP (line 15968)
-- new Variable (line 16044)
-- new Variable (line 16051)
-- new Variable (line 16057)
-- new Variable (line 16094)
-- new Variable (line 16123)
-- new Variable (line 16308)
-- new Variable (line 16354)
-- new VM\ClassProperty (line 16419)
-- new Error (line 16465)
-- new Error (line 16500)
-- new Error (line 16503)
-- new Error (line 16506)
-- new Error (line 16509)
-- new ObjectEntry (line 16511)
-- new Error (line 16524)
-- new Error (line 16527)
+- new VM\NativeFiberStackOverflow (line 9953)
+- new VM\BuiltinCallbackCatchRedirect (line 10004)
+- new VM\BuiltinCallbackCatchRedirect (line 10022)
+- new Variable (line 10125)
+- new Variable (line 10233)
+- new Variable (line 10366)
+- new ScriptExit (line 10522)
+- new Exception (line 10539)
+- new ScriptExit (line 10547)
+- new Error (line 10810)
+- new VM\PropertyHookRefWriteSignal (line 10858)
+- new Variable (line 10882)
+- new VM\PropertyHookRefWriteSignal (line 10887)
+- new VM\PropertyHookFiberSuspendSignal (line 10890)
+- new VM\PropertyHookRefWriteSignal (line 11012)
+- new Variable (line 11029)
+- new VM\PropertyHookRefWriteSignal (line 11043)
+- new VM\PropertyHookRefWriteSignal (line 11055)
+- new Variable (line 11286)
+- new Variable (line 11309)
+- new Variable (line 11319)
+- new Variable (line 11329)
+- new VM\PropertyHookRefWriteSignal (line 11335)
+- new VM\PropertyHookRefWriteSignal (line 11343)
+- new VM\PropertyHookRefWriteSignal (line 11346)
+- new Variable (line 11358)
+- new Variable (line 11372)
+- new VM\PropertyHookRefWriteSignal (line 11378)
+- new Variable (line 11409)
+- new VM\PropertyHookRefWriteSignal (line 11414)
+- new VM\PropertyHookFiberSuspendSignal (line 11417)
+- new Error (line 11916)
+- new Error (line 11926)
+- new Error (line 11936)
+- new Error (line 11946)
+- new ClassEntry (line 12716)
+- new Variable (line 12717)
+- new VM\ClassProperty (line 12718)
+- new ObjectEntry (line 12721)
+- new Variable (line 12724)
+- new Variable (line 12805)
+- new Error (line 12891)
+- new Variable (line 12983)
+- new VM\GeneratorUncaughtThrow (line 12985)
+- new Error (line 13054)
+- new Variable (line 13099)
+- new VM\GeneratorUncaughtThrow (line 13113)
+- new Variable (line 13202)
+- new VM\GeneratorUncaughtThrow (line 13222)
+- new Variable (line 13290)
+- new Variable (line 13292)
+- new Variable (line 13296)
+- new Variable (line 13426)
+- new Variable (line 13468)
+- new Variable (line 13639)
+- new Variable (line 13655)
+- new Variable (line 13700)
+- new Variable (line 13841)
+- new Variable (line 13915)
+- new Variable (line 14079)
+- new VM\PropertyIsInitializedHandler (line 14088)
+- new Error (line 14203)
+- new VM\EnumFromHandler (line 14228)
+- new CompileError (line 14954)
+- new VM\ClassProperty (line 15119)
+- new Variable (line 15427)
+- new Variable (line 15622)
+- new Variable (line 15624)
+- new ClassEntry (line 15667)
+- new Func\PHP (line 15674)
+- new VM\ClassProperty (line 15802)
+- new Func\PHP (line 15949)
+- new Variable (line 16025)
+- new Variable (line 16032)
+- new Variable (line 16038)
+- new Variable (line 16075)
+- new Variable (line 16104)
+- new Variable (line 16289)
+- new Variable (line 16335)
+- new VM\ClassProperty (line 16400)
+- new Error (line 16446)
+- new Error (line 16481)
+- new Error (line 16484)
+- new Error (line 16487)
+- new Error (line 16490)
+- new ObjectEntry (line 16492)
+- new Error (line 16505)
+- new Error (line 16508)
+- new Error (line 16511)
- new Error (line 16530)
-- new Error (line 16549)
-- new ObjectEntry (line 16553)
-- new Variable (line 16555)
-- new Variable (line 16569)
-- new Variable (line 16596)
-- new Variable (line 16609)
-- new Error (line 16739)
-- new Error (line 16744)
-- new VM\ObjectEntry (line 16748)
-- new Variable (line 16892)
-- new Variable (line 16910)
-- new NoDiscardMetadata (line 17079)
-- new Variable (line 17248)
-- new Variable (line 17250)
-- new Variable (line 17350)
-- 489 class method(s)
+- new ObjectEntry (line 16534)
+- new Variable (line 16536)
+- new Variable (line 16550)
+- new Variable (line 16577)
+- new Variable (line 16590)
+- new Error (line 16720)
+- new Error (line 16725)
+- new VM\ObjectEntry (line 16729)
+- new Variable (line 16873)
+- new Variable (line 16891)
+- new NoDiscardMetadata (line 17060)
+- new Variable (line 17229)
+- new Variable (line 17231)
+- new Variable (line 17331)
+- 488 class method(s)
- 25 closure(s)
### `lib/VM/AbstractPropertyHookCheck.php`
@@ -44328,10 +44328,10 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
### `lib/VM/BuiltinExceptionSupport.php`
**Warnings** (review for bootstrap subset):
-- new ObjectEntry (line 554)
-- new Variable (line 558)
-- new ObjectEntry (line 574)
-- new Variable (line 578)
+- new ObjectEntry (line 544)
+- new Variable (line 548)
+- new ObjectEntry (line 564)
+- new Variable (line 568)
- 37 class method(s)
### `lib/VM/BuiltinExecute.php`
@@ -44766,18 +44766,18 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
### `lib/VM/ExceptionSupport.php`
**Warnings** (review for bootstrap subset):
-- new ReflectionObject (line 365)
-- new ScriptExit (line 387)
-- new ScriptExit (line 417)
-- new ErrorException (line 573)
-- new SoapFault (line 603)
-- new Error (line 616)
-- new FiberStackOverflow (line 619)
-- new Error (line 621)
-- new Error (line 624)
-- new Exception (line 626)
-- new Exception (line 648)
-- new Error (line 656)
+- new ReflectionObject (line 364)
+- new ScriptExit (line 386)
+- new ScriptExit (line 416)
+- new ErrorException (line 572)
+- new SoapFault (line 602)
+- new Error (line 615)
+- new FiberStackOverflow (line 618)
+- new Error (line 620)
+- new Error (line 623)
+- new Exception (line 625)
+- new Exception (line 647)
+- new Error (line 655)
- 26 class method(s)
### `lib/VM/ExceptionTrace.php`