Skip to content

Commit 7a8b1f6

Browse files
Generated arginfo header files: use known strings for prop names when… (php#15751)
Instead of allocating, using, and then releasing a zend_string for every property name unconditionally, only do so when the minimum supported version of PHP does not have that string in its known strings (ZEND_KNOWN_STRINGS). If the string is already known, just use the known version directly. This is already done for some non-generated class registrations, e.g. in `zend_enum_register_props()`.
1 parent 52b514b commit 7a8b1f6

16 files changed

+207
-177
lines changed

Zend/zend_attributes_arginfo.h

+3-9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Zend/zend_exceptions_arginfo.h

+15-45
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Zend/zend_string.h

+2
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,8 @@ EMPTY_SWITCH_DEFAULT_CASE()
560560
#endif
561561
}
562562

563+
// When adding a new string here, please also update build/gen_stub.php to the
564+
// known strings to be used in property registration; see gh-15751
563565
#define ZEND_KNOWN_STRINGS(_) \
564566
_(ZEND_STR_FILE, "file") \
565567
_(ZEND_STR_LINE, "line") \

build/gen_stub.php

+147-3
Original file line numberDiff line numberDiff line change
@@ -2918,6 +2918,100 @@ class PropertyInfo extends VariableLike
29182918
public bool $isDocReadonly;
29192919
public bool $isVirtual;
29202920

2921+
// Map possible variable names to the known string constant, see
2922+
// ZEND_KNOWN_STRINGS
2923+
private const PHP_80_KNOWN = [
2924+
"file" => "ZEND_STR_FILE",
2925+
"line" => "ZEND_STR_LINE",
2926+
"function" => "ZEND_STR_FUNCTION",
2927+
"class" => "ZEND_STR_CLASS",
2928+
"object" => "ZEND_STR_OBJECT",
2929+
"type" => "ZEND_STR_TYPE",
2930+
// ZEND_STR_OBJECT_OPERATOR and ZEND_STR_PAAMAYIM_NEKUDOTAYIM are
2931+
// not valid variable names
2932+
"args" => "ZEND_STR_ARGS",
2933+
"unknown" => "ZEND_STR_UNKNOWN",
2934+
"eval" => "ZEND_STR_EVAL",
2935+
"include" => "ZEND_STR_INCLUDE",
2936+
"require" => "ZEND_STR_REQUIRE",
2937+
"include_once" => "ZEND_STR_INCLUDE_ONCE",
2938+
"require_once" => "ZEND_STR_REQUIRE_ONCE",
2939+
"scalar" => "ZEND_STR_SCALAR",
2940+
"error_reporting" => "ZEND_STR_ERROR_REPORTING",
2941+
"static" => "ZEND_STR_STATIC",
2942+
// ZEND_STR_THIS cannot be used since $this cannot be reassigned
2943+
"value" => "ZEND_STR_VALUE",
2944+
"key" => "ZEND_STR_KEY",
2945+
"__invoke" => "ZEND_STR_MAGIC_INVOKE",
2946+
"previous" => "ZEND_STR_PREVIOUS",
2947+
"code" => "ZEND_STR_CODE",
2948+
"message" => "ZEND_STR_MESSAGE",
2949+
"severity" => "ZEND_STR_SEVERITY",
2950+
"string" => "ZEND_STR_STRING",
2951+
"trace" => "ZEND_STR_TRACE",
2952+
"scheme" => "ZEND_STR_SCHEME",
2953+
"host" => "ZEND_STR_HOST",
2954+
"port" => "ZEND_STR_PORT",
2955+
"user" => "ZEND_STR_USER",
2956+
"pass" => "ZEND_STR_PASS",
2957+
"path" => "ZEND_STR_PATH",
2958+
"query" => "ZEND_STR_QUERY",
2959+
"fragment" => "ZEND_STR_FRAGMENT",
2960+
"NULL" => "ZEND_STR_NULL",
2961+
"boolean" => "ZEND_STR_BOOLEAN",
2962+
"integer" => "ZEND_STR_INTEGER",
2963+
"double" => "ZEND_STR_DOUBLE",
2964+
"array" => "ZEND_STR_ARRAY",
2965+
"resource" => "ZEND_STR_RESOURCE",
2966+
// ZEND_STR_CLOSED_RESOURCE has a space in it
2967+
"name" => "ZEND_STR_NAME",
2968+
// ZEND_STR_ARGV and ZEND_STR_ARGC are superglobals that wouldn't be
2969+
// variable names
2970+
"Array" => "ZEND_STR_ARRAY_CAPITALIZED",
2971+
"bool" => "ZEND_STR_BOOL",
2972+
"int" => "ZEND_STR_INT",
2973+
"float" => "ZEND_STR_FLOAT",
2974+
"callable" => "ZEND_STR_CALLABLE",
2975+
"iterable" => "ZEND_STR_ITERABLE",
2976+
"void" => "ZEND_STR_VOID",
2977+
"false" => "ZEND_STR_FALSE",
2978+
"null" => "ZEND_STR_NULL_LOWERCASE",
2979+
"mixed" => "ZEND_STR_MIXED",
2980+
];
2981+
2982+
// NEW in 8.1
2983+
private const PHP_81_KNOWN = [
2984+
"Unknown" => "ZEND_STR_UNKNOWN_CAPITALIZED",
2985+
"never" => "ZEND_STR_NEVER",
2986+
"__sleep" => "ZEND_STR_SLEEP",
2987+
"__wakeup" => "ZEND_STR_WAKEUP",
2988+
"cases" => "ZEND_STR_CASES",
2989+
"from" => "ZEND_STR_FROM",
2990+
"tryFrom" => "ZEND_STR_TRYFROM",
2991+
"tryfrom" => "ZEND_STR_TRYFROM_LOWERCASE",
2992+
// Omit ZEND_STR_AUTOGLOBAL_(SERVER|ENV|REQUEST)
2993+
];
2994+
2995+
// NEW in 8.2
2996+
private const PHP_82_KNOWN = [
2997+
"true" => "ZEND_STR_TRUE",
2998+
"Traversable" => "ZEND_STR_TRAVERSABLE",
2999+
"count" => "ZEND_STR_COUNT",
3000+
"SensitiveParameter" => "ZEND_STR_SENSITIVEPARAMETER",
3001+
];
3002+
3003+
// Only new string in 8.3 is ZEND_STR_CONST_EXPR_PLACEHOLDER which is
3004+
// not a valid variable name ("[constant expression]")
3005+
3006+
// NEW in 8.4
3007+
private const PHP_84_KNOWN = [
3008+
"exit" => "ZEND_STR_EXIT",
3009+
"Deprecated" => "ZEND_STR_DEPRECATED_CAPITALIZED",
3010+
"since" => "ZEND_STR_SINCE",
3011+
"get" => "ZEND_STR_GET",
3012+
"set" => "ZEND_STR_SET",
3013+
];
3014+
29213015
/**
29223016
* @var AttributeInfo[] $attributes
29233017
*/
@@ -3003,8 +3097,8 @@ public function getDeclaration(array $allConstInfos): string {
30033097
$code .= $defaultValue->initializeZval($zvalName);
30043098
}
30053099

