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
16 changes: 8 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ jobs:
opcache_gate: composer test:opcache
- ts: zts
ts_label: ZTS
# The file-cache relocator does not support ZTS payloads yet
# (issue #118): its tests self-skip on ZTS, so the non-skip gate
# excludes that group while still proving the SHM tests ran
# Since issue #118 the file-cache relocator supports ZTS payloads,
# so this gate covers the full opcache group (the script is the
# named alias the ZTS legs call; it no longer excludes anything)
opcache_gate: composer test:opcache-zts
steps:
- uses: actions/checkout@v7
Expand Down Expand Up @@ -203,8 +203,8 @@ jobs:
run: composer test

# Same gates as the Linux legs (issue #124): the opcache/SHM tests must
# have RUN. As on Linux, the ZTS leg excludes the file-cache relocator
# group (no ZTS payload support yet, issue #118).
# have RUN. Since issue #118 the relocator group runs on ZTS too, so
# both legs cover the full opcache group.
- name: Opcache/SHM coverage must not silently skip
if: steps.artifacts.outputs.present == 'true'
run: ${{ matrix.ts == 'zts' && 'composer test:opcache-zts' || 'composer test:opcache' }}
Expand Down Expand Up @@ -384,12 +384,12 @@ jobs:
include:
- ts: nts
ts_label: NTS
# ZTS excludes the relocator tests (no ZTS payload support yet,
# issue #118) but still gates the SHM coverage against silent skips
opcache_args: --group opcache --fail-on-skipped
- ts: zts
ts_label: ZTS
opcache_args: --group opcache --exclude-group opcache-relocator --fail-on-skipped
# Since issue #118 the relocator tests run on ZTS too - both legs
# gate the full opcache group against silent skips
opcache_args: --group opcache --fail-on-skipped
steps:
- uses: actions/checkout@v7

Expand Down
14 changes: 8 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@ PRs), or manually via `workflow_dispatch` against any branch.
Darwin covers **NTS and ZTS**: the workflow's matrix crosses both
architectures with both thread-safety modes (setup-php builds the ZTS PHP via
`phpts: ts`). As on Linux, the ZTS artifacts reach EG/CG through the TSRM
offsets, and the opcache file-cache relocator stays unsupported on ZTS
(issue #118). After changing the generator on this branch, remember the 8.5
offsets; the opcache file-cache relocator runs on ZTS since issue #118.
After changing the generator on this branch, remember the 8.5
line on `master` needs its own `workflow_dispatch` run to refresh its darwin
artifacts.

Expand Down Expand Up @@ -192,10 +192,12 @@ composer test:internal # destructive/segfault-prone group, process-isolated
- `ZENGINE_STRICT_LAYOUT_CHECK=1` (set in the test bootstrap) makes
`Core::init()` verify every struct layout against `layouts.json` before
touching engine memory — the anti-segfault airbag. Keep it on in development.
- On **ZTS** builds the file-cache relocator tests (`opcache-relocator` group)
self-skip — ZTS payloads are not supported yet (issue #118). The non-skip
gate for the remaining opcache/SHM coverage is `composer test:opcache-zts`;
CI runs both release and debug test legs on NTS **and** ZTS.
- The file-cache relocator supports **ZTS** payloads since issue #118 (the
binary layout is thread-safety-agnostic: zend_file_cache.c has no ZTS
conditionals and every walked struct is layout-identical across the modes).
`composer test:opcache-zts` stays as the named alias CI's ZTS legs call; it
now runs the full opcache group, relocator tests included. CI runs both
release and debug test legs on NTS **and** ZTS.
- `composer test:opcache-runner` runs the suite the way an opcache-enabled
consumer does — `opcache.enable_cli=1` in the **runner process itself**, so
every test file is compiled into shared memory (CI has a dedicated Linux job
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"test": "phpunit",
"test:internal": "phpunit --group internal --process-isolation",
"test:opcache": "phpunit --group opcache --fail-on-skipped",
"test:opcache-zts": "phpunit --group opcache --exclude-group opcache-relocator --fail-on-skipped",
"test:opcache-zts": "phpunit --group opcache --fail-on-skipped",
"test:opcache-runner": "phpunit --exclude-group performance --exclude-group internal --exclude-group opcache-incompatible",
"test:performance": "phpunit --group performance --fail-on-skipped",
"phpstan": "phpstan analyse",
Expand All @@ -53,7 +53,7 @@
"test": "Run the test suite (segfault-prone internal group excluded)",
"test:internal": "Run the segfault-prone internal test group with process isolation (use a debug PHP build)",
"test:opcache": "Run the opcache/shared-memory tests and FAIL if any of them skipped (they are self-skipping when opcache is unavailable)",
"test:opcache-zts": "Same non-skip gate for ZTS builds: excludes the file-cache relocator tests, which do not support ZTS payloads yet (issue #118)",
"test:opcache-zts": "Same non-skip gate on ZTS builds - kept as the named alias CI's ZTS legs call; since issue #118 the file-cache relocator tests run there too",
"test:opcache-runner": "Run the suite for an opcache-ACTIVE runner (opcache.enable_cli=1): excludes the usual performance/internal groups plus opcache-incompatible, the issue-linked tests that cannot hold when the runner's own files live in shared memory",
"test:performance": "Run the excluded performance group (the 'zero FFI at call time' benchmark) and FAIL if it silently skipped - its verdict is timing-based, so the CI leg that runs it is informational",
"phpstan": "Run static analysis at the maximum level",
Expand Down
10 changes: 7 additions & 3 deletions docs/opcache-binary.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,12 +191,16 @@ $report->appliedMethods; // what actually happened, per entry
`opcache.preload`-based features) keep rejecting Windows loudly, and the
Windows half of the original platform ticket was retired when
[#119](https://github.com/lisachenko/z-engine/issues/119) was rescoped to
macOS/arm64. ZTS payloads stay tracked in
[#118](https://github.com/lisachenko/z-engine/issues/118).
macOS/arm64. ZTS payloads are supported since
[#118](https://github.com/lisachenko/z-engine/issues/118): the file-cache
binary layout is thread-safety-agnostic (zend_file_cache.c has no ZTS
conditionals, and every struct the walker dereferences is layout-identical
across the modes — only EG/CG/module_entry differ, none of which appear in
a payload).
- **Strict, never silent.** Anything the port cannot handle raises
`unsupportedPayload` rather than writing a subtly corrupt binary; with every
payload shape of the 8.4 walker now ported, that guard covers the platform
predicates above (Windows/32-bit, and ZTS until #118). Global functions,
predicates above (Windows/32-bit). Global functions,
classes with constants, typed properties (union/intersection/DNF type lists
included), trait-using classes (aliases and insteadof precedences included),
closures and arrow functions (nested dynamic_func_defs included),
Expand Down
20 changes: 9 additions & 11 deletions src/OpCache/PayloadRelocator.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,12 @@
/**
* Turns the position-independent file-cache payload into a live in-memory
* image and back, a faithful port of ext/opcache/zend_file_cache.c
* (unserialize = {@see relocate}, serialize = {@see derelocate}) for the
* linux-x64 non-thread-safe build. Thread-safe (ZTS) payloads use a different
* binary layout and are rejected until issue #118 lands ZTS-specific walking.
* (unserialize = {@see relocate}, serialize = {@see derelocate}) for 64-bit
* POSIX builds, NTS and ZTS alike: zend_file_cache.c has no thread-safety
* conditionals, and every struct the walker dereferences is layout-identical
* across the two modes (only EG/CG/module_entry differ on ZTS, none of which
* appear in a payload) - verified against the generated layouts.json of both
* targets (issue #118).
*
* In the file every interior pointer is stored as a byte offset from the
* buffer start (SERIALIZE_PTR) and every interned string as a tagged offset
Expand Down Expand Up @@ -97,12 +100,12 @@ final class PayloadRelocator
* Whether the relocator can handle payloads of the running build at all
*
* The exact predicate the constructor enforces, exposed so callers (and the tests
* covering them) can skip cleanly instead of provoking the throw. Windows payloads
* are tracked in issue #119, ZTS ones in issue #118.
* covering them) can skip cleanly instead of provoking the throw. Windows opcache
* support is an intentional non-goal (issue #119 was rescoped to macOS/arm64).
*/
public static function isSupported(): bool
{
return PHP_INT_SIZE === 8 && \DIRECTORY_SEPARATOR === '/' && !\ZEND_THREAD_SAFE;
return PHP_INT_SIZE === 8 && \DIRECTORY_SEPARATOR === '/';
}

/**
Expand All @@ -114,11 +117,6 @@ public function __construct(private readonly object $buffer, private readonly Ca
if (PHP_INT_SIZE !== 8 || \DIRECTORY_SEPARATOR !== '/') {
throw OpCacheException::unsupportedPayload('the relocator supports 64-bit non-Windows builds only');
}
if (\ZEND_THREAD_SAFE) {
throw OpCacheException::unsupportedPayload(
'ZTS file-cache payloads use a different binary layout - tracked in issue #118',
);
}
$this->base = Core::addressOf(Core::addr($buffer));
$this->size = $metaInfo->memSize();
$this->strSectionBase = $this->base + $this->size;
Expand Down
4 changes: 2 additions & 2 deletions tests/OpCache/ClosureRelocationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ protected function setUp(): void
{
if (!PayloadRelocator::isSupported()) {
self::markTestSkipped(
'The file-cache relocator supports 64-bit POSIX NTS payloads only'
. ' (ZTS is issue #118, Windows is issue #119)',
'The file-cache relocator supports 64-bit POSIX payloads only'
. ' (Windows opcache support is an intentional non-goal, issue #119)',
);
}
}
Expand Down
4 changes: 2 additions & 2 deletions tests/OpCache/IteratorFuncsRelocationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ protected function setUp(): void
{
if (!PayloadRelocator::isSupported()) {
self::markTestSkipped(
'The file-cache relocator supports 64-bit POSIX NTS payloads only'
. ' (ZTS is issue #118, Windows is issue #119)',
'The file-cache relocator supports 64-bit POSIX payloads only'
. ' (Windows opcache support is an intentional non-goal, issue #119)',
);
}
}
Expand Down
4 changes: 2 additions & 2 deletions tests/OpCache/PropertyHookRelocationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ protected function setUp(): void
{
if (!PayloadRelocator::isSupported()) {
self::markTestSkipped(
'The file-cache relocator supports 64-bit POSIX NTS payloads only'
. ' (ZTS is issue #118, Windows is issue #119)',
'The file-cache relocator supports 64-bit POSIX payloads only'
. ' (Windows opcache support is an intentional non-goal, issue #119)',
);
}
}
Expand Down
4 changes: 2 additions & 2 deletions tests/OpCache/ReflectionOpcacheFileTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ protected function setUp(): void
{
if (!PayloadRelocator::isSupported()) {
self::markTestSkipped(
'The file-cache relocator supports 64-bit POSIX NTS payloads only'
. ' (ZTS is issue #118, Windows is issue #119)',
'The file-cache relocator supports 64-bit POSIX payloads only'
. ' (Windows opcache support is an intentional non-goal, issue #119)',
);
}
}
Expand Down
4 changes: 2 additions & 2 deletions tests/OpCache/RefreshWorkflowTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ protected function setUp(): void
{
if (!PayloadRelocator::isSupported()) {
self::markTestSkipped(
'The file-cache relocator supports 64-bit POSIX NTS payloads only'
. ' (ZTS is issue #118, Windows is issue #119)',
'The file-cache relocator supports 64-bit POSIX payloads only'
. ' (Windows opcache support is an intentional non-goal, issue #119)',
);
}
}
Expand Down
4 changes: 2 additions & 2 deletions tests/OpCache/SerializerRoundTripTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ protected function setUp(): void
{
if (!PayloadRelocator::isSupported()) {
self::markTestSkipped(
'The file-cache relocator supports 64-bit POSIX NTS payloads only'
. ' (ZTS is issue #118, Windows is issue #119)',
'The file-cache relocator supports 64-bit POSIX payloads only'
. ' (Windows opcache support is an intentional non-goal, issue #119)',
);
}
}
Expand Down
4 changes: 2 additions & 2 deletions tests/OpCache/TraitRelocationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ protected function setUp(): void
{
if (!PayloadRelocator::isSupported()) {
self::markTestSkipped(
'The file-cache relocator supports 64-bit POSIX NTS payloads only'
. ' (ZTS is issue #118, Windows is issue #119)',
'The file-cache relocator supports 64-bit POSIX payloads only'
. ' (Windows opcache support is an intentional non-goal, issue #119)',
);
}
}
Expand Down
4 changes: 2 additions & 2 deletions tests/OpCache/TypeListRelocationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ protected function setUp(): void
{
if (!PayloadRelocator::isSupported()) {
self::markTestSkipped(
'The file-cache relocator supports 64-bit POSIX NTS payloads only'
. ' (ZTS is issue #118, Windows is issue #119)',
'The file-cache relocator supports 64-bit POSIX payloads only'
. ' (Windows opcache support is an intentional non-goal, issue #119)',
);
}
}
Expand Down
Loading