Commit 93fd714daa6 for php.net

commit 93fd714daa6b32372d6b7c913433c386054455c7
Author: Weilin Du <weilindu@php.net>
Date:   Tue Sep 15 00:03:28 2026 +0800

    ext/standard: Optimize str_repeat() when the multiplier is one (#23681)

    Just reuse the input string when the multiplier is one :)

    Co-authored-by: Nora Dossche <7771979+ndossche@users.noreply.github.com>

diff --git a/UPGRADING b/UPGRADING
index 07223cd7a21..ee7f4c3ab73 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -1110,6 +1110,7 @@ PHP 8.6 UPGRADE NOTES
   . Improved performance of intval('+0b...', 2) and intval('0b...', 2).
   . Improved performance of str_split().
   . Improved performance of str_pad().
+  . Improved performance of str_repeat() when the multiplier is 1.

 - URI:
   . Improved performance of Uri\WhatWg\Url::parse() when collecting
diff --git a/Zend/Optimizer/zend_func_infos.h b/Zend/Optimizer/zend_func_infos.h
index b14de7888a9..0add5a32f91 100644
--- a/Zend/Optimizer/zend_func_infos.h
+++ b/Zend/Optimizer/zend_func_infos.h
@@ -493,7 +493,6 @@ static const func_info_t func_infos[] = {
 	F1("hebrev", MAY_BE_STRING),
 	F1("strip_tags", MAY_BE_STRING),
 	F1("str_getcsv", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_NULL),
-	F1("str_repeat", MAY_BE_STRING),
 	F1("count_chars", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_LONG|MAY_BE_STRING),
 	F1("localeconv", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_ARRAY),
 	F1("sscanf", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_ANY|MAY_BE_LONG|MAY_BE_NULL),
diff --git a/ext/opcache/tests/jit/str_repeat_refcount.phpt b/ext/opcache/tests/jit/str_repeat_refcount.phpt
new file mode 100644
index 00000000000..9a9b83cb929
--- /dev/null
+++ b/ext/opcache/tests/jit/str_repeat_refcount.phpt
@@ -0,0 +1,23 @@
+--TEST--
+str_repeat() may return a shared string
+--EXTENSIONS--
+opcache
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit=1205
+opcache.jit_buffer_size=32M
+--FILE--
+<?php
+function test(int $length): void {
+    $input = str_repeat('a', $length);
+    str_repeat($input, 1);
+    $overwrite = str_repeat('b', $length);
+    var_dump($input, $overwrite);
+}
+test(16);
+?>
+--EXPECT--
+string(16) "aaaaaaaaaaaaaaaa"
+string(16) "bbbbbbbbbbbbbbbb"
diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php
index 6b3b11a5fa3..4b455ec331b 100644
--- a/ext/standard/basic_functions.stub.php
+++ b/ext/standard/basic_functions.stub.php
@@ -2593,7 +2593,6 @@ function parse_str(string $string, &$result): void {}
  */
 function str_getcsv(string $string, string $separator = ",", string $enclosure = "\"", string $escape = "\\"): array {}

-/** @refcount 1 */
 function str_repeat(string $string, int $times): string {}

 /**
diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h
index 677c5e66860..b770a1e8684 100644
Binary files a/ext/standard/basic_functions_arginfo.h and b/ext/standard/basic_functions_arginfo.h differ
diff --git a/ext/standard/basic_functions_decl.h b/ext/standard/basic_functions_decl.h
index d6031776699..aab4e4b5f09 100644
Binary files a/ext/standard/basic_functions_decl.h and b/ext/standard/basic_functions_decl.h differ
diff --git a/ext/standard/string.c b/ext/standard/string.c
index f7c2ed37cf6..2c5990a6a8c 100644
--- a/ext/standard/string.c
+++ b/ext/standard/string.c
@@ -5638,6 +5638,10 @@ PHP_FUNCTION(str_repeat)
 	if (ZSTR_LEN(input_str) == 0 || mult == 0)
 		RETURN_EMPTY_STRING();

+	if (mult == 1) {
+		RETURN_STR_COPY(input_str);
+	}
+
 	/* Initialize the result string */
 	result = zend_string_safe_alloc(ZSTR_LEN(input_str), mult, 0, 0);
 	result_len = ZSTR_LEN(input_str) * mult;