Skip to content

Arginfo: reuse zend_string objects for initializing attribute values #19241

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 78 additions & 21 deletions build/gen_stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -3319,8 +3319,12 @@ public function __construct(string $class, array $args) {
$this->args = $args;
}

/** @param array<string, ConstInfo> $allConstInfos */
public function generateCode(string $invocation, string $nameSuffix, array $allConstInfos, ?int $phpVersionIdMinimumCompatibility): string {
/**
* @param array<string, ConstInfo> $allConstInfos
* @param array<string, string> &$declaredStrings Map of string content to
* the name of a zend_string already created with that content
*/
public function generateCode(string $invocation, string $nameSuffix, array $allConstInfos, ?int $phpVersionIdMinimumCompatibility, array &$declaredStrings = []): string {
$escapedAttributeName = strtr($this->class, '\\', '_');
[$stringInit, $nameCode, $stringRelease] = StringBuilder::getString(
"attribute_name_{$escapedAttributeName}_$nameSuffix",
Expand All @@ -3344,6 +3348,9 @@ public function generateCode(string $invocation, string $nameSuffix, array $allC
);
if ($strInit === '') {
$initValue = "\tZVAL_STR(&attribute_{$escapedAttributeName}_{$nameSuffix}->args[$i].value, $strUse);\n";
} elseif (isset($declaredStrings[$strVal])) {
$strUse = $declaredStrings[$strVal];
$initValue = "\tZVAL_STR_COPY(&attribute_{$escapedAttributeName}_{$nameSuffix}->args[$i].value, $strUse);\n";
}
}
if ($initValue === '') {
Expand All @@ -3353,6 +3360,9 @@ public function generateCode(string $invocation, string $nameSuffix, array $allC
true,
"attribute_{$escapedAttributeName}_{$nameSuffix}_arg{$i}_str"
);
if ($arg->value instanceof Node\Scalar\String_) {
$declaredStrings[$arg->value->value] = "attribute_{$escapedAttributeName}_{$nameSuffix}_arg{$i}_str";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this string that you construct (i.e. the variable name) should be split out to a separate variable, as you already construct it previously on line 3361 too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"this string" being "attribute_{$escapedAttributeName}_{$nameSuffix}_arg{$i}_str" ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that the other instance where the variable is declared is just 3 lines earlier, I don't think a variable is needed

}
} else {
$code .= $initValue;
}
Expand Down Expand Up @@ -3603,6 +3613,8 @@ function (Name $item) {
$php80CondEnd = "#endif\n";
}

$declaredStrings = [];

if (!empty($this->attributes)) {
$code .= $php80CondStart;

Expand All @@ -3611,26 +3623,27 @@ function (Name $item) {
"zend_add_class_attribute(class_entry",
"class_{$escapedName}_$key",
$allConstInfos,
$this->phpVersionIdMinimumCompatibility
$this->phpVersionIdMinimumCompatibility,
$declaredStrings
);
}

$code .= $php80CondEnd;
}

if ($attributeInitializationCode = generateConstantAttributeInitialization($this->constInfos, $allConstInfos, $this->phpVersionIdMinimumCompatibility, $this->cond)) {
if ($attributeInitializationCode = generateConstantAttributeInitialization($this->constInfos, $allConstInfos, $this->phpVersionIdMinimumCompatibility, $this->cond, $declaredStrings)) {
$code .= $php80CondStart;
$code .= "\n" . $attributeInitializationCode;
$code .= $php80CondEnd;
}

if ($attributeInitializationCode = generatePropertyAttributeInitialization($this->propertyInfos, $allConstInfos, $this->phpVersionIdMinimumCompatibility)) {
if ($attributeInitializationCode = generatePropertyAttributeInitialization($this->propertyInfos, $allConstInfos, $this->phpVersionIdMinimumCompatibility, $declaredStrings)) {
$code .= $php80CondStart;
$code .= "\n" . $attributeInitializationCode;
$code .= $php80CondEnd;
}

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

if ($fileInfo->generateClassEntries) {
$attributeInitializationCode = generateFunctionAttributeInitialization($fileInfo->funcInfos, $allConstInfos, $fileInfo->getMinimumPhpVersionIdCompatibility(), null);
$attributeInitializationCode .= generateGlobalConstantAttributeInitialization($fileInfo->constInfos, $allConstInfos, $fileInfo->getMinimumPhpVersionIdCompatibility(), null);
$declaredStrings = [];
$attributeInitializationCode = generateFunctionAttributeInitialization($fileInfo->funcInfos, $allConstInfos, $fileInfo->getMinimumPhpVersionIdCompatibility(), null, $declaredStrings);
$attributeInitializationCode .= generateGlobalConstantAttributeInitialization($fileInfo->constInfos, $allConstInfos, $fileInfo->getMinimumPhpVersionIdCompatibility(), null, $declaredStrings);
if ($attributeInitializationCode) {
if (!$php80MinimumCompatibility) {
$attributeInitializationCode = "\n#if (PHP_VERSION_ID >= " . PHP_80_VERSION_ID . ")" . $attributeInitializationCode . "#endif\n";
Expand Down Expand Up @@ -5244,12 +5258,16 @@ function generateFunctionEntries(?Name $className, array $funcInfos, ?string $co
return $code;
}

/** @param iterable<FuncInfo> $funcInfos */
function generateFunctionAttributeInitialization(iterable $funcInfos, array $allConstInfos, ?int $phpVersionIdMinimumCompatibility, ?string $parentCond = null): string {
/**
* @param iterable<FuncInfo> $funcInfos
* @param array<string, string> &$declaredStrings Map of string content to
* the name of a zend_string already created with that content
*/
function generateFunctionAttributeInitialization(iterable $funcInfos, array $allConstInfos, ?int $phpVersionIdMinimumCompatibility, ?string $parentCond = null, array &$declaredStrings = []): string {
return generateCodeWithConditions(
$funcInfos,
"",
static function (FuncInfo $funcInfo) use ($allConstInfos, $phpVersionIdMinimumCompatibility) {
static function (FuncInfo $funcInfo) use ($allConstInfos, $phpVersionIdMinimumCompatibility, &$declaredStrings) {
$code = null;

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

// Make sure we don't try and use strings that might only be
// conditionally available; string reuse is only among declarations
// that are always there
if ($funcInfo->cond) {
$useDeclared = [];
} else {
$useDeclared = &$declaredStrings;
}

foreach ($funcInfo->attributes as $key => $attribute) {
$code .= $attribute->generateCode(
"zend_add_function_attribute(zend_hash_str_find_ptr($functionTable, \"" . $funcInfo->name->getNameForAttributes() . "\", sizeof(\"" . $funcInfo->name->getNameForAttributes() . "\") - 1)",
"func_" . $funcInfo->name->getNameForAttributes() . "_$key",
$allConstInfos,
$phpVersionIdMinimumCompatibility
$phpVersionIdMinimumCompatibility,
$useDeclared
);
}

Expand All @@ -5273,7 +5301,8 @@ static function (FuncInfo $funcInfo) use ($allConstInfos, $phpVersionIdMinimumCo
"zend_add_parameter_attribute(zend_hash_str_find_ptr($functionTable, \"" . $funcInfo->name->getNameForAttributes() . "\", sizeof(\"" . $funcInfo->name->getNameForAttributes() . "\") - 1), $index",
"func_{$funcInfo->name->getNameForAttributes()}_arg{$index}_$key",
$allConstInfos,
$phpVersionIdMinimumCompatibility
$phpVersionIdMinimumCompatibility,
$useDeclared
);
}
}
Expand All @@ -5287,12 +5316,15 @@ static function (FuncInfo $funcInfo) use ($allConstInfos, $phpVersionIdMinimumCo
/**
* @param iterable<ConstInfo> $constInfos
* @param array<string, ConstInfo> $allConstInfos
* @param array<string, string> &$declaredStrings Map of string content to
* the name of a zend_string already created with that content
*/
function generateGlobalConstantAttributeInitialization(
iterable $constInfos,
array $allConstInfos,
?int $phpVersionIdMinimumCompatibility,
?string $parentCond = null
?string $parentCond = null,
array &$declaredStrings = []
): string {
$isConditional = false;
if ($phpVersionIdMinimumCompatibility !== null && $phpVersionIdMinimumCompatibility < PHP_85_VERSION_ID) {
Expand All @@ -5301,12 +5333,20 @@ function generateGlobalConstantAttributeInitialization(
$code = generateCodeWithConditions(
$constInfos,
"",
static function (ConstInfo $constInfo) use ($allConstInfos, $isConditional) {
static function (ConstInfo $constInfo) use ($allConstInfos, $isConditional, &$declaredStrings) {
$code = "";

if ($constInfo->attributes === []) {
return null;
}
// Make sure we don't try and use strings that might only be
// conditionally available; string reuse is only among declarations
// that are always there
if ($constInfo->cond) {
$useDeclared = [];
} else {
$useDeclared = &$declaredStrings;
}
$constName = str_replace('\\', '\\\\', $constInfo->name->__toString());
$constVarName = 'const_' . $constName;

Expand All @@ -5321,7 +5361,8 @@ static function (ConstInfo $constInfo) use ($allConstInfos, $isConditional) {
"zend_add_global_constant_attribute($constVarName",
$constVarName . "_$key",
$allConstInfos,
PHP_85_VERSION_ID
PHP_85_VERSION_ID,
$useDeclared
);
}

Expand All @@ -5338,25 +5379,37 @@ static function (ConstInfo $constInfo) use ($allConstInfos, $isConditional) {
/**
* @param iterable<ConstInfo> $constInfos
* @param array<string, ConstInfo> $allConstInfos
* @param array<string, string> &$declaredStrings Map of string content to
* the name of a zend_string already created with that content
*/
function generateConstantAttributeInitialization(
iterable $constInfos,
array $allConstInfos,
?int $phpVersionIdMinimumCompatibility,
?string $parentCond = null
?string $parentCond = null,
array &$declaredStrings = []
): string {
return generateCodeWithConditions(
$constInfos,
"",
static function (ConstInfo $constInfo) use ($allConstInfos, $phpVersionIdMinimumCompatibility) {
static function (ConstInfo $constInfo) use ($allConstInfos, $phpVersionIdMinimumCompatibility, &$declaredStrings) {
$code = null;

// Make sure we don't try and use strings that might only be
// conditionally available; string reuse is only among declarations
// that are always there
if ($constInfo->cond) {
$useDeclared = [];
} else {
$useDeclared = &$declaredStrings;
}
foreach ($constInfo->attributes as $key => $attribute) {
$code .= $attribute->generateCode(
"zend_add_class_constant_attribute(class_entry, const_" . $constInfo->name->getDeclarationName(),
"const_" . $constInfo->name->getDeclarationName() . "_$key",
$allConstInfos,
$phpVersionIdMinimumCompatibility
$phpVersionIdMinimumCompatibility,
$useDeclared
);
}

Expand All @@ -5369,11 +5422,14 @@ static function (ConstInfo $constInfo) use ($allConstInfos, $phpVersionIdMinimum
/**
* @param iterable<PropertyInfo> $propertyInfos
* @param array<string, ConstInfo> $allConstInfos
* @param array<string, string> &$declaredStrings Map of string content to
* the name of a zend_string already created with that content
*/
function generatePropertyAttributeInitialization(
iterable $propertyInfos,
array $allConstInfos,
?int $phpVersionIdMinimumCompatibility
?int $phpVersionIdMinimumCompatibility,
array &$declaredStrings
): string {
$code = "";
foreach ($propertyInfos as $propertyInfo) {
Expand All @@ -5382,7 +5438,8 @@ function generatePropertyAttributeInitialization(
"zend_add_property_attribute(class_entry, property_" . $propertyInfo->name->getDeclarationName(),
"property_" . $propertyInfo->name->getDeclarationName() . "_" . $key,
$allConstInfos,
$phpVersionIdMinimumCompatibility
$phpVersionIdMinimumCompatibility,
$declaredStrings
);
}
}
Expand Down
12 changes: 4 additions & 8 deletions ext/date/php_date_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions ext/enchant/enchant_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions ext/filter/filter_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading