summaryrefslogtreecommitdiff
path: root/pp.c
diff options
context:
space:
mode:
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;