feat(stdlib): lower SPL runtime calls directly

master
韩天峰 8 hours ago
parent a31c84ed7f
commit 0eba3b72f9
  1. 18
      phpunit/code/spl-runtime-direct-calls.php
  2. 30
      phpunit/src/SplRuntimeOptimizerTest.php
  3. 39
      src/Optimizer/FuncCallOptimizer.php
  4. 60
      tests/compiler/stdlib/spl-runtime-direct.phpt

@ -0,0 +1,18 @@
<?php
function splRuntimeDirectCalls(Iterator $iterator, object $object, string $constantName): array
{
return [
iterator_count($iterator),
iterator_to_array($iterator),
iterator_to_array($iterator, false),
spl_object_hash($object),
spl_object_id($object),
constant($constantName),
];
}
function splRuntimeDynamicConstant(mixed $constantName): mixed
{
return constant($constantName);
}

@ -0,0 +1,30 @@
<?php
use TypePhp\CompilerTest;
final class SplRuntimeOptimizerTest extends BaseTest
{
public function testCallsUseDirectPhpxWrappersWhenArgumentTypesAreSafe(): void
{
global $translator;
$compiler = CompilerTest::create(TYPEPHP_ROOT_PATH);
$translator = $compiler;
$source = TYPEPHP_ROOT_PATH . '/phpunit/code/spl-runtime-direct-calls.php';
$compiler->addFiles([$source]);
$compiler->prepareFile($source);
$generated = $compiler->convertFile($source);
$code = file_get_contents($generated);
self::assertIsString($code);
self::assertSame(1, substr_count($code, 'php::fn::iterator_count('));
self::assertSame(2, substr_count($code, 'php::fn::iterator_to_array('));
self::assertSame(1, substr_count($code, 'php::fn::spl_object_hash('));
self::assertSame(1, substr_count($code, 'php::fn::spl_object_id('));
self::assertSame(1, substr_count($code, 'php::fn::constant('));
// A mixed name must retain Zend's runtime parameter validation rather
// than being coerced into the String ABI used by the direct wrapper.
self::assertStringContainsString('php::call(', $code);
}
}

@ -195,6 +195,45 @@ trait FuncCallOptimizer
'intrinsic' => true, 'intrinsic' => true,
], ],
// SPL and runtime constant queries. These wrappers preserve
// Zend's runtime validation and iterator side effects while
// avoiding zend_call_function for ordinary positional calls.
'iterator_count' => [
'args' => 'v',
'minArgs' => 1,
'maxArgs' => 1,
'returnType' => Type::INT,
'intrinsic' => true,
],
'iterator_to_array' => [
'args' => 'v_?b',
'minArgs' => 1,
'maxArgs' => 2,
'returnType' => Type::ARRAY,
'intrinsic' => true,
],
'spl_object_hash' => [
'args' => 'v',
'minArgs' => 1,
'maxArgs' => 1,
'returnType' => Type::STR,
'intrinsic' => true,
],
'spl_object_id' => [
'args' => 'v',
'minArgs' => 1,
'maxArgs' => 1,
'returnType' => Type::INT,
'intrinsic' => true,
],
'constant' => [
'args' => 's',
'minArgs' => 1,
'maxArgs' => 1,
'returnType' => Type::ANY,
'intrinsic' => true,
],
'strncmp' => ['constFold' => self::FOLD_CMP3], 'strncmp' => ['constFold' => self::FOLD_CMP3],
'strncasecmp' => ['constFold' => self::FOLD_CMP3], 'strncasecmp' => ['constFold' => self::FOLD_CMP3],
'explode' => [], 'explode' => [],

@ -0,0 +1,60 @@
--TEST--
SPL iterator, object identity, and constant functions use direct wrappers
--FILE--
<?php
function makeIterator(): Iterator
{
return new ArrayIterator(['name' => 'phpx', 4 => 42]);
}
function main(): void
{
var_dump(iterator_count(makeIterator()));
var_dump(iterator_to_array(makeIterator()));
var_dump(iterator_to_array(makeIterator(), false));
$object = new stdClass();
var_dump(spl_object_id($object) > 0);
var_dump(strlen(spl_object_hash($object)) === 32);
var_dump(spl_object_id($object) === spl_object_id($object));
define('TYPEPHP_RUNTIME_FAST_CONSTANT', ['ok' => true]);
var_dump(constant('TYPEPHP_RUNTIME_FAST_CONSTANT'));
try {
iterator_count(42);
} catch (TypeError $error) {
echo $error->getMessage(), "\n";
}
try {
spl_object_hash('invalid');
} catch (TypeError $error) {
echo $error->getMessage(), "\n";
}
}
?>
--EXPECT--
int(2)
array(2) {
["name"]=>
string(4) "phpx"
[4]=>
int(42)
}
array(2) {
[0]=>
string(4) "phpx"
[1]=>
int(42)
}
bool(true)
bool(true)
bool(true)
array(1) {
["ok"]=>
bool(true)
}
iterator_count(): Argument #1 ($iterator) must be of type Traversable|array, int given
spl_object_hash(): Argument #1 ($object) must be of type object, string given
Loading…
Cancel
Save