#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#define NEED_sv_2pv_flags
#define NEED_vnewSVpvf
#define NEED_warner
#include "ppport.h"
#include "const-c.inc"
/*#define DEBUG*/
#define PERL_VERSION_DECIMAL(r,v,s) (r*1000000 + v*1000 + s)
#define PERL_DECIMAL_VERSION \
PERL_VERSION_DECIMAL(PERL_REVISION,PERL_VERSION,PERL_SUBVERSION)
#define PERL_VERSION_GE(r,v,s) \
(PERL_DECIMAL_VERSION >= PERL_VERSION_DECIMAL(r,v,s))
#ifndef UNLIKELY
# define UNLIKELY(x) (x)
#endif
#ifndef LIKELY
# define LIKELY(x) (x)
#endif
#ifndef OpSIBLING
#define OpSIBLING(o) o->op_sibling
#endif
#ifndef OpMORESIB_set
#define OpMORESIB_set(o, sib) (o->op_sibling = sib)
#endif
#define OPT_MY 1
#define OPT_ALIAS 2
#ifdef DEBUG
static void analyse_op_tree(pTHX_ OP *o, int depth){
for(int i=0; i<depth; ++i)
printf(" ");
printf("%s=%p op_next=%p op_flags=%X op_private=%X\n", OP_NAME(o), (void*)o, (void*)o->op_next, o->op_flags, o->op_private);
if( o->op_flags & OPf_KIDS )
for(OP *kid=cUNOPo->op_first; kid; kid=OpSIBLING(kid))
analyse_op_tree(aTHX_ kid, depth+1);
}
#endif
static int sv_alias_get(pTHX_ SV* sv, MAGIC *mg){
#ifdef DEBUG
puts("sv_alias_get");
#endif
sv_setsv_flags(sv, mg->mg_obj, SV_GMAGIC);
return 0;
}
static int sv_alias_set(pTHX_ SV* sv, MAGIC *mg){
#ifdef DEBUG
puts("sv_alias_set");
#endif
sv_setsv_flags(mg->mg_obj, sv, 0);
SvSETMAGIC(mg->mg_obj);
return 0;
}
static MGVTBL sv_alias_vtbl = {
sv_alias_get,
sv_alias_set,
(U32 (*)(pTHX_ SV*, MAGIC*)) NULL,
(int (*)(pTHX_ SV*, MAGIC*)) NULL,
(int (*)(pTHX_ SV*, MAGIC*)) NULL
};
static void prepare_anonlist_node(pTHX_ OP * parent, OP * o, U32 opt);
static void prepare_anonhash_node(pTHX_ OP * parent, OP * o, U32 opt);
static inline void my_sv_set(pTHX_ SV ** dst, SV ** src, U32 is_alias){
if( src ){
if( is_alias ){
sv_magicext(*dst, *src, PERL_MAGIC_ext, &sv_alias_vtbl, NULL, 0);
}
else{
SvGETMAGIC(*src);
SvSetMagicSV_nosteal(*dst, *src);
}
}
else{
if( is_alias ){
warn("take alias on a non-exist magic element");
SvSetSV(*dst, &PL_sv_undef);
}
else{
SvSetMagicSV(*dst, &PL_sv_undef);
}
}
}
static inline int anonlist_set_common(pTHX_ SV * sv, MAGIC * mg, U32 opt){
SV ** list_holder = (SV**)(mg->mg_ptr + sizeof(I32*));
I32 * const_index = *(I32**)mg->mg_ptr;
I32 nitems = (mg->mg_len - sizeof(I32*)) / sizeof(SV*);
#ifdef DEBUG
printf("anonlist_set opt=%u, nitems=%d\nconst_index =", (unsigned int)opt, (int)nitems);
for(I32 i=0; const_index[i]<nitems; ++i)
printf(" %d", const_index[i]);
printf(" %d\n", nitems);
#endif
if( !SvROK(sv) ){
warn("assign non-ref value but SvTYPE=%d to a list pattern", SvTYPE(sv));
return 0;
}
SV * src = SvRV(sv);
if( SvTYPE(src)!=SVt_PVAV ){
warn("assign non array ref value but a ref of SvTYPE=%d to a list pattern", SvTYPE(SvRV(sv)));
return 0;
}
I32 key = 0;
for(I32 i=0; i<nitems; ++i, ++list_holder){
if( i==*const_index ){
if( SvOK(*list_holder) )
key = (I32) SvIV(*list_holder);
else
++key;
++const_index;
}
else{
switch( SvTYPE(*list_holder) ){
case SVt_PVAV:
{
AV *dst = (AV*)(*list_holder);
int magic = SvMAGICAL(dst) != 0;
I32 last_key = key < 0 ? -1 : AvFILL((AV*)src);
ENTER;
SAVEFREESV(SvREFCNT_inc_simple_NN((SV*)dst));
av_clear(dst);
av_extend(dst, last_key+1-key);
I32 j = 0;
while( key <= last_key ){
SV ** ptr_val = av_fetch((AV*)src, key, 0);
SV * new_sv = newSV(0);
my_sv_set(aTHX_ &new_sv, ptr_val, i != -*const_index-1 && opt & OPT_ALIAS);
SV ** didstore = av_store(dst, j, new_sv);
if( magic ){
if( !didstore )
sv_2mortal(new_sv);
SvSETMAGIC(new_sv);
}
++j;
++key;
}
#if PERL_VERSION_GE(5,14,0)
if( PL_delaymagic & DM_ARRAY_ISA )
SvSETMAGIC(*list_holder);
#endif
LEAVE;
}
break;
case SVt_PVHV:
{
HV *dst = (HV*)(*list_holder);
int magic = SvMAGICAL(dst) != 0;
I32 last_key = key < 0 ? -1 : AvFILL((AV*)src);
if( key <= last_key && ((last_key - key) & 1) == 0 )
Perl_warner(aTHX_ packWARN(WARN_MISC), "Odd number of elements in hash assignment");
ENTER;
SAVEFREESV(SvREFCNT_inc_simple_NN((SV*)dst));
hv_clear(dst);
while( key <= last_key ){
SV ** ptr_key = av_fetch((AV*)src, key, 0);
SV ** ptr_val = key < last_key ? av_fetch((AV*)src, key+1, 0) : NULL;
SV * new_key;
if( ptr_key )
if( SvGMAGICAL(*ptr_key) )
new_key = sv_mortalcopy(*ptr_key);
else
new_key = *ptr_key;
else
new_key = newSV(0);
SV * new_val = newSV(0);
my_sv_set(aTHX_ &new_val, ptr_val, i != -*const_index-1 && opt & OPT_ALIAS);
HE * didstore = hv_store_ent(dst, new_key, new_val, 0);
if( magic ){
if( !didstore )
sv_2mortal(new_val);
SvSETMAGIC(new_val);
}
key += 2;
}
LEAVE;
}
break;
default:
{
SV ** ptr_val = av_fetch((AV*)src, key, 0);
my_sv_set(aTHX_ list_holder, ptr_val, (i != -*const_index-1 && opt & OPT_ALIAS));
}
}
if( i == -*const_index-1 )
++const_index;
++key;
}
}
return 0;
}
static int anonlist_set(pTHX_ SV * sv, MAGIC * mg){
return anonlist_set_common(aTHX_ sv, mg, 0);
}
static int anonlist_alias_set(pTHX_ SV * sv, MAGIC * mg){
return anonlist_set_common(aTHX_ sv, mg, OPT_ALIAS);
}
static inline int anonhash_set_common(pTHX_ SV * sv, MAGIC * mg, U32 opt){
SV * src;
char *key = "";
STRLEN keylen = 0;
SV ** list_holder = (SV**)(mg->mg_ptr + sizeof(I32*));
I32 * const_index = *(I32**)mg->mg_ptr;
I32 nitems = (mg->mg_len - sizeof(I32*)) / sizeof(SV*);
#ifdef DEBUG
printf("anonhash_set opt=%u\n", (unsigned int)opt);
#endif
if( !SvROK(sv) ){
warn("assign non-ref value to a hash pattern");
return 0;
}
src = SvRV(sv);
switch( SvTYPE(src) ){
case SVt_PVHV:
case SVt_PVAV:
break;
default:
warn("assign non hash ref value but a ref to a SvTYPE=%d to a hash pattern", SvTYPE(src));
return 0;
}
for(I32 i=0; i<nitems; ++i, ++list_holder){
if( i==*const_index ){
key = SvPV(*list_holder, keylen);
#ifdef DEBUG
printf("got key: %s\n", key);
#endif
++const_index;
}
else{
if( SvTYPE(src)==SVt_PVHV ){
SV ** ptr_val = hv_fetch((HV*)src, key, keylen, 0);
#ifdef DEBUG
if( ptr_val )
printf("got val: %s\n", SvPV_nolen(*ptr_val));
else
printf("got val: NULL\n");
#endif
my_sv_set(aTHX_ list_holder, ptr_val, (i != -*const_index-1 && opt & OPT_ALIAS));
}
else{ /* SvTYPE(src)==SVt_PVAV */
I32 j = AvFILL((AV*)src);
if( j>=0 )
if( j & 1 )
--j;
else
warn("assign an array with odd number of elements to a hash pattern");
while( j>=0 ){
SV ** target_key_ptr = av_fetch((AV*)src, j, 0);
int found;
if( target_key_ptr ){
STRLEN target_keylen;
char * target_key = SvPV(*target_key_ptr, target_keylen);
found = (keylen == target_keylen && 0 == memcmp(key, target_key, keylen));
}
else{
found = (keylen == 0);
}
if( found )
break;
j -= 2;
}
U32 is_alias = (i != -*const_index-1 && opt & OPT_ALIAS);
if( j>=0 ){ /* found */
SV ** target_val_ptr = av_fetch((AV*)src, j+1, (is_alias ? 1 : 0));
my_sv_set(aTHX_ list_holder, target_val_ptr, is_alias);
}
else{ /* not found */
my_sv_set(aTHX_ list_holder, NULL, is_alias);
}
}
if( i == -*const_index-1 )
++const_index;
}
}
return 0;
}
static int anonhash_alias_set(pTHX_ SV * sv, MAGIC * mg){
return anonhash_set_common(aTHX_ sv, mg, OPT_ALIAS);
}
static int anonhash_set(pTHX_ SV * sv, MAGIC * mg){
return anonhash_set_common(aTHX_ sv, mg, 0);
}
static inline void init_set_vtbl(MGVTBL *vtbl, int(*setter)(pTHX_ SV*, MAGIC*)){
vtbl->svt_get = NULL;
vtbl->svt_set = setter;
vtbl->svt_len = NULL;
vtbl->svt_clear = NULL;
vtbl->svt_free = NULL;
}
static MGVTBL anonlist_vtbl, anonlist_alias_vtbl, anonhash_vtbl, anonhash_alias_vtbl;
static inline OP * my_pp_anonlisthash_common(pTHX_ MGVTBL *vtbl){
dVAR; dSP; dMARK;
int nitems = SP-MARK;
I32 holder_size = nitems * sizeof(SV*) + sizeof(I32*);
char * list_holder = alloca(holder_size);
Copy(MARK+1, list_holder + sizeof(I32*), nitems, SV*);
*(I32**)list_holder = (I32*)SvPVX(cSVOPx_sv(OpSIBLING(PL_op)));
SP = MARK+1;
SV * ret = SETs(sv_2mortal(newSV(0)));
SvUPGRADE(ret, SVt_PVMG);
sv_magicext(ret, ret, PERL_MAGIC_ext, vtbl, list_holder, holder_size);
RETURN;
}
static OP * my_pp_anonlist(pTHX){
return my_pp_anonlisthash_common(aTHX_ &anonlist_vtbl);
}
static OP * my_pp_anonlist_alias(pTHX){
return my_pp_anonlisthash_common(aTHX_ &anonlist_alias_vtbl);
}
static OP * my_pp_anonhash(pTHX){
return my_pp_anonlisthash_common(aTHX_ &anonhash_vtbl);
}
static OP * my_pp_anonhash_alias(pTHX){
return my_pp_anonlisthash_common(aTHX_ &anonhash_alias_vtbl);
}
#ifndef PadlistARRAY
typedef AV PADNAMELIST;
typedef SV PADNAME;
#endif
#ifndef padnamelist_fetch
# define padnamelist_fetch(a,b) *av_fetch(a,b,FALSE)
#endif
/* Taken from pp_ctl.c in 5.8.8 */
/* Thanks to Daniel Silva (dsilva @ github) */
static CV*
THX_find_runcv(pTHX_ U32 *db_seqp)
{
PERL_SI *si;
if (db_seqp)
*db_seqp = PL_curcop->cop_seq;
for (si = PL_curstackinfo; si; si = si->si_prev) {
I32 ix;
for (ix = si->si_cxix; ix >= 0; ix--) {
const PERL_CONTEXT *cx = &(si->si_cxstack[ix]);
if (CxTYPE(cx) == CXt_SUB || CxTYPE(cx) == CXt_FORMAT) {
CV * const cv = cx->blk_sub.cv;
/* skip DB:: code */
if (db_seqp && PL_debstash && CvSTASH(cv) == PL_debstash) {
*db_seqp = cx->blk_oldcop->cop_seq;
continue;
}
return cv;
}
else if (CxTYPE(cx) == CXt_EVAL && !CxTRYBLOCK(cx))
return PL_compcv;
}
}
return PL_main_cv;
}
#ifndef find_runcv
# define find_runcv(d) THX_find_runcv(aTHX_ d)
#endif
static OP* my_pp_fetch_next_padname(pTHX){
#ifdef DEBUG
puts("my_pp_fetch_next_padname");
#endif
CV *curr_cv = find_runcv(NULL);
if( curr_cv && CvPADLIST(curr_cv) ){
PADNAMELIST* padlist_av =
#ifdef PadlistARRAY
PadlistNAMES(CvPADLIST(curr_cv));
#else
(AV*)(*av_fetch((AV*)CvPADLIST(curr_cv), 0, FALSE));
#endif
PADNAME* padname_sv = padnamelist_fetch(
padlist_av,
OpSIBLING(PL_op)->op_targ
);
STRLEN padnamelen;
char * padname;
#ifdef PadlistARRAY
padnamelen = PadnameLEN(padname_sv);
padname = PadnamePV(padname_sv);
#else
padname = SvPV(padname_sv, padnamelen);
#endif
if( padnamelen>=3 && padname[0]=='$' && padname[1]=='#' ){
#ifdef DEBUG
printf("got name: %s\n", padname+2);
#endif
sv_setpvn(cSVOP_sv, padname+2, padnamelen-2);
}
else{
#ifdef DEBUG
printf("got name: %s\n", padname+1);
#endif
sv_setpvn(cSVOP_sv, padname+1, padnamelen-1);
}
}
PL_op->op_ppaddr = PL_ppaddr[OP_CONST];
#ifdef DEBUG
puts("my_pp_fetch_next_padname end");
#endif
return PL_ppaddr[OP_CONST](aTHXR);
}
static void prepare_anonlisthash_list1(pTHX_ OP *o, U32 opt, UV *const_count, UV *pattern_count, int *last_is_const_p){
for(OP *kid=cLISTOPo->op_first; kid; kid=OpSIBLING(kid))
switch( kid->op_type ){
case OP_PUSHMARK:
break;
case OP_NULL:
case OP_LIST:
if( kid->op_flags & OPf_KIDS )
prepare_anonlisthash_list1(aTHX_ kid, opt, const_count, pattern_count, last_is_const_p);
break;
case OP_ANONLIST:
++*pattern_count;
prepare_anonlist_node(aTHX_ o, kid, opt);
kid = OpSIBLING(kid); /* skip pattern structure op node */
if( last_is_const_p )
*last_is_const_p = 0;
break;
case OP_ANONHASH:
++*pattern_count;
prepare_anonhash_node(aTHX_ o, kid, opt);
kid = OpSIBLING(kid); /* skip pattern structure op node */
if( last_is_const_p )
*last_is_const_p = 0;
break;
case OP_CONST:
case OP_UNDEF:
++*const_count;
if( last_is_const_p )
*last_is_const_p = 1;
break;
case OP_PADAV:
case OP_PADHV:
case OP_RV2AV:
case OP_RV2HV:
kid->op_flags |= OPf_REF;
/* fall through */
case OP_PADSV:
case OP_RV2SV:
if( last_is_const_p ){
if( *last_is_const_p )
*last_is_const_p = 0;
else
++*const_count;
}
break;
default:
croak("invalid des pattern (can't contain %s)", OP_NAME(kid));
}
}
static void prepare_anonlisthash_list2(pTHX_ OP *o, U32 opt, I32 *const_index_buffer, I32 *p, I32 *q, int *last_is_const_p){
OP *kid0 = cLISTOPo->op_first;
for(OP *kid=OpSIBLING(kid0); kid; kid0=kid, kid=OpSIBLING(kid)){
if( (kid->op_flags & OPf_KIDS) && (kid->op_type == OP_LIST || kid->op_type == OP_NULL) ){
prepare_anonlisthash_list2(aTHX_ kid, opt, const_index_buffer, p, q, last_is_const_p);
continue;
}
if( kid->op_type == OP_CONST || kid->op_type == OP_UNDEF ){
const_index_buffer[(*p)++] = *q;
if( last_is_const_p )
*last_is_const_p = 1;
}
else if( kid->op_type == OP_ANONLIST || kid->op_type == OP_ANONHASH ){
const_index_buffer[(*p)++] = -*q-1;
kid = OpSIBLING(kid);
if( last_is_const_p )
*last_is_const_p = 0;
}
else{
if( last_is_const_p ){
if( *last_is_const_p ){
*last_is_const_p = 0;
}
else{
#ifdef DEBUG
printf("put const index\n");
#endif
const_index_buffer[(*p)++] = (*q)++;
switch( kid->op_type ){
case OP_PADSV:
case OP_PADAV:
case OP_PADHV: {
OP * keyname_op = newSVOP(OP_CUSTOM, 0, newSV(0));
keyname_op->op_ppaddr = my_pp_fetch_next_padname;
#ifdef op_sibling_splice
op_sibling_splice(o, kid0, 0, keyname_op);
#else
OpMORESIB_set(kid0, keyname_op);
OpMORESIB_set(keyname_op, kid);
#endif
break;
}
case OP_RV2SV:
case OP_RV2AV:
case OP_RV2HV:
if( kid->op_flags & OPf_KIDS ){
OP * gvop = kUNOP->op_first;
if( gvop->op_type == OP_GVSV || gvop->op_type == OP_GV ){
#ifdef GvNAME_HEK
HEK * gv_name_hek = GvNAME_HEK(cGVOPx_gv(gvop));
SV * keyname_sv = newSVpvn(HEK_KEY(gv_name_hek), HEK_LEN(gv_name_hek));
#else
GV * gv = cGVOPx_gv(gvop);
SV * keyname_sv = newSVpvn(GvNAME(gv), GvNAMELEN(gv));
#endif
OP * keyname_op = newSVOP(OP_CONST, 0, keyname_sv);
#ifdef op_sibling_splice
op_sibling_splice(o, kid0, 0,
keyname_op);
#else
OpMORESIB_set(kid0, keyname_op);
OpMORESIB_set(keyname_op, kid);
#endif
}
}
break;
}
}
}
}
++*q;
}
}
static void prepare_anonlisthash_node(pTHX_ OP *parent, OP *o, U32 opt,
int is_hash){
UV const_count = 0;
UV pattern_count = 0;
PERL_UNUSED_ARG(parent);
if( is_hash ){
int last_is_const = 0;
prepare_anonlisthash_list1(aTHX_ o, opt, &const_count, &pattern_count, &last_is_const);
}
else{
prepare_anonlisthash_list1(aTHX_ o, opt, &const_count, &pattern_count, NULL);
}
#ifdef DEBUG
printf("const_count=%u, pattern_count=%u\n", (unsigned int)const_count, (unsigned int)pattern_count);
#endif
I32 p = 0, q = 0;
I32 buffer_len = (const_count+pattern_count+1) * sizeof(I32);
SV *buffer_sv = newSV(buffer_len+1);
*(SvPVX(buffer_sv)+buffer_len) = '\0';
I32 * const_index_buffer = (I32*)SvPVX(buffer_sv);
if( is_hash ){
int last_is_const = 0;
prepare_anonlisthash_list2(aTHX_ o, opt, const_index_buffer, &p, &q, &last_is_const);
}
else{
prepare_anonlisthash_list2(aTHX_ o, opt, const_index_buffer, &p, &q, NULL);
}
const_index_buffer[p] = q;
#ifdef DEBUG
printf("const_index:");
for(I32 i=0; i<=p; ++i)
printf(" %d", const_index_buffer[i]);
puts("");
#endif
OP *buffer_op = newSVOP(OP_CONST, 0, buffer_sv);
buffer_op->op_type = OP_NULL;
buffer_op->op_targ = OP_CONST;
#ifdef op_sibling_splice
op_sibling_splice(parent, o, 0, buffer_op);
#else
OpMORESIB_set(buffer_op, OpSIBLING(o));
OpMORESIB_set(o, buffer_op);
#endif
}
static void prepare_anonlist_node(pTHX_ OP * parent, OP * o, U32 opt){
#ifdef DEBUG
printf("prepare anonlist node\n");
#endif
prepare_anonlisthash_node(aTHX_ parent, o, opt, 0);
if( opt & OPT_ALIAS )
o->op_ppaddr = my_pp_anonlist_alias;
else
o->op_ppaddr = my_pp_anonlist;
}
static void prepare_anonhash_node(pTHX_ OP * parent, OP * o, U32 opt){
#ifdef DEBUG
printf("prepare anonhash node\n");
#endif
prepare_anonlisthash_node(aTHX_ parent, o, opt, 1);
if( opt & OPT_ALIAS )
o->op_ppaddr = my_pp_anonhash_alias;
else
o->op_ppaddr = my_pp_anonhash;
}
static unsigned int traverse_args(pTHX_ U32 opt, unsigned int found_index,
OP * parent, OP * o){
if( o->op_type == OP_NULL ){
if( o->op_flags & OPf_KIDS )
for(OP *kid=cUNOPo->op_first; kid; kid=OpSIBLING(kid))
found_index = traverse_args(aTHX_ opt, found_index, o,kid);
return found_index;
}
/* use the second kid (the first arg) */
if( found_index==1 ){
switch( o->op_type ){
case OP_ANONLIST:
prepare_anonlist_node(aTHX_ parent, o, opt);
break;
case OP_ANONHASH:
prepare_anonhash_node(aTHX_ parent, o, opt);
break;
default:
croak("des arg must be exactly an anonymous list or anonymous hash");
}
}
else if( found_index==4 ){
croak("des arg must be exactly an anonymous list or anonymous hash");
}
return found_index+1;
}
static OP* my_pp_entersub(pTHX){
dVAR;
dMARK; /* drop the first pushmark */
dSP;
POPs; /* drop the sub name */
#ifdef DEBUG
printf("my_pp_entersub\n");
#endif
RETURN;
}
static OP* des_check(pTHX_ OP* o, GV *namegv, SV *ckobj){
#ifdef DEBUG
analyse_op_tree(aTHX_ o, 0);
#endif
if( o->op_flags & OPf_KIDS ){
unsigned int found_index = 0;
for(OP *kid=cUNOPo->op_first; kid; kid=OpSIBLING(kid))
found_index = traverse_args(aTHX_ 0, found_index, o, kid);
o->op_ppaddr = my_pp_entersub;
}
return o;
}
static OP* des_alias_check(pTHX_ OP* o, GV *namegv, SV *ckobj){
#ifdef DEBUG
analyse_op_tree(aTHX_ o, 0);
#endif
if( o->op_flags & OPf_KIDS ){
unsigned int found_index = 0;
for(OP *kid=cUNOPo->op_first; kid; kid=OpSIBLING(kid))
found_index = traverse_args(aTHX_ OPT_ALIAS,found_index,o,kid);
o->op_ppaddr = my_pp_entersub;
}
return o;
}
#if !PERL_VERSION_GE(5,14,0)
static CV* my_des_cvs[2];
static OP* (*orig_entersub_check)(pTHX_ OP*);
static OP* my_entersub_check(pTHX_ OP* o){
CV *cv = NULL;
OP *cvop = OpSIBLING(((OpSIBLING(cUNOPo->op_first)) ? cUNOPo : ((UNOP*)cUNOPo->op_first))->op_first);
while( OpSIBLING(cvop) )
cvop = OpSIBLING(cvop);
if( cvop->op_type == OP_RV2CV && !(o->op_private & OPpENTERSUB_AMPER) ){
SVOP *tmpop = (SVOP*)((UNOP*)cvop)->op_first;
switch (tmpop->op_type) {
case OP_GV: {
GV *gv = cGVOPx_gv(tmpop);
cv = GvCVu(gv);
if (!cv)
tmpop->op_private |= OPpEARLY_CV;
} break;
case OP_CONST: {
SV *sv = cSVOPx_sv(tmpop);
if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVCV)
cv = (CV*)SvRV(sv);
} break;
}
if( cv==my_des_cvs[0] )
return des_check(aTHX_ o, NULL, NULL);
if( cv==my_des_cvs[1] )
return des_alias_check(aTHX_ o, NULL, NULL);
}
return orig_entersub_check(aTHX_ o);
}
#endif
MODULE = DestructAssign PACKAGE = DestructAssign
INCLUDE: const-xs.inc
BOOT:
init_set_vtbl(&anonlist_vtbl, anonlist_set);
init_set_vtbl(&anonlist_alias_vtbl, anonlist_alias_set);
init_set_vtbl(&anonhash_vtbl, anonhash_set);
init_set_vtbl(&anonhash_alias_vtbl, anonhash_alias_set);
#if PERL_VERSION_GE(5,14,0)
cv_set_call_checker(get_cv("DestructAssign::des", TRUE), des_check, &PL_sv_undef);
cv_set_call_checker(get_cv("DestructAssign::des_alias", TRUE), des_alias_check, &PL_sv_undef);
#else
my_des_cvs[0] = get_cv("DestructAssign::des", TRUE);
my_des_cvs[1] = get_cv("DestructAssign::des_alias", TRUE);
orig_entersub_check = PL_check[OP_ENTERSUB];
PL_check[OP_ENTERSUB] = my_entersub_check;
#endif