refactor(Php): 优化字符串字面量处理和函数调用优化

- 提取字符串字面量处理逻辑到独立方法 getLiteralString
- 将 C++ 接口参数类型从 const char* 改为 const php::String&
- 修改字面量字符串数组类型从 php::Var 为 php::Str
- 添加 function_exists 函数调用的优化处理
- 更新头文件中的函数声明和内联函数参数类型
- 调整示例代码中的性能测试部分注释状态
pull/1/head
韩天峰 7 months ago
parent 5b44e4d390
commit 6dd8d2d6bc
  1. 136
      examples/micro_bench.php
  2. 25
      src/Php/CompilerBase.php
  3. 3
      src/Php/FuncCallOptimizer.php
  4. 2
      src/Php/Translator.php
  5. 12
      src/cpp/php_aot_helper.h
  6. 6
      src/template/extension.cc.php

@ -18,7 +18,7 @@ function hallo2() {
function simpleicall($n) { function simpleicall($n) {
for ($i = 0; $i < $n; $i++) for ($i = 0; $i < $n; $i++)
function_exists('hallo'); $ret = function_exists('hallo');
} }
class Foo { class Foo {
@ -287,74 +287,74 @@ function main()
empty_loop(N); empty_loop(N);
$t = end_test($t, 'empty_loop'); $t = end_test($t, 'empty_loop');
$overhead = $last_time; $overhead = $last_time;
simpleucall(N); // simpleucall(N);
$t = end_test($t, 'func()', $overhead); // $t = end_test($t, 'func()', $overhead);
simpleudcall(N); // simpleudcall(N);
$t = end_test($t, 'undef_func()', $overhead); // $t = end_test($t, 'undef_func()', $overhead);
simpleicall(N); simpleicall(N);
$t = end_test($t, 'int_func()', $overhead); $t = end_test($t, 'int_func()', $overhead);
Foo::read_static(N); // Foo::read_static(N);
$t = end_test($t, '$x = self::$x', $overhead); // $t = end_test($t, '$x = self::$x', $overhead);
Foo::write_static(N); // Foo::write_static(N);
$t = end_test($t, 'self::$x = 0', $overhead); // $t = end_test($t, 'self::$x = 0', $overhead);
Foo::isset_static(N); // Foo::isset_static(N);
$t = end_test($t, 'isset(self::$x)', $overhead); // $t = end_test($t, 'isset(self::$x)', $overhead);
Foo::empty_static(N); // Foo::empty_static(N);
$t = end_test($t, 'empty(self::$x)', $overhead); // $t = end_test($t, 'empty(self::$x)', $overhead);
read_static(N); // read_static(N);
$t = end_test($t, '$x = Foo::$x', $overhead); // $t = end_test($t, '$x = Foo::$x', $overhead);
write_static(N); // write_static(N);
$t = end_test($t, 'Foo::$x = 0', $overhead); // $t = end_test($t, 'Foo::$x = 0', $overhead);
isset_static(N); // isset_static(N);
$t = end_test($t, 'isset(Foo::$x)', $overhead); // $t = end_test($t, 'isset(Foo::$x)', $overhead);
empty_static(N); // empty_static(N);
$t = end_test($t, 'empty(Foo::$x)', $overhead); // $t = end_test($t, 'empty(Foo::$x)', $overhead);
Foo::call_static(N); // Foo::call_static(N);
$t = end_test($t, 'self::f()', $overhead); // $t = end_test($t, 'self::f()', $overhead);
call_static(N); // call_static(N);
$t = end_test($t, 'Foo::f()', $overhead); // $t = end_test($t, 'Foo::f()', $overhead);
$x = new Foo(); // $x = new Foo();
$x->read_prop(N); // $x->read_prop(N);
$t = end_test($t, '$x = $this->x', $overhead); // $t = end_test($t, '$x = $this->x', $overhead);
$x->write_prop(N); // $x->write_prop(N);
$t = end_test($t, '$this->x = 0', $overhead); // $t = end_test($t, '$this->x = 0', $overhead);
$x->assign_add_prop(N); // $x->assign_add_prop(N);
$t = end_test($t, '$this->x += 2', $overhead); // $t = end_test($t, '$this->x += 2', $overhead);
$x->pre_inc_prop(N); // $x->pre_inc_prop(N);
$t = end_test($t, '++$this->x', $overhead); // $t = end_test($t, '++$this->x', $overhead);
$x->pre_dec_prop(N); // $x->pre_dec_prop(N);
$t = end_test($t, '--$this->x', $overhead); // $t = end_test($t, '--$this->x', $overhead);
$x->post_inc_prop(N); // $x->post_inc_prop(N);
$t = end_test($t, '$this->x++', $overhead); // $t = end_test($t, '$this->x++', $overhead);
$x->post_dec_prop(N); // $x->post_dec_prop(N);
$t = end_test($t, '$this->x--', $overhead); // $t = end_test($t, '$this->x--', $overhead);
$x->isset_prop(N); // $x->isset_prop(N);
$t = end_test($t, 'isset($this->x)', $overhead); // $t = end_test($t, 'isset($this->x)', $overhead);
$x->empty_prop(N); // $x->empty_prop(N);
$t = end_test($t, 'empty($this->x)', $overhead); // $t = end_test($t, 'empty($this->x)', $overhead);
$x->call(N); // $x->call(N);
$t = end_test($t, '$this->f()', $overhead); // $t = end_test($t, '$this->f()', $overhead);
$x->read_const(N); // $x->read_const(N);
$t = end_test($t, '$x = Foo::TEST', $overhead); // $t = end_test($t, '$x = Foo::TEST', $overhead);
create_object(N); // create_object(N);
$t = end_test($t, 'new Foo()', $overhead); // $t = end_test($t, 'new Foo()', $overhead);
read_const(N); // read_const(N);
$t = end_test($t, '$x = TEST', $overhead); // $t = end_test($t, '$x = TEST', $overhead);
read_auto_global(N); // read_auto_global(N);
$t = end_test($t, '$x = $_GET', $overhead); // $t = end_test($t, '$x = $_GET', $overhead);
read_global_var(N); // read_global_var(N);
$t = end_test($t, '$x = $GLOBALS[\'v\']', $overhead); // $t = end_test($t, '$x = $GLOBALS[\'v\']', $overhead);
read_hash(N); // read_hash(N);
$t = end_test($t, '$x = $hash[\'v\']', $overhead); // $t = end_test($t, '$x = $hash[\'v\']', $overhead);
read_str_offset(N); // read_str_offset(N);
$t = end_test($t, '$x = $str[0]', $overhead); // $t = end_test($t, '$x = $str[0]', $overhead);
issetor(N); // issetor(N);
$t = end_test($t, '$x = $a ?: null', $overhead); // $t = end_test($t, '$x = $a ?: null', $overhead);
issetor2(N); // issetor2(N);
$t = end_test($t, '$x = $f ?: tmp', $overhead); // $t = end_test($t, '$x = $f ?: tmp', $overhead);
ternary(N); // ternary(N);
$t = end_test($t, '$x = $f ? $f : $a', $overhead); // $t = end_test($t, '$x = $f ? $f : $a', $overhead);
ternary2(N); // ternary2(N);
$t = end_test($t, '$x = $f ? $f : tmp', $overhead); // $t = end_test($t, '$x = $f ? $f : tmp', $overhead);
total(); total();
} }

@ -607,11 +607,11 @@ class CompilerBase extends \PhpAot\Core\Translator
if (isset($this->classMap[$className])) { if (isset($this->classMap[$className])) {
$id = $this->classMap[$className]; $id = $this->classMap[$className];
} else { } else {
$id = $this->classIndex++; $id = $this->classIndex++;
$this->classMap[$className] = $id; $this->classMap[$className] = $id;
} }
return 'php_get_class(' . $id . ', "' . $this->escapeString($className) . '")'; return 'php_get_class(' . $id . ', ' . $this->getLiteralString($className) . ')';
} }
protected function getFuncPtr(string $funcName): string protected function getFuncPtr(string $funcName): string
@ -622,7 +622,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$id = $this->funcIndex++; $id = $this->funcIndex++;
$this->funcMap[$funcName] = $id; $this->funcMap[$funcName] = $id;
} }
return $id . ', "' . $this->escapeString($funcName) . '"'; return $id . ', ' . $this->getLiteralString($funcName);
} }
protected function parseFunctionDeclaration(Node\Stmt\Function_|Node\Stmt\ClassMethod $v): FunctionDef protected function parseFunctionDeclaration(Node\Stmt\Function_|Node\Stmt\ClassMethod $v): FunctionDef
@ -712,7 +712,16 @@ class CompilerBase extends \PhpAot\Core\Translator
} }
} }
protected function parseScalar(Node $expr) protected function getLiteralString(string $string): string
{
if ($this->noLiteralStrings) {
return '"' . $this->escapeString($string) . '"';
}
$index = $this->literalStrings[$string] ?? $this->addLiteralString($string);
return self::LITERAL_STRINGS . '[' . $index . ']';
}
protected function parseScalar(Node\Scalar $expr)
{ {
$type = $expr->getType(); $type = $expr->getType();
switch ($type) { switch ($type) {
@ -721,13 +730,7 @@ class CompilerBase extends \PhpAot\Core\Translator
case 'Scalar_Float': case 'Scalar_Float':
return $this->parseScalarFloat($expr); return $this->parseScalarFloat($expr);
case 'Scalar_String': case 'Scalar_String':
if ($this->noLiteralStrings) { return $this->getLiteralString($expr->value);
return '"' . $this->escapeString($expr->value) . '"';
}
$index = $this->literalStrings[$expr->value] ?? $this->addLiteralString($expr->value);
return self::LITERAL_STRINGS . '[' . $index . ']';
default: default:
abort($expr); abort($expr);
} }

@ -44,6 +44,9 @@ trait FuncCallOptimizer
if ($name === 'abs') { if ($name === 'abs') {
return 'php::math::abs(' . $this->parseIdentifier($expr->args[0]->value) . ')'; return 'php::math::abs(' . $this->parseIdentifier($expr->args[0]->value) . ')';
} }
if ($name === 'function_exists') {
return 'php::fn::function_exists(' . $this->parseIdentifier($expr->args[0]->value) . ')';
}
return false; return false;
} }

