diff --git a/pp.c b/pp.c index d0df82836323..b2897adefd20 100644 --- a/pp.c +++ b/pp.c @@ -5846,10 +5846,30 @@ 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 (!SvSMAGICAL(ary)) { + /* The av_unshift above means that many of the checks inside + * av_store are unnecessary. If ary does not have store magic + * 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) ); + assert( !AvREAL(ary) || AvARRAY(ary)[i] == NULL ); + 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;