Skip to content

Complete ph7_vm_reset for compile-once / execute-many VM reuse#246

Merged
alganet merged 1 commit into
mainfrom
feature/vm-reset-reuse
Jun 16, 2026
Merged

Complete ph7_vm_reset for compile-once / execute-many VM reuse#246
alganet merged 1 commit into
mainfrom
feature/vm-reset-reuse

Conversation

@alganet

@alganet alganet commented Jun 16, 2026

Copy link
Copy Markdown
Owner

ph7_vm_reset() previously cleared only the output blob, the script return value and the HTTP response headers, so re-executing one compiled VM bled globals, superglobals, function/class statics, runtime closures, output buffers, the reference table and every allocated object into the next run -- and the -S server therefore recompiled the script on every request.

PH7_VmReset now restores the VM to its post-PH7_VmMakeReady state while preserving the compiled program and all definitions:

  • A watermark (nSuperBaseline, captured in PH7_VmMakeReady just before the superglobals are created) marks the per-exec/persistent boundary in the aMemObj object pool.
  • Reset unlinks the whole reference table (before releasing objects, so by-ref array nodes never dangle), releases the per-exec object pool above the watermark (engine teardown only -- user __destruct is suppressed via a new bInReset flag to stay crash-safe, matching PH7's prior no-global-destructor behaviour), frees runtime closures and resets all function/method static sentinels in one pass over hFunction, frees class static typed-property slots, truncates the pool back to the watermark, then re-runs the real init helpers (VmEnterFrame, PH7_HashmapCreateSuper, and VmMountUserClassAttrs -- the static/const-attr half split out of VmMountUserClass so methods are not re-installed).
  • Definitions persist deliberately: include_once markers (aIncluded) are kept so runtime-included definitions survive without recompiling or redeclare errors, and user constants are not trimmed -- a re-run define() overwrites the value in place (PH7_VmRegisterConstant now frees the old user value on overwrite; case-insensitive define() aliases get their own value copy), so no leak and include_once+define keeps working across requests.

The -S dev server compiles each script once and reset-reuses it per request via a small path-keyed VM cache with mtime invalidation (so edits are still picked up; PHL_NO_REUSE=1 forces the legacy compile-per-request path).

Verified: no state bleed across requests (globals, statics, class statics, closures, superglobals), definitions/constants persist across include_once, flat memory over thousands of requests; make test + test-compat green under phl and php 8.5.7, full corpus unchanged (24 known error-format failures). Unblocks ESP32 B1.

Regression: tests/ph7/002-integration/server/vm_reuse_no_bleed.phpt

ph7_vm_reset() previously cleared only the output blob, the script return
value and the HTTP response headers, so re-executing one compiled VM bled
globals, superglobals, function/class statics, runtime closures, output
buffers, the reference table and every allocated object into the next run --
and the -S server therefore recompiled the script on every request.

PH7_VmReset now restores the VM to its post-PH7_VmMakeReady state while
preserving the compiled program and all definitions:

- A watermark (nSuperBaseline, captured in PH7_VmMakeReady just before the
  superglobals are created) marks the per-exec/persistent boundary in the
  aMemObj object pool.
- Reset unlinks the whole reference table (before releasing objects, so by-ref
  array nodes never dangle), releases the per-exec object pool above the
  watermark (engine teardown only -- user __destruct is suppressed via a new
  bInReset flag to stay crash-safe, matching PH7's prior no-global-destructor
  behaviour), frees runtime closures and resets all function/method static
  sentinels in one pass over hFunction, frees class static typed-property
  slots, truncates the pool back to the watermark, then re-runs the real init
  helpers (VmEnterFrame, PH7_HashmapCreateSuper, and VmMountUserClassAttrs --
  the static/const-attr half split out of VmMountUserClass so methods are not
  re-installed).
- Definitions persist deliberately: include_once markers (aIncluded) are kept
  so runtime-included definitions survive without recompiling or redeclare
  errors, and user constants are not trimmed -- a re-run define() overwrites
  the value in place (PH7_VmRegisterConstant now frees the old user value on
  overwrite; case-insensitive define() aliases get their own value copy), so
  no leak and include_once+define keeps working across requests.

The -S dev server compiles each script once and reset-reuses it per request
via a small path-keyed VM cache with mtime invalidation (so edits are still
picked up; PHL_NO_REUSE=1 forces the legacy compile-per-request path).

Verified: no state bleed across requests (globals, statics, class statics,
closures, superglobals), definitions/constants persist across include_once,
flat memory over thousands of requests; make test + test-compat green under
phl and php 8.5.7, full corpus unchanged (24 known error-format failures).
Unblocks ESP32 B1.

Regression: tests/ph7/002-integration/server/vm_reuse_no_bleed.phpt
@alganet alganet force-pushed the feature/vm-reset-reuse branch from 9bcaa50 to 43ee4fd Compare June 16, 2026 00:23
@alganet alganet merged commit 16a877f into main Jun 16, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant