Skip to content

epic(opcache): first-class support for opcache-enabled environments #245

Description

@lisachenko

Global tracking epic for making z-engine work correctly — or fail loudly and documentedly — wherever opcache is enabled. All opcache tickets are attached as sub-issues; this body carries the goal, the possible/impossible boundary, and the roadmap grouping.

Goal

A consumer running opcache.enable=1 (CLI, FPM, preload) gets one of exactly two behaviours from every z-engine API: it works (via the copy-out model, map-ptr indirection, file-cache patching, …) or it throws a named exception and is documented in the support matrix (docs/hot-swap.md, docs/opcache-binary.md). Silent no-ops — the failure mode of #238 — are treated as bugs.

Current state

Possible vs. impossible

Achievable (tracked here): relocator payload coverage (#112#117), ZTS relocator (#118), macOS/arm64 relocator (#119), SHM publication of patched binaries (#121, long-horizon), hot-swap wiring (#122), offset validation + trust model (#123), SHM refresh() integration test (#125), PHPStan shapes (#126), handler installation during lazy linking via inheritance-cache decline (#241 — the real fix for #238), first-redefine()-under-opcache (#242), module-entry visibility under opcache (#243), live static-variables reads (#239, fixed in PR #244), optimizer-aware frame introspection (#240, fixed in PR #244).

Impossible or intentionally out of scope (throw + document):

  1. Windows opcache support — deliberate non-goal. The relocator throws OpCacheException::unsupportedPayload on Windows; feat(opcache): macOS/arm64 support for the relocator (absolute-address oplines) #119 was rescoped to macOS/arm64; docs/opcache-binary.md records the policy.
  2. Sharing process-local FFI trampolines across workers — fundamentally unsound: a handler address published into SHM/the inheritance cache dangles in sibling FPM workers. Handler features must stay process-local (why feat(opcache): decline inheritance-cache publication for classes that receive handlers during linking #241 declines the cache and the default_object_handlers route was rejected).
  3. Preventing the opcache optimizer from rewriting op_arrays — not controllable from userland; introspection reports the optimized truth, documented with the opcache.optimization_level=0 recommendation (feat(reflection): optimizer-aware frame-variable presence/enumeration API on ExecutionData #240).
  4. Mutating preloaded classes — refused by design (bucket outlives request memory).
  5. 32-bit builds — permanently out for the relocator.

Roadmap grouping

  1. Correctness under active opcache (bugs found by the runner job): bug(opcache): a write_property handler installed from an interface_gets_implemented hook never fires when opcache is enabled #238feat(opcache): decline inheritance-cache publication for classes that receive handlers during linking #241, bug(opcache): the first redefine() does not take effect when opcache is active in the process (RedefineLeakPlateauTest child) #242, bug(opcache): registered module entry is not visible when opcache is active in the process (persistent-heap request-cycle scenario) #243; done: bug(opcache): getStaticVariables() reads the defaults table instead of the live static_variables_ptr table for opcache-shared functions #239, feat(reflection): optimizer-aware frame-variable presence/enumeration API on ExecutionData #240 (PR feat(opcache): hold the suite under an opcache-active runner — CI job, lazy-linking guard, static-vars and introspection fixes #244).
  2. Relocator payload coverage: feat(opcache): relocate intersection/union type lists in cache binaries #112, feat(opcache): relocate PHP 8.4 property hooks in cache binaries #113, feat(opcache): relocate trait-using classes in cache binaries #114, feat(opcache): relocate closures/arrow functions (dynamic_func_defs) in cache binaries #115, feat(opcache): relocate iterator-aware and ArrayAccess classes in cache binaries #116 — prerequisites for the graph serializer feat(opcache): support graph-growing mutations in the cache serializer #117.
  3. Platform envelope: feat(opcache): ZTS support for the file-cache relocator #118 (ZTS), feat(opcache): macOS/arm64 support for the relocator (absolute-address oplines) #119 (macOS/arm64); Windows intentionally excluded.
  4. Hardening & tests: opcache: bounds-validate relocation offsets and document the trust model #123 (bounds/trust model), test(opcache): integration-test refresh() under real opcache shared memory #125 (SHM refresh() integration), chore(opcache): replace path-scoped PHPStan ignores with struct shapes #126 (PHPStan shapes).
  5. The headline unlock: feat(opcache): load patched binaries into opcache shared memory (ZCSG) #121 (ZCSG publication) → feat(opcache): wire the binary-patch pipeline to the hot-swap API #122 (hot-swap wiring) — patched binaries applied to live code.

Related (not sub-issues)

Done / history

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestopcacheIssue is related to opcache integration. Either doesn't work well or behaves incorrect.

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions