diff --git a/lib/JIT.php b/lib/JIT.php index 3cefbf24..0fe081dd 100644 --- a/lib/JIT.php +++ b/lib/JIT.php @@ -381,7 +381,8 @@ private function isSkippedCompilerHotPathName(string $name): bool || str_contains($lower, 'findcoalesce') || str_contains($lower, 'resolvecoalesce') || str_contains($lower, 'resolveisset') - || str_contains($lower, 'operandschainequal'); + || str_contains($lower, 'operandschainequal') + || str_contains($lower, 'isredundantcoalescetailassign'); } private function isSkippedSelfHostEntryName(string $name): bool @@ -416,7 +417,7 @@ private function isSkippedWebBootstrapHotPathName(string $name): bool || str_contains($lower, 'deployroot') || str_contains($lower, 'sourcebundler') || (str_contains($lower, '\\web\\conststringfolder::') && !$this->isConstStringFolderRealLoweringMethod($lower)) - || (str_contains($lower, '\\web\\superglobals::') && !str_ends_with($lower, '::issuperglobalname')); + || str_contains($lower, '\\web\\superglobals::'); } @@ -439,6 +440,11 @@ private function isSkippedLibSpineSmokeHotPathName(string $name): bool /** IncludePathResolver methods with safe LLVM 9 lowering during self-host AOT (#816). */ private function isIncludePathResolverRealLoweringMethod(string $lower): bool { + // resolve() nullable return still hits ICmp type mismatch in full self-host probe (#1097). + if ($this->shouldUseSelfHostJitStubs()) { + return false; + } + return str_ends_with($lower, '::resolve'); } diff --git a/lib/JIT/Call/Native.php b/lib/JIT/Call/Native.php index e36a7cbb..1971024a 100644 --- a/lib/JIT/Call/Native.php +++ b/lib/JIT/Call/Native.php @@ -64,6 +64,25 @@ protected function compileArg(Context $context, Variable $arg, int $argNum): Val $value = $context->helper->loadValue($arg); switch ($typeName) { case '__object__*': + if ( + null !== $arg->objectPropertySlot + && Variable::TYPE_VALUE === $arg->objectPropertyType + ) { + return $context->builder->call( + $context->lookupFunction('__value__readObject'), + $value + ); + } + $valueTy = $value->typeOf(); + if ( + \PHPLLVM\Type::KIND_POINTER === $valueTy->getKind() + && '__value__' === $context->getStringFromType($valueTy->getElementType()) + ) { + return $context->builder->call( + $context->lookupFunction('__value__readObject'), + $value + ); + } switch ($arg->type) { case Variable::TYPE_OBJECT: return $value; diff --git a/lib/JIT/Call/Native.pre b/lib/JIT/Call/Native.pre index 571aaa06..69d4f2f2 100755 --- a/lib/JIT/Call/Native.pre +++ b/lib/JIT/Call/Native.pre @@ -63,6 +63,25 @@ class Native implements Call { $value = $context->helper->loadValue($arg); switch ($typeName) { case '__object__*': + if ( + null !== $arg->objectPropertySlot + && Variable::TYPE_VALUE === $arg->objectPropertyType + ) { + return $context->builder->call( + $context->lookupFunction('__value__readObject'), + $value + ); + } + $valueTy = $value->typeOf(); + if ( + \PHPLLVM\Type::KIND_POINTER === $valueTy->getKind() + && '__value__' === $context->getStringFromType($valueTy->getElementType()) + ) { + return $context->builder->call( + $context->lookupFunction('__value__readObject'), + $value + ); + } switch ($arg->type) { case Variable::TYPE_OBJECT: return $value; diff --git a/lib/JIT/Helper.php b/lib/JIT/Helper.php index 338934a9..1fcb68b4 100644 --- a/lib/JIT/Helper.php +++ b/lib/JIT/Helper.php @@ -884,12 +884,18 @@ public function binaryOp(OpCode $opcode, Variable $left, Variable $right): Varia } } if (Variable::TYPE_OBJECT === $leftType && $leftType === $rightType) { + $voidp = $this->context->getTypeFromString('void')->pointerType(0); + $leftNorm = $this->context->builder->pointerCast($leftValue, $voidp); + $rightNorm = $this->context->builder->pointerCast($rightValue, $voidp); + $sizeT = $this->context->getTypeFromString('size_t'); + $leftPtr = $this->context->builder->ptrToInt($leftNorm, $sizeT); + $rightPtr = $this->context->builder->ptrToInt($rightNorm, $sizeT); if (OpCode::TYPE_IDENTICAL === $opcode->type) { - $result = $this->context->builder->icmp(Builder::INT_EQ, $leftValue, $rightValue); + $result = $this->context->builder->icmp(Builder::INT_EQ, $leftPtr, $rightPtr); goto return_bool; } if (OpCode::TYPE_NOT_IDENTICAL === $opcode->type) { - $result = $this->context->builder->icmp(Builder::INT_NE, $leftValue, $rightValue); + $result = $this->context->builder->icmp(Builder::INT_NE, $leftPtr, $rightPtr); goto return_bool; } } @@ -978,16 +984,38 @@ public function loadValue(Variable $variable): PHPLLVM\Value { $this->context->getTypeFromString('__hashtable__*') ); } + if (Variable::TYPE_OBJECT === $variable->objectPropertyType) { + return $this->context->builder->pointerCast( + $loaded, + $this->context->getTypeFromString('__object__*') + ); + } if (Variable::TYPE_STRING === $variable->objectPropertyType) { return $this->context->builder->pointerCast( $loaded, $this->context->getTypeFromString('__string__*') ); } + if (Variable::TYPE_VALUE === $variable->objectPropertyType) { + $valuePtr = $this->context->builder->pointerCast( + $loaded, + $this->context->getTypeFromString('__value__*') + ); + if (Variable::TYPE_OBJECT === $variable->type) { + return $this->context->builder->call( + $this->context->lookupFunction('__value__readObject'), + $valuePtr + ); + } + + return $valuePtr; + } + + $llvmType = Variable::getStringType($variable->objectPropertyType); return $this->context->builder->pointerCast( $loaded, - $this->context->getTypeFromString('__value__*') + $this->context->getTypeFromString($llvmType) ); } if ($variable->kind === Variable::KIND_VALUE) { @@ -1007,14 +1035,11 @@ private static function isOrderedCompareOpcode(int $opcodeType): bool private function operandJitType(Variable $var): int { if (null !== $var->objectPropertySlot && null !== $var->objectPropertyType) { - if (Variable::TYPE_HASHTABLE === $var->objectPropertyType) { - return Variable::TYPE_HASHTABLE; - } - if (Variable::TYPE_STRING === $var->objectPropertyType) { - return Variable::TYPE_STRING; + if (Variable::TYPE_VALUE === $var->objectPropertyType) { + return Variable::TYPE_VALUE; } - return Variable::TYPE_VALUE; + return $var->objectPropertyType; } return $var->type; diff --git a/lib/JIT/Helper.pre b/lib/JIT/Helper.pre index 249ebd66..9b121a81 100644 --- a/lib/JIT/Helper.pre +++ b/lib/JIT/Helper.pre @@ -444,16 +444,38 @@ return_bool: $this->context->getTypeFromString('__hashtable__*') ); } + if (Variable::TYPE_OBJECT === $variable->objectPropertyType) { + return $this->context->builder->pointerCast( + $loaded, + $this->context->getTypeFromString('__object__*') + ); + } if (Variable::TYPE_STRING === $variable->objectPropertyType) { return $this->context->builder->pointerCast( $loaded, $this->context->getTypeFromString('__string__*') ); } + if (Variable::TYPE_VALUE === $variable->objectPropertyType) { + $valuePtr = $this->context->builder->pointerCast( + $loaded, + $this->context->getTypeFromString('__value__*') + ); + if (Variable::TYPE_OBJECT === $variable->type) { + return $this->context->builder->call( + $this->context->lookupFunction('__value__readObject'), + $valuePtr + ); + } + + return $valuePtr; + } + + $llvmType = Variable::getStringType($variable->objectPropertyType); return $this->context->builder->pointerCast( $loaded, - $this->context->getTypeFromString('__value__*') + $this->context->getTypeFromString($llvmType) ); } if ($variable->kind === Variable::KIND_VALUE) { @@ -465,14 +487,11 @@ return_bool: private function operandJitType(Variable $var): int { if (null !== $var->objectPropertySlot && null !== $var->objectPropertyType) { - if (Variable::TYPE_HASHTABLE === $var->objectPropertyType) { - return Variable::TYPE_HASHTABLE; - } - if (Variable::TYPE_STRING === $var->objectPropertyType) { - return Variable::TYPE_STRING; + if (Variable::TYPE_VALUE === $var->objectPropertyType) { + return Variable::TYPE_VALUE; } - return Variable::TYPE_VALUE; + return $var->objectPropertyType; } return $var->type; diff --git a/lib/JIT/JitValueBox.php b/lib/JIT/JitValueBox.php index 1eeec18d..0359c4a6 100644 --- a/lib/JIT/JitValueBox.php +++ b/lib/JIT/JitValueBox.php @@ -43,9 +43,7 @@ public static function isValueOperand(Variable $var): bool return true; } return null !== $var->objectPropertySlot - && null !== $var->objectPropertyType - && Variable::TYPE_HASHTABLE !== $var->objectPropertyType - && Variable::TYPE_STRING !== $var->objectPropertyType; + && Variable::TYPE_VALUE === $var->objectPropertyType; } /**