From 58a4702ed21e19c5397305b28c4615608853d134 Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Mon, 11 May 2026 19:46:12 +0800 Subject: [PATCH] =?UTF-8?q?perf(php):=20=E4=BC=98=E5=8C=96=E5=A4=A7?= =?UTF-8?q?=E6=95=B0=E7=BB=84=E5=86=85=E5=AD=98=E5=88=86=E9=85=8D=E7=AD=96?= =?UTF-8?q?=E7=95=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 引入 MAX_BYTES_IN_STACK 常量控制栈上数组大小限制 - 实现超过 65536 字节的数组自动转到堆上分配 - 在 StdArrayParser 中计算数组总字节数并存储到 bytes 属性 - 根据数组大小选择栈上初始化或堆上 unique_ptr 分配方式 - 避免大数组在栈上分配导致的内存溢出问题 --- src/Php/CompilerBase.php | 10 ++++++++-- src/Php/Parser/StdArrayParser.php | 7 +++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index d50af5f2..4f35f874 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -102,6 +102,8 @@ class CompilerBase extends \PhpAot\Core\Translator public const string OP_NOT_EMPTY = 'notEmpty'; public const string OP_REFVAL = 'toReference'; public const string OP_NOP = "if (0) {}\n"; + // 超过65536字节的数组,将从栈上转移到堆 + public const int MAX_BYTES_IN_STACK = 65536; protected string $lang = 'PHP'; protected string $cppCompiler = ''; protected array $literalStrings = []; @@ -5367,8 +5369,12 @@ class CompilerBase extends \PhpAot\Core\Translator $code .= $this->getIndent(); if ($type === self::TYPE_STD_ARRAY) { $info = $this->context->stdArrays[$name]; - $code .= "auto {$name}_unique_ptr = std::make_unique<{$info['decl']}>();\n"; - $code .= $this->getIndent() . ' auto &' . $name . ' = *' . $name . '_unique_ptr;'; + if ($info['bytes'] > self::MAX_BYTES_IN_STACK) { + $code .= "auto {$name}_unique_ptr = std::make_unique<{$info['decl']}>();\n"; + $code .= $this->getIndent() . ' auto &' . $name . ' = *' . $name . '_unique_ptr;'; + } else { + $code .= $info['decl'] . ' ' . $name . '{};'; + } } else { $code .= $type . ' ' . $name; if ($type === self::TYPE_INT or $type === self::TYPE_FLOAT or $type === self::TYPE_BOOL) { diff --git a/src/Php/Parser/StdArrayParser.php b/src/Php/Parser/StdArrayParser.php index a41988ae..6e532856 100644 --- a/src/Php/Parser/StdArrayParser.php +++ b/src/Php/Parser/StdArrayParser.php @@ -108,6 +108,7 @@ trait StdArrayParser { $tmp = $expr; $nesting = []; + $totalBytes = 0; while (true) { if (count($tmp->args) !== 2) { @@ -116,6 +117,7 @@ trait StdArrayParser if (!$this->isScalarInt($tmp->args[1]->value)) { $this->fatalError($tmp, 'std::array() expects second argument to be an integer'); } + $byte = 0; $size = $tmp->args[1]->value->value; $nesting[] = $size; $typeExpr = $tmp->args[0]->value; @@ -126,12 +128,15 @@ trait StdArrayParser switch ($typeExpr->name->name) { case 'type_int': $type = self::TYPE_INT; + $byte = 8; break; case 'type_float': $type = self::TYPE_FLOAT; + $byte = 8; break; case 'type_bool': $type = self::TYPE_BOOL; + $byte = 1; break; default: $this->fatalError($tmp, 'An incorrect `std::array` definition'); @@ -139,6 +144,7 @@ trait StdArrayParser } break; } + $totalBytes += $size * $byte; if ($this->isStaticCall($typeExpr)) { $tmp = $typeExpr; if (!$this->isNameExpr($tmp->class) || !$this->isIdExpr($tmp->name) || $tmp->class->toString() !== 'std' || $tmp->name->toString() !== 'array') { @@ -158,6 +164,7 @@ trait StdArrayParser 'decl' => $decl, 'type' => $type, 'sizes' => array_reverse($nesting), + 'bytes' => $totalBytes, ]; return '// ' . $decl; }