pull/1/head
韩天峰 6 months ago
parent f17ffa6b6f
commit 1441a7e5be
  1. 10
      src/Php/AstNodeType.php
  2. 94
      src/Php/CompilerBase.php
  3. 11
      src/Php/Context/FunctionContext.php
  4. 4
      src/Php/Generator/ClosureGenerator.php
  5. 4
      src/Php/Generator/PlaceHolderGenerator.php
  6. 16
      src/Php/MagicMethodDetector.php
  7. 2
      src/Php/Preprocessor.php
  8. 9
      src/Php/Translator.php

@ -10,8 +10,8 @@ namespace PhpAot\Php;
use PhpParser\Node; use PhpParser\Node;
use PhpParser\Node\Expr; use PhpParser\Node\Expr;
use PhpParser\NodeAbstract;
use PhpParser\Node\VariadicPlaceholder; use PhpParser\Node\VariadicPlaceholder;
use PhpParser\NodeAbstract;
trait AstNodeType trait AstNodeType
{ {
@ -102,9 +102,9 @@ trait AstNodeType
protected function isCallExpr(NodeAbstract $expr): bool protected function isCallExpr(NodeAbstract $expr): bool
{ {
return $expr instanceof Node\Expr\FuncCall return $expr instanceof Expr\FuncCall
or $expr instanceof Node\Expr\MethodCall or $expr instanceof Expr\MethodCall
or $expr instanceof Node\Expr\StaticCall; or $expr instanceof Expr\StaticCall;
} }
protected function isPlaceholderExpr(NodeAbstract $expr): bool protected function isPlaceholderExpr(NodeAbstract $expr): bool
@ -127,6 +127,6 @@ trait AstNodeType
if ($expr instanceof Node\Stmt\Expression) { if ($expr instanceof Node\Stmt\Expression) {
$expr = $expr->expr; $expr = $expr->expr;
} }
return $expr instanceof Node\Expr\Exit_; return $expr instanceof Expr\Exit_;
} }
} }

