ext/XS-APItest/t/clone-with-stack.t test clone with CLONEf_COPY_STACKS works
ext/XS-APItest/t/cophh.t test COPHH API
ext/XS-APItest/t/coplabel.t test cop_*_label
-ext/XS-APItest/t/copstash.t test alloccopstash
+ext/XS-APItest/t/cop.t test other cop stuff
ext/XS-APItest/t/copyhints.t test hv_copy_hints_hv() API
ext/XS-APItest/t/customop.t XS::APItest: tests for custom ops
ext/XS-APItest/t/eval-filter.t Simple source filter/eval test
#ifdef USE_ITHREADS
PADOFFSET cop_stashoff; /* offset into PL_stashpad, for the
package the line was compiled in */
- char * cop_file; /* file name the following line # is from */
+ PADOFFSET cop_filegvoff; /* PL_filegv offset, for the file name the
+ following line # is from */
#else
HV * cop_stash; /* package line was compiled in */
GV * cop_filegv; /* file the following line # is from */
};
#ifdef USE_ITHREADS
-# define CopFILE(c) ((c)->cop_file)
-# define CopFILEGV(c) (CopFILE(c) \
- ? gv_fetchfile(CopFILE(c)) : NULL)
-
-# ifdef NETWARE
-# define CopFILE_set(c,pv) ((c)->cop_file = savepv(pv))
-# define CopFILE_setn(c,pv,l) ((c)->cop_file = savepv((pv),(l)))
-# else
-# define CopFILE_set(c,pv) ((c)->cop_file = savesharedpv(pv))
-# define CopFILE_setn(c,pv,l) ((c)->cop_file = savesharedpvn((pv),(l)))
-# endif
-
-# define CopFILESV(c) (CopFILE(c) \
- ? GvSV(gv_fetchfile(CopFILE(c))) : NULL)
-# define CopFILEAV(c) (CopFILE(c) \
- ? GvAV(gv_fetchfile(CopFILE(c))) : NULL)
-# define CopFILEAVx(c) (assert_(CopFILE(c)) \
- GvAV(gv_fetchfile(CopFILE(c))))
+# define CopFILEGV(c) PL_filegvpad[(c)->cop_filegvoff]
+# define CopFILEGV_set(c,gv) ((c)->cop_filegvoff = (gv) \
+ ? allocfilegv((GV *)SvREFCNT_inc_NN(gv)) \
+ : 0)
# define CopSTASH(c) PL_stashpad[(c)->cop_stashoff]
# define CopSTASH_set(c,hv) ((c)->cop_stashoff = (hv) \
? alloccopstash(hv) \
: 0)
-# ifdef NETWARE
-# define CopFILE_free(c) SAVECOPFILE_FREE(c)
-# else
-# define CopFILE_free(c) (PerlMemShared_free(CopFILE(c)),(CopFILE(c) = NULL))
-# endif
+# define CopFILE_free(c) S_CopFILE_free(aTHX_ c)
#else
# define CopFILEGV(c) ((c)->cop_filegv)
# define CopFILEGV_set(c,gv) ((c)->cop_filegv = (GV*)SvREFCNT_inc(gv))
-# define CopFILE_set(c,pv) CopFILEGV_set((c), gv_fetchfile(pv))
-# define CopFILE_setn(c,pv,l) CopFILEGV_set((c), gv_fetchfile_flags((pv),(l),0))
-# define CopFILESV(c) (CopFILEGV(c) ? GvSV(CopFILEGV(c)) : NULL)
-# define CopFILEAV(c) (CopFILEGV(c) ? GvAV(CopFILEGV(c)) : NULL)
-# ifdef DEBUGGING
-# define CopFILEAVx(c) (assert(CopFILEGV(c)), GvAV(CopFILEGV(c)))
-# else
-# define CopFILEAVx(c) (GvAV(CopFILEGV(c)))
-# endif
-# define CopFILE(c) (CopFILEGV(c) && GvSV(CopFILEGV(c)) \
- ? SvPVX(GvSV(CopFILEGV(c))) : NULL)
# define CopSTASH(c) ((c)->cop_stash)
# define CopSTASH_set(c,hv) ((c)->cop_stash = (hv))
# define CopFILE_free(c) (SvREFCNT_dec(CopFILEGV(c)),(CopFILEGV(c) = NULL))
#endif /* USE_ITHREADS */
+#define CopFILE_set(c,pv) CopFILEGV_set((c), gv_fetchfile(pv))
+#define CopFILE_setn(c,pv,l) CopFILEGV_set((c), gv_fetchfile_flags((pv),(l),0))
+#define CopFILESV(c) (CopFILEGV(c) ? GvSV(CopFILEGV(c)) : NULL)
+#define CopFILEAV(c) (CopFILEGV(c) ? GvAV(CopFILEGV(c)) : NULL)
+#define CopFILEAVx(c) (assert_(CopFILEGV(c)) GvAV(CopFILEGV(c)))
+#define CopFILE(c) (CopFILEGV(c) && GvSV(CopFILEGV(c)) \
+ ? SvPVX(GvSV(CopFILEGV(c))) : NULL)
#define CopSTASHPV(c) (CopSTASH(c) ? HvNAME_get(CopSTASH(c)) : NULL)
/* cop_stash is not refcounted */
#define CopSTASHPV_set(c,pv) CopSTASH_set((c), gv_stashpv(pv,GV_ADD))
|const U32 flags
#ifdef USE_ITHREADS
AMp |PADOFFSET|alloccopstash|NN HV *hv
+AMp |PADOFFSET|allocfilegv |NN GV *gv
#endif
: Used in perly.y
pR |OP* |oopsAV |NN OP* o
Xop |bool |feature_is_enabled|NN const char *const name \
|STRLEN namelen
+: Some static inline functions that implement macros need predeclaration
+: because they are used inside other static inline functions.
+Aoi |void |SvREFCNT_dec_NN|NN SV *sv
+
: ex: set ts=8 sts=4 sw=4 noet:
#endif
#if defined(USE_ITHREADS)
#define alloccopstash(a) Perl_alloccopstash(aTHX_ a)
+#define allocfilegv(a) Perl_allocfilegv(aTHX_ a)
#define any_dup(a,b) Perl_any_dup(aTHX_ a,b)
#define cx_dup(a,b,c,d) Perl_cx_dup(aTHX_ a,b,c,d)
#define dirp_dup(a,b) Perl_dirp_dup(aTHX_ a,b)
#define PL_exitlist (vTHX->Iexitlist)
#define PL_exitlistlen (vTHX->Iexitlistlen)
#define PL_fdpid (vTHX->Ifdpid)
+#define PL_filegvpad (vTHX->Ifilegvpad)
+#define PL_filegvpadix (vTHX->Ifilegvpadix)
+#define PL_filegvpadmax (vTHX->Ifilegvpadmax)
#define PL_filemode (vTHX->Ifilemode)
#define PL_firstgv (vTHX->Ifirstgv)
#define PL_forkprocess (vTHX->Iforkprocess)
=item file
+=item filegvoff (threaded only)
+
=item cop_seq
=item arybase
#ifdef USE_ITHREADS
STR_WITH_LEN("pmoffset"),IVp, offsetof(struct pmop, op_pmoffset),/*20*/
STR_WITH_LEN("filegv"), 0, -1, /*21*/
+# if PERL_VERSION < 19
STR_WITH_LEN("file"), char_pp, offsetof(struct cop, cop_file), /*22*/
+# else
+ STR_WITH_LEN("file"), 0, -1, /*22*/
+# endif
STR_WITH_LEN("stash"), 0, -1, /*23*/
# if PERL_VERSION < 17
STR_WITH_LEN("stashpv"), char_pp, offsetof(struct cop, cop_stashpv), /*24*/
STR_WITH_LEN("folded"), 0, -1, /*50*/
#endif
#endif
+#if PERL_VERSION < 19 || !defined(USE_ITHREADS)
+ STR_WITH_LEN("filegvoff"),0, -1, /*51*/
+#else
+ STR_WITH_LEN("filegvoff"),PADOFFSETp,offsetof(struct cop, cop_filegvoff),/*51*/
+#endif
};
#include "const-c.inc"
ret = make_sv_object(aTHX_ (SV *)CopFILEGV((COP*)o));
break;
#endif
-#ifndef USE_ITHREADS
+#if !defined(USE_ITHREADS) || PERL_VERSION >= 19
case 22: /* file */
ret = sv_2mortal(newSVpv(CopFILE((COP*)o), 0));
break;
OUTPUT:
RETVAL
+bool
+test_allocfilegv()
+CODE:
+ RETVAL = PL_filegvpad[allocfilegv(PL_defgv)] == PL_defgv;
+OUTPUT:
+ RETVAL
+
#endif
bool
use Test::More;
BEGIN { plan skip_all => 'no threads' unless $Config{useithreads} }
-plan tests => 1;
+plan tests => 2;
use XS::APItest;
ok test_alloccopstash;
+ok test_allocfilegv;
continue;
file = GvFILE(gv);
CopLINE_set(PL_curcop, GvLINE(gv));
-#ifdef USE_ITHREADS
- CopFILE(PL_curcop) = (char *)file; /* set for warning */
-#else
- CopFILEGV(PL_curcop)
- = gv_fetchfile_flags(file, HEK_LEN(GvFILE_HEK(gv)), 0);
-#endif
+ /* set file name for warning */
+ CopFILE_setn(PL_curcop, file, HEK_LEN(GvFILE_HEK(gv)));
+ SvREFCNT_dec(CopFILEGV(PL_curcop));
Perl_warner(aTHX_ packWARN(WARN_ONCE),
"Name \"%"HEKf"::%"HEKf
"\" used only once: possible typo",
return AvFILL(av);
}
+/* ------------------------------- cop.h ------------------------------ */
+
+#ifdef USE_ITHREADS
+PERL_STATIC_INLINE void
+S_CopFILE_free(pTHX_ COP * const c)
+{
+ GV * const gv = CopFILEGV(c);
+ if (!gv) return;
+ if (SvREFCNT(gv) == 1) PL_filegvpad[c->cop_filegvoff] = NULL;
+ SvREFCNT_dec_NN(gv);
+ c->cop_filegvoff = 0;
+}
+#endif
+
/* ------------------------------- cv.h ------------------------------- */
PERL_STATIC_INLINE I32 *
S_SvREFCNT_dec_NN(pTHX_ SV *sv)
{
U32 rc = SvREFCNT(sv);
+ PERL_ARGS_ASSERT_SVREFCNT_DEC_NN;
if (LIKELY(rc > 1))
SvREFCNT(sv) = rc - 1;
else
PERLVAR(I, stashpad, HV **) /* for CopSTASH */
PERLVARI(I, stashpadmax, PADOFFSET, 64)
PERLVARI(I, stashpadix, PADOFFSET, 0)
+PERLVAR(I, filegvpad, GV **) /* for CopFILEGV */
+PERLVARI(I, filegvpadmax, PADOFFSET, 64)
+PERLVARI(I, filegvpadix, PADOFFSET, 0)
#endif
#ifdef USE_REENTRANT_API
PL_stashpad
PL_stashpadix
PL_stashpadmax
+ PL_filegvpad
+ PL_filegvpadix
+ PL_filegvpadmax
Perl_alloccopstash
Perl_clone_params_del
Perl_clone_params_new
*/
#ifdef USE_ITHREADS
+
PADOFFSET
-Perl_alloccopstash(pTHX_ HV *hv)
+S_alloc_global_pad_slot(pTHX_ SV *sv, svtype type, SV ***padp,
+ PADOFFSET *ixp, PADOFFSET *maxp)
{
PADOFFSET off = 0, o = 1;
bool found_slot = FALSE;
+ SV **pad = *padp;
- PERL_ARGS_ASSERT_ALLOCCOPSTASH;
-
- if (PL_stashpad[PL_stashpadix] == hv) return PL_stashpadix;
+ if (pad[*ixp] == sv) return *ixp;
- for (; o < PL_stashpadmax; ++o) {
- if (PL_stashpad[o] == hv) return PL_stashpadix = o;
- if (!PL_stashpad[o] || SvTYPE(PL_stashpad[o]) != SVt_PVHV)
+ for (; o < *maxp; ++o) {
+ if (pad[o] == sv) return *ixp = o;
+ if (!pad[o] || SvTYPE(pad[o]) != type)
found_slot = TRUE, off = o;
}
if (!found_slot) {
- Renew(PL_stashpad, PL_stashpadmax + 10, HV *);
- Zero(PL_stashpad + PL_stashpadmax, 10, HV *);
- off = PL_stashpadmax;
- PL_stashpadmax += 10;
+ Renew(*padp, *maxp + 10, SV *);
+ pad = *padp;
+ Zero(pad + *maxp, 10, SV *);
+ off = *maxp;
+ *maxp += 10;
}
- PL_stashpad[PL_stashpadix = off] = hv;
+ pad[*ixp = off] = sv;
return off;
}
+
+PADOFFSET
+Perl_alloccopstash(pTHX_ HV *hv)
+{
+ PERL_ARGS_ASSERT_ALLOCCOPSTASH;
+ return S_alloc_global_pad_slot(aTHX_
+ (SV *)hv, SVt_PVHV, (SV ***)&PL_stashpad, &PL_stashpadix,
+ &PL_stashpadmax
+ );
+}
+#endif
+
+/*
+=for apidoc allocfilegv
+
+Available only under threaded builds, this function allocates an entry in
+C<PL_filegvpad> for the GV passed to it.
+
+=cut
+*/
+
+#ifdef USE_ITHREADS
+PADOFFSET
+Perl_allocfilegv(pTHX_ GV *gv)
+{
+ PERL_ARGS_ASSERT_ALLOCFILEGV;
+ return S_alloc_global_pad_slot(aTHX_
+ (SV *)gv, SVt_PVGV, (SV ***)&PL_filegvpad, &PL_filegvpadix,
+ &PL_filegvpadmax
+ );
+}
#endif
/* free the body of an op without examining its contents.
PL_parser->copline = NOLINE;
}
#ifdef USE_ITHREADS
- CopFILE_set(cop, CopFILE(PL_curcop)); /* XXX share in a pvtable? */
+ /* While CopFILEGV_set does work under ithreads, this is faster, as it
+ avoids a linear scan of the filegv pad: */
+ if((cop->cop_filegvoff = PL_curcop->cop_filegvoff))
+ SvREFCNT_inc_void_NN(PL_filegvpad[cop->cop_filegvoff]);
#else
CopFILEGV_set(cop, CopFILEGV(PL_curcop));
#endif
firstcop->cop_line = secondcop->cop_line;
#ifdef USE_ITHREADS
firstcop->cop_stashoff = secondcop->cop_stashoff;
- firstcop->cop_file = secondcop->cop_file;
+ firstcop->cop_filegvoff = secondcop->cop_filegvoff;
#else
firstcop->cop_stash = secondcop->cop_stash;
firstcop->cop_filegv = secondcop->cop_filegv;
#ifdef USE_ITHREADS
secondcop->cop_stashoff = 0;
- secondcop->cop_file = NULL;
+ secondcop->cop_filegvoff = 0;
#else
secondcop->cop_stash = NULL;
secondcop->cop_filegv = NULL;
Perl_av_create_and_push(aTHX_ &PL_regex_padav, newSVpvs(""));
PL_regex_pad = AvARRAY(PL_regex_padav);
Newxz(PL_stashpad, PL_stashpadmax, HV *);
+ Newxz(PL_filegvpad, PL_filegvpadmax, GV *);
#endif
#ifdef USE_REENTRANT_API
Perl_reentrant_init(aTHX);
#ifdef USE_ITHREADS
Safefree(PL_stashpad); /* must come after sv_clean_all */
+ Safefree(PL_filegvpad);
#endif
AvREAL_off(PL_fdpid); /* no surviving entries */
#define PERL_ARGS_ASSERT_SLAB_FREE \
assert(op)
+PERL_STATIC_INLINE void S_SvREFCNT_dec_NN(pTHX_ SV *sv)
+ __attribute__nonnull__(pTHX_1);
+#define PERL_ARGS_ASSERT_SVREFCNT_DEC_NN \
+ assert(sv)
+
PERL_CALLCONV bool Perl__is_uni_FOO(pTHX_ const U8 classnum, const UV c)
__attribute__warn_unused_result__;
#define PERL_ARGS_ASSERT_ALLOCCOPSTASH \
assert(hv)
+PERL_CALLCONV PADOFFSET Perl_allocfilegv(pTHX_ GV *gv)
+ __attribute__nonnull__(pTHX_1);
+#define PERL_ARGS_ASSERT_ALLOCFILEGV \
+ assert(gv)
+
PERL_CALLCONV void* Perl_any_dup(pTHX_ void* v, const PerlInterpreter* proto_perl)
__attribute__warn_unused_result__
__attribute__nonnull__(pTHX_2);
case SAVEt_READONLY_OFF:
SvREADONLY_off(ARG0_SV);
break;
+#ifdef USE_ITHREADS
+ case SAVEt_COPFILEFREE:
+ CopFILE_free((COP *)ARG0_PTR);
+ break;
+#endif
default:
Perl_croak(aTHX_ "panic: leave_scope inconsistency %u", type);
}
#define SAVEt_PARSER 19
#define SAVEt_STACK_POS 20
#define SAVEt_READONLY_OFF 21
+#ifdef USE_ITHREADS
+# define SAVEt_COPFILEFREE 22
+#endif
-#define SAVEt_ARG1_MAX 21
+#define SAVEt_ARG1_MAX 22
/* two args */
-#define SAVEt_APTR 22
#define SAVEt_AV 23
#define SAVEt_DESTRUCTOR 24
#define SAVEt_DESTRUCTOR_X 25
#define SAVEt_SVREF 44
#define SAVEt_VPTR 45
#define SAVEt_ADELETE 46
+#define SAVEt_APTR 47
-#define SAVEt_ARG2_MAX 46
+#define SAVEt_ARG2_MAX 47
/* three args */
-#define SAVEt_DELETE 47
#define SAVEt_HELEM 48
#define SAVEt_PADSV_AND_MORTALIZE 49
#define SAVEt_SET_SVFLAGS 50
#define SAVEt_GVSLOT 51
#define SAVEt_AELEM 52
+#define SAVEt_DELETE 53
#define SAVEf_SETMAGIC 1
#define SAVEf_KEEPOLDELEM 2
#ifdef USE_ITHREADS
# define SAVECOPSTASH_FREE(c) SAVEIV((c)->cop_stashoff)
-# define SAVECOPFILE(c) SAVEPPTR(CopFILE(c))
-# define SAVECOPFILE_FREE(c) SAVESHAREDPV(CopFILE(c))
+# define SAVECOPFILE(c) SAVEIV((c)->cop_filegvoff)
+# define SAVECOPFILE_FREE(c) ( \
+ SAVEIV((c)->cop_filegvoff), \
+ save_pushptr((void *)(c), SAVEt_COPFILEFREE) \
+ )
#else
# /* XXX not refcounted */
# define SAVECOPSTASH_FREE(c) SAVESPTR(CopSTASH(c))
ptr = POPPTR(ss,ix);
TOPPTR(nss,ix) = parser_dup((const yy_parser*)ptr, param);
break;
+ case SAVEt_COPFILEFREE:
+ ptr = POPPTR(ss,ix);
+ TOPPTR(nss,ix) = any_dup(ptr, param->proto_perl);
+ break;
default:
Perl_croak(aTHX_
"panic: ss_dup inconsistency (%"IVdf")", (IV) type);
Zero(PL_sv_consts, SV_CONSTS_COUNT, SV*);
- /* This PV will be free'd special way so must set it same way op.c does */
- PL_compiling.cop_file = savesharedpv(PL_compiling.cop_file);
- ptr_table_store(PL_ptr_table, proto_perl->Icompiling.cop_file, PL_compiling.cop_file);
-
ptr_table_store(PL_ptr_table, &proto_perl->Icompiling, &PL_compiling);
PL_compiling.cop_warnings = DUP_WARNINGS(PL_compiling.cop_warnings);
CopHINTHASH_set(&PL_compiling, cophh_copy(CopHINTHASH_get(&PL_compiling)));
for (; o < PL_stashpadmax; ++o)
PL_stashpad[o] = hv_dup(proto_perl->Istashpad[o], param);
}
+ PL_filegvpadmax = proto_perl->Ifilegvpadmax;
+ PL_filegvpadix = proto_perl->Ifilegvpadix ;
+ Newx(PL_filegvpad, PL_filegvpadmax, GV *);
+ {
+ PADOFFSET o = 0;
+ for (; o < PL_filegvpadmax; ++o)
+ PL_filegvpad[o] = gv_dup(proto_perl->Ifilegvpad[o], param);
+ }
/* shortcuts to various I/O objects */
PL_ofsgv = gv_dup_inc(proto_perl->Iofsgv, param);