Skip to content

fix(codegen): keep Zend operand read order around hoisted side effects - #52

Open
AlessioGiacobbe wants to merge 2 commits into
swoole:masterfrom
AlessioGiacobbe:split/eval-order-side-effects
Open

fix(codegen): keep Zend operand read order around hoisted side effects#52
AlessioGiacobbe wants to merge 2 commits into
swoole:masterfrom
AlessioGiacobbe:split/eval-order-side-effects

Conversation

@AlessioGiacobbe

Copy link
Copy Markdown
Contributor

When a later call argument or concat operand hoisted a side effect, it executed before earlier operands were read: $j = 1; two($j, $j = 5) printed "5,5" where Zend SENDs left-to-right and prints "1,5"; $m . "," . ($m = 9) printed "9,9" instead of "1,9".

Earlier plain-variable operands are now snapshotted at their exact Zend read positions when a later operand materializes statements. Concat read positions were probed against Zend empirically (the VM reads the first two chain items together after both items' side effects), and plain arithmetic ($k + ($k = 5)) is deliberately unchanged — Zend itself reads the CV at the op, so the existing codegen already matches; a no-regression test pins that.

Verified against Zend 8.4.13; codegen tests + phpt included.

Part of the split of #39.

Lowering a later call argument or concat operand that materializes
captured statements (an assignment, a call result) appended them to the
enclosing statement, executing the side effect before earlier operands
were read: two($j, $j = 5) with $j = 1 produced "5,5" (Zend "1,5") and
$m . "," . ($m = 9) produced "9,9" (Zend "1,9").

Call arguments: Zend SENDs strictly left to right, so when a later
argument hoists statements, every earlier by-value plain-variable
argument is snapshotted into a temporary at its own argument position.
By-reference parameters, unpacked arguments, $this and $GLOBALS are
left alone.

Concat chains: Zend reads a CV operand when its CONCAT opcode executes,
so in the left-associated chain the first two items are read together
at the first op (after both items' side effects: $s . ($s = 'b') . $s
is "bbb") and each later item after the side effects of everything up
to itself. The flattened braced-list lowering now snapshots a
plain-variable item exactly at that read position, deferring the first
item's snapshot until the second item has been lowered.

Plain arithmetic is intentionally unchanged: Zend's ADD reads the CV at
op time, so $k + ($k = 5) is 10 in both worlds, and the existing
codegen already matches.
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