Skip to content
Closed
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
33 changes: 29 additions & 4 deletions lib/Compiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,7 @@ protected function compileOps(array $ops, Block $block): void {
$block = $this->compileNullsafePropertyFetch($child, $block);
} elseif (
$child instanceof Op\Expr\ArrayDimFetch
&& $i + 1 < $opCount
&& $this->isArrayDimFetchOnlyCoalesceLeft($child, $ops[$i + 1])
&& $this->findsCoalesceUsingFetchAsLeft($ops, $i, $child)
) {
// Lowered by compileCoalesce via isset(container, dim) — no eager fetch (#99, #273).
break;
Expand Down Expand Up @@ -129,6 +128,29 @@ private function isArrayDimFetchOnlyCoalesceLeft(
return $left === $fetch->result;
}

/**
* php-cfg may emit ConstFetch (e.g. ?? right literal) between fetch and Coalesce; still skip eager fetch.
*
* @param Op[] $ops
*/
private function findsCoalesceUsingFetchAsLeft(array $ops, int $fetchIndex, Op\Expr\ArrayDimFetch $fetch): bool
{
$opCount = count($ops);
for ($j = $fetchIndex + 1; $j < $opCount; ++$j) {
$candidate = $ops[$j];
if ($candidate instanceof Op\Expr\BinaryOp\Coalesce) {
return $this->isArrayDimFetchOnlyCoalesceLeft($fetch, $candidate);
}
if ($candidate instanceof Op\Expr\ConstFetch) {
continue;
}

return false;
}

return false;
}

protected function compileClassLike(Op\Stmt\ClassLike $class, Block $block): OpCode {
$type = 0;
if ($class instanceof Op\Stmt\Class_) {
Expand Down Expand Up @@ -637,11 +659,13 @@ protected function compileIsset(Op\Expr\Isset_ $expr, Block $block): array

protected function compileCoalesce(Op\Expr\BinaryOp\Coalesce $expr, Block $block): Block
{
if ($expr->result instanceof Temporary) {
$expr->result->usages[] = $expr->result;
}
$resultSlot = $this->compileOperand($expr->result, $block, false);

$endBlock = new Block($block->orig);
$endBlock->inheritUndefinedLocals = true;
$endBlock->inheritScopeFrom($block);

$rightBlock = new Block($block->orig);
$rightBlock->inheritUndefinedLocals = true;
Expand All @@ -656,7 +680,6 @@ protected function compileCoalesce(Op\Expr\BinaryOp\Coalesce $expr, Block $block

$leftBlock = new Block($block->orig);
$leftBlock->inheritUndefinedLocals = true;
$leftBlock->inheritScopeFrom($block);

$checkSlot = $this->compileBoolTemporary($block);
$dimFetch = $this->findCoalesceArrayDimFetch($expr->left, $block);
Expand All @@ -672,6 +695,7 @@ protected function compileCoalesce(Op\Expr\BinaryOp\Coalesce $expr, Block $block
$dimSlot
));
if (null !== $dimFetch) {
$leftBlock->inheritScopeFrom($block);
$this->compileArrayDimFetchRead($dimFetch, $leftBlock);
$leftSlot = $this->compileOperand($dimFetch->result, $leftBlock, true);
$leftBlock->addOpCode(new OpCode(
Expand Down Expand Up @@ -723,6 +747,7 @@ protected function compileCoalesce(Op\Expr\BinaryOp\Coalesce $expr, Block $block
$coalesceOp->block2 = $rightBlock;
$coalesceOp->block3 = $endBlock;
$block->addOpCode($coalesceOp);
$endBlock->inheritScopeFrom($block);

return $endBlock;
}
Expand Down
4 changes: 2 additions & 2 deletions lib/JIT.php
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ private function compileBlockInternal(
break;
}
if ($value->type === Variable::TYPE_HASHTABLE) {
$fetched = $value->dimFetch($dim, $resultOp->type, $forWrite);
$fetched = $value->dimFetch($dim, $resultOp->type, $forWrite, $dimOp);
if ($forWrite) {
$this->context->setVariableOp($resultOp, $fetched);
} else {
Expand Down Expand Up @@ -561,7 +561,7 @@ private function compileBlockInternal(
$leftBb = JIT\CoalesceHelper::compileBranch($this, $func, $op->block1);
$rightBb = JIT\CoalesceHelper::compileBranch($this, $func, $op->block2);
$builder->positionAtEnd($branchBlock);
$this->context->freeDeadVariables($func, $branchBlock, $block);
// Do not free here: $op->arg1 is assigned in branch blocks (#99, #148).
$builder->branchIf($condition, $leftBb, $rightBb);
if (null !== $op->block3) {
$mergeBb = JIT\BasicBlockHelper::append($this->context, 'coalesce_merge');
Expand Down
2 changes: 1 addition & 1 deletion lib/JIT/IssetHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ private static function superglobalName(Variable $container, ?Operand $container
return null;
}

private static function literalStringKey(?Operand $dimOp): ?string
public static function literalStringKey(?Operand $dimOp): ?string
{
if (null === $dimOp) {
return null;
Expand Down
5 changes: 4 additions & 1 deletion lib/JIT/Variable.php
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ public function toString(\gcc_jit_block_ptr $block): Variable {
}
}

public function dimFetch(self $dim, ?Type $expectedType = null, bool $forWrite = false): Variable {
public function dimFetch(self $dim, ?Type $expectedType = null, bool $forWrite = false, ?Operand $dimOp = null): Variable {
switch ($this->type) {
case self::TYPE_STRING:
$ptr = StringOffsetHelper::dimFetch(
Expand All @@ -395,6 +395,9 @@ public function dimFetch(self $dim, ?Type $expectedType = null, bool $forWrite =
&& (null === $expectedType || Type::TYPE_ARRAY !== $expectedType->type)
) {
$key = $dim->compileTimeString;
if (null === $key && isset($dimOp)) {
$key = IssetHelper::literalStringKey($dimOp);
}
if (null !== $key) {
$baked = SuperglobalInit::compileTimeReadString(
$this->context,
Expand Down