@ -84,10 +84,8 @@ class CompilerBase extends \PhpAot\Core\Translator
protected string $phpxDir = '~/workspace/projects/phpx'; protected string $phpxDir = '~/workspace/projects/phpx';
protected string $lang = 'PHP'; protected string $lang = 'PHP';
protected string $cppCompiler = 'g++'; protected string $cppCompiler = 'g++';
protected array $literalStrings = []; protected array $literalStrings = [];
protected int $literalStringIndex = 0; protected int $literalStringIndex = 0;
protected int $anonClassIndex = 0; protected int $anonClassIndex = 0;
protected int $classIndex = 0; protected int $classIndex = 0;
@ -96,6 +94,7 @@ class CompilerBase extends \PhpAot\Core\Translator
*/ */
protected array $classMap = []; protected array $classMap = [];
protected int $funcIndex = 0; protected int $funcIndex = 0;
/** /**
* @var array<string, int> * @var array<string, int>
*/ */
@ -682,9 +681,7 @@ class CompilerBase extends \PhpAot\Core\Translator
} }
/** /**
* @param string $propName
* @param string $className 必须是带有命名空间的完整类名 * @param string $className 必须是带有命名空间的完整类名
* @return int
*/ */
protected function getPropertyId(string $className, string $propName): int protected function getPropertyId(string $className, string $propName): int
{ {
@ -948,8 +945,6 @@ class CompilerBase extends \PhpAot\Core\Translator
/** /**
* @param $params array<Node\Param> * @param $params array<Node\Param>
* @param FunctionDef $functionDef
* @return void
*/ */
protected function parseParams(array $params, FunctionDef $functionDef): void protected function parseParams(array $params, FunctionDef $functionDef): void
{ {
@ -2223,8 +2218,6 @@ class CompilerBase extends \PhpAot\Core\Translator
/** /**
* @param array<Node\Arg|Node\VariadicPlaceholder> $callArgs * @param array<Node\Arg|Node\VariadicPlaceholder> $callArgs
* @param string $nativeFunc
* @return string
*/ */
protected function parseNativeCallArgs(array $callArgs, string $nativeFunc): string protected function parseNativeCallArgs(array $callArgs, string $nativeFunc): string
{ {
@ -2259,7 +2252,7 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($argInfo->variadic) { if ($argInfo->variadic) {
$argsSlice = array_slice($args, $i); $argsSlice = array_slice($args, $i);
if (count($argsSlice) === 1 and $argsSlice[0]->unpack) { if (count($argsSlice) === 1 and $argsSlice[0]->unpack) {
if ($this->isVarExpr($arg->value) ) { if ($this->isVarExpr($arg->value)) {
$var =$this->parseIdentifier($arg->value); $var =$this->parseIdentifier($arg->value);
if ($this->getVarType($var) === self::TYPE_ARRAY) { if ($this->getVarType($var) === self::TYPE_ARRAY) {
$argList[] = $var; $argList[] = $var;
@ -2357,7 +2350,8 @@ class CompilerBase extends \PhpAot\Core\Translator
$list_args[] = $globalVar; $list_args[] = $globalVar;
} }
continue; continue;
} elseif ($this->isVarExpr($arg->value->var) and !$this->hasVar($array)) { }
if ($this->isVarExpr($arg->value->var) and !$this->hasVar($array)) {
$this->fatalError($arg, 'Undefined variable `$' . $array . '`'); $this->fatalError($arg, 'Undefined variable `$' . $array . '`');
} }
if ($byRef) { if ($byRef) {
@ -3078,7 +3072,7 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($node->byRef) { if ($node->byRef) {
if (!$this->hasVar($valueVar)) { if (!$this->hasVar($valueVar)) {
$this->addLocalVar($valueVar, self::TYPE_REF); $this->addLocalVar($valueVar, self::TYPE_REF);
} else if ($this->getVarType($valueVar) !== self::TYPE_REF) { } elseif ($this->getVarType($valueVar) !== self::TYPE_REF) {
$this->fatalError($node, 'Cannot assign value to reference of type'); $this->fatalError($node, 'Cannot assign value to reference of type');
} }
$code .= $this->getIndent() . ' ' . $valueVar . ' = iter.valueRef();' . PHP_EOL; $code .= $this->getIndent() . ' ' . $valueVar . ' = iter.valueRef();' . PHP_EOL;
@ -3137,8 +3131,6 @@ class CompilerBase extends \PhpAot\Core\Translator
* 为了兼容已有代码,默认不使用原生类型,而是将整数和浮点数作为 php 变量处理 * 为了兼容已有代码,默认不使用原生类型,而是将整数和浮点数作为 php 变量处理
* 原生 int/float/bool 类型,是不支持自动转换的,例如如果 int 计算超过最大值后,会自动转为 float,除法若不能除尽,则会转为 float * 原生 int/float/bool 类型,是不支持自动转换的,例如如果 int 计算超过最大值后,会自动转为 float,除法若不能除尽,则会转为 float
* 某些情况下高性能计算,可能需要使用原生类型,使用 $a = std::int(0) 来显式地使用原生类型 * 某些情况下高性能计算,可能需要使用原生类型,使用 $a = std::int(0) 来显式地使用原生类型
* @param string $type
* @return string
*/ */
protected function getNativeType(string $type): string protected function getNativeType(string $type): string
{ {
@ -4201,7 +4193,7 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($this->isCallExpr($expr->expr)) { if ($this->isCallExpr($expr->expr)) {
$nativeCall = $expr->expr->getAttribute('nativeCall'); $nativeCall = $expr->expr->getAttribute('nativeCall');
if ($nativeCall and $this->nativeFunctions[$nativeCall]->returnType === self::TYPE_VOID) { if ($nativeCall and $this->nativeFunctions[$nativeCall]->returnType === self::TYPE_VOID) {
return $beforeCode . PHP_EOL . $code . ";" . PHP_EOL . "return " . self::VALUE_NULL . ';'; return $beforeCode . PHP_EOL . $code . ';' . PHP_EOL . 'return ' . self::VALUE_NULL . ';';
} }
} }
return $beforeCode . PHP_EOL . 'return ' . $code . ';'; return $beforeCode . PHP_EOL . 'return ' . $code . ';';
@ -4250,38 +4242,6 @@ class CompilerBase extends \PhpAot\Core\Translator
return $stmts[array_key_last($stmts)] instanceof Node\Stmt\Return_; return $stmts[array_key_last($stmts)] instanceof Node\Stmt\Return_;
} }
/**
* 混杂数组赋值,需要拆分为多行插入
*/
private function parseArrayMixed(Node\Expr\Array_ $node): string
{
$tmpVar = $this->genTmpVarName();
$this->addLocalVar($tmpVar, self::TYPE_ARRAY);
$items = $node->items;
foreach ($items as $item) {
$value = $this->parseIdentifier($item->value);
if ($item->unpack) {
$this->context->beforeStmtLines[] = $this->getIndent() . $tmpVar . '.merge(' . $value . ');';
} elseif ($item->key) {
$key = $this->parseIdentifier($item->key);
if (str_starts_with($key, self::LITERAL_STRINGS)) {
$key = "{$key}.toStdString()";
} elseif ($key === '0L') {
$key = 'php::zero';
}
$this->context->beforeStmtLines[] = $this->getIndent() . $tmpVar . '.set(' . $key . ', ' . $value . ');';
} else {
$this->context->beforeStmtLines[] = $this->getIndent() . $tmpVar . '.append(' . $value . ');';
}
}
// 释放临时变量,避免修改数组产生数组复制操作
$this->context->afterStmtLines[] = $this->getIndent() . $tmpVar . '.unset();';
return $tmpVar;
}
protected function parseNullsafePropertyFetch(Node\Expr\NullsafePropertyFetch $expr): string protected function parseNullsafePropertyFetch(Node\Expr\NullsafePropertyFetch $expr): string
{ {
return $this->parseNullsafeExpr($expr); return $this->parseNullsafeExpr($expr);
@ -4330,22 +4290,54 @@ class CompilerBase extends \PhpAot\Core\Translator
foreach ($list as $key => $item) { foreach ($list as $key => $item) {
$tmpVar = $this->addTmpVar($key !== $last ? self::TYPE_OBJECT : self::TYPE_VAR); $tmpVar = $this->addTmpVar($key !== $last ? self::TYPE_OBJECT : self::TYPE_VAR);
$code .= "if ($object.isNull()) { return " . self::VALUE_NULL . "; }"; $code .= "if ({$object}.isNull()) { return " . self::VALUE_NULL . '; }';
if ($item[0] == 'property') { if ($item[0] == 'property') {
$code .= $this->getIndent() . "$tmpVar = $object.attr({$item[1]}, $update);"; $code .= $this->getIndent() . "{$tmpVar} = {$object}.attr({$item[1]}, {$update});";
} else { } else {
$args = $this->parseCallArgs($item[2]); $args = $this->parseCallArgs($item[2]);
$code .= $this->getIndent() . "$tmpVar = $object.exec({$item[1]}, $args);"; $code .= $this->getIndent() . "{$tmpVar} = {$object}.exec({$item[1]}, {$args});";
} }
$object = $tmpVar; $object = $tmpVar;
} }
$code .= $this->getIndent() . "return $object; };"; $code .= $this->getIndent() . "return {$object}; };";
$this->context->beforeStmtLines[] = $code; $this->context->beforeStmtLines[] = $code;
return "$tmpFn()"; return "{$tmpFn}()";
} }
protected function parseFullyQualifiedName(Node\Name\FullyQualified $expr): string protected function parseFullyQualifiedName(Node\Name\FullyQualified $expr): string
{ {
return $expr->name; return $expr->name;
} }
/**
* 混杂数组赋值,需要拆分为多行插入
*/
private function parseArrayMixed(Node\Expr\Array_ $node): string
{
$tmpVar = $this->genTmpVarName();
$this->addLocalVar($tmpVar, self::TYPE_ARRAY);
$items = $node->items;
foreach ($items as $item) {
$value = $this->parseIdentifier($item->value);
if ($item->unpack) {
$this->context->beforeStmtLines[] = $this->getIndent() . $tmpVar . '.merge(' . $value . ');';
} elseif ($item->key) {
$key = $this->parseIdentifier($item->key);
if (str_starts_with($key, self::LITERAL_STRINGS)) {
$key = "{$key}.toStdString()";
} elseif ($key === '0L') {
$key = 'php::zero';
}
$this->context->beforeStmtLines[] = $this->getIndent() . $tmpVar . '.set(' . $key . ', ' . $value . ');';
} else {
$this->context->beforeStmtLines[] = $this->getIndent() . $tmpVar . '.append(' . $value . ');';
}
}
// 释放临时变量,避免修改数组产生数组复制操作
$this->context->afterStmtLines[] = $this->getIndent() . $tmpVar . '.unset();';
return $tmpVar;
}
} }

@ -1,4 +1,10 @@
<?php <?php
/**
* This file is part of Swoole-Compiler(AOT).
*
* @link https://www.swoole.com/
* @contact service@swoole.com
*/
namespace PhpAot\Php\Context; namespace PhpAot\Php\Context;
@ -10,10 +16,12 @@ class FunctionContext
public array $objects = []; public array $objects = [];
public array $localVars = []; public array $localVars = [];
public array $staticVars = []; public array $staticVars = [];
/** /**
* @var array<string, string> * @var array<string, string>
*/ */
public array $objectWrappers = []; public array $objectWrappers = [];
/** /**
* @var array<string, string> * @var array<string, string>
*/ */
@ -22,6 +30,7 @@ class FunctionContext
public array $arguments = []; public array $arguments = [];
public bool $inLoop = false; public bool $inLoop = false;
public bool $inClosure = false; public bool $inClosure = false;
/** /**
* 赋值表达式的左值,写操作,右值为读操作. * 赋值表达式的左值,写操作,右值为读操作.
*/ */
@ -29,7 +38,7 @@ class FunctionContext
public array $beforeStmtLines = []; public array $beforeStmtLines = [];
public array $afterStmtLines = []; public array $afterStmtLines = [];
function __construct() public function __construct()
{ {
$this->localVars = []; $this->localVars = [];
$this->staticVars = []; $this->staticVars = [];

@ -16,8 +16,8 @@ trait ClosureGenerator
protected function genScopeSwitchCode(): string protected function genScopeSwitchCode(): string
{ {
$tmpScope = $this->genTmpVarName(); $tmpScope = $this->genTmpVarName();
$code = "auto $tmpScope = php_switch_scope(this_);" . PHP_EOL; $code = "auto {$tmpScope} = php_switch_scope(this_);" . PHP_EOL;
$code .= "ON_SCOPE_EXIT({ php_restore_scope($tmpScope); });" . PHP_EOL; $code .= "ON_SCOPE_EXIT({ php_restore_scope({$tmpScope}); });" . PHP_EOL;
return $code; return $code;
} }

@ -16,8 +16,8 @@ trait PlaceHolderGenerator
$fn = $ce . ', ' . $this->getFuncPtr('Closure::fromCallable'); $fn = $ce . ', ' . $this->getFuncPtr('Closure::fromCallable');
$tmpVar = $this->genTmpVarName(); $tmpVar = $this->genTmpVarName();
if ($this->classDef) { if ($this->classDef) {
$this->context->beforeStmtLines[] = "auto $tmpVar = php_switch_scope(this_);"; $this->context->beforeStmtLines[] = "auto {$tmpVar} = php_switch_scope(this_);";
$this->context->afterStmtLines[] = "php_restore_scope($tmpVar);"; $this->context->afterStmtLines[] = "php_restore_scope({$tmpVar});";
} }
return 'php::call(' . $fn . ', {' . $callable . '})'; return 'php::call(' . $fn . ', {' . $callable . '})';
} }

@ -13,14 +13,6 @@ use PhpParser\NodeAbstract;
trait MagicMethodDetector trait MagicMethodDetector
{ {
protected function checkArgType(string $givenType, string $expectType, bool $canBeVar = true): bool
{
if ($canBeVar and $givenType == self::TYPE_VAR) {
return true;
}
return $givenType == $expectType;
}
public function checkRequiredArgNum(string $name, MethodDef $methodDef, NodeAbstract $v): void public function checkRequiredArgNum(string $name, MethodDef $methodDef, NodeAbstract $v): void
{ {
$argInfoList = $methodDef->functionDef->argInfoList; $argInfoList = $methodDef->functionDef->argInfoList;
@ -69,4 +61,12 @@ trait MagicMethodDetector
} }
} }
} }
protected function checkArgType(string $givenType, string $expectType, bool $canBeVar = true): bool
{
if ($canBeVar and $givenType == self::TYPE_VAR) {
return true;
}
return $givenType == $expectType;
}
} }

@ -180,7 +180,7 @@ class Preprocessor extends CompilerBase
protected function prepareClass(Node\Stmt\Class_|Node\Stmt\Trait_|Node\Stmt\Enum_ $class): string protected function prepareClass(Node\Stmt\Class_|Node\Stmt\Trait_|Node\Stmt\Enum_ $class): string
{ {
$this->class = $this->parseIdentifier($class->name); $this->class = $this->parseIdentifier($class->name);
if ($class->extends) { if (!empty($class->extends)) {
$this->parentClass = $this->getParentClass($class->extends); $this->parentClass = $this->getParentClass($class->extends);
$fullClassName = $this->getNamespacedClassName($this->class); $fullClassName = $this->getNamespacedClassName($this->class);
$this->classExtends[$fullClassName] = $this->parentClass; $this->classExtends[$fullClassName] = $this->parentClass;

@ -298,7 +298,7 @@ class Translator extends Preprocessor
$objectFile = $this->getObjectFile($cppFile); $objectFile = $this->getObjectFile($cppFile);
$this->compileFile($cppFile, $objectFile); $this->compileFile($cppFile, $objectFile);
if (!is_file($objectFile)) { if (!is_file($objectFile)) {
throw new \Exception("compile error"); throw new \Exception('compile error');
} }
$objectFiles[] = $objectFile; $objectFiles[] = $objectFile;
} }
@ -323,8 +323,9 @@ class Translator extends Preprocessor
$pid = pcntl_fork(); $pid = pcntl_fork();
if ($pid == -1) { if ($pid == -1) {
throw new \Exception("Failed to fork process"); throw new \Exception('Failed to fork process');
} elseif ($pid === 0) { }
if ($pid === 0) {
// 子进程:执行编译 // 子进程:执行编译
try { try {
$this->compileFile($cppFile, $objectFile, true); $this->compileFile($cppFile, $objectFile, true);
@ -377,7 +378,7 @@ class Translator extends Preprocessor
} }
if (!empty($failedFiles)) { if (!empty($failedFiles)) {
throw new \Exception("Compilation failed for: " . implode(', ', $failedFiles)); throw new \Exception('Compilation failed for: ' . implode(', ', $failedFiles));
} }
$this->climate->green("Successfully compiled {$totalFiles} files"); $this->climate->green("Successfully compiled {$totalFiles} files");

Loading…
Cancel
Save