@ -197,7 +197,7 @@ class Translator extends Preprocessor
} }
$literalStringsCount = count($this->literalStrings); $literalStringsCount = count($this->literalStrings);
$lines[] = 'extern php::Var ' . self::LITERAL_STRINGS . '[' . $literalStringsCount . '];' . PHP_EOL; $lines[] = 'extern ' . self::TYPE_STR . ' ' . self::LITERAL_STRINGS . '[' . $literalStringsCount . '];' . PHP_EOL;
$classCount = count($this->classMap); $classCount = count($this->classMap);
$lines[] = 'extern zend_class_entry *' . self::PREFIX . self::CLASS_MAP . '[' . $classCount . '];' . PHP_EOL; $lines[] = 'extern zend_class_entry *' . self::PREFIX . self::CLASS_MAP . '[' . $classCount . '];' . PHP_EOL;

@ -1,20 +1,20 @@
#include <phpx.h> #include <phpx.h>
extern zend_class_entry *php_get_class(int class_id, const char *class_name); extern zend_class_entry *php_get_class(int class_id, const php::String &class_name);
extern zend_function *php_get_func(int func_id, const char *func_name); extern zend_function *php_get_func(int func_id, const php::String &func_name);
static inline php::Variant CALL(int func_id, const char *func_name, const std::initializer_list<php::Variant> &args) { static inline php::Variant CALL(int func_id, const php::String &func_name, const std::initializer_list<php::Variant> &args) {
return php::call(php_get_func(func_id, func_name), args); return php::call(php_get_func(func_id, func_name), args);
} }
static inline php::Variant CALL(int func_id, const char *func_name) { static inline php::Variant CALL(int func_id, const php::String &func_name) {
return php::call(php_get_func(func_id, func_name)); return php::call(php_get_func(func_id, func_name));
} }
static inline php::Variant CALL_SILENT(int func_id, const char *func_name, const std::initializer_list<php::Variant> &args) { static inline php::Variant CALL_SILENT(int func_id, const php::String &func_name, const std::initializer_list<php::Variant> &args) {
return php::silentCall(php_get_func(func_id, func_name), args); return php::silentCall(php_get_func(func_id, func_name), args);
} }
static inline php::Variant CALL_SILENT(int func_id, const char *func_name) { static inline php::Variant CALL_SILENT(int func_id, const php::String &func_name) {
return php::silentCall(php_get_func(func_id, func_name)); return php::silentCall(php_get_func(func_id, func_name));
} }

@ -27,14 +27,14 @@ zend_class_entry *<?= Translator::PREFIX . Translator::CLASS_MAP . '[' . count($
// func // func
zend_function *<?= Translator::PREFIX . Translator::FUNC_MAP . '[' . count($this->funcMap) . ']' ?>; zend_function *<?= Translator::PREFIX . Translator::FUNC_MAP . '[' . count($this->funcMap) . ']' ?>;
zend_class_entry *php_get_class(int class_id, const char *class_name) { zend_class_entry *php_get_class(int class_id, const php::String &class_name) {
if (UNEXPECTED(<?= Translator::PREFIX . Translator::CLASS_MAP ?>[class_id] == nullptr)) { if (UNEXPECTED(<?= Translator::PREFIX . Translator::CLASS_MAP ?>[class_id] == nullptr)) {
<?= Translator::PREFIX . Translator::CLASS_MAP ?>[class_id] = php::getClassEntrySafe(class_name); <?= Translator::PREFIX . Translator::CLASS_MAP ?>[class_id] = php::getClassEntrySafe(class_name);
} }
return <?= Translator::PREFIX . Translator::CLASS_MAP ?>[class_id]; return <?= Translator::PREFIX . Translator::CLASS_MAP ?>[class_id];
} }
zend_function *php_get_func(int func_id, const char *func_name) { zend_function *php_get_func(int func_id, const php::String &func_name) {
if (UNEXPECTED(<?= Translator::PREFIX . Translator::FUNC_MAP ?>[func_id] == nullptr)) { if (UNEXPECTED(<?= Translator::PREFIX . Translator::FUNC_MAP ?>[func_id] == nullptr)) {
<?= Translator::PREFIX . Translator::FUNC_MAP ?>[func_id] = php::getFunction(func_name); <?= Translator::PREFIX . Translator::FUNC_MAP ?>[func_id] = php::getFunction(func_name);
} }
@ -42,7 +42,7 @@ zend_function *php_get_func(int func_id, const char *func_name) {
} }
// literal strings // literal strings
php::Var <?=Translator::LITERAL_STRINGS?>[] = { php::Str <?=Translator::LITERAL_STRINGS?>[] = {
<?php <?php
foreach ($this->literalStrings as $str => $index): foreach ($this->literalStrings as $str => $index):
?> ?>

Loading…
Cancel
Save