diff --git a/lib/JIT.php b/lib/JIT.php index 664c9d7e..0be76b09 100644 --- a/lib/JIT.php +++ b/lib/JIT.php @@ -614,7 +614,16 @@ private function isSkippedLibSpineSmokeHotPathName(string $name): bool || str_contains($lower, '\\web\\cgiaotdriver::') || str_contains($lower, '\\web\\cgidriver::') || str_contains($lower, '\\web\\projectdeploy::') - || str_contains($lower, '\\ext\\standard\\jit'); + || str_contains($lower, '\\ext\\standard\\jit') + || str_contains($lower, '\\jit\\varfetchhelper::') + || str_contains($lower, '\\jit\\unsethelper::') + || str_contains($lower, '\\jit\\arraybuiltinhelper::') + || str_contains($lower, '\\jit\\reflectionbuiltinhelper::') + || str_contains($lower, '\\jit\\typecheck::') + || str_contains($lower, '\\jit\\errorhandlercallbackpolicy::') + || str_contains($lower, '\\jit\\builtin\\stringparsestr::') + || str_contains($lower, '\\jit\\builtin\\type\\object_::') + || str_contains($lower, '\\jit\\builtin\\type\\hashtable::'); } /** IncludePathResolver methods with safe LLVM 9 lowering during self-host AOT (#816). */ diff --git a/lib/JIT/ArrayBuiltinHelper.php b/lib/JIT/ArrayBuiltinHelper.php index 994846a0..f3206175 100644 --- a/lib/JIT/ArrayBuiltinHelper.php +++ b/lib/JIT/ArrayBuiltinHelper.php @@ -258,8 +258,7 @@ public static function popLast(Context $context, Variable $array): Value private static function copyValueEntryToBox(Context $context, Value $destPtr, Value $entry): void { - static $seq = 0; - $tag = 'vb'.(string) ++$seq; + $tag = 'vb'.(string) ++self::$copyListEntrySeq; $valueMap = $context->structFieldMap['__value__']; $typeByte = $context->builder->load( $context->builder->structGep($entry, $valueMap['type']) @@ -349,8 +348,7 @@ private static function copyValueEntryToBox(Context $context, Value $destPtr, Va private static function copyValueEntrySlot(Context $context, Value $fromEntry, Value $toEntry): void { - static $seq = 0; - $tag = 'vs'.(string) ++$seq; + $tag = 'vs'.(string) ++self::$copyListEntrySeq; $valueMap = $context->structFieldMap['__value__']; $typeByte = $context->builder->load( $context->builder->structGep($fromEntry, $valueMap['type']) @@ -935,8 +933,7 @@ private static function copyPackedValueEntry( Value $dest, Value $destIndex ): void { - static $seq = 0; - $tag = 'pv'.(string) ++$seq; + $tag = 'pv'.(string) ++self::$copyListEntrySeq; $valueMap = $context->structFieldMap['__value__']; $typeByte = $context->builder->load( $context->builder->structGep($srcEntry, $valueMap['type']) @@ -2309,8 +2306,7 @@ private static function buildChunkFromNativeArray( Variable $array, Value $size ): Value { - static $seq = 0; - $tag = 'acn'.(string) ++$seq; + $tag = 'acn'.(string) ++self::$copyListEntrySeq; $elemType = $array->type & ~Variable::IS_NATIVE_ARRAY; $sizeT = $context->getTypeFromString('size_t'); $htPtr = $context->getTypeFromString('__hashtable__*'); @@ -2416,8 +2412,7 @@ private static function buildChunkFromNativeArray( private static function buildChunkFromHashTable(Context $context, Value $src, Value $size): Value { - static $seq = 0; - $tag = 'ac'.(string) ++$seq; + $tag = 'ac'.(string) ++self::$copyListEntrySeq; $map = $context->structFieldMap['__hashtable__']; $sizeT = $context->getTypeFromString('size_t'); $htPtr = $context->getTypeFromString('__hashtable__*'); @@ -2792,8 +2787,7 @@ private static function buildColumnFromHashTable( Value $src, Value $columnKeyStr ): Value { - static $seq = 0; - $tag = (string) ++$seq; + $tag = (string) ++self::$copyListEntrySeq; $map = $context->structFieldMap['__hashtable__']; $valueMap = $context->structFieldMap['__value__']; $sizeT = $context->getTypeFromString('size_t'); @@ -3001,8 +2995,7 @@ private static function filterCopyListEntry( private static function listEntryTruthy(Context $context, Value $entry): Value { - static $seq = 0; - $tag = 'ft'.(string) ++$seq; + $tag = 'ft'.(string) ++self::$copyListEntrySeq; $valueMap = $context->structFieldMap['__value__']; $typeByte = $context->builder->load( $context->builder->structGep($entry, $valueMap['type']) diff --git a/lib/JIT/Builtin/Type/HashTable.php b/lib/JIT/Builtin/Type/HashTable.php index e66c3a3b..237c5a42 100644 --- a/lib/JIT/Builtin/Type/HashTable.php +++ b/lib/JIT/Builtin/Type/HashTable.php @@ -116,7 +116,10 @@ public function register(): void */ private function registerFn(string $name, string $returnType, array $paramTypes): void { - $params = array_map(fn (string $t) => $this->context->getTypeFromString($t), $paramTypes); + $params = []; + foreach ($paramTypes as $t) { + $params[] = $this->context->getTypeFromString($t); + } $ft = $this->context->context->functionType( $this->context->getTypeFromString($returnType), false, diff --git a/lib/JIT/Builtin/Type/Object_.php b/lib/JIT/Builtin/Type/Object_.php index 5c1ca181..fb88a42e 100755 --- a/lib/JIT/Builtin/Type/Object_.php +++ b/lib/JIT/Builtin/Type/Object_.php @@ -73,7 +73,10 @@ public function register(): void */ private function registerFn(string $name, string $returnType, array $paramTypes): void { - $params = array_map(fn (string $t) => $this->context->getTypeFromString($t), $paramTypes); + $params = []; + foreach ($paramTypes as $t) { + $params[] = $this->context->getTypeFromString($t); + } $ft = $this->context->context->functionType( $this->context->getTypeFromString($returnType), false, @@ -630,19 +633,8 @@ public function lookup(string $name): int private function ensureExternalClassConstants(int $id, string $lcname): void { - $seed = function (array $constants) use ($id): void { - foreach ($constants as $name => $value) { - if (!isset($this->classConstants[$id][$name])) { - $this->classConstants[$id][$name] = [ - 'type' => Variable::TYPE_NATIVE_LONG, - 'value' => $value, - ]; - } - } - }; - if ('phpcompiler\\vm\\variable' === $lcname) { - $seed([ + $this->seedExternalClassConstants($id, [ 'type_undefined' => \PHPCompiler\VM\Variable::TYPE_UNDEFINED, 'type_null' => \PHPCompiler\VM\Variable::TYPE_NULL, 'type_integer' => \PHPCompiler\VM\Variable::TYPE_INTEGER, @@ -656,7 +648,7 @@ private function ensureExternalClassConstants(int $id, string $lcname): void ]); } if ('phpcompiler\\jit\\variable' === $lcname || 'variable' === $lcname) { - $seed([ + $this->seedExternalClassConstants($id, [ 'type_null' => \PHPCompiler\JIT\Variable::TYPE_NULL, 'type_native_long' => \PHPCompiler\JIT\Variable::TYPE_NATIVE_LONG, 'type_native_bool' => \PHPCompiler\JIT\Variable::TYPE_NATIVE_BOOL, @@ -672,16 +664,28 @@ private function ensureExternalClassConstants(int $id, string $lcname): void ]); } if ('phptypes\\type' === $lcname || 'type' === $lcname) { - $seed(['type_null'=>\PHPTypes\Type::TYPE_NULL,'type_boolean'=>\PHPTypes\Type::TYPE_BOOLEAN,'type_long'=>\PHPTypes\Type::TYPE_LONG,'type_double'=>\PHPTypes\Type::TYPE_DOUBLE,'type_string'=>\PHPTypes\Type::TYPE_STRING,'type_object'=>\PHPTypes\Type::TYPE_OBJECT,'type_array'=>\PHPTypes\Type::TYPE_ARRAY,'type_callable'=>\PHPTypes\Type::TYPE_CALLABLE,'type_union'=>\PHPTypes\Type::TYPE_UNION,'type_intersection'=>\PHPTypes\Type::TYPE_INTERSECTION]); + $this->seedExternalClassConstants($id, ['type_null'=>\PHPTypes\Type::TYPE_NULL,'type_boolean'=>\PHPTypes\Type::TYPE_BOOLEAN,'type_long'=>\PHPTypes\Type::TYPE_LONG,'type_double'=>\PHPTypes\Type::TYPE_DOUBLE,'type_string'=>\PHPTypes\Type::TYPE_STRING,'type_object'=>\PHPTypes\Type::TYPE_OBJECT,'type_array'=>\PHPTypes\Type::TYPE_ARRAY,'type_callable'=>\PHPTypes\Type::TYPE_CALLABLE,'type_union'=>\PHPTypes\Type::TYPE_UNION,'type_intersection'=>\PHPTypes\Type::TYPE_INTERSECTION]); } if ('phpcompiler\\runtime' === $lcname || 'runtime' === $lcname) { - $seed([ + $this->seedExternalClassConstants($id, [ 'mode_normal' => \PHPCompiler\Runtime::MODE_NORMAL, 'mode_aot' => \PHPCompiler\Runtime::MODE_AOT, ]); } } + private function seedExternalClassConstants(int $id, array $constants): void + { + foreach ($constants as $name => $value) { + if (!isset($this->classConstants[$id][$name])) { + $this->classConstants[$id][$name] = [ + 'type' => Variable::TYPE_NATIVE_LONG, + 'value' => $value, + ]; + } + } + } + private function registerExternalClass(string $lcname): void { $id = count($this->classes); @@ -1311,7 +1315,7 @@ private function jitConstantFromEntry(array $entry): Variable /** * @return int|float|bool|string|null */ - private function compileTimeValueFromVm(VMVariable $value): int|float|bool|string|null + private function compileTimeValueFromVm(VMVariable $value) { switch ($value->type) { case VMVariable::TYPE_NULL: diff --git a/lib/JIT/VarFetchHelper.php b/lib/JIT/VarFetchHelper.php index 59c45858..02e32f4a 100644 --- a/lib/JIT/VarFetchHelper.php +++ b/lib/JIT/VarFetchHelper.php @@ -56,26 +56,17 @@ private static function resolveBinding(Context $context, Block $block, string $n $operands[] = $op; } } - usort( - $operands, - static function (Operand $a, Operand $b): int { - $rank = static function (Operand $op): int { - $resolved = OperandName::resolve($op); - if ($op instanceof \PHPCfg\Operand\Temporary && null !== $resolved && '' !== $resolved) { - return 3; - } - if ($op instanceof \PHPCfg\Operand\Variable) { - return 2; - } - - return 1; - }; - - return $rank($b) <=> $rank($a); + $best = null; + $bestRank = -1; + foreach ($operands as $op) { + $rank = self::operandBindingRank($op); + if ($rank > $bestRank) { + $bestRank = $rank; + $best = $op; } - ); - if ([] !== $operands) { - return $context->getVariableFromOp($operands[0]); + } + if (null !== $best) { + return $context->getVariableFromOp($best); } } $found = ScopeBuiltinHelper::findVariableByName($context, $name); @@ -88,4 +79,17 @@ static function (Operand $a, Operand $b): int { return null; } + + private static function operandBindingRank(Operand $op): int + { + $resolved = OperandName::resolve($op); + if ($op instanceof \PHPCfg\Operand\Temporary && null !== $resolved && '' !== $resolved) { + return 3; + } + if ($op instanceof \PHPCfg\Operand\Variable) { + return 2; + } + + return 1; + } } diff --git a/test/selfhost/compiler_lib_spine_smoke/main.php b/test/selfhost/compiler_lib_spine_smoke/main.php index 8aa10ead..856ceed4 100644 --- a/test/selfhost/compiler_lib_spine_smoke/main.php +++ b/test/selfhost/compiler_lib_spine_smoke/main.php @@ -107,18 +107,27 @@ require_once __DIR__.'/../../../lib/JIT/Builtin/StringHttpBuildQuery.php'; require_once __DIR__.'/../../../lib/JIT/Builtin/StringSerialize.php'; require_once __DIR__.'/../../../lib/JIT/Builtin/StringSuperglobalName.php'; +require_once __DIR__.'/../../../lib/JIT/Builtin/StringParseStr.php'; require_once __DIR__.'/../../../lib/JIT/Builtin/StringPregMatch.php'; require_once __DIR__.'/../../../lib/JIT/Builtin/StringUnserialize.php'; require_once __DIR__.'/../../../lib/JIT/Builtin/StringFilePutContents.php'; require_once __DIR__.'/../../../lib/JIT/Builtin/Type/Value.php'; require_once __DIR__.'/../../../lib/JIT/Builtin/Type/NativeArray.php'; require_once __DIR__.'/../../../lib/JIT/Builtin/Type/MaskedArray.php'; +require_once __DIR__.'/../../../lib/JIT/Builtin/Type/Object_.php'; +require_once __DIR__.'/../../../lib/JIT/Builtin/Type/HashTable.php'; require_once __DIR__.'/../../../lib/MethodVisibility.php'; require_once __DIR__.'/../../../lib/JIT/Helper.php'; require_once __DIR__.'/../../../lib/JIT/Builtin/Internal.php'; require_once __DIR__.'/../../../lib/JIT/Builtin/VarArg.php'; require_once __DIR__.'/../../../lib/JIT/Context.php'; require_once __DIR__.'/../../../lib/JIT/HashTableHelper.php'; +require_once __DIR__.'/../../../lib/JIT/ErrorHandlerCallbackPolicy.php'; +require_once __DIR__.'/../../../lib/JIT/TypeCheck.php'; +require_once __DIR__.'/../../../lib/JIT/VarFetchHelper.php'; +require_once __DIR__.'/../../../lib/JIT/UnsetHelper.php'; +require_once __DIR__.'/../../../lib/JIT/ArrayBuiltinHelper.php'; +require_once __DIR__.'/../../../lib/JIT/ReflectionBuiltinHelper.php'; require_once __DIR__.'/../../../lib/JIT.php'; require_once __DIR__.'/../../../lib/VM/OutputBuffer.php'; require_once __DIR__.'/../../../lib/VM.php'; diff --git a/test/unit/BootstrapSelfhostBundleTest.php b/test/unit/BootstrapSelfhostBundleTest.php index 8ffe29d1..04e10cda 100644 --- a/test/unit/BootstrapSelfhostBundleTest.php +++ b/test/unit/BootstrapSelfhostBundleTest.php @@ -30,8 +30,17 @@ final class BootstrapSelfhostBundleTest extends TestCase 'lib/JIT/Builtin/StringHttpBuildQuery.php', 'lib/JIT/Builtin/StringSerialize.php', 'lib/JIT/Builtin/StringSuperglobalName.php', + 'lib/JIT/Builtin/StringParseStr.php', 'lib/JIT/Builtin/StringPregMatch.php', 'lib/JIT/Builtin/StringUnserialize.php', + 'lib/JIT/Builtin/Type/Object_.php', + 'lib/JIT/Builtin/Type/HashTable.php', + 'lib/JIT/VarFetchHelper.php', + 'lib/JIT/UnsetHelper.php', + 'lib/JIT/ArrayBuiltinHelper.php', + 'lib/JIT/ReflectionBuiltinHelper.php', + 'lib/JIT/TypeCheck.php', + 'lib/JIT/ErrorHandlerCallbackPolicy.php', 'lib/JIT/Builtin/StringUrldecode.php', 'ext/standard/JitAddslashes.php', 'ext/standard/JitBase64Encode.php', @@ -105,7 +114,7 @@ public function testCompilerLibSpineSmokeBundleUnitCountAndKeyUnits(): void $this->assertFileExists($entry); $contents = (string) file_get_contents($entry); $count = substr_count($contents, 'require_once __DIR__'); - $this->assertSame(179, $count, '108 compiler_minimal units + 71 M2 spine units'); + $this->assertSame(188, $count, '108 compiler_minimal units + 80 M2 spine units'); foreach (self::LIB_SPINE_SMOKE_NEW_UNITS as $unit) { $this->assertStringContainsString( "require_once __DIR__.'/../../../{$unit}';",