@@ -44,67 +44,82 @@ Perl_newSVobject(pTHX_ Size_t fieldcount)
44
44
return sv ;
45
45
}
46
46
47
- XS (initfields );
48
- XS (initfields )
47
+ PP (pp_initfield )
49
48
{
50
- dXSARGS ;
51
- assert (items == 1 );
52
-
53
- SV * instance = POPs ;
54
-
55
- HV * stash = (HV * )XSANY .any_ptr ;
56
- assert (HvSTASH_IS_CLASS (stash ));
57
-
58
- struct xpvhv_aux * aux = HvAUX (stash );
59
-
60
- if (aux -> xhv_class_superclass ) {
61
- struct xpvhv_aux * superaux = HvAUX (aux -> xhv_class_superclass );
62
-
63
- ENTER ;
64
- SAVETMPS ;
65
-
66
- EXTEND (SP , 1 );
67
- PUSHMARK (SP );
68
- PUSHs (instance );
69
- PUTBACK ;
70
-
71
- call_sv ((SV * )superaux -> xhv_class_initfields_cv , G_VOID );
72
-
73
- SPAGAIN ;
49
+ dSP ;
50
+ UNOP_AUX_item * aux = cUNOP_AUX -> op_aux ;
74
51
75
- FREETMPS ;
76
- LEAVE ;
77
- }
52
+ SV * self = PAD_SVl ( PADIX_SELF ) ;
53
+ assert ( SvTYPE ( SvRV ( self )) == SVt_PVOBJ ) ;
54
+ SV * instance = SvRV ( self );
78
55
79
56
SV * * fields = ObjectFIELDS (instance );
80
57
81
- PADNAMELIST * fieldnames = aux -> xhv_class_fields ;
82
-
83
- for (U32 i = 0 ; fieldnames && i <= PadnamelistMAX (fieldnames ); i ++ ) {
84
- PADNAME * pn = PadnamelistARRAY (fieldnames )[i ];
85
- PADOFFSET fieldix = PadnameFIELDINFO (pn )-> fieldix ;
86
-
87
- SV * val = NULL ;
58
+ PADOFFSET fieldix = aux [0 ].uv ;
88
59
89
- switch (PadnamePV (pn )[0 ]) {
90
- case '$' :
60
+ SV * val ;
61
+ switch (PL_op -> op_private & (OPpINITFIELD_AV |OPpINITFIELD_HV )) {
62
+ case 0 :
63
+ if (PL_op -> op_flags & OPf_STACKED )
64
+ val = newSVsv (POPs );
65
+ else
91
66
val = newSV (0 );
92
- break ;
93
-
94
- case '@' :
95
- val = (SV * )newAV ();
96
- break ;
97
-
98
- case '%' :
99
- val = (SV * )newHV ();
100
- break ;
67
+ break ;
68
+
69
+ case OPpINITFIELD_AV :
70
+ {
71
+ AV * av ;
72
+ if (PL_op -> op_flags & OPf_STACKED ) {
73
+ SV * * svp = PL_stack_base + POPMARK + 1 ;
74
+ STRLEN count = SP - svp + 1 ;
75
+
76
+ av = newAV_alloc_x (count );
77
+
78
+ av_extend (av , count );
79
+ while (svp <= SP ) {
80
+ av_push_simple (av , newSVsv (* svp ));
81
+ svp ++ ;
82
+ }
83
+ }
84
+ else
85
+ av = newAV ();
86
+ val = (SV * )av ;
87
+ break ;
88
+ }
101
89
102
- default :
103
- NOT_REACHED ;
90
+ case OPpINITFIELD_HV :
91
+ {
92
+ HV * hv = newHV ();
93
+ if (PL_op -> op_flags & OPf_STACKED ) {
94
+ SV * * svp = PL_stack_base + POPMARK + 1 ;
95
+ STRLEN svcount = SP - svp + 1 ;
96
+
97
+ if (svcount % 2 )
98
+ Perl_warner (aTHX_
99
+ packWARN (WARN_MISC ), "Odd number of elements in hash field initialization" );
100
+
101
+ while (svp <= SP ) {
102
+ SV * key = * svp ; svp ++ ;
103
+ SV * val = svp <= SP ? * svp : & PL_sv_undef ; svp ++ ;
104
+
105
+ hv_store_ent (hv , key , newSVsv (val ), 0 );
106
+ }
107
+ }
108
+ val = (SV * )hv ;
109
+ break ;
104
110
}
111
+ }
112
+
113
+ fields [fieldix ] = val ;
105
114
106
- fields [fieldix ] = val ;
115
+ PADOFFSET padix = PL_op -> op_targ ;
116
+ if (padix ) {
117
+ SAVESPTR (PAD_SVl (padix ));
118
+ SV * sv = PAD_SVl (padix ) = SvREFCNT_inc (val );
119
+ save_freesv (sv );
107
120
}
121
+
122
+ RETURN ;
108
123
}
109
124
110
125
XS (injected_constructor );
@@ -146,14 +161,16 @@ XS(injected_constructor)
146
161
SvOBJECT_on (instance );
147
162
SvSTASH_set (instance , MUTABLE_HV (SvREFCNT_inc_simple (stash )));
148
163
164
+ SV * self = sv_2mortal (newRV_noinc (instance ));
165
+
149
166
assert (aux -> xhv_class_initfields_cv );
150
167
{
151
168
ENTER ;
152
169
SAVETMPS ;
153
170
154
171
EXTEND (SP , 1 );
155
172
PUSHMARK (SP );
156
- PUSHs (instance );
173
+ PUSHs (self );
157
174
PUTBACK ;
158
175
159
176
call_sv ((SV * )aux -> xhv_class_initfields_cv , G_VOID );
@@ -164,8 +181,6 @@ XS(injected_constructor)
164
181
LEAVE ;
165
182
}
166
183
167
- SV * self = sv_2mortal (newRV_noinc (instance ));
168
-
169
184
if (aux -> xhv_class_adjust_blocks ) {
170
185
CV * * cvp = (CV * * )AvARRAY (aux -> xhv_class_adjust_blocks );
171
186
U32 nblocks = av_count (aux -> xhv_class_adjust_blocks );
@@ -340,6 +355,25 @@ Perl_class_setup_stash(pTHX_ HV *stash)
340
355
aux -> xhv_aux_flags |= HvAUXf_IS_CLASS ;
341
356
342
357
SAVEDESTRUCTOR_X (invoke_class_seal , stash );
358
+
359
+ /* Prepare a suspended compcv for parsing field init expressions */
360
+ {
361
+ I32 floor_ix = start_subparse (FALSE, 0 );
362
+
363
+ CvIsMETHOD_on (PL_compcv );
364
+
365
+ /* We don't want to make `$self` visible during the expression but we
366
+ * still need to give it a name. Make it unusable from pure perl
367
+ */
368
+ PADOFFSET padix = pad_add_name_pvs ("$(self)" , 0 , NULL , NULL );
369
+ assert (padix == PADIX_SELF );
370
+ PERL_UNUSED_VAR (padix );
371
+
372
+ Newx (aux -> xhv_class_suspended_initfields_compcv , 1 , struct suspended_compcv );
373
+ suspend_compcv (aux -> xhv_class_suspended_initfields_compcv );
374
+
375
+ LEAVE_SCOPE (floor_ix );
376
+ }
343
377
}
344
378
345
379
#define split_package_ver (value , pkgname , pkgversion ) S_split_package_ver(aTHX_ value, pkgname, pkgversion)
@@ -555,14 +589,141 @@ Perl_class_seal_stash(pTHX_ HV *stash)
555
589
assert (HvSTASH_IS_CLASS (stash ));
556
590
struct xpvhv_aux * aux = HvAUX (stash );
557
591
592
+ /* generate initfields CV */
558
593
{
559
- CV * newcv = newXS_flags (NULL , initfields , __FILE__ , NULL , 0 );
560
- CvXSUBANY (newcv ).any_ptr = stash ;
594
+ I32 floor_ix = PL_savestack_ix ;
595
+ SAVEI32 (PL_subline );
596
+ save_item (PL_subname );
597
+
598
+ resume_compcv_final (aux -> xhv_class_suspended_initfields_compcv );
599
+
600
+ /* Some OP_INITFIELD ops will need to populate the pad with their
601
+ * result because later ops will rely on it. There's no need to do
602
+ * this for every op though. Store a mapping to work out which ones
603
+ * we'll need.
604
+ */
605
+ PADNAMELIST * pnl = PadlistNAMES (CvPADLIST (PL_compcv ));
606
+ HV * fieldix_to_padix = newHV ();
607
+ SAVEFREESV ((SV * )fieldix_to_padix );
608
+
609
+ /* padix 0 == @_; padix 1 == $self. Start at 2 */
610
+ for (PADOFFSET padix = 2 ; padix <= PadnamelistMAX (pnl ); padix ++ ) {
611
+ PADNAME * pn = PadnamelistARRAY (pnl )[padix ];
612
+ if (!pn || !PadnameIsFIELD (pn ))
613
+ continue ;
614
+
615
+ U32 fieldix = PadnameFIELDINFO (pn )-> fieldix ;
616
+ hv_store_ent (fieldix_to_padix , sv_2mortal (newSVuv (fieldix )), newSVuv (padix ), 0 );
617
+ }
618
+
619
+ OP * ops = NULL ;
620
+
621
+ ops = op_append_list (OP_LINESEQ , ops ,
622
+ newUNOP_AUX (OP_METHSTART , 0 , NULL , NULL ));
623
+
624
+ if (aux -> xhv_class_superclass ) {
625
+ HV * superstash = aux -> xhv_class_superclass ;
626
+ assert (HvSTASH_IS_CLASS (superstash ));
627
+ struct xpvhv_aux * superaux = HvAUX (superstash );
628
+
629
+ /* Build an OP_ENTERSUB */
630
+ OP * o = NULL ;
631
+ o = op_append_list (OP_LIST , o ,
632
+ newPADxVOP (OP_PADSV , 0 , PADIX_SELF ));
633
+ /* TODO: This won't work at all well under `use threads` because
634
+ * it embeds the CV * to the superclass initfields CV right into
635
+ * the optree. Maybe we'll have to pop it in the pad or something
636
+ */
637
+ o = op_append_list (OP_LIST , o ,
638
+ newSVOP (OP_CONST , 0 , (SV * )superaux -> xhv_class_initfields_cv ));
639
+
640
+ ops = op_append_list (OP_LINESEQ , ops ,
641
+ op_convert_list (OP_ENTERSUB , OPf_WANT_VOID |OPf_STACKED , o ));
642
+ }
643
+
644
+ PADNAMELIST * fieldnames = aux -> xhv_class_fields ;
645
+
646
+ for (U32 i = 0 ; fieldnames && i <= PadnamelistMAX (fieldnames ); i ++ ) {
647
+ PADNAME * pn = PadnamelistARRAY (fieldnames )[i ];
648
+ char sigil = PadnamePV (pn )[0 ];
649
+ PADOFFSET fieldix = PadnameFIELDINFO (pn )-> fieldix ;
650
+
651
+ /* Extract the OP_{NEXT,DB}STATE op from the defop so we can
652
+ * splice it in
653
+ */
654
+ OP * valop = PadnameFIELDINFO (pn )-> defop ;
655
+ if (valop && valop -> op_type == OP_LINESEQ ) {
656
+ OP * o = cLISTOPx (valop )-> op_first ;
657
+ cLISTOPx (valop )-> op_first = NULL ;
658
+ cLISTOPx (valop )-> op_last = NULL ;
659
+ /* have to clear the OPf_KIDS flag or op_free() will get upset */
660
+ valop -> op_flags &= ~OPf_KIDS ;
661
+ op_free (valop );
662
+ assert (valop -> op_type == OP_FREED );
663
+
664
+ OP * fieldcop = o ;
665
+ assert (fieldcop -> op_type == OP_NEXTSTATE || fieldcop -> op_type == OP_DBSTATE );
666
+ o = OpSIBLING (o );
667
+ OpLASTSIB_set (fieldcop , NULL );
668
+
669
+ valop = o ;
670
+ OpLASTSIB_set (valop , NULL );
671
+
672
+ ops = op_append_list (OP_LINESEQ , ops , fieldcop );
673
+ }
674
+
675
+ U8 op_priv = 0 ;
676
+ switch (sigil ) {
677
+ case '$' :
678
+ break ;
679
+
680
+ case '@' :
681
+ op_priv = OPpINITFIELD_AV ;
682
+ break ;
683
+
684
+ case '%' :
685
+ op_priv = OPpINITFIELD_HV ;
686
+ break ;
687
+
688
+ default :
689
+ NOT_REACHED ;
690
+ }
691
+
692
+ UNOP_AUX_item * aux ;
693
+ Newx (aux , 1 , UNOP_AUX_item );
694
+
695
+ aux [0 ].uv = fieldix ;
696
+
697
+ OP * fieldop = newUNOP_AUX (OP_INITFIELD , valop ? OPf_STACKED : 0 , valop , aux );
698
+ fieldop -> op_private = op_priv ;
699
+
700
+ HE * he ;
701
+ if ((he = hv_fetch_ent (fieldix_to_padix , sv_2mortal (newSVuv (fieldix )), 0 , 0 )) &&
702
+ SvOK (HeVAL (he ))) {
703
+ fieldop -> op_targ = SvUV (HeVAL (he ));
704
+ }
705
+
706
+ ops = op_append_list (OP_LINESEQ , ops , fieldop );
707
+ }
561
708
562
- aux -> xhv_class_initfields_cv = newcv ;
709
+ CV * initfields = newATTRSUB (floor_ix , NULL , NULL , NULL , ops );
710
+
711
+ aux -> xhv_class_initfields_cv = initfields ;
563
712
}
564
713
}
565
714
715
+ void
716
+ Perl_class_prepare_initfield_parse (pTHX )
717
+ {
718
+ PERL_ARGS_ASSERT_CLASS_PREPARE_INITFIELD_PARSE ;
719
+
720
+ assert (HvSTASH_IS_CLASS (PL_curstash ));
721
+ struct xpvhv_aux * aux = HvAUX (PL_curstash );
722
+
723
+ resume_compcv_and_save (aux -> xhv_class_suspended_initfields_compcv );
724
+ CvOUTSIDE_SEQ (PL_compcv ) = PL_cop_seqmax ;
725
+ }
726
+
566
727
void
567
728
Perl_class_prepare_method_parse (pTHX_ CV * cv )
568
729
{
@@ -656,6 +817,7 @@ Perl_class_add_field(pTHX_ HV *stash, PADNAME *pn)
656
817
657
818
PadnameFIELDINFO (pn )-> fieldix = fieldix ;
658
819
PadnameFIELDINFO (pn )-> fieldstash = (HV * )SvREFCNT_inc (stash );
820
+ PadnameFIELDINFO (pn )-> defop = NULL ;
659
821
660
822
if (!aux -> xhv_class_fields )
661
823
aux -> xhv_class_fields = newPADNAMELIST (0 );
@@ -664,6 +826,34 @@ Perl_class_add_field(pTHX_ HV *stash, PADNAME *pn)
664
826
PadnameREFCNT_inc (pn );
665
827
}
666
828
829
+ void
830
+ Perl_class_set_field_defop (pTHX_ PADNAME * pn , OP * defop )
831
+ {
832
+ PERL_ARGS_ASSERT_CLASS_SET_FIELD_DEFOP ;
833
+
834
+ assert (HvSTASH_IS_CLASS (PL_curstash ));
835
+
836
+ forbid_outofblock_ops (defop , "field initialiser expression" );
837
+
838
+ if (PadnameFIELDINFO (pn )-> defop )
839
+ op_free (PadnameFIELDINFO (pn )-> defop );
840
+
841
+ char sigil = PadnamePV (pn )[0 ];
842
+ switch (sigil ) {
843
+ case '$' :
844
+ defop = op_contextualize (defop , G_SCALAR );
845
+ break ;
846
+
847
+ case '@' :
848
+ case '%' :
849
+ defop = op_contextualize (op_force_list (defop ), G_LIST );
850
+ break ;
851
+ }
852
+
853
+ PadnameFIELDINFO (pn )-> defop = newLISTOP (OP_LINESEQ , 0 ,
854
+ newSTATEOP (0 , NULL , NULL ), defop );
855
+ }
856
+
667
857
void
668
858
Perl_class_add_ADJUST (pTHX_ HV * stash , CV * cv )
669
859
{
0 commit comments