feat(compiler): 优化对象属性访问性能

- 引入 PropertyDef 实体类来管理属性定义
- 添加 OBJECT_PROP 常量用于标识对象属性
- 修复 findNativeProperty 方法中的参数传递问题
- 实现 native 属性类型的引用优化,提升 this_ 对象的属性访问性能
- 为整型和浮点型属性创建直接引用访问机制
- 改进属性查找逻辑,支持 nativePropertyDef 和 nativeClassDef 属性
- 在编译代码中添加对象属性引用声明,优化运行时性能
- 添加测试用例验证默认数组属性功能
pull/1/head
韩天峰 4 months ago
parent 12ff420d87
commit c86059217d
  1. 45
      src/Php/CompilerBase.php
  2. 2
      src/Php/Context/FunctionContext.php
  3. 25
      tests/aot/object_property/001.phpt

@ -15,6 +15,7 @@ use PhpAot\Php\Entity\ConstantDef;
use PhpAot\Php\Entity\FunctionDef; use PhpAot\Php\Entity\FunctionDef;
use PhpAot\Php\Entity\InterfaceDef; use PhpAot\Php\Entity\InterfaceDef;
use PhpAot\Php\Entity\MethodDef; use PhpAot\Php\Entity\MethodDef;
use PhpAot\Php\Entity\PropertyDef;
use PhpAot\Php\Exception\DynamicCall; use PhpAot\Php\Exception\DynamicCall;
use PhpAot\Php\Exception\PlaceHolder; use PhpAot\Php\Exception\PlaceHolder;
use PhpAot\Php\Exception\Redo; use PhpAot\Php\Exception\Redo;
@ -75,6 +76,7 @@ class CompilerBase extends \PhpAot\Core\Translator
public const string ANON_CLASS = '_anon_class_'; public const string ANON_CLASS = '_anon_class_';
public const string STATIC_VAR = '_static_var_'; public const string STATIC_VAR = '_static_var_';
public const string GLOBAL_VAR = '_global_var_'; public const string GLOBAL_VAR = '_global_var_';
public const string OBJECT_PROP = '_object_prop_';
public const string CLASS_MAP = 'class_map'; public const string CLASS_MAP = 'class_map';
public const string FUNC_MAP = 'func_map'; public const string FUNC_MAP = 'func_map';
public const string PROP_MAP = 'property_map'; public const string PROP_MAP = 'property_map';
@ -3427,10 +3429,10 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($this->classDef->trait) { if ($this->classDef->trait) {
goto _dynamic_attr; goto _dynamic_attr;
} }
$nativeProperty = $this->findNativeProperty($object, $propertyName, $this->class, $this->namespace); $nativeProperty = $this->findNativeProperty($expr, $propertyName, $this->class, $this->namespace);
} elseif ($this->isTypedObject($objectName)) { } elseif ($this->isTypedObject($objectName)) {
$className = $this->getObjectType($objectName); $className = $this->getObjectType($objectName);
$nativeProperty = $this->findNativeProperty($object, $propertyName, $className); $nativeProperty = $this->findNativeProperty($expr, $propertyName, $className);
} }
if ($nativeProperty) { if ($nativeProperty) {
$expr->setAttribute('nativeProperty', $nativeProperty); $expr->setAttribute('nativeProperty', $nativeProperty);
@ -3446,7 +3448,27 @@ class CompilerBase extends \PhpAot\Core\Translator
$object = $expr->var; $object = $expr->var;
$property = $expr->name; $property = $expr->name;
$id = $this->getPropertyIdentifier($expr, $object, $property); $id = $this->getPropertyIdentifier($expr, $object, $property);
return $this->parseIdentifier($object) . '.attr(' . $id . ', ' . $this->escapeBool($update) . ')'; $objectVar = $this->parseIdentifier($object);
$getProperty = $objectVar . '.attr(' . $id . ', ' . $this->escapeBool($update) . ')';
// 将属性设置为 native 类型的引用,以提高性能,仅适用于 this_ ,其他类型对象可能会在中间发生改变
// TODO 分析对象是否为 SSA , 如果是 SSA 则可以将属性设置为引用
if ($expr->hasAttribute('nativePropertyDef') and $this->nativeTypes and $objectVar === 'this_') {
/**
* @var $def PropertyDef
*/
$def = $expr->getAttribute('nativePropertyDef');
if ($def->type === self::TYPE_INT or $def->type === self::TYPE_FLOAT) {
$propVar = self::OBJECT_PROP . $objectVar . self::NAMESPACE_SEPARATOR . $this->parseIdentifier($property);
if (!isset($this->context->objectProps[$propVar])) {
$this->context->objectProps[$propVar] = [
'type' => $def->type,
'getter' => $getProperty,
];
}
return $propVar;
}
}
return $getProperty;
} }
protected function parseAssignOpShiftRight(Expr\AssignOp\ShiftRight $node): string protected function parseAssignOpShiftRight(Expr\AssignOp\ShiftRight $node): string
@ -4240,7 +4262,8 @@ class CompilerBase extends \PhpAot\Core\Translator
$findClass = $namespace . '\\' . $class; $findClass = $namespace . '\\' . $class;
} }
$scope = $this->class ? ltrim($namespace . '\\' . $class, '\\') : ''; $scope = $this->class ? ltrim($namespace . '\\' . $class, '\\') : '';
$propertyDef = null;
$classDef = null;
while (true) { while (true) {
if ($this->hasClass($findClass)) { if ($this->hasClass($findClass)) {
$classDef = $this->getClass($findClass); $classDef = $this->getClass($findClass);
@ -4251,16 +4274,16 @@ class CompilerBase extends \PhpAot\Core\Translator
return null; return null;
} }
if ($propertyDef->isPublic()) { if ($propertyDef->isPublic()) {
return $this->getPropertyOffset($classDef->getNamespacedName(false), $property); break;
} }
if ($propertyDef->isProtected()) { if ($propertyDef->isProtected()) {
if ($scope) { if ($scope) {
return $this->getPropertyOffset($classDef->getNamespacedName(false), $property); break;
} }
$this->fatalError($expr, "Cannot access protected property `{$property}` of class `{$class}`"); $this->fatalError($expr, "Cannot access protected property `{$property}` of class `{$class}`");
} else { } else {
if ($scope === $findClass) { if ($scope === $findClass) {
return $this->getPropertyOffset($classDef->getNamespacedName(false), $property); break;
} }
$this->fatalError($expr, "Cannot access private property `{$property}` of class `{$class}`"); $this->fatalError($expr, "Cannot access private property `{$property}` of class `{$class}`");
} }
@ -4271,6 +4294,11 @@ class CompilerBase extends \PhpAot\Core\Translator
} }
break; break;
} }
if ($propertyDef and $classDef) {
$expr->setAttribute('nativePropertyDef', $propertyDef);
$expr->setAttribute('nativeClassDef', $classDef);
return $this->getPropertyOffset($classDef->getNamespacedName(false), $property);
}
return null; return null;
} }
@ -4784,6 +4812,9 @@ class CompilerBase extends \PhpAot\Core\Translator
foreach ($this->context->globalVars as $name => $type) { foreach ($this->context->globalVars as $name => $type) {
$code .= $this->getIndent() . self::TYPE_VAR . ' &' . $name . ' = ' . $this->escapeGlobalVar($name) . ';' . PHP_EOL; $code .= $this->getIndent() . self::TYPE_VAR . ' &' . $name . ' = ' . $this->escapeGlobalVar($name) . ';' . PHP_EOL;
} }
foreach ($this->context->objectProps as $name => $info) {
$code .= $this->getIndent() . $info['type'] . ' &' . $name . ' = Z_LVAL_P(' . $info['getter'] . '.unwrap_ptr());' . PHP_EOL;
}
return $code; return $code;
} }

@ -33,6 +33,7 @@ class FunctionContext
public bool $inAssignExpr = false; public bool $inAssignExpr = false;
public array $beforeStmtLines = []; public array $beforeStmtLines = [];
public array $afterStmtLines = []; public array $afterStmtLines = [];
public array $objectProps;
public function __construct() public function __construct()
{ {
@ -40,6 +41,7 @@ class FunctionContext
$this->staticVars = []; $this->staticVars = [];
$this->arguments = []; $this->arguments = [];
$this->objects = []; $this->objects = [];
$this->objectProps = [];
$this->ceWrappers = []; $this->ceWrappers = [];
$this->tmpVarIndex = 0; $this->tmpVarIndex = 0;
$this->inLoop = false; $this->inLoop = false;

@ -0,0 +1,25 @@
--TEST--
default array property
--FILE--
<?php
use native_types;
class Test {
protected int $x = 100;
function bar() {
$n = 12345;
while($n--) {
$this->x += $n;
}
var_dump($this->x);
}
}
function main() {
$obj = new Test;
$obj->bar();
}
?>
--EXPECT--
int(76193440)
Loading…
Cancel
Save