summaryrefslogtreecommitdiff
path: root/pp.c
diff options
context:
space:
mode:
authorRichard Leach <richardleach@users.noreply.github.com>2021-06-12 01:28:25 +0100
committerTony Cook <tony@develop-help.com>2022-06-08 14:26:35 +1000
commit2ebf8a2046483a8d79ad2050abd76cc78e70dd3c (patch)
tree4b499a7f71f236d3f0b5bc358c0cb89cadd3e0bd /pp.c
parentdd834db38c17eed742a7adc0c4baad02341dcd03 (diff)
downloadperl-2ebf8a2046483a8d79ad2050abd76cc78e70dd3c.tar.gz
pp_unshift: av_store is often unnecessary
Diffstat (limited to 'pp.c')
-rw-r--r--pp.c27
1 files changed, 24 insertions, 3 deletions
diff --git a/pp.c b/pp.c
index 4908cb5892..168b96d4f4 100644
--- a/pp.c
+++ b/pp.c
@@ -5859,10 +5859,31 @@ PP(pp_unshift)
av_unshift(ary, SP - MARK);
PL_delaymagic = DM_DELAY;
- while (MARK < SP) {
- SV * const sv = newSVsv(*++MARK);
- (void)av_store(ary, i++, sv);
+
+ if (!SvMAGICAL(ary)) {
+ /* The av_unshift above means that many of the checks inside
+ * av_store are unnecessary. If ary does not have magic attached
+ * then a simple direct assignment is possible here. */
+ while (MARK < SP) {
+ SV * const sv = newSVsv(*++MARK);
+ assert( !SvTIED_mg((const SV *)ary, PERL_MAGIC_tied) );
+ assert( i >= 0 );
+ assert( !SvREADONLY(ary) );
+ assert( AvREAL(ary) || !AvREIFY(ary) );
+ assert( i <= AvMAX(ary) );
+ assert( i <= AvFILLp(ary) );
+ if (AvREAL(ary))
+ SvREFCNT_dec(AvARRAY(ary)[i]);
+ AvARRAY(ary)[i] = sv;
+ i++;
+ }
+ } else {
+ while (MARK < SP) {
+ SV * const sv = newSVsv(*++MARK);
+ (void)av_store(ary, i++, sv);
+ }
}
+
if (PL_delaymagic & DM_ARRAY_ISA)
mg_set(MUTABLE_SV(ary));
PL_delaymagic = old_delaymagic;