@@ -5814,15 +5814,26 @@ instead.
5814
5814
*/
5815
5815
5816
5816
void
5817
- Perl_sv_clear (pTHX_ register SV * const sv )
5817
+ Perl_sv_clear (pTHX_ SV * const orig_sv )
5818
5818
{
5819
5819
dVAR ;
5820
- const U32 type = SvTYPE (sv );
5821
- const struct body_details * const sv_type_details
5822
- = bodies_by_type + type ;
5823
5820
HV * stash ;
5821
+ U32 type ;
5822
+ const struct body_details * sv_type_details ;
5823
+ SV * iter_sv = NULL ;
5824
+ SV * next_sv = NULL ;
5825
+ register SV * sv = orig_sv ;
5824
5826
5825
5827
PERL_ARGS_ASSERT_SV_CLEAR ;
5828
+
5829
+ /* within this loop, sv is the SV currently being freed, and
5830
+ * iter_sv is the most recent AV or whatever that's being iterated
5831
+ * over to provide more SVs */
5832
+
5833
+ while (sv ) {
5834
+
5835
+ type = SvTYPE (sv );
5836
+
5826
5837
assert (SvREFCNT (sv ) == 0 );
5827
5838
assert (SvTYPE (sv ) != SVTYPEMASK );
5828
5839
@@ -5833,7 +5844,7 @@ Perl_sv_clear(pTHX_ register SV *const sv)
5833
5844
goto free_rv ;
5834
5845
SvFLAGS (sv ) &= SVf_BREAK ;
5835
5846
SvFLAGS (sv ) |= SVTYPEMASK ;
5836
- return ;
5847
+ goto free_head ;
5837
5848
}
5838
5849
5839
5850
if (SvOBJECT (sv )) {
@@ -5885,7 +5896,7 @@ Perl_sv_clear(pTHX_ register SV *const sv)
5885
5896
Perl_croak (aTHX_ "DESTROY created new reference to dead object '%s'" ,
5886
5897
HvNAME_get (stash ));
5887
5898
/* DESTROY gave object new lease on life */
5888
- return ;
5899
+ goto get_next_sv ;
5889
5900
}
5890
5901
}
5891
5902
@@ -5942,11 +5953,23 @@ Perl_sv_clear(pTHX_ register SV *const sv)
5942
5953
hv_undef (MUTABLE_HV (sv ));
5943
5954
break ;
5944
5955
case SVt_PVAV :
5945
- if (PL_comppad == MUTABLE_AV (sv )) {
5946
- PL_comppad = NULL ;
5947
- PL_curpad = NULL ;
5956
+ {
5957
+ AV * av = MUTABLE_AV (sv );
5958
+ if (PL_comppad == av ) {
5959
+ PL_comppad = NULL ;
5960
+ PL_curpad = NULL ;
5961
+ }
5962
+ if (AvREAL (av ) && AvFILLp (av ) > -1 ) {
5963
+ next_sv = AvARRAY (av )[AvFILLp (av )-- ];
5964
+ /* save old iter_sv in top-most slot of AV,
5965
+ * and pray that it doesn't get wiped in the meantime */
5966
+ AvARRAY (av )[AvMAX (av )] = iter_sv ;
5967
+ iter_sv = sv ;
5968
+ goto get_next_sv ; /* process this new sv */
5969
+ }
5970
+ Safefree (AvALLOC (av ));
5948
5971
}
5949
- av_undef ( MUTABLE_AV ( sv ));
5972
+
5950
5973
break ;
5951
5974
case SVt_PVLV :
5952
5975
if (LvTYPE (sv ) == 'T' ) { /* for tie: return HE to pool */
@@ -6029,16 +6052,77 @@ Perl_sv_clear(pTHX_ register SV *const sv)
6029
6052
break ;
6030
6053
}
6031
6054
6055
+ free_body :
6056
+
6032
6057
SvFLAGS (sv ) &= SVf_BREAK ;
6033
6058
SvFLAGS (sv ) |= SVTYPEMASK ;
6034
6059
6060
+ sv_type_details = bodies_by_type + type ;
6035
6061
if (sv_type_details -> arena ) {
6036
6062
del_body (((char * )SvANY (sv ) + sv_type_details -> offset ),
6037
6063
& PL_body_roots [type ]);
6038
6064
}
6039
6065
else if (sv_type_details -> body_size ) {
6040
6066
safefree (SvANY (sv ));
6041
6067
}
6068
+
6069
+ free_head :
6070
+ /* caller is responsible for freeing the head of the original sv */
6071
+ if (sv != orig_sv && !SvREFCNT (sv ))
6072
+ del_SV (sv );
6073
+
6074
+ /* grab and free next sv, if any */
6075
+ get_next_sv :
6076
+ while (1 ) {
6077
+ sv = NULL ;
6078
+ if (next_sv ) {
6079
+ sv = next_sv ;
6080
+ next_sv = NULL ;
6081
+ }
6082
+ else if (!iter_sv ) {
6083
+ break ;
6084
+ } else if (SvTYPE (iter_sv ) == SVt_PVAV ) {
6085
+ AV * const av = (AV * )iter_sv ;
6086
+ if (AvFILLp (av ) > -1 ) {
6087
+ sv = AvARRAY (av )[AvFILLp (av )-- ];
6088
+ }
6089
+ else { /* no more elements of current AV to free */
6090
+ sv = iter_sv ;
6091
+ type = SvTYPE (sv );
6092
+ /* restore previous value, squirrelled away */
6093
+ iter_sv = AvARRAY (av )[AvMAX (av )];
6094
+ Safefree (AvALLOC (av ));
6095
+ goto free_body ;
6096
+ }
6097
+ }
6098
+
6099
+ /* unrolled SvREFCNT_dec and sv_free2 follows: */
6100
+
6101
+ if (!sv )
6102
+ continue ;
6103
+ if (!SvREFCNT (sv )) {
6104
+ sv_free (sv );
6105
+ continue ;
6106
+ }
6107
+ if (-- (SvREFCNT (sv )))
6108
+ continue ;
6109
+ #ifdef DEBUGGING
6110
+ if (SvTEMP (sv )) {
6111
+ Perl_ck_warner_d (aTHX_ packWARN (WARN_DEBUGGING ),
6112
+ "Attempt to free temp prematurely: SV 0x%" UVxf
6113
+ pTHX__FORMAT , PTR2UV (sv ) pTHX__VALUE );
6114
+ continue ;
6115
+ }
6116
+ #endif
6117
+ if (SvREADONLY (sv ) && SvIMMORTAL (sv )) {
6118
+ /* make sure SvREFCNT(sv)==0 happens very seldom */
6119
+ SvREFCNT (sv ) = (~(U32 )0 )/2 ;
6120
+ continue ;
6121
+ }
6122
+ break ;
6123
+ } /* while 1 */
6124
+
6125
+ } /* while sv */
6042
6126
}
6043
6127
6044
6128
/*
0 commit comments