perf: streamline dynamic property writes

master
韩天峰 6 hours ago
parent 6df71ec557
commit 7d7977fc5a
  1. 20
      src/Parser/AssignOpTrait.php
  2. 2
      src/Parser/ForeachTrait.php
  3. 2
      src/Parser/PropertyAccessTrait.php
  4. 60
      tests/compiler/object_property/dynamic-property-write-fast-path.phpt

@ -102,7 +102,12 @@ trait AssignOpTrait
return $code . '((' . $tmp . ' = ' . $value . ', ' . "{$array}.offsetSet({$dim}, {$tmp})" . '), ' . $tmp . ')';
}
protected function parseAssignPropertyFetch(NodeAbstract $left, NodeAbstract $right, ?PropertyWriteTarget $target = null): string
protected function parseAssignPropertyFetch(
NodeAbstract $left,
NodeAbstract $right,
?PropertyWriteTarget $target = null,
bool $resultUnused = false,
): string
{
if ($target !== null) {
$this->assertCanAssignPropertyWrite($target, $right);
@ -115,6 +120,15 @@ trait AssignOpTrait
$rightExpr = $this->wrapObjectPropertyAssignTypeCheck($left, $right, $rightExpr);
}
if ($resultUnused
&& $left instanceof Expr\PropertyFetch
&& !$this->shouldMaterializeOrderedOperand($left->name)
&& $this->canEmitDirectArrayWriteOperand($right)
&& $this->canEmitDynamicPropertyTarget($target)
) {
return $this->emitDynamicPropertyFetchWrite($left, $rightExpr, $target);
}
$tmp = $this->genTmpVarName();
$this->addLocalVar($tmp, Type::VAR);
// Comma expression: store RHS → execute side effect → evaluate to stored value
@ -494,7 +508,7 @@ trait AssignOpTrait
}
if ($propertyWriteTarget !== null && $this->shouldUseDynamicNativePropertyWrite($left, $type)) {
return $this->parseAssignPropertyFetch($left, $right, $propertyWriteTarget);
return $this->parseAssignPropertyFetch($left, $right, $propertyWriteTarget, $resultUnused);
}
if ($this->isVarExpr($left)) {
@ -645,7 +659,7 @@ trait AssignOpTrait
}
}
} elseif ($this->isPropertyFetch($left) and !$this->isNativePropertyAccess($left)) {
return $this->parseAssignPropertyFetch($left, $right, $propertyWriteTarget);
return $this->parseAssignPropertyFetch($left, $right, $propertyWriteTarget, $resultUnused);
} elseif ($this->isArrayDimFetch($left) and $this->isVarExpr($left->var)) {
$tmp = $this->parseIdentifier($left->var);
if ($this->getVarType($tmp) === Type::STR and $left->dim === null) {

@ -124,7 +124,7 @@ trait ForeachTrait
{
$iterator = $this->genTmpVarName();
$byRef = $node->byRef ? 'true' : 'false';
$scope = $this->class ? $this->getClassEntryPtr($this->getFullClassName()) : 'nullptr';
$scope = $this->class ? $this->getLocalClassEntryPtr($this->getFullClassName()) : 'nullptr';
$code = '{' . PHP_EOL;
$this->indentLevel++;
$code .= $this->getIndent() . "php::ForeachIterator $iterator{{$iterableVar}, $byRef, $scope};" . PHP_EOL;

@ -41,7 +41,7 @@ trait PropertyAccessTrait
{
$scope = $this->usesTraitPropertyScope($object)
? 'php::FakeScopeGuard::current()'
: ($this->class ? $this->getClassEntryPtr($this->getFullClassName()) : 'nullptr');
: ($this->class ? $this->getLocalClassEntryPtr($this->getFullClassName()) : 'nullptr');
return 'typephp_write_property_scoped('
. $object . ', ' . $property . ', ' . $value . ', ' . $scope . ')';
}

@ -0,0 +1,60 @@
--TEST--
Dynamic property statement writes preserve scope, evaluation and reference value semantics
--FILE--
<?php
declare(strict_types=1);
final class DynamicWriter
{
private int $hidden = 0;
public function write(string $name, mixed $value): void
{
$this->$name = $value;
}
public function writeFromReference(string $name, mixed &$value): void
{
$this->$name = $value;
}
public function writeComputed(string $name, int &$calls): void
{
$this->$name = nextDynamicValue($calls);
}
public function value(): int
{
return $this->hidden;
}
}
function nextDynamicValue(int &$calls): int
{
$calls++;
return 41;
}
function main(): void
{
$writer = new DynamicWriter();
$name = 'hidden';
$writer->write($name, 17);
var_dump($writer->value());
$calls = 0;
$writer->writeComputed($name, $calls);
var_dump($writer->value(), $calls);
$source = 42;
$writer->writeFromReference($name, $source);
$source = 43;
var_dump($writer->value(), $source);
}
?>
--EXPECT--
int(17)
int(41)
int(1)
int(42)
int(43)
Loading…
Cancel
Save