Skip to content

Commit ff810d5

Browse files
Arginfo: reuse zend_string objects for initializing attribute values (#19241)
Avoid initializing the same string content multiple times and make use of the fact that the strings created to initialize attribute values are not freed by simply making use of an existing zend_string with the same content if one is available.
1 parent 068aaed commit ff810d5

File tree

11 files changed

+113
-91
lines changed

11 files changed

+113
-91
lines changed

build/gen_stub.php

Lines changed: 78 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3319,8 +3319,12 @@ public function __construct(string $class, array $args) {
33193319
$this->args = $args;
33203320
}
33213321

3322-
/** @param array<string, ConstInfo> $allConstInfos */
3323-
public function generateCode(string $invocation, string $nameSuffix, array $allConstInfos, ?int $phpVersionIdMinimumCompatibility): string {
3322+
/**
3323+
* @param array<string, ConstInfo> $allConstInfos
3324+
* @param array<string, string> &$declaredStrings Map of string content to
3325+
* the name of a zend_string already created with that content
3326+
*/
3327+
public function generateCode(string $invocation, string $nameSuffix, array $allConstInfos, ?int $phpVersionIdMinimumCompatibility, array &$declaredStrings = []): string {
33243328
$escapedAttributeName = strtr($this->class, '\\', '_');
33253329
[$stringInit, $nameCode, $stringRelease] = StringBuilder::getString(
33263330
"attribute_name_{$escapedAttributeName}_$nameSuffix",
@@ -3344,6 +3348,9 @@ public function generateCode(string $invocation, string $nameSuffix, array $allC
33443348
);
33453349
if ($strInit === '') {
33463350
$initValue = "\tZVAL_STR(&attribute_{$escapedAttributeName}_{$nameSuffix}->args[$i].value, $strUse);\n";
3351+
} elseif (isset($declaredStrings[$strVal])) {
3352+
$strUse = $declaredStrings[$strVal];
3353+
$initValue = "\tZVAL_STR_COPY(&attribute_{$escapedAttributeName}_{$nameSuffix}->args[$i].value, $strUse);\n";
33473354
}
33483355
}
33493356
if ($initValue === '') {
@@ -3353,6 +3360,9 @@ public function generateCode(string $invocation, string $nameSuffix, array $allC
33533360
true,
33543361
"attribute_{$escapedAttributeName}_{$nameSuffix}_arg{$i}_str"
33553362
);
3363+
if ($arg->value instanceof Node\Scalar\String_) {
3364+
$declaredStrings[$arg->value->value] = "attribute_{$escapedAttributeName}_{$nameSuffix}_arg{$i}_str";
3365+
}
33563366
} else {
33573367
$code .= $initValue;
33583368
}
@@ -3603,6 +3613,8 @@ function (Name $item) {
36033613
$php80CondEnd = "#endif\n";
36043614
}
36053615

3616+
$declaredStrings = [];
3617+
36063618
if (!empty($this->attributes)) {
36073619
$code .= $php80CondStart;
36083620

@@ -3611,26 +3623,27 @@ function (Name $item) {
36113623
"zend_add_class_attribute(class_entry",
36123624
"class_{$escapedName}_$key",
36133625
$allConstInfos,
3614-
$this->phpVersionIdMinimumCompatibility
3626+
$this->phpVersionIdMinimumCompatibility,
3627+
$declaredStrings
36153628
);
36163629
}
36173630

36183631
$code .= $php80CondEnd;
36193632
}
36203633

3621-
if ($attributeInitializationCode = generateConstantAttributeInitialization($this->constInfos, $allConstInfos, $this->phpVersionIdMinimumCompatibility, $this->cond)) {
3634+
if ($attributeInitializationCode = generateConstantAttributeInitialization($this->constInfos, $allConstInfos, $this->phpVersionIdMinimumCompatibility, $this->cond, $declaredStrings)) {
36223635
$code .= $php80CondStart;
36233636
$code .= "\n" . $attributeInitializationCode;
36243637
$code .= $php80CondEnd;
36253638
}
36263639

3627-
if ($attributeInitializationCode = generatePropertyAttributeInitialization($this->propertyInfos, $allConstInfos, $this->phpVersionIdMinimumCompatibility)) {
3640+
if ($attributeInitializationCode = generatePropertyAttributeInitialization($this->propertyInfos, $allConstInfos, $this->phpVersionIdMinimumCompatibility, $declaredStrings)) {
36283641
$code .= $php80CondStart;
36293642
$code .= "\n" . $attributeInitializationCode;
36303643
$code .= $php80CondEnd;
36313644
}
36323645

3633-
if ($attributeInitializationCode = generateFunctionAttributeInitialization($this->funcInfos, $allConstInfos, $this->phpVersionIdMinimumCompatibility, $this->cond)) {
3646+
if ($attributeInitializationCode = generateFunctionAttributeInitialization($this->funcInfos, $allConstInfos, $this->phpVersionIdMinimumCompatibility, $this->cond, $declaredStrings)) {
36343647
$code .= $php80CondStart;
36353648
$code .= "\n" . $attributeInitializationCode;
36363649
$code .= $php80CondEnd;
@@ -5185,8 +5198,9 @@ static function (FuncInfo $funcInfo) use ($fileInfo, &$generatedFunctionDeclarat
51855198
$php80MinimumCompatibility = $fileInfo->getMinimumPhpVersionIdCompatibility() === null || $fileInfo->getMinimumPhpVersionIdCompatibility() >= PHP_80_VERSION_ID;
51865199

51875200
if ($fileInfo->generateClassEntries) {
5188-
$attributeInitializationCode = generateFunctionAttributeInitialization($fileInfo->funcInfos, $allConstInfos, $fileInfo->getMinimumPhpVersionIdCompatibility(), null);
5189-
$attributeInitializationCode .= generateGlobalConstantAttributeInitialization($fileInfo->constInfos, $allConstInfos, $fileInfo->getMinimumPhpVersionIdCompatibility(), null);
5201+
$declaredStrings = [];
5202+
$attributeInitializationCode = generateFunctionAttributeInitialization($fileInfo->funcInfos, $allConstInfos, $fileInfo->getMinimumPhpVersionIdCompatibility(), null, $declaredStrings);
5203+
$attributeInitializationCode .= generateGlobalConstantAttributeInitialization($fileInfo->constInfos, $allConstInfos, $fileInfo->getMinimumPhpVersionIdCompatibility(), null, $declaredStrings);
51905204
if ($attributeInitializationCode) {
51915205
if (!$php80MinimumCompatibility) {
51925206
$attributeInitializationCode = "\n#if (PHP_VERSION_ID >= " . PHP_80_VERSION_ID . ")" . $attributeInitializationCode . "#endif\n";
@@ -5244,12 +5258,16 @@ function generateFunctionEntries(?Name $className, array $funcInfos, ?string $co
52445258
return $code;
52455259
}
52465260

5247-
/** @param iterable<FuncInfo> $funcInfos */
5248-
function generateFunctionAttributeInitialization(iterable $funcInfos, array $allConstInfos, ?int $phpVersionIdMinimumCompatibility, ?string $parentCond = null): string {
5261+
/**
5262+
* @param iterable<FuncInfo> $funcInfos
5263+
* @param array<string, string> &$declaredStrings Map of string content to
5264+
* the name of a zend_string already created with that content
5265+
*/
5266+
function generateFunctionAttributeInitialization(iterable $funcInfos, array $allConstInfos, ?int $phpVersionIdMinimumCompatibility, ?string $parentCond = null, array &$declaredStrings = []): string {
52495267
return generateCodeWithConditions(
52505268
$funcInfos,
52515269
"",
5252-
static function (FuncInfo $funcInfo) use ($allConstInfos, $phpVersionIdMinimumCompatibility) {
5270+
static function (FuncInfo $funcInfo) use ($allConstInfos, $phpVersionIdMinimumCompatibility, &$declaredStrings) {
52535271
$code = null;
52545272

52555273
if ($funcInfo->name instanceof MethodName) {
@@ -5258,12 +5276,22 @@ static function (FuncInfo $funcInfo) use ($allConstInfos, $phpVersionIdMinimumCo
52585276
$functionTable = "CG(function_table)";
52595277
}
52605278

5279+
// Make sure we don't try and use strings that might only be
5280+
// conditionally available; string reuse is only among declarations
5281+
// that are always there
5282+
if ($funcInfo->cond) {
5283+
$useDeclared = [];
5284+
} else {
5285+
$useDeclared = &$declaredStrings;
5286+
}
5287+
52615288
foreach ($funcInfo->attributes as $key => $attribute) {
52625289
$code .= $attribute->generateCode(
52635290
"zend_add_function_attribute(zend_hash_str_find_ptr($functionTable, \"" . $funcInfo->name->getNameForAttributes() . "\", sizeof(\"" . $funcInfo->name->getNameForAttributes() . "\") - 1)",
52645291
"func_" . $funcInfo->name->getNameForAttributes() . "_$key",
52655292
$allConstInfos,
5266-
$phpVersionIdMinimumCompatibility
5293+
$phpVersionIdMinimumCompatibility,
5294+
$useDeclared
52675295
);
52685296
}
52695297

@@ -5273,7 +5301,8 @@ static function (FuncInfo $funcInfo) use ($allConstInfos, $phpVersionIdMinimumCo
52735301
"zend_add_parameter_attribute(zend_hash_str_find_ptr($functionTable, \"" . $funcInfo->name->getNameForAttributes() . "\", sizeof(\"" . $funcInfo->name->getNameForAttributes() . "\") - 1), $index",
52745302
"func_{$funcInfo->name->getNameForAttributes()}_arg{$index}_$key",
52755303
$allConstInfos,
5276-
$phpVersionIdMinimumCompatibility
5304+
$phpVersionIdMinimumCompatibility,
5305+
$useDeclared
52775306
);
52785307
}
52795308
}
@@ -5287,12 +5316,15 @@ static function (FuncInfo $funcInfo) use ($allConstInfos, $phpVersionIdMinimumCo
52875316
/**
52885317
* @param iterable<ConstInfo> $constInfos
52895318
* @param array<string, ConstInfo> $allConstInfos
5319+
* @param array<string, string> &$declaredStrings Map of string content to
5320+
* the name of a zend_string already created with that content
52905321
*/
52915322
function generateGlobalConstantAttributeInitialization(
52925323
iterable $constInfos,
52935324
array $allConstInfos,
52945325
?int $phpVersionIdMinimumCompatibility,
5295-
?string $parentCond = null
5326+
?string $parentCond = null,
5327+
array &$declaredStrings = []
52965328
): string {
52975329
$isConditional = false;
52985330
if ($phpVersionIdMinimumCompatibility !== null && $phpVersionIdMinimumCompatibility < PHP_85_VERSION_ID) {
@@ -5301,12 +5333,20 @@ function generateGlobalConstantAttributeInitialization(
53015333
$code = generateCodeWithConditions(
53025334
$constInfos,
53035335
"",
5304-
static function (ConstInfo $constInfo) use ($allConstInfos, $isConditional) {
5336+
static function (ConstInfo $constInfo) use ($allConstInfos, $isConditional, &$declaredStrings) {
53055337
$code = "";
53065338

53075339
if ($constInfo->attributes === []) {
53085340
return null;
53095341
}
5342+
// Make sure we don't try and use strings that might only be
5343+
// conditionally available; string reuse is only among declarations
5344+
// that are always there
5345+
if ($constInfo->cond) {
5346+
$useDeclared = [];
5347+
} else {
5348+
$useDeclared = &$declaredStrings;
5349+
}
53105350
$constName = str_replace('\\', '\\\\', $constInfo->name->__toString());
53115351
$constVarName = 'const_' . $constName;
53125352

@@ -5321,7 +5361,8 @@ static function (ConstInfo $constInfo) use ($allConstInfos, $isConditional) {
53215361
"zend_add_global_constant_attribute($constVarName",
53225362
$constVarName . "_$key",
53235363
$allConstInfos,
5324-
PHP_85_VERSION_ID
5364+
PHP_85_VERSION_ID,
5365+
$useDeclared
53255366
);
53265367
}
53275368

@@ -5338,25 +5379,37 @@ static function (ConstInfo $constInfo) use ($allConstInfos, $isConditional) {
53385379
/**
53395380
* @param iterable<ConstInfo> $constInfos
53405381
* @param array<string, ConstInfo> $allConstInfos
5382+
* @param array<string, string> &$declaredStrings Map of string content to
5383+
* the name of a zend_string already created with that content
53415384
*/
53425385
function generateConstantAttributeInitialization(
53435386
iterable $constInfos,
53445387
array $allConstInfos,
53455388
?int $phpVersionIdMinimumCompatibility,
5346-
?string $parentCond = null
5389+
?string $parentCond = null,
5390+
array &$declaredStrings = []
53475391
): string {
53485392
return generateCodeWithConditions(
53495393
$constInfos,
53505394
"",
5351-
static function (ConstInfo $constInfo) use ($allConstInfos, $phpVersionIdMinimumCompatibility) {
5395+
static function (ConstInfo $constInfo) use ($allConstInfos, $phpVersionIdMinimumCompatibility, &$declaredStrings) {
53525396
$code = null;
53535397

5398+
// Make sure we don't try and use strings that might only be
5399+
// conditionally available; string reuse is only among declarations
5400+
// that are always there
5401+
if ($constInfo->cond) {
5402+
$useDeclared = [];
5403+
} else {
5404+
$useDeclared = &$declaredStrings;
5405+
}
53545406
foreach ($constInfo->attributes as $key => $attribute) {
53555407
$code .= $attribute->generateCode(
53565408
"zend_add_class_constant_attribute(class_entry, const_" . $constInfo->name->getDeclarationName(),
53575409
"const_" . $constInfo->name->getDeclarationName() . "_$key",
53585410
$allConstInfos,
5359-
$phpVersionIdMinimumCompatibility
5411+
$phpVersionIdMinimumCompatibility,
5412+
$useDeclared
53605413
);
53615414
}
53625415

@@ -5369,11 +5422,14 @@ static function (ConstInfo $constInfo) use ($allConstInfos, $phpVersionIdMinimum
53695422
/**
53705423
* @param iterable<PropertyInfo> $propertyInfos
53715424
* @param array<string, ConstInfo> $allConstInfos
5425+
* @param array<string, string> &$declaredStrings Map of string content to
5426+
* the name of a zend_string already created with that content
53725427
*/
53735428
function generatePropertyAttributeInitialization(
53745429
iterable $propertyInfos,
53755430
array $allConstInfos,
5376-
?int $phpVersionIdMinimumCompatibility
5431+
?int $phpVersionIdMinimumCompatibility,
5432+
array &$declaredStrings
53775433
): string {
53785434
$code = "";
53795435
foreach ($propertyInfos as $propertyInfo) {
@@ -5382,7 +5438,8 @@ function generatePropertyAttributeInitialization(
53825438
"zend_add_property_attribute(class_entry, property_" . $propertyInfo->name->getDeclarationName(),
53835439
"property_" . $propertyInfo->name->getDeclarationName() . "_" . $key,
53845440
$allConstInfos,
5385-
$phpVersionIdMinimumCompatibility
5441+
$phpVersionIdMinimumCompatibility,
5442+
$declaredStrings
53865443
);
53875444
}
53885445
}

ext/date/php_date_arginfo.h

Lines changed: 4 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/enchant/enchant_arginfo.h

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/filter/filter_arginfo.h

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)