pull/1/head
韩天峰 8 months ago
parent 8df7d16efb
commit 6ac8494173
  1. 40
      examples/bench.php
  2. 69
      src/Php/Translator.php
  3. 9
      tests/aot/strlen.phpt

@ -1,19 +1,25 @@
<?php <?php
function simple() { function simple()
$a = 0; {
for ($i = 0; $i < 1000000; $i++) $a = 0;
$a++; $total_count = 10000000;
for ($i = 0; $i < $total_count; $i++)
$a++;
assert($a == $total_count);
$thisisanotherlongname = 0; $thisisanotherlongname = 0;
for ($thisisalongname = 0; $thisisalongname < 1000000; $thisisalongname++) for ($thisisalongname = 0; $thisisalongname < $total_count; $thisisalongname++)
$thisisanotherlongname++; $thisisanotherlongname++;
assert($thisisanotherlongname == $total_count);
} }
/****/ /****/
function simplecall() { function simplecall() {
for ($i = 0; $i < 1000000; $i++) for ($i = 0; $i < 1000000; $i++)
strlen("hallo"); strlen("hallo" . $i);
} }
/****/ /****/
@ -342,10 +348,10 @@ function strcat($n) {
/*****/ /*****/
function gethrtime() function gethrtime(): float
{ {
$hrtime = hrtime(); $hrtime = hrtime();
return (($hrtime[0] * 1000000000 + $hrtime[1]) / 1000000000); return (($hrtime[0] * 1000000000.0 + $hrtime[1]) / 1000000000.0);
} }
function start_test() function start_test()
@ -359,7 +365,7 @@ function end_test($start, $name)
global $total; global $total;
$end = gethrtime(); $end = gethrtime();
ob_end_clean(); ob_end_clean();
$total += $end - $start; $total += ($end - $start);
$num = number_format($end - $start, 3); $num = number_format($end - $start, 3);
$pad = str_repeat(" ", 24 - strlen($name) - strlen($num)); $pad = str_repeat(" ", 24 - strlen($name) - strlen($num));
@ -370,12 +376,12 @@ function end_test($start, $name)
function total() function total()
{ {
global $total; global $total;
$pad = str_repeat("-", 24); $pad = str_repeat("-", 24);
echo $pad."\n"; echo $pad . "\n";
$num = number_format($total,3); $num = number_format($total, 3);
$pad = str_repeat(" ", 24-strlen("Total")-strlen($num)); $pad = str_repeat(" ", 24 - strlen("Total") - strlen($num));
echo "Total".$pad.$num."\n"; echo "Total" . $pad . $num . "\n";
} }
function main() function main()

@ -22,6 +22,7 @@ class Translator extends \PhpAot\Core\Translator
const string TYPE_OBJECT = 'php::Object'; const string TYPE_OBJECT = 'php::Object';
const string TYPE_ARRAY = 'php::Array'; const string TYPE_ARRAY = 'php::Array';
const string TYPE_STR = 'php::Str'; const string TYPE_STR = 'php::Str';
const string TYPE_REF = 'php::Var';
const string VALUE_NAN = 'std::numeric_limits<double>::quiet_NaN()'; const string VALUE_NAN = 'std::numeric_limits<double>::quiet_NaN()';
const string VALUE_INF = 'std::numeric_limits<double>::infinity()'; const string VALUE_INF = 'std::numeric_limits<double>::infinity()';
@ -29,7 +30,6 @@ class Translator extends \PhpAot\Core\Translator
private string $phpxDir = '~/workspace/projects/phpx'; private string $phpxDir = '~/workspace/projects/phpx';
protected string $lang = 'PHP'; protected string $lang = 'PHP';
private string $cppCompiler = 'g++'; private string $cppCompiler = 'g++';
private array $scope = [];
private array $arguments = []; private array $arguments = [];
private int $tmpVarIndex = 0; private int $tmpVarIndex = 0;
private array $zendTypeMap = [ private array $zendTypeMap = [
@ -67,11 +67,13 @@ class Translator extends \PhpAot\Core\Translator
'argc' => self::TYPE_INT, 'argc' => self::TYPE_INT,
'argv' => self::TYPE_ARRAY, 'argv' => self::TYPE_ARRAY,
]; ];
private array $localVars = [];
const string PREFIX = 'php_'; const string PREFIX = 'php_';
private string $rootPath; private string $rootPath;
private int $debugLine = 0; private int $debugLine = 0;
private CLImate $climate; private CLImate $climate;
private array $definedFunctions = [];
public function __construct(string $rootPath) public function __construct(string $rootPath)
{ {
@ -113,6 +115,7 @@ class Translator extends \PhpAot\Core\Translator
exit(0); exit(0);
} }
$this->optimizeLevel = $climate->arguments->get('optimize'); $this->optimizeLevel = $climate->arguments->get('optimize');
$this->definedFunctions = array_flip(get_defined_functions()['internal']);
} }
function showUsage(): void function showUsage(): void
@ -228,6 +231,9 @@ class Translator extends \PhpAot\Core\Translator
public function convert(string $file): string public function convert(string $file): string
{ {
if (!file_exists($file)) {
throw new \Exception('File not exists: ' . $file);
}
$phpCode = file_get_contents($file); $phpCode = file_get_contents($file);
$this->file = realpath($file); $this->file = realpath($file);
$this->dir = dirname($this->file); $this->dir = dirname($this->file);
@ -271,7 +277,7 @@ class Translator extends \PhpAot\Core\Translator
private function resetScope(): void private function resetScope(): void
{ {
$this->scope = []; $this->localVars = [];
$this->arguments = []; $this->arguments = [];
$this->tmpVarIndex = 0; $this->tmpVarIndex = 0;
} }
@ -308,7 +314,7 @@ class Translator extends \PhpAot\Core\Translator
$code = $this->getReturnType() . ' ' . self::PREFIX . $name . '(' . $params . ') {' . PHP_EOL; $code = $this->getReturnType() . ' ' . self::PREFIX . $name . '(' . $params . ') {' . PHP_EOL;
$this->indentLevel++; $this->indentLevel++;
foreach ($this->scope as $name => $type) { foreach ($this->localVars as $name => $type) {
if (isset($this->arguments[$name])) { if (isset($this->arguments[$name])) {
continue; continue;
} }
@ -364,7 +370,7 @@ class Translator extends \PhpAot\Core\Translator
$name = $this->parseIdentifier($param->var); $name = $this->parseIdentifier($param->var);
$list[] = $type . ' ' . $name; $list[] = $type . ' ' . $name;
$this->arguments[$name] = $type; $this->arguments[$name] = $type;
$this->addVar($name, $type); $this->addLocalVar($name, $type);
$argInfo = new ArgInfo(); $argInfo = new ArgInfo();
$argInfo->name = $name; $argInfo->name = $name;
@ -599,7 +605,7 @@ class Translator extends \PhpAot\Core\Translator
$code = ''; $code = '';
// 这是 PHP 的初始化+赋值写法,需要先创建数组 // 这是 PHP 的初始化+赋值写法,需要先创建数组
if (!$this->hasVar($array) and $left->var->getType() === 'Expr_Variable') { if (!$this->hasVar($array) and $left->var->getType() === 'Expr_Variable') {
$this->addVar($array, self::TYPE_ARRAY); $this->addLocalVar($array, self::TYPE_ARRAY);
} }
if ($left->dim === null) { if ($left->dim === null) {
return $code . "$array.offsetSet(php::null, " . $this->parseExpr($right) . ")"; return $code . "$array.offsetSet(php::null, " . $this->parseExpr($right) . ")";
@ -643,7 +649,7 @@ class Translator extends \PhpAot\Core\Translator
if (!$this->hasVar($var)) { if (!$this->hasVar($var)) {
$type = $this->detectExprType($right); $type = $this->detectExprType($right);
$this->addVar($var, $type); $this->addLocalVar($var, $type);
} }
return $var . ' = ' . $this->convertExprType($expr, $this->detectExprType($left), $this->detectExprType($right)); return $var . ' = ' . $this->convertExprType($expr, $this->detectExprType($left), $this->detectExprType($right));
} }
@ -666,6 +672,11 @@ class Translator extends \PhpAot\Core\Translator
return filter_var($str, FILTER_VALIDATE_INT); return filter_var($str, FILTER_VALIDATE_INT);
} }
private function isCoreFunction(string $fname)
{
return array_key_exists($fname, $this->definedFunctions);
}
/** /**
* 尽可能转为数字,优先级 浮点 > 整数 > 字符串 * 尽可能转为数字,优先级 浮点 > 整数 > 字符串
*/ */
@ -730,12 +741,9 @@ class Translator extends \PhpAot\Core\Translator
return $this->parseBinaryOp($expr->left, $expr->right, '*'); return $this->parseBinaryOp($expr->left, $expr->right, '*');
} }
private function addVar(string $name, string $type): void private function addLocalVar(string $name, string $type): void
{ {
$this->scope[$name] = $type; $this->localVars[$name] = $type;
if (!str_starts_with($type, 'php::')) {
throw new Exception("error type: ".$type);
}
} }
private function addGlobalVar(string $name, string $type): void private function addGlobalVar(string $name, string $type): void
@ -745,7 +753,12 @@ class Translator extends \PhpAot\Core\Translator
private function hasVar(string $name): bool private function hasVar(string $name): bool
{ {
return isset($this->scope[$name]); return $this->hasLocalVar($name) || $this->hasGlobalVar($name);
}
private function hasLocalVar(string $name): bool
{
return isset($this->localVars[$name]);
} }
private function resetReturnType(string $type): void private function resetReturnType(string $type): void
@ -757,10 +770,10 @@ class Translator extends \PhpAot\Core\Translator
private function detectVarType($var): string private function detectVarType($var): string
{ {
$name = $this->parseIdentifier($var); $name = $this->parseIdentifier($var);
if ($this->hasVar($name)) { if ($this->hasLocalVar($name)) {
return $this->scope[$name]; return $this->localVars[$name];
} }
if ($this->hasGlobalVar($name)) { if ($this->hasLocalVar($name)) {
return $this->globalVars[$name]; return $this->globalVars[$name];
} }
return self::TYPE_VAR; return self::TYPE_VAR;
@ -988,7 +1001,7 @@ class Translator extends \PhpAot\Core\Translator
$name = $this->parseIdentifier($left); $name = $this->parseIdentifier($left);
if (!$this->hasVar($name)) { if (!$this->hasVar($name)) {
$type = $this->detectExprType($expr->expr); $type = $this->detectExprType($expr->expr);
$this->addVar($name, $type); $this->addLocalVar($name, $type);
} }
} }
$list_cond[] = $this->parseExpr($expr); $list_cond[] = $this->parseExpr($expr);
@ -1087,14 +1100,22 @@ class Translator extends \PhpAot\Core\Translator
if ($this->isInternalFunction($name)) { if ($this->isInternalFunction($name)) {
return self::PREFIX . $name . '(' . $this->parseCallArgs($expr->args, $name) . ')'; return self::PREFIX . $name . '(' . $this->parseCallArgs($expr->args, $name) . ')';
} }
if ($this->isCoreFunction($name)) {
$fn = 'php::' . $name;
} else {
$fn = '"' . $name . '"';
}
if ($name === 'strlen' and $expr->args[0]->value->getType() === 'Expr_Variable') {
return '((php::Int)' . $this->parseIdentifier($expr->args[0]->value) . '.length())';
}
if (empty($expr->args)) { if (empty($expr->args)) {
return 'php::call("' . $name . '")'; return 'php::call(' . $fn . ')';
} else { } else {
return 'php::call("' . $name . '", {' . $this->parseCallArgs($expr->args, $name) . '})'; return 'php::call(' . $fn . ', {' . $this->parseCallArgs($expr->args, $name) . '})';
} }
} }
private function parseCallArgs($args, string $funcName): string private function parseCallArgs(array $args, string $funcName = ''): string
{ {
$internalFunction = $this->isInternalFunction($funcName); $internalFunction = $this->isInternalFunction($funcName);
$list_args = []; $list_args = [];
@ -1110,7 +1131,7 @@ class Translator extends \PhpAot\Core\Translator
if ($arg->value->getType() === 'Expr_Variable') { if ($arg->value->getType() === 'Expr_Variable') {
$name = $this->parseIdentifier($arg->value); $name = $this->parseIdentifier($arg->value);
if (!$this->hasVar($name)) { if (!$this->hasVar($name)) {
$this->definitions[] = self::TYPE_VAR . ' ' . $name . ' = php::newReference();'; $this->addLocalVar($name, self::TYPE_REF);
} }
} }
} }
@ -1573,7 +1594,7 @@ class Translator extends \PhpAot\Core\Translator
$this->indentLevel++; $this->indentLevel++;
if ($node->keyVar) { if ($node->keyVar) {
$code .= $this->getIndent() . self::TYPE_VAR . ' ' . $keyVar . ' = iter.key();' . PHP_EOL; $code .= $this->getIndent() . self::TYPE_VAR . ' ' . $keyVar . ' = iter.key();' . PHP_EOL;
$this->addVar($keyVar, self::TYPE_VAR); $this->addLocalVar($keyVar, self::TYPE_VAR);
} }
if ($node->valueVar->getType() == 'Expr_ArrayDimFetch') { if ($node->valueVar->getType() == 'Expr_ArrayDimFetch') {
@ -1585,7 +1606,7 @@ class Translator extends \PhpAot\Core\Translator
$code .= $this->getIndent() . "$array.offsetSet($dim, iter.value());"; $code .= $this->getIndent() . "$array.offsetSet($dim, iter.value());";
} else { } else {
$code .= $this->getIndent() . self::TYPE_VAR . ' ' . $valueVar . ' = iter.value();' . PHP_EOL; $code .= $this->getIndent() . self::TYPE_VAR . ' ' . $valueVar . ' = iter.value();' . PHP_EOL;
$this->addVar($valueVar, self::TYPE_VAR); $this->addLocalVar($valueVar, self::TYPE_VAR);
} }
$code .= $this->parseStmts($stmts); $code .= $this->parseStmts($stmts);
$this->indentLevel--; $this->indentLevel--;
@ -1631,7 +1652,7 @@ class Translator extends \PhpAot\Core\Translator
$var_def = $type . ' ' . $tmp_var . ' = ' . $this->parseExpr($cond) . ';' . PHP_EOL; $var_def = $type . ' ' . $tmp_var . ' = ' . $this->parseExpr($cond) . ';' . PHP_EOL;
// 保存作用域,switch 可能会解析失败,在这个过程中会增加变量,需重置 // 保存作用域,switch 可能会解析失败,在这个过程中会增加变量,需重置
$scope = $this->scope; $localVars = $this->localVars;
if ($type === self::TYPE_INT or $type === self::TYPE_FLOAT) { if ($type === self::TYPE_INT or $type === self::TYPE_FLOAT) {
$code = 'switch (' . $tmp_var . ') {' . PHP_EOL; $code = 'switch (' . $tmp_var . ') {' . PHP_EOL;
@ -1642,7 +1663,7 @@ class Translator extends \PhpAot\Core\Translator
} else { } else {
$condType = $case->cond->getType(); $condType = $case->cond->getType();
if ($condType !== 'Scalar_Int' and $condType !== 'Scalar_Float') { if ($condType !== 'Scalar_Int' and $condType !== 'Scalar_Float') {
$this->scope = $scope; $this->localVars = $localVars;
goto _fail; goto _fail;
} }
$code .= $this->getIndent() . 'case ' . $this->parseScalarValue($case->cond) . ': {' . PHP_EOL; $code .= $this->getIndent() . 'case ' . $this->parseScalarValue($case->cond) . ': {' . PHP_EOL;

@ -0,0 +1,9 @@
--TEST--
strlen
--FILE--
<?php
$str = "hello world";
var_dump(strlen($str));
?>
--EXPECT--
int(11)
Loading…
Cancel
Save