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
1 change: 1 addition & 0 deletions docs/capabilities-syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Tracking issues: [#58](https://github.com/PurHur/php-compiler/issues/58), [#145]
| Magic constant `__LINE__` | yes | yes | yes | [#715](https://github.com/PurHur/php-compiler/issues/715) | Per-site line on TYPE_SCRIPT_MAGIC; include stack for multi-file units; compliance PHPT |
| Literal `include`/`require` with `__DIR__` | yes | yes | yes | [#475](https://github.com/PurHur/php-compiler/issues/475) | Compile-time inlining via IncludeHelper; two-file PHPT + MiniWebApp JIT gate (#587) |
| foreach by-reference (`&$v`) | yes | yes | yes | [#1222](https://github.com/PurHur/php-compiler/issues/1222) | Packed and string-keyed arrays; VM + JIT lowering |
| By-reference parameters (`function f(&$x)`) | yes | no | no | [#140](https://github.com/PurHur/php-compiler/issues/140) | VM aliases caller slots via TYPE_INDIRECT; JIT pointer args deferred; VM-only lowering |
| Static property `Class::$prop` | yes | yes | yes | [#1225](https://github.com/PurHur/php-compiler/issues/1225) | Class-scoped storage; `self::` / `static::`; literal property names in JIT |
| `unset()` on variables and array offsets | yes | yes | yes | [#1224](https://github.com/PurHur/php-compiler/issues/1224) | VM + JIT assign null to lvalue slots |
| Keyed array destructuring (`["a" => $x]`) | yes | yes | yes | [#1234](https://github.com/PurHur/php-compiler/issues/1234) | Skip string-key CFG split for fetch+assign destructuring pairs (#1234) |
Expand Down
3 changes: 3 additions & 0 deletions lib/Block.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ class Block {
/** Declared parameter names by index (issue #168). */
public array $paramNames = [];

/** Parameter indices declared with `&$param` (issue #140). */
public array $paramByRef = [];

/** Resolved absolute paths for TYPE_INCLUDE opcodes (arg3 index, issue #54). */
public array $literalIncludePaths = [];

Expand Down
4 changes: 3 additions & 1 deletion lib/Compiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,9 @@ protected function compileTypeConstrainedVariable(Block $block, Type $type): int


protected function compileParam(Op\Expr\Param $param, Block $block, int $paramIdx): OpCode {
assert(false === $param->byRef);
if ($param->byRef) {
$block->paramByRef[$paramIdx] = true;
}
if ($param->variadic) {
assert(null === $param->defaultVar);
if (null !== $block->variadicParamIndex) {
Expand Down
6 changes: 5 additions & 1 deletion lib/VM.php
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,11 @@ private function runFrames(): int
$packed->append($copy);
}
} elseif (array_key_exists($recvIdx, $frame->calledArgs)) {
$arg1->copyFrom($frame->calledArgs[$recvIdx]);
if (isset($frame->block->paramByRef[(int) $op->arg2])) {
$arg1->indirect($frame->calledArgs[$recvIdx]);
} else {
$arg1->copyFrom($frame->calledArgs[$recvIdx]);
}
} elseif (null !== $op->arg3 && isset($frame->block->constants[$op->arg3])) {
$arg1->copyFrom($frame->block->constants[$op->arg3]);
} else {
Expand Down
20 changes: 17 additions & 3 deletions script/capability-syntax-lib.php
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,16 @@ function syntaxRowDefinitions(): array
'notes' => ['Packed and string-keyed arrays; VM + JIT lowering'],
'probe' => '$a = [1, 2, 3]; foreach ($a as &$v) { $v *= 2; } echo $a[0], $a[1], $a[2];',
],
[
'id' => 'ref_param',
'construct' => 'By-reference parameters (`function f(&$x)`)',
'opcodes' => ['TYPE_ARG_RECV', 'TYPE_ARG_SEND'],
'issue' => 140,
'jit' => false,
'aot' => false,
'notes' => ['VM aliases caller slots via TYPE_INDIRECT; JIT pointer args deferred'],
'probe' => 'function inc(&$n) { $n++; } $x = 1; inc($x); echo $x;',
],
[
'id' => 'static_property_fetch',
'construct' => 'Static property `Class::$prop`',
Expand Down Expand Up @@ -315,9 +325,13 @@ function collectSyntaxCapabilities(string $root, array $definitions, array $hand
$vm = $opcodeDriven
? opcodesSupported($handlers['vm'], $def['opcodes'])
: (is_string($def['probe']) && $def['probe'] !== '' && probeVmCompile($def['probe']));
$jit = $opcodeDriven
? opcodesSupported($handlers['jit'], $def['opcodes'])
: $vm;
if (array_key_exists('jit', $def)) {
$jit = $def['jit'];
} else {
$jit = $opcodeDriven
? opcodesSupported($handlers['jit'], $def['opcodes'])
: $vm;
}
if (array_key_exists('aot', $def)) {
$aot = $def['aot'];
} elseif (is_string($def['probe']) && $def['probe'] !== '') {
Expand Down
19 changes: 19 additions & 0 deletions test/compliance/cases/language/ref_param.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
By-reference parameter mutates caller variable (VM, issue #140)
--FILE--
<?php
function inc(&$n) {
$n++;
}
$x = 1;
inc($x);
echo $x, "\n";
function scale(&$n, $factor) {
$n *= $factor;
}
$y = 3;
scale($y, 4);
echo $y, "\n";
--EXPECT--
2
12