File Coverage

Clone.xs
Criterion Covered Total %
statement 109 129 84.5
branch 53 74 71.6
condition n/a
subroutine n/a
pod n/a
total 162 203 79.8


line stmt bran cond sub pod time code
1             #include
2              
3             #include "EXTERN.h"
4             #include "perl.h"
5             #include "XSUB.h"
6             #include "ppport.h"
7              
8             #define CLONE_KEY(x) ((char *) &x)
9              
10             #define CLONE_STORE(x,y) \
11             do { \
12             if (!hv_store(hseen, CLONE_KEY(x), PTRSIZE, SvREFCNT_inc(y), 0)) { \
13             SvREFCNT_dec(y); /* Restore the refcount */ \
14             croak("Can't store clone in seen hash (hseen)"); \
15             } \
16             else { \
17             TRACEME(("storing ref = 0x%x clone = 0x%x\n", ref, clone)); \
18             TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone))); \
19             TRACEME(("ref = 0x%x(%d)\n", ref, SvREFCNT(ref))); \
20             } \
21             } while (0)
22              
23             #define CLONE_FETCH(x) (hv_fetch(hseen, CLONE_KEY(x), PTRSIZE, 0))
24              
25             static SV *hv_clone (SV *, SV *, HV *, int);
26             static SV *av_clone (SV *, SV *, HV *, int);
27             static SV *sv_clone (SV *, HV *, int);
28             static SV *rv_clone (SV *, HV *, int);
29              
30             #ifdef DEBUG_CLONE
31             #define TRACEME(a) printf("%s:%d: ",__FUNCTION__, __LINE__) && printf a;
32             #else
33             #define TRACEME(a)
34             #endif
35              
36             static SV *
37 27           hv_clone (SV * ref, SV * target, HV* hseen, int depth)
38             {
39 27           HV *clone = (HV *) target;
40 27           HV *self = (HV *) ref;
41 27           HE *next = NULL;
42 27 50         int recur = depth ? depth - 1 : 0;
43              
44             assert(SvTYPE(ref) == SVt_PVHV);
45              
46             TRACEME(("ref = 0x%x(%d)\n", ref, SvREFCNT(ref)));
47              
48 27           hv_iterinit (self);
49 71 100         while ((next = hv_iternext (self)))
50             {
51 44           SV *key = hv_iterkeysv (next);
52             TRACEME(("clone item %s\n", SvPV_nolen(key) ));
53 44           hv_store_ent (clone, key,
54             sv_clone (hv_iterval (self, next), hseen, recur), 0);
55             }
56              
57             TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone)));
58 27           return (SV *) clone;
59             }
60              
61             static SV *
62 16           av_clone (SV * ref, SV * target, HV* hseen, int depth)
63             {
64 16           AV *clone = (AV *) target;
65 16           AV *self = (AV *) ref;
66             SV **svp;
67 16           SV *val = NULL;
68 16           I32 arrlen = 0;
69 16           int i = 0;
70 16 50         int recur = depth ? depth - 1 : 0;
71              
72             assert(SvTYPE(ref) == SVt_PVAV);
73              
74             TRACEME(("ref = 0x%x(%d)\n", ref, SvREFCNT(ref)));
75              
76             /* The following is a holdover from a very old version */
77             /* possible cause of memory leaks */
78             /* if ( (SvREFCNT(ref) > 1) ) */
79             /* CLONE_STORE(ref, (SV *)clone); */
80              
81 16           arrlen = av_len (self);
82 16           av_extend (clone, arrlen);
83              
84 58 100         for (i = 0; i <= arrlen; i++)
85             {
86 42           svp = av_fetch (self, i, 0);
87 42 50         if (svp)
88 42           av_store (clone, i, sv_clone (*svp, hseen, recur));
89             }
90              
91             TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone)));
92 16           return (SV *) clone;
93             }
94              
95             static SV *
96 0           rv_clone (SV * ref, HV* hseen, int depth)
97             {
98 0           SV *clone = NULL;
99 0           SV *rv = NULL;
100              
101             assert(SvROK(ref));
102              
103             TRACEME(("ref = 0x%x(%d)\n", ref, SvREFCNT(ref)));
104              
105 0 0         if (!SvROK (ref))
106 0           return NULL;
107              
108 0 0         if (sv_isobject (ref))
109             {
110 0           clone = newRV_noinc(sv_clone (SvRV(ref), hseen, depth));
111 0           sv_2mortal (sv_bless (clone, SvSTASH (SvRV (ref))));
112             }
113             else
114 0           clone = newRV_inc(sv_clone (SvRV(ref), hseen, depth));
115            
116             TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone)));
117 0           return clone;
118             }
119              
120             static SV *
121 209           sv_clone (SV * ref, HV* hseen, int depth)
122             {
123 209           SV *clone = ref;
124 209           SV **seen = NULL;
125             UV visible;
126 209           int magic_ref = 0;
127              
128 209 50         if (!ref)
129             {
130             TRACEME(("NULL\n"));
131 0           return NULL;
132             }
133              
134             #if PERL_REVISION >= 5 && PERL_VERSION > 8
135             /* This is a hack for perl 5.9.*, save everything */
136             /* until I find out why mg_find is no longer working */
137 209           visible = 1;
138             #else
139             visible = (SvREFCNT(ref) > 1) || (SvMAGICAL(ref) && mg_find(ref, '<'));
140             #endif
141              
142             TRACEME(("ref = 0x%x(%d)\n", ref, SvREFCNT(ref)));
143              
144 209 100         if (depth == 0)
145 6           return SvREFCNT_inc(ref);
146              
147 203 50         if (visible && (seen = CLONE_FETCH(ref)))
    100          
148             {
149             TRACEME(("fetch ref (0x%x)\n", ref));
150 13           return SvREFCNT_inc(*seen);
151             }
152              
153             TRACEME(("switch: (0x%x)\n", ref));
154 190           switch (SvTYPE (ref))
155             {
156             case SVt_NULL: /* 0 */
157             TRACEME(("sv_null\n"));
158 3           clone = newSVsv (ref);
159 3           break;
160             case SVt_IV: /* 1 */
161             TRACEME(("int scalar\n"));
162             case SVt_NV: /* 2 */
163             TRACEME(("double scalar\n"));
164 86           clone = newSVsv (ref);
165 86           break;
166             #if PERL_VERSION <= 10
167             case SVt_RV: /* 3 */
168             TRACEME(("ref scalar\n"));
169             clone = newSVsv (ref);
170             break;
171             #endif
172             case SVt_PV: /* 4 */
173             TRACEME(("string scalar\n"));
174             /*
175             * Note: when using a Debug Perl with READONLY_COW
176             * we cannot do 'sv_buf_to_rw + sv_buf_to_ro' as these APIs calls are not exported
177             */
178             #if defined(SV_COW_REFCNT_MAX) && !defined(PERL_DEBUG_READONLY_COW)
179             /* only for simple PVs unblessed */
180 44 100         if ( SvIsCOW(ref) && !SvOOK(ref) && SvLEN(ref) > 0 ) {
    50          
    100          
181              
182 58 100         if ( CowREFCNT(ref) < (SV_COW_REFCNT_MAX - 1) ) {
183             /* cannot use newSVpv_share as this going to use a new PV we do not want to clone it */
184             /* create a fresh new PV */
185 27           clone = newSV(0);
186 27           sv_upgrade(clone, SVt_PV);
187 27           SvPOK_on(clone);
188 27           SvIsCOW_on(clone);
189              
190             /* points the str slot to the COWed one */
191 27           SvPV_set(clone, SvPVX(ref) );
192 27           CowREFCNT(ref)++;
193              
194             /* preserve cur, len, flags and utf8 flag */
195 27           SvCUR_set(clone, SvCUR(ref));
196 27           SvLEN_set(clone, SvLEN(ref));
197 27           SvFLAGS(clone) = SvFLAGS(ref); /* preserve all the flags from the original SV */
198              
199 27 50         if (SvUTF8(ref))
200 27           SvUTF8_on(clone);
201             } else {
202             /* we are above SV_COW_REFCNT_MAX, create a new SvPV but preserve the COW */
203 2           clone = newSVsv (ref);
204 2           SvIsCOW_on(clone);
205 2           CowREFCNT(clone) = 0; /* set the CowREFCNT to 0 */
206             }
207              
208             } else {
209 15           clone = newSVsv (ref);
210             }
211             #else
212             clone = newSVsv (ref);
213             #endif
214 44           break;
215             case SVt_PVIV: /* 5 */
216             TRACEME (("PVIV double-type\n"));
217             case SVt_PVNV: /* 6 */
218             TRACEME (("PVNV double-type\n"));
219 3           clone = newSVsv (ref);
220 3           break;
221             case SVt_PVMG: /* 7 */
222             TRACEME(("magic scalar\n"));
223 7           clone = newSVsv (ref);
224 7           break;
225             case SVt_PVAV: /* 10 */
226 17           clone = (SV *) newAV();
227 17           break;
228             case SVt_PVHV: /* 11 */
229 28           clone = (SV *) newHV();
230 28           break;
231             #if PERL_VERSION <= 8
232             case SVt_PVBM: /* 8 */
233             #elif PERL_VERSION >= 11
234             case SVt_REGEXP: /* 8 */
235             #endif
236             case SVt_PVLV: /* 9 */
237             case SVt_PVCV: /* 12 */
238             case SVt_PVGV: /* 13 */
239             case SVt_PVFM: /* 14 */
240             case SVt_PVIO: /* 15 */
241             TRACEME(("default: type = 0x%x\n", SvTYPE (ref)));
242 2           clone = SvREFCNT_inc(ref); /* just return the ref */
243 2           break;
244             default:
245 0           croak("unknown type: 0x%x", SvTYPE(ref));
246             }
247              
248             /**
249             * It is *vital* that this is performed *before* recursion,
250             * to properly handle circular references. cb 2001-02-06
251             */
252              
253 190 50         if ( visible && ref != clone )
    100          
254 188 50         CLONE_STORE(ref,clone);
255              
256             /*
257             * We'll assume (in the absence of evidence to the contrary) that A) a
258             * tied hash/array doesn't store its elements in the usual way (i.e.
259             * the mg->mg_object(s) take full responsibility for them) and B) that
260             * references aren't tied.
261             *
262             * If theses assumptions hold, the three options below are mutually
263             * exclusive.
264             *
265             * More precisely: 1 & 2 are probably mutually exclusive; 2 & 3 are
266             * definitely mutually exclusive; we have to test 1 before giving 2
267             * a chance; and we'll assume that 1 & 3 are mutually exclusive unless
268             * and until we can be test-cased out of our delusion.
269             *
270             * chocolateboy: 2001-05-29
271             */
272            
273             /* 1: TIED */
274 190 100         if (SvMAGICAL(ref) )
275             {
276             MAGIC* mg;
277 6           MGVTBL *vtable = 0;
278              
279 12 100         for (mg = SvMAGIC(ref); mg; mg = mg->mg_moremagic)
280             {
281 6           SV *obj = (SV *) NULL;
282             /* we don't want to clone a qr (regexp) object */
283             /* there are probably other types as well ... */
284             TRACEME(("magic type: %c\n", mg->mg_type));
285             /* Some mg_obj's can be null, don't bother cloning */
286 6 100         if ( mg->mg_obj != NULL )
287             {
288 4           switch (mg->mg_type)
289             {
290             case 'r': /* PERL_MAGIC_qr */
291 0           obj = mg->mg_obj;
292 0           break;
293             case 't': /* PERL_MAGIC_taint */
294             case '<': /* PERL_MAGIC_backref */
295             case '@': /* PERL_MAGIC_arylen_p */
296 0           continue;
297             break;
298             case 'P': /* PERL_MAGIC_tied */
299             case 'p': /* PERL_MAGIC_tiedelem */
300             case 'q': /* PERL_MAGIC_tiedscalar */
301 3           magic_ref++;
302             /* fall through */
303             default:
304 4           obj = sv_clone(mg->mg_obj, hseen, -1);
305             }
306             } else {
307             TRACEME(("magic object for type %c in NULL\n", mg->mg_type));
308             }
309              
310             { /* clone the mg_ptr pv */
311 6           char *mg_ptr = mg->mg_ptr; /* default */
312              
313 6 100         if (mg->mg_len >= 0) { /* copy the pv */
314 4 50         if (mg_ptr) {
315 0           Newxz(mg_ptr, mg->mg_len+1, char); /* add +1 for the NULL at the end? */
316 4           Copy(mg->mg_ptr, mg_ptr, mg->mg_len, char);
317             }
318 2 50         } else if (mg->mg_len == HEf_SVKEY) {
319             /* let's share the SV for now */
320 0           SvREFCNT_inc((SV*)mg->mg_ptr);
321             /* maybe we also want to clone the SV... */
322             //if (mg_ptr) mg->mg_ptr = (char*) sv_clone((SV*)mg->mg_ptr, hseen, -1);
323 2 50         } else if (mg->mg_len == -1 && mg->mg_type == PERL_MAGIC_utf8) { /* copy the cache */
    50          
324 3 100         if (mg->mg_ptr) {
325             STRLEN *cache;
326 1           Newxz(cache, PERL_MAGIC_UTF8_CACHESIZE * 2, STRLEN);
327 1           mg_ptr = (char *) cache;
328 1           Copy(mg->mg_ptr, mg_ptr, PERL_MAGIC_UTF8_CACHESIZE * 2, STRLEN);
329             }
330 0 0         } else if ( mg->mg_ptr != NULL) {
331 0           croak("Unsupported magic_ptr clone");
332             }
333              
334             /* this is plain old magic, so do the same thing */
335 6           sv_magic(clone,
336             obj,
337             mg->mg_type,
338             mg_ptr,
339             mg->mg_len);
340              
341             }
342             }
343             /* major kludge - why does the vtable for a qr type need to be null? */
344 6 50         if ( (mg = mg_find(clone, 'r')) )
345 0           mg->mg_virtual = (MGVTBL *) NULL;
346             }
347             /* 2: HASH/ARRAY - (with 'internal' elements) */
348 190 100         if ( magic_ref )
349             {
350             ;;
351             }
352 187 100         else if ( SvTYPE(ref) == SVt_PVHV )
353 27           clone = hv_clone (ref, clone, hseen, depth);
354 160 100         else if ( SvTYPE(ref) == SVt_PVAV )
355 16           clone = av_clone (ref, clone, hseen, depth);
356             /* 3: REFERENCE (inlined for speed) */
357 144 100         else if (SvROK (ref))
358             {
359             TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone)));
360 71           SvREFCNT_dec(SvRV(clone));
361 71           SvRV(clone) = sv_clone (SvRV(ref), hseen, depth); /* Clone the referent */
362 71 100         if (sv_isobject (ref))
363             {
364 20           sv_bless (clone, SvSTASH (SvRV (ref)));
365             }
366 71 100         if (SvWEAKREF(ref)) {
367 3           sv_rvweaken(clone);
368             }
369             }
370              
371             TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone)));
372 190           return clone;
373             }
374              
375             MODULE = Clone PACKAGE = Clone
376              
377             PROTOTYPES: ENABLE
378              
379             void
380             clone(self, depth=-1)
381             SV *self
382             int depth
383             PREINIT:
384 48           SV *clone = &PL_sv_undef;
385 48           HV *hseen = newHV();
386             PPCODE:
387             TRACEME(("ref = 0x%x\n", self));
388 48           clone = sv_clone(self, hseen, depth);
389 48           hv_clear(hseen); /* Free HV */
390 48           SvREFCNT_dec((SV *)hseen);
391 48 50         EXTEND(SP,1);
392 48           PUSHs(sv_2mortal(clone));