3006-
$code .= "\tzend_string *property_{$propertyName}_name = zend_string_init(\"$propertyName\", sizeof(\"$propertyName\") - 1, 1);\n";
3007-
$nameCode = "property_{$propertyName}_name";
3100+
[$stringInit, $nameCode, $stringRelease] = $this->getString($propertyName);
3101+
$code .= $stringInit;
30083102

30093103
if ($this->exposedDocComment) {
30103104
$commentCode = "property_{$propertyName}_comment";
@@ -3035,11 +3129,61 @@ public function getDeclaration(array $allConstInfos): string {
30353129
);
30363130
$code .= implode("", $flagsCode);
30373131

3038-
$code .= "\tzend_string_release(property_{$propertyName}_name);\n";
3132+
$code .= $stringRelease;
30393133

30403134
return $code;
30413135
}
30423136

3137+
/**
3138+
* Get an array of three strings:
3139+
* - declaration of zend_string, if needed, or empty otherwise
3140+
* - usage of that zend_string, or usage with ZSTR_KNOWN()
3141+
* - freeing the zend_string, if needed
3142+
*
3143+
* @param string $propName
3144+
* @return string[]
3145+
*/
3146+
private function getString(string $propName): array {
3147+
// Generally strings will not be known
3148+
$nameCode = "property_{$propName}_name";
3149+
$result = [
3150+
"\tzend_string *$nameCode = zend_string_init(\"$propName\", sizeof(\"$propName\") - 1, 1);\n",
3151+
$nameCode,
3152+
"\tzend_string_release($nameCode);\n"
3153+
];
3154+
// If not set, use the current latest version
3155+
$allVersions = ALL_PHP_VERSION_IDS;
3156+
$minPhp = $phpVersionIdMinimumCompatibility ?? end($allVersions);
3157+
if ($minPhp < PHP_80_VERSION_ID) {
3158+
// No known strings in 7.0
3159+
return $result;
3160+
}
3161+
$include = self::PHP_80_KNOWN;
3162+
switch ($minPhp) {
3163+
case PHP_84_VERSION_ID:
3164+
$include = array_merge($include, self::PHP_84_KNOWN);
3165+
// Intentional fall through
3166+
3167+
case PHP_83_VERSION_ID:
3168+
case PHP_82_VERSION_ID:
3169+
$include = array_merge($include, self::PHP_82_KNOWN);
3170+
// Intentional fall through
3171+
3172+
case PHP_81_VERSION_ID:
3173+
$include = array_merge($include, self::PHP_81_KNOWN);
3174+
break;
3175+
}
3176+
if (array_key_exists($propName,$include)) {
3177+
$knownStr = $include[$propName];
3178+
return [
3179+
'',
3180+
"ZSTR_KNOWN($knownStr)",
3181+
'',
3182+
];
3183+
}
3184+
return $result;
3185+
}
3186+
30433187
/**
30443188
* @return array<int, string[]>
30453189
*/

ext/bcmath/bcmath_arginfo.h

+1-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/curl/curl_file_arginfo.h

+1